diff options
Diffstat (limited to 'arch/powerpc')
249 files changed, 3048 insertions, 2115 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index e93df95b79e7..2580e27e4328 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 @@ -213,7 +214,6 @@ config PPC select GENERIC_IRQ_SHOW_LEVEL select GENERIC_PCI_IOMAP if PCI select GENERIC_SMP_IDLE_THREAD - select GENERIC_TIME_VSYSCALL select HAS_IOPORT if PCI select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_HUGE_VMALLOC if HAVE_ARCH_HUGE_VMAP @@ -256,7 +256,6 @@ config PPC select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER if !COMPILE_TEST && (PPC64 || (PPC32 && CC_IS_GCC)) select HAVE_GCC_PLUGINS - select HAVE_GENERIC_VDSO select HAVE_HARDLOCKUP_DETECTOR_ARCH if PPC_BOOK3S_64 && SMP select HAVE_HARDLOCKUP_DETECTOR_PERF if PERF_EVENTS && HAVE_PERF_EVENTS_NMI select HAVE_HW_BREAKPOINT if PERF_EVENTS && (PPC_BOOK3S || PPC_8xx) @@ -281,10 +280,13 @@ config PPC select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP select HAVE_PREEMPT_DYNAMIC_KEY + select HAVE_POSIX_CPU_TIMERS_TASK_WORK select HAVE_RETHOOK if KPROBES select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RELIABLE_STACKTRACE select HAVE_RSEQ + select HAVE_RUST if PPC32 + select HAVE_RUST if PPC64 && CPU_LITTLE_ENDIAN select HAVE_SAMPLE_FTRACE_DIRECT if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS select HAVE_SAMPLE_FTRACE_DIRECT_MULTI if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS select HAVE_SETUP_PER_CPU_AREA if PPC64 @@ -328,6 +330,7 @@ config PPC select SYSCTL_EXCEPTION_TRACE select THREAD_INFO_IN_TASK select TRACE_IRQFLAGS_SUPPORT + select VDSO_DATASTORE select VDSO_GETRANDOM # # Please keep this list sorted alphabetically. diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index f15e5920080b..e8718bc13eeb 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -83,11 +83,10 @@ config MSI_BITMAP_SELFTEST depends on DEBUG_KERNEL config GUEST_STATE_BUFFER_TEST - def_tristate n + def_tristate KUNIT_ALL_TESTS prompt "Enable Guest State Buffer unit tests" depends on KUNIT depends on KVM_BOOK3S_HV_POSSIBLE - default KUNIT_ALL_TESTS help The Guest State Buffer is a data format specified in the PAPR. It is by hcalls to communicate the state of L2 guests between diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index a58b1029592c..9385db478c59 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -61,6 +61,13 @@ else KBUILD_LDFLAGS_MODULE += $(objtree)/arch/powerpc/lib/crtsavres.o endif +ifdef CONFIG_PPC64 +KBUILD_RUSTFLAGS += --target=powerpc64le-unknown-linux-gnu +KBUILD_RUSTFLAGS += -Ctarget-feature=-mma,-vsx,-hard-float,-altivec +else +KBUILD_RUSTFLAGS += --target=powerpc-unknown-linux-gnu +endif + ifdef CONFIG_CPU_LITTLE_ENDIAN KBUILD_CPPFLAGS += -mlittle-endian KBUILD_LDFLAGS += -EL 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/serial.c b/arch/powerpc/boot/serial.c index c6d32a8c3612..1d221ff420fd 100644 --- a/arch/powerpc/boot/serial.c +++ b/arch/powerpc/boot/serial.c @@ -37,7 +37,6 @@ static void serial_edit_cmdline(char *buf, int len, unsigned int timeout) char ch, *cp; struct serial_console_data *scdp = console_ops.data; - cp = buf; count = strlen(buf); cp = &buf[count]; count++; diff --git a/arch/powerpc/boot/simpleboot.c b/arch/powerpc/boot/simpleboot.c index c80691d83880..27591df41e9e 100644 --- a/arch/powerpc/boot/simpleboot.c +++ b/arch/powerpc/boot/simpleboot.c @@ -68,7 +68,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, /* finally, setup the timebase */ node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", "cpu", sizeof("cpu")); - if (!node) + if (node < 0) fatal("Cannot find cpu node\n"); timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); if (timebase && (size == 4)) diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c index 31eece29f56d..b12aa2c0b8e7 100644 --- a/arch/powerpc/boot/stdio.c +++ b/arch/powerpc/boot/stdio.c @@ -326,17 +326,6 @@ int vsprintf(char *buf, const char *fmt, va_list args) return str-buf; } -int sprintf(char * buf, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i=vsprintf(buf,fmt,args); - va_end(args); - return i; -} - static char sprint_buf[1024]; int diff --git a/arch/powerpc/boot/stdio.h b/arch/powerpc/boot/stdio.h index 884d5959a9ae..d5a7a0f54453 100644 --- a/arch/powerpc/boot/stdio.h +++ b/arch/powerpc/boot/stdio.h @@ -12,9 +12,6 @@ extern int printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); #define fprintf(fmt, args...) printf(args) -extern int sprintf(char *buf, const char *fmt, ...) - __attribute__((format(printf, 2, 3))); - extern int vsprintf(char *buf, const char *fmt, va_list args); #endif /* _PPC_BOOT_STDIO_H_ */ diff --git a/arch/powerpc/boot/string.S b/arch/powerpc/boot/string.S index d2a2dbf1eefc..76801eb6d937 100644 --- a/arch/powerpc/boot/string.S +++ b/arch/powerpc/boot/string.S @@ -18,19 +18,6 @@ strcpy: bne 1b blr - .globl strncpy -strncpy: - cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r6,r3,-1 - addi r4,r4,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r6) - bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ - blr - .globl strcat strcat: addi r5,r3,-1 diff --git a/arch/powerpc/boot/string.h b/arch/powerpc/boot/string.h index 8c2ec0c05e4e..2b28d185343c 100644 --- a/arch/powerpc/boot/string.h +++ b/arch/powerpc/boot/string.h @@ -4,7 +4,6 @@ #include <stddef.h> extern char *strcpy(char *dest, const char *src); -extern char *strncpy(char *dest, const char *src, size_t n); extern char *strcat(char *dest, const char *src); extern char *strchr(const char *s, int c); extern char *strrchr(const char *s, int c); diff --git a/arch/powerpc/boot/treeboot-akebono.c b/arch/powerpc/boot/treeboot-akebono.c index e3cc2599869c..1b529037480f 100644 --- a/arch/powerpc/boot/treeboot-akebono.c +++ b/arch/powerpc/boot/treeboot-akebono.c @@ -146,7 +146,7 @@ void platform_init(char *userdata) node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", "cpu", sizeof("cpu")); - if (!node) + if (node < 0) fatal("Cannot find cpu node\n"); timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); if (timebase && (size == 4)) diff --git a/arch/powerpc/boot/treeboot-currituck.c b/arch/powerpc/boot/treeboot-currituck.c index d53e8a592f81..5b5363b74f9f 100644 --- a/arch/powerpc/boot/treeboot-currituck.c +++ b/arch/powerpc/boot/treeboot-currituck.c @@ -102,7 +102,7 @@ void platform_init(void) node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", "cpu", sizeof("cpu")); - if (!node) + if (node < 0) fatal("Cannot find cpu node\n"); timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); if (timebase && (size == 4)) 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/configs/44x/akebono_defconfig b/arch/powerpc/configs/44x/akebono_defconfig index 11ad5ed3cc90..bdb0e6ece6ec 100644 --- a/arch/powerpc/configs/44x/akebono_defconfig +++ b/arch/powerpc/configs/44x/akebono_defconfig @@ -124,7 +124,6 @@ CONFIG_XMON_DEFAULT=y CONFIG_PPC_EARLY_DEBUG=y CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0x00010000 CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x33f -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/44x/bamboo_defconfig b/arch/powerpc/configs/44x/bamboo_defconfig index acbce718eaa8..bfffea3a54b2 100644 --- a/arch/powerpc/configs/44x/bamboo_defconfig +++ b/arch/powerpc/configs/44x/bamboo_defconfig @@ -46,6 +46,5 @@ CONFIG_DETECT_HUNG_TASK=y # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/44x/currituck_defconfig b/arch/powerpc/configs/44x/currituck_defconfig index 7283b7d4a1a5..6d6ec5d569b1 100644 --- a/arch/powerpc/configs/44x/currituck_defconfig +++ b/arch/powerpc/configs/44x/currituck_defconfig @@ -83,7 +83,6 @@ CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0x10000000 CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x200 CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/44x/ebony_defconfig b/arch/powerpc/configs/44x/ebony_defconfig index 93d2a4e64af9..0d6f9bdf8ad3 100644 --- a/arch/powerpc/configs/44x/ebony_defconfig +++ b/arch/powerpc/configs/44x/ebony_defconfig @@ -52,7 +52,6 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/44x/eiger_defconfig b/arch/powerpc/configs/44x/eiger_defconfig index 509300f400e2..48ab405ab80b 100644 --- a/arch/powerpc/configs/44x/eiger_defconfig +++ b/arch/powerpc/configs/44x/eiger_defconfig @@ -79,7 +79,6 @@ CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_CTS=y CONFIG_CRYPTO_LRW=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y diff --git a/arch/powerpc/configs/44x/fsp2_defconfig b/arch/powerpc/configs/44x/fsp2_defconfig index 5492537f4c6c..b8b21fa15a07 100644 --- a/arch/powerpc/configs/44x/fsp2_defconfig +++ b/arch/powerpc/configs/44x/fsp2_defconfig @@ -115,7 +115,6 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig index fb9a15573546..4f7cd127dc77 100644 --- a/arch/powerpc/configs/44x/icon_defconfig +++ b/arch/powerpc/configs/44x/icon_defconfig @@ -82,6 +82,5 @@ CONFIG_DETECT_HUNG_TASK=y # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/44x/iss476-smp_defconfig b/arch/powerpc/configs/44x/iss476-smp_defconfig index 0f6380e1e612..5188ec5406fd 100644 --- a/arch/powerpc/configs/44x/iss476-smp_defconfig +++ b/arch/powerpc/configs/44x/iss476-smp_defconfig @@ -62,7 +62,6 @@ CONFIG_DETECT_HUNG_TASK=y CONFIG_PPC_EARLY_DEBUG=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/44x/katmai_defconfig b/arch/powerpc/configs/44x/katmai_defconfig index 1a0f1c3e0ee9..59622bd1327d 100644 --- a/arch/powerpc/configs/44x/katmai_defconfig +++ b/arch/powerpc/configs/44x/katmai_defconfig @@ -51,6 +51,5 @@ CONFIG_DETECT_HUNG_TASK=y # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/44x/rainier_defconfig b/arch/powerpc/configs/44x/rainier_defconfig index 6dd67de06a0b..22d10c33f374 100644 --- a/arch/powerpc/configs/44x/rainier_defconfig +++ b/arch/powerpc/configs/44x/rainier_defconfig @@ -57,6 +57,5 @@ CONFIG_PPC_EARLY_DEBUG=y CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0xef600300 CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig index e28d76416537..1e883938ca11 100644 --- a/arch/powerpc/configs/44x/redwood_defconfig +++ b/arch/powerpc/configs/44x/redwood_defconfig @@ -78,7 +78,6 @@ CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_CTS=y CONFIG_CRYPTO_LRW=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y diff --git a/arch/powerpc/configs/44x/sequoia_defconfig b/arch/powerpc/configs/44x/sequoia_defconfig index b4984eab43eb..ce8912b406eb 100644 --- a/arch/powerpc/configs/44x/sequoia_defconfig +++ b/arch/powerpc/configs/44x/sequoia_defconfig @@ -58,6 +58,5 @@ CONFIG_DETECT_HUNG_TASK=y # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/44x/taishan_defconfig b/arch/powerpc/configs/44x/taishan_defconfig index 3ea5932ab852..8263b3b7d0a1 100644 --- a/arch/powerpc/configs/44x/taishan_defconfig +++ b/arch/powerpc/configs/44x/taishan_defconfig @@ -52,6 +52,5 @@ CONFIG_DETECT_HUNG_TASK=y # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/44x/warp_defconfig b/arch/powerpc/configs/44x/warp_defconfig index 5757625469c4..d6014b9c5708 100644 --- a/arch/powerpc/configs/44x/warp_defconfig +++ b/arch/powerpc/configs/44x/warp_defconfig @@ -12,7 +12,7 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_EBONY is not set CONFIG_WARP=y -CONFIG_PPC4xx_GPIO=y +CONFIG_GPIO_PPC44X=y CONFIG_HZ_1000=y CONFIG_CMDLINE="ip=on" # CONFIG_PCI is not set diff --git a/arch/powerpc/configs/52xx/cm5200_defconfig b/arch/powerpc/configs/52xx/cm5200_defconfig index 2412a6bf7ee6..ddf1280fe295 100644 --- a/arch/powerpc/configs/52xx/cm5200_defconfig +++ b/arch/powerpc/configs/52xx/cm5200_defconfig @@ -75,4 +75,3 @@ CONFIG_PRINTK_TIME=y CONFIG_DETECT_HUNG_TASK=y # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/52xx/motionpro_defconfig b/arch/powerpc/configs/52xx/motionpro_defconfig index 6186ead1e105..d7165dbed529 100644 --- a/arch/powerpc/configs/52xx/motionpro_defconfig +++ b/arch/powerpc/configs/52xx/motionpro_defconfig @@ -88,4 +88,3 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y CONFIG_DETECT_HUNG_TASK=y # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/52xx/tqm5200_defconfig b/arch/powerpc/configs/52xx/tqm5200_defconfig index 688f703d8e22..1d2d68b0f137 100644 --- a/arch/powerpc/configs/52xx/tqm5200_defconfig +++ b/arch/powerpc/configs/52xx/tqm5200_defconfig @@ -89,4 +89,3 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y CONFIG_DETECT_HUNG_TASK=y # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/83xx/asp8347_defconfig b/arch/powerpc/configs/83xx/asp8347_defconfig index 10192410b33c..07e00c8d6023 100644 --- a/arch/powerpc/configs/83xx/asp8347_defconfig +++ b/arch/powerpc/configs/83xx/asp8347_defconfig @@ -68,4 +68,3 @@ CONFIG_NFS_FS=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig index 16a42e2267fb..140dd429278e 100644 --- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig @@ -83,4 +83,3 @@ CONFIG_NFS_FS=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_DETECT_HUNG_TASK=y -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig index 80d40ae668eb..7616771f072c 100644 --- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig @@ -82,4 +82,3 @@ CONFIG_NFS_FS=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_DETECT_HUNG_TASK=y -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig index b99caba8724a..e670d16e6fd7 100644 --- a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig @@ -74,4 +74,3 @@ CONFIG_NLS_CODEPAGE_932=y CONFIG_NLS_ISO8859_8=y CONFIG_NLS_ISO8859_1=y CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig index 11163052fdba..fcf91b52af2d 100644 --- a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig +++ b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig @@ -80,4 +80,3 @@ CONFIG_TMPFS=y CONFIG_NFS_FS=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig index 312d39e4242c..7d060b6f49ca 100644 --- a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig +++ b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig @@ -72,4 +72,3 @@ CONFIG_TMPFS=y CONFIG_NFS_FS=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig index ac27f99faab8..4567345aea9a 100644 --- a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig @@ -76,4 +76,3 @@ CONFIG_NFS_FS=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/85xx-hw.config b/arch/powerpc/configs/85xx-hw.config index 2b19c20a9a2c..6b8471810143 100644 --- a/arch/powerpc/configs/85xx-hw.config +++ b/arch/powerpc/configs/85xx-hw.config @@ -90,6 +90,7 @@ CONFIG_PPC_EPAPR_HV_BYTECHAN=y CONFIG_QE_GPIO=y CONFIG_QUICC_ENGINE=y CONFIG_RAPIDIO=y +CONFIG_RAS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_CMOS=y CONFIG_RTC_DRV_DS1307=y diff --git a/arch/powerpc/configs/amigaone_defconfig b/arch/powerpc/configs/amigaone_defconfig index 69ef3dc31c4b..11dfd964465a 100644 --- a/arch/powerpc/configs/amigaone_defconfig +++ b/arch/powerpc/configs/amigaone_defconfig @@ -76,7 +76,6 @@ CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_TILEBLITTING=y CONFIG_FB_RADEON=y CONFIG_FB_3DFX=y @@ -112,5 +111,4 @@ CONFIG_DEBUG_MUTEXES=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y CONFIG_CRYPTO_CBC=m -CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig index 7a31b52e92e1..b5ed8945ec33 100644 --- a/arch/powerpc/configs/cell_defconfig +++ b/arch/powerpc/configs/cell_defconfig @@ -197,5 +197,4 @@ CONFIG_DEBUG_MUTEXES=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y diff --git a/arch/powerpc/configs/chrp32_defconfig b/arch/powerpc/configs/chrp32_defconfig index b799c95480ae..36662f293587 100644 --- a/arch/powerpc/configs/chrp32_defconfig +++ b/arch/powerpc/configs/chrp32_defconfig @@ -76,7 +76,6 @@ CONFIG_SERIAL_8250_CONSOLE=y CONFIG_NVRAM=y # CONFIG_HWMON is not set CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_OF=y CONFIG_FB_MATROX=y CONFIG_FB_MATROX_MILLENIUM=y @@ -116,5 +115,4 @@ CONFIG_DEBUG_MUTEXES=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y CONFIG_CRYPTO_CBC=m -CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/ep8248e_defconfig b/arch/powerpc/configs/ep8248e_defconfig index 0d8d3f41f194..c3167726706d 100644 --- a/arch/powerpc/configs/ep8248e_defconfig +++ b/arch/powerpc/configs/ep8248e_defconfig @@ -64,7 +64,6 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_BDI_SWITCH=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/fsl-emb-nonhw.config b/arch/powerpc/configs/fsl-emb-nonhw.config index 2f81bc2d819e..391c99117ee0 100644 --- a/arch/powerpc/configs/fsl-emb-nonhw.config +++ b/arch/powerpc/configs/fsl-emb-nonhw.config @@ -19,7 +19,6 @@ CONFIG_CPUSETS=y CONFIG_CRAMFS=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y CONFIG_DEBUG_FS=y diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig index 04bbb37f5978..04afb1594890 100644 --- a/arch/powerpc/configs/g5_defconfig +++ b/arch/powerpc/configs/g5_defconfig @@ -85,6 +85,8 @@ CONFIG_PMAC_SMU=y CONFIG_MAC_EMUMOUSEBTN=y CONFIG_WINDFARM=y CONFIG_WINDFARM_PM81=y +CONFIG_WINDFARM_PM72=y +CONFIG_WINDFARM_RM31=y CONFIG_WINDFARM_PM91=y CONFIG_WINDFARM_PM112=y CONFIG_WINDFARM_PM121=y @@ -121,7 +123,6 @@ CONFIG_I2C_CHARDEV=y CONFIG_AGP=m CONFIG_AGP_UNINORTH=m CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_TILEBLITTING=y CONFIG_FB_OF=y CONFIG_FB_NVIDIA=y @@ -234,7 +235,6 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_MUTEXES=y CONFIG_BOOTX_TEXT=y CONFIG_CRYPTO_BENCHMARK=m -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m diff --git a/arch/powerpc/configs/linkstation_defconfig b/arch/powerpc/configs/linkstation_defconfig index 31f84d08b6ef..e1c1b00b0c81 100644 --- a/arch/powerpc/configs/linkstation_defconfig +++ b/arch/powerpc/configs/linkstation_defconfig @@ -128,7 +128,6 @@ CONFIG_NLS_UTF8=m CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA1=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_SERPENT=m diff --git a/arch/powerpc/configs/mgcoge_defconfig b/arch/powerpc/configs/mgcoge_defconfig index f65001e7877f..a31e1184f912 100644 --- a/arch/powerpc/configs/mgcoge_defconfig +++ b/arch/powerpc/configs/mgcoge_defconfig @@ -78,5 +78,4 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_SCHED_DEBUG is not set CONFIG_BDI_SWITCH=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig index a815d9e5e3e8..d603d8e93958 100644 --- a/arch/powerpc/configs/mpc83xx_defconfig +++ b/arch/powerpc/configs/mpc83xx_defconfig @@ -98,6 +98,5 @@ CONFIG_NFS_FS=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_DEV_TALITOS=y diff --git a/arch/powerpc/configs/mvme5100_defconfig b/arch/powerpc/configs/mvme5100_defconfig index c82754c14e15..3918768d7cd2 100644 --- a/arch/powerpc/configs/mvme5100_defconfig +++ b/arch/powerpc/configs/mvme5100_defconfig @@ -113,7 +113,6 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=20 CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_SHA1=m CONFIG_CRYPTO_BLOWFISH=m diff --git a/arch/powerpc/configs/pasemi_defconfig b/arch/powerpc/configs/pasemi_defconfig index 8bbf51b38480..89bcbeb05067 100644 --- a/arch/powerpc/configs/pasemi_defconfig +++ b/arch/powerpc/configs/pasemi_defconfig @@ -98,7 +98,6 @@ CONFIG_SENSORS_LM85=y CONFIG_SENSORS_LM90=y CONFIG_DRM=y CONFIG_DRM_RADEON=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_TILEBLITTING=y CONFIG_FB_VGA16=y CONFIG_FB_NVIDIA=y diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig index ae45f70b29f0..728c8cabfb83 100644 --- a/arch/powerpc/configs/pmac32_defconfig +++ b/arch/powerpc/configs/pmac32_defconfig @@ -281,7 +281,6 @@ CONFIG_DETECT_HUNG_TASK=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y CONFIG_BOOTX_TEXT=y -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m diff --git a/arch/powerpc/configs/powernv_defconfig b/arch/powerpc/configs/powernv_defconfig index cc9802420237..2b9b46704180 100644 --- a/arch/powerpc/configs/powernv_defconfig +++ b/arch/powerpc/configs/powernv_defconfig @@ -196,7 +196,6 @@ CONFIG_I2C_CHARDEV=y # CONFIG_PTP_1588_CLOCK is not set CONFIG_DRM=y CONFIG_DRM_AST=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_OF=y CONFIG_FB_MATROX=m CONFIG_FB_MATROX_MILLENIUM=y @@ -315,7 +314,6 @@ CONFIG_FTR_FIXUP_SELFTEST=y CONFIG_MSI_BITMAP_SELFTEST=y CONFIG_XMON=y CONFIG_CRYPTO_BENCHMARK=m -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_WP512=m diff --git a/arch/powerpc/configs/ppc44x_defconfig b/arch/powerpc/configs/ppc44x_defconfig index 41c930f74ed4..d351551e266f 100644 --- a/arch/powerpc/configs/ppc44x_defconfig +++ b/arch/powerpc/configs/ppc44x_defconfig @@ -22,7 +22,7 @@ CONFIG_GLACIER=y CONFIG_REDWOOD=y CONFIG_EIGER=y CONFIG_YOSEMITE=y -CONFIG_PPC4xx_GPIO=y +CONFIG_GPIO_PPC44X=y CONFIG_MATH_EMULATION=y CONFIG_NET=y CONFIG_PACKET=y @@ -93,6 +93,5 @@ CONFIG_NLS_ISO8859_1=m CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y # CONFIG_CRYPTO_HW is not set CONFIG_VIRTUALIZATION=y diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 3bf518e3a573..1eb8e3457e8b 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -210,7 +210,6 @@ CONFIG_BNX2X=m CONFIG_CHELSIO_T1=m CONFIG_BE2NET=m CONFIG_IBMVETH=m -CONFIG_EHEA=m CONFIG_IBMVNIC=m CONFIG_E100=y CONFIG_E1000=y @@ -249,7 +248,6 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_AMD8111=y CONFIG_I2C_PASEMI=y CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_OF=y CONFIG_FB_MATROX=y CONFIG_FB_MATROX_MILLENIUM=y @@ -379,7 +377,6 @@ CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_LZO=m diff --git a/arch/powerpc/configs/ppc64e_defconfig b/arch/powerpc/configs/ppc64e_defconfig index 0fd49f67331f..f365b79c7802 100644 --- a/arch/powerpc/configs/ppc64e_defconfig +++ b/arch/powerpc/configs/ppc64e_defconfig @@ -118,7 +118,6 @@ CONFIG_SERIAL_8250_CONSOLE=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_AMD8111=y CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_OF=y CONFIG_FB_MATROX=y CONFIG_FB_MATROX_MILLENIUM=y @@ -221,7 +220,6 @@ CONFIG_XMON=y CONFIG_CRYPTO_BENCHMARK=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index ccabc6e17168..acffc5c17f92 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -228,7 +228,6 @@ CONFIG_ATM=m CONFIG_ATM_BR2684=m CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m -CONFIG_ATALK=m CONFIG_DEV_APPLETALK=m CONFIG_IPDDP=m CONFIG_IPDDP_ENCAP=y @@ -282,9 +281,6 @@ CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIBCM203X=m CONFIG_BT_HCIBPA10X=m CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIDTL1=m -CONFIG_BT_HCIBT3C=m -CONFIG_BT_HCIBLUECARD=m CONFIG_BT_HCIVHCI=m CONFIG_CFG80211=m CONFIG_MAC80211=m @@ -393,6 +389,7 @@ CONFIG_NETCONSOLE=m CONFIG_TUN=m CONFIG_VETH=m CONFIG_VIRTIO_NET=m +CONFIG_EL3=m CONFIG_VORTEX=m CONFIG_TYPHOON=m CONFIG_ADAPTEC_STARFIRE=m @@ -415,7 +412,6 @@ CONFIG_TULIP_MMIO=y CONFIG_WINBOND_840=m CONFIG_DM9102=m CONFIG_ULI526X=m -CONFIG_PCMCIA_XIRCOM=m CONFIG_DL2K=m CONFIG_SUNDANCE=m CONFIG_FEC_MPC52xx=m @@ -551,7 +547,6 @@ CONFIG_GAMEPORT_EMU10K1=m CONFIG_GAMEPORT_FM801=m # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_NONSTANDARD=y -CONFIG_SYNCLINK_GT=m CONFIG_NOZOMI=m CONFIG_N_HDLC=m CONFIG_SERIAL_8250=y @@ -576,8 +571,6 @@ CONFIG_PPDEV=m CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_VIRTIO=m CONFIG_NVRAM=y -CONFIG_DTLK=m -CONFIG_IPWIRELESS=m CONFIG_I2C_CHARDEV=m CONFIG_I2C_HYDRA=m CONFIG_I2C_MPC=m @@ -1051,7 +1044,6 @@ CONFIG_SECURITY_SELINUX_DISABLE=y CONFIG_CRYPTO_BENCHMARK=m CONFIG_CRYPTO_CTS=m CONFIG_CRYPTO_LRW=m -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_XTS=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_XCBC=m @@ -1063,7 +1055,6 @@ CONFIG_CRYPTO_ANUBIS=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index 7cfae0b7b2f3..22cfe85b7db7 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -145,7 +145,6 @@ CONFIG_CIFS=m CONFIG_NLS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y -CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_LZO=m CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig index ff1bed4b6d2c..005536ee75bb 100644 --- a/arch/powerpc/configs/skiroot_defconfig +++ b/arch/powerpc/configs/skiroot_defconfig @@ -214,7 +214,6 @@ CONFIG_SENSORS_IBMPOWERNV=m CONFIG_DRM=m CONFIG_DRM_AST=m CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y diff --git a/arch/powerpc/crypto/aes-spe-glue.c b/arch/powerpc/crypto/aes-spe-glue.c index 7d2827e65240..e038488087e6 100644 --- a/arch/powerpc/crypto/aes-spe-glue.c +++ b/arch/powerpc/crypto/aes-spe-glue.c @@ -9,6 +9,7 @@ */ #include <crypto/aes.h> +#include <linux/minmax.h> #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> @@ -140,7 +141,7 @@ static int ppc_ecb_crypt(struct skcipher_request *req, bool enc) err = skcipher_walk_virt(&walk, req, false); while ((nbytes = walk.nbytes) != 0) { - nbytes = min_t(unsigned int, nbytes, MAX_BYTES); + nbytes = min(nbytes, MAX_BYTES); nbytes = round_down(nbytes, AES_BLOCK_SIZE); spe_begin(); @@ -179,7 +180,7 @@ static int ppc_cbc_crypt(struct skcipher_request *req, bool enc) err = skcipher_walk_virt(&walk, req, false); while ((nbytes = walk.nbytes) != 0) { - nbytes = min_t(unsigned int, nbytes, MAX_BYTES); + nbytes = min(nbytes, MAX_BYTES); nbytes = round_down(nbytes, AES_BLOCK_SIZE); spe_begin(); @@ -220,7 +221,7 @@ static int ppc_ctr_crypt(struct skcipher_request *req) err = skcipher_walk_virt(&walk, req, false); while ((nbytes = walk.nbytes) != 0) { - nbytes = min_t(unsigned int, nbytes, MAX_BYTES); + nbytes = min(nbytes, MAX_BYTES); if (nbytes < walk.total) nbytes = round_down(nbytes, AES_BLOCK_SIZE); @@ -248,7 +249,7 @@ static int ppc_xts_crypt(struct skcipher_request *req, bool enc) twk = ctx->key_twk; while ((nbytes = walk.nbytes) != 0) { - nbytes = min_t(unsigned int, nbytes, MAX_BYTES); + nbytes = min(nbytes, MAX_BYTES); nbytes = round_down(nbytes, AES_BLOCK_SIZE); spe_begin(); diff --git a/arch/powerpc/crypto/aes_cbc.c b/arch/powerpc/crypto/aes_cbc.c index 4a9f285f0970..9c271b4642c8 100644 --- a/arch/powerpc/crypto/aes_cbc.c +++ b/arch/powerpc/crypto/aes_cbc.c @@ -72,7 +72,7 @@ static int p8_aes_cbc_setkey(struct crypto_skcipher *tfm, const u8 *key, return ret ? -EINVAL : 0; } -static int p8_aes_cbc_crypt(struct skcipher_request *req, int enc) +static int p8_aes_cbc_crypt(struct skcipher_request *req, bool enc) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); const struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm); @@ -110,12 +110,12 @@ static int p8_aes_cbc_crypt(struct skcipher_request *req, int enc) static int p8_aes_cbc_encrypt(struct skcipher_request *req) { - return p8_aes_cbc_crypt(req, 1); + return p8_aes_cbc_crypt(req, true); } static int p8_aes_cbc_decrypt(struct skcipher_request *req) { - return p8_aes_cbc_crypt(req, 0); + return p8_aes_cbc_crypt(req, false); } struct skcipher_alg p8_aes_cbc_alg = { diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild index 2e23533b67e3..805b5aeebb6f 100644 --- a/arch/powerpc/include/asm/Kbuild +++ b/arch/powerpc/include/asm/Kbuild @@ -5,4 +5,5 @@ generated-y += syscall_table_spu.h generic-y += agp.h generic-y += mcs_spinlock.h generic-y += qrwlock.h +generic-y += ring_buffer.h generic-y += early_ioremap.h diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index e67e64ac6e8c..f4db7d7fbd5c 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -490,13 +490,13 @@ static inline pte_t pte_clear_soft_dirty(pte_t pte) } #endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */ -#ifdef CONFIG_NUMA_BALANCING +#ifdef CONFIG_ARCH_HAS_PTE_PROTNONE static inline int pte_protnone(pte_t pte) { return (pte_raw(pte) & cpu_to_be64(_PAGE_PRESENT | _PAGE_PTE | _PAGE_RWX)) == cpu_to_be64(_PAGE_PRESENT | _PAGE_PTE); } -#endif /* CONFIG_NUMA_BALANCING */ +#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */ static inline bool pte_hw_valid(pte_t pte) { @@ -1060,19 +1060,19 @@ static inline pte_t *pmdp_ptep(pmd_t *pmd) #define pmd_mksoft_dirty(pmd) pte_pmd(pte_mksoft_dirty(pmd_pte(pmd))) #define pmd_clear_soft_dirty(pmd) pte_pmd(pte_clear_soft_dirty(pmd_pte(pmd))) -#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION +#ifdef CONFIG_ARCH_HAS_PMD_SOFTLEAVES #define pmd_swp_mksoft_dirty(pmd) pte_pmd(pte_swp_mksoft_dirty(pmd_pte(pmd))) #define pmd_swp_soft_dirty(pmd) pte_swp_soft_dirty(pmd_pte(pmd)) #define pmd_swp_clear_soft_dirty(pmd) pte_pmd(pte_swp_clear_soft_dirty(pmd_pte(pmd))) #endif #endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */ -#ifdef CONFIG_NUMA_BALANCING +#ifdef CONFIG_ARCH_HAS_PTE_PROTNONE static inline int pmd_protnone(pmd_t pmd) { return pte_protnone(pmd_pte(pmd)); } -#endif /* CONFIG_NUMA_BALANCING */ +#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */ #define pmd_write(pmd) pte_write(pmd_pte(pmd)) diff --git a/arch/powerpc/include/asm/cpu_setup.h b/arch/powerpc/include/asm/cpu_setup.h index 30e2fe389502..26d2c0e2c99c 100644 --- a/arch/powerpc/include/asm/cpu_setup.h +++ b/arch/powerpc/include/asm/cpu_setup.h @@ -9,10 +9,12 @@ void __setup_cpu_power7(unsigned long offset, struct cpu_spec *spec); void __setup_cpu_power8(unsigned long offset, struct cpu_spec *spec); void __setup_cpu_power9(unsigned long offset, struct cpu_spec *spec); void __setup_cpu_power10(unsigned long offset, struct cpu_spec *spec); +void __setup_cpu_power12(unsigned long offset, struct cpu_spec *spec); void __restore_cpu_power7(void); void __restore_cpu_power8(void); void __restore_cpu_power9(void); void __restore_cpu_power10(void); +void __restore_cpu_power12(void); void __setup_cpu_e500v1(unsigned long offset, struct cpu_spec *spec); void __setup_cpu_e500v2(unsigned long offset, struct cpu_spec *spec); diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index ec16c12296da..a3be81c47df3 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -194,6 +194,7 @@ static inline void cpu_feature_keys_init(void) { } #define CPU_FTR_DAWR1 LONG_ASM_CONST(0x0008000000000000) #define CPU_FTR_DEXCR_NPHIE LONG_ASM_CONST(0x0010000000000000) #define CPU_FTR_P11_PVR LONG_ASM_CONST(0x0020000000000000) +#define CPU_FTR_ARCH_32 LONG_ASM_CONST(0x0040000000000000) #ifndef __ASSEMBLER__ @@ -457,6 +458,18 @@ static inline void cpu_feature_keys_init(void) { } #define CPU_FTRS_POWER11 (CPU_FTRS_POWER10 | CPU_FTR_P11_PVR) +#define CPU_FTRS_POWER12 (CPU_FTR_LWSYNC | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_ARCH_206 |\ + CPU_FTR_MMCRA | CPU_FTR_SMT | \ + CPU_FTR_COHERENT_ICACHE | \ + CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ + CPU_FTR_DSCR | \ + CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ + CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \ + CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_ARCH_207S | \ + CPU_FTR_ARCH_300 | CPU_FTR_ARCH_31 | CPU_FTR_ARCH_32 | \ + CPU_FTR_DAWR | CPU_FTR_DAWR1) + #define CPU_FTRS_CELL (CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ @@ -476,7 +489,7 @@ static inline void cpu_feature_keys_init(void) { } (CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | CPU_FTRS_POWER8 | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_VSX_COMP | CPU_FTRS_POWER9 | \ CPU_FTRS_POWER9_DD2_1 | CPU_FTRS_POWER9_DD2_2 | \ - CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10 | CPU_FTRS_POWER11) + CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10 | CPU_FTRS_POWER11 | CPU_FTRS_POWER12) #else #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | \ @@ -484,7 +497,7 @@ static inline void cpu_feature_keys_init(void) { } CPU_FTRS_POWER8 | CPU_FTRS_CELL | CPU_FTRS_PA6T | \ CPU_FTR_VSX_COMP | CPU_FTR_ALTIVEC_COMP | CPU_FTRS_POWER9 | \ CPU_FTRS_POWER9_DD2_1 | CPU_FTRS_POWER9_DD2_2 | \ - CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10 | CPU_FTRS_POWER11) + CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10 | CPU_FTRS_POWER11 | CPU_FTRS_POWER12) #endif /* CONFIG_CPU_LITTLE_ENDIAN */ #endif #else diff --git a/arch/powerpc/include/asm/entry-common.h b/arch/powerpc/include/asm/entry-common.h new file mode 100644 index 000000000000..8e91489fdf2b --- /dev/null +++ b/arch/powerpc/include/asm/entry-common.h @@ -0,0 +1,537 @@ +/* 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 + /* + * Adjust the nap return address before irq_exit_rcu(). irq_exit_rcu() + * may invoke softirqs with interrupts re-enabled, allowing a nested + * async interrupt to arrive. If _TLF_NAPPING is still set at that + * point, the nested interrupt would erroneously redirect its own + * return address to power4_idle_nap_return, corrupting the stack. + */ + 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(); + } 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 */ + hard_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) +{ + 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 + /* + * Do not restore KUAP here. Generic entry might treat this as the last + * arch step before userspace but PowerPC still has kernel work after + * irqentry_exit()/syscall_exit_to_user_mode() i.e. in + * interrupt_exit_user_prepare() / syscall_exit_prepare() may enable + * IRQs and retry. Those functions restore KUAP immediately before rfi, + * which is where it should belong. + */ +} + +#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..1b45a49e9bed 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,17 @@ 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); \ + nap_adjust_return(regs); \ + irq_exit_rcu(); \ + instrumentation_end(); \ + arch_interrupt_async_exit_prepare(regs); \ + irqentry_exit(regs, state); \ } \ NOKPROBE_SYMBOL(func); \ \ @@ -572,14 +280,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 +398,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/jump_label.h b/arch/powerpc/include/asm/jump_label.h index d4eaba459a0e..3016e9c8d6bc 100644 --- a/arch/powerpc/include/asm/jump_label.h +++ b/arch/powerpc/include/asm/jump_label.h @@ -15,14 +15,20 @@ #define JUMP_ENTRY_TYPE stringify_in_c(FTR_ENTRY_LONG) #define JUMP_LABEL_NOP_SIZE 4 +#define JUMP_TABLE_ENTRY(key, label) \ + ".pushsection __jump_table, \"aw\" \n\t" \ + ".long 1b - ., " label " - . \n\t" \ + JUMP_ENTRY_TYPE key " - . \n\t" \ + ".popsection \n\t" + +#define ARCH_STATIC_BRANCH_ASM(key, label) \ + "1: nop \n\t" \ + JUMP_TABLE_ENTRY(key, label) + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) { - asm goto("1:\n\t" - "nop # arch_static_branch\n\t" - ".pushsection __jump_table, \"aw\"\n\t" - ".long 1b - ., %l[l_yes] - .\n\t" - JUMP_ENTRY_TYPE "%c0 - .\n\t" - ".popsection \n\t" + asm goto( + ARCH_STATIC_BRANCH_ASM("%c0", "%l[l_yes]") : : "i" (&((char *)key)[branch]) : : l_yes); return false; @@ -34,10 +40,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool { asm goto("1:\n\t" "b %l[l_yes] # arch_static_branch_jump\n\t" - ".pushsection __jump_table, \"aw\"\n\t" - ".long 1b - ., %l[l_yes] - .\n\t" - JUMP_ENTRY_TYPE "%c0 - .\n\t" - ".popsection \n\t" + JUMP_TABLE_ENTRY("%c0", "%l[l_yes]") : : "i" (&((char *)key)[branch]) : : l_yes); return false; 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/kexec_ranges.h b/arch/powerpc/include/asm/kexec_ranges.h index 14055896cbcb..8489e844b447 100644 --- a/arch/powerpc/include/asm/kexec_ranges.h +++ b/arch/powerpc/include/asm/kexec_ranges.h @@ -7,7 +7,6 @@ void sort_memory_ranges(struct crash_mem *mrngs, bool merge); struct crash_mem *realloc_mem_ranges(struct crash_mem **mem_ranges); int add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size); -int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size); int get_exclude_memory_ranges(struct crash_mem **mem_ranges); int get_reserved_memory_ranges(struct crash_mem **mem_ranges); int get_crash_memory_ranges(struct crash_mem **mem_ranges); diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 0953f2daa466..169ea6a7fbad 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -319,6 +319,7 @@ struct kvmppc_ops { bool (*hash_v3_possible)(void); int (*create_vm_debugfs)(struct kvm *kvm); int (*create_vcpu_debugfs)(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry); + int (*get_compat_caps)(struct kvm_ppc_compat_caps *host_caps); }; extern struct kvmppc_ops *kvmppc_hv_ops; diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 3298eec123a3..256f9309bf4f 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -169,7 +169,7 @@ struct machdep_calls { #ifdef CONFIG_PCI_IOV void (*pcibios_fixup_sriov)(struct pci_dev *pdev); - resource_size_t (*pcibios_iov_resource_alignment)(struct pci_dev *, int resno); + resource_size_t (*pcibios_iov_resource_alignment)(const struct pci_dev *, int resno); int (*pcibios_sriov_enable)(struct pci_dev *pdev, u16 num_vfs); int (*pcibios_sriov_disable)(struct pci_dev *pdev); #endif /* CONFIG_PCI_IOV */ diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 5f9c5d436e17..4fd7f81a2930 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -133,6 +133,7 @@ #define MMU_FTRS_POWER9 MMU_FTRS_POWER6 #define MMU_FTRS_POWER10 MMU_FTRS_POWER6 #define MMU_FTRS_POWER11 MMU_FTRS_POWER6 +#define MMU_FTRS_POWER12 MMU_FTRS_POWER6 #define MMU_FTRS_CELL MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ MMU_FTR_CI_LARGE_PAGE #define MMU_FTRS_PA6T MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ diff --git a/arch/powerpc/include/asm/papr-watchdog.h b/arch/powerpc/include/asm/papr-watchdog.h new file mode 100644 index 000000000000..bf876fc2caae --- /dev/null +++ b/arch/powerpc/include/asm/papr-watchdog.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ASM_POWERPC_PAPR_WATCHDOG_H +#define _ASM_POWERPC_PAPR_WATCHDOG_H + +/* + * H_WATCHDOG Input + * + * R4: "flags": + * + * Bits 48-55: "operation" + */ +#define PSERIES_WDTF_OP_START 0x100UL /* start timer */ +#define PSERIES_WDTF_OP_STOP 0x200UL /* stop timer */ +#define PSERIES_WDTF_OP_QUERY 0x300UL /* query timer capabilities */ + +/* + * Bits 56-63: "timeoutAction" (for "Start Watchdog" only) + */ +#define PSERIES_WDTF_ACTION_HARD_POWEROFF 0x1UL /* poweroff */ +#define PSERIES_WDTF_ACTION_HARD_RESTART 0x2UL /* restart */ +#define PSERIES_WDTF_ACTION_DUMP_RESTART 0x3UL /* dump + restart */ + +/* + * R5: "watchdogNumber": + * PAPR says use -1 (all ones) to stop all watchdogs. + */ +#define PSERIES_WDT_NUM_ALL ((unsigned long)-1) + +/* + * H_WATCHDOG Output + * + * R3: Return code + * + * H_SUCCESS The operation completed. + * + * H_BUSY The hypervisor is too busy; retry the operation. + * + * H_PARAMETER The given "flags" are somehow invalid. Either the + * "operation" or "timeoutAction" is invalid, or a + * reserved bit is set. + * + * H_P2 The given "watchdogNumber" is zero or exceeds the + * supported maximum value. + * + * H_P3 The given "timeoutInMs" is below the supported + * minimum value. + * + * H_NOOP The given "watchdogNumber" is already stopped. + * + * H_HARDWARE The operation failed for ineffable reasons. + * + * H_FUNCTION The H_WATCHDOG hypercall is not supported by this + * hypervisor. + * + * R4: + * + * - For the "Query Watchdog Capabilities" operation, a 64-bit + * structure: + */ +#define PSERIES_WDTQ_MIN_TIMEOUT(cap) (((cap) >> 48) & 0xffff) +#define PSERIES_WDTQ_MAX_NUMBER(cap) (((cap) >> 32) & 0xffff) + +#endif /* _ASM_POWERPC_PAPR_WATCHDOG_H */ diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h index 46a9c4491ed0..72f286e74786 100644 --- a/arch/powerpc/include/asm/pci.h +++ b/arch/powerpc/include/asm/pci.h @@ -82,8 +82,6 @@ extern int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, extern int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma, enum pci_mmap_state mmap_state); -extern void pci_adjust_legacy_attr(struct pci_bus *bus, - enum pci_mmap_state mmap_type); #define HAVE_PCI_LEGACY 1 extern void pcibios_claim_one_bus(struct pci_bus *b); diff --git a/arch/powerpc/include/asm/pmac_low_i2c.h b/arch/powerpc/include/asm/pmac_low_i2c.h index 21bd7297c87f..fead8fae08ab 100644 --- a/arch/powerpc/include/asm/pmac_low_i2c.h +++ b/arch/powerpc/include/asm/pmac_low_i2c.h @@ -79,10 +79,6 @@ extern int pmac_i2c_match_adapter(struct device_node *dev, struct i2c_adapter *adapter); -/* (legacy) Locking functions exposed to i2c-keywest */ -extern int pmac_low_i2c_lock(struct device_node *np); -extern int pmac_low_i2c_unlock(struct device_node *np); - /* Access functions for platform code */ extern int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled); extern void pmac_i2c_close(struct pmac_i2c_bus *bus); diff --git a/arch/powerpc/include/asm/preempt.h b/arch/powerpc/include/asm/preempt.h deleted file mode 100644 index 000e2b9681f3..000000000000 --- a/arch/powerpc/include/asm/preempt.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_POWERPC_PREEMPT_H -#define __ASM_POWERPC_PREEMPT_H - -#include <asm-generic/preempt.h> - -#if defined(CONFIG_PREEMPT_DYNAMIC) -#include <linux/jump_label.h> -DECLARE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched); -#define need_irq_preemption() \ - (static_branch_unlikely(&sk_dynamic_irqentry_exit_cond_resched)) -#else -#define need_irq_preemption() (IS_ENABLED(CONFIG_PREEMPTION)) -#endif - -#endif /* __ASM_POWERPC_PREEMPT_H */ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index f679a11a7e7f..2076852e6c2e 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 */ @@ -115,7 +117,8 @@ extern unsigned int boot_cpu_node_count; #define OV1_PPC_2_07 0x01 /* set if we support PowerPC 2.07 */ #define OV1_PPC_3_00 0x80 /* set if we support PowerPC 3.00 */ -#define OV1_PPC_3_1 0x40 /* set if we support PowerPC 3.1 */ +#define OV1_PPC_3_1 0x40 /* set if we support PowerPC 3.1 */ +#define OV1_PPC_3_2 0x20 /* set if we support PowerPC 3.2 */ /* Option vector 2: Open Firmware options supported */ #define OV2_REAL_MODE 0x20 /* set if we want OF in real mode */ diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 94aa1de2b06e..d53c4dd4d8b6 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -174,9 +174,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/reg.h b/arch/powerpc/include/asm/reg.h index 3449dd2b577d..541a493e13bf 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -492,11 +492,12 @@ * determine both the compatibility level which we want to emulate and the * compatibility level which the host is capable of emulating. */ +#define PCR_ARCH_31 0x20 /* Architecture 3.1 */ #define PCR_ARCH_300 0x10 /* Architecture 3.00 */ #define PCR_ARCH_207 0x8 /* Architecture 2.07 */ #define PCR_ARCH_206 0x4 /* Architecture 2.06 */ #define PCR_ARCH_205 0x2 /* Architecture 2.05 */ -#define PCR_LOW_BITS (PCR_ARCH_207 | PCR_ARCH_206 | PCR_ARCH_205 | PCR_ARCH_300) +#define PCR_LOW_BITS (PCR_ARCH_207 | PCR_ARCH_206 | PCR_ARCH_205 | PCR_ARCH_300 | PCR_ARCH_31) #define PCR_MASK ~(PCR_HIGH_BITS | PCR_LOW_BITS) /* PCR Reserved Bits */ #define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */ #define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */ @@ -1344,6 +1345,7 @@ #define PVR_POWER9 0x004E #define PVR_POWER10 0x0080 #define PVR_POWER11 0x0082 +#define PVR_POWER12 0x0083 #define PVR_BE 0x0070 #define PVR_PA6T 0x0090 @@ -1356,6 +1358,19 @@ #define PVR_ARCH_300 0x0f000005 #define PVR_ARCH_31 0x0f000006 #define PVR_ARCH_31_P11 0x0f000007 +#define PVR_ARCH_32 0x0f000008 + +/* + * Kernel-internal sentinel for invalid processor compatibility modes. + * PAPR specifies that the first byte of a valid logical PVR value is + * 0x0f. So 0xffffffff lies permanently outside the PAPR-defined range + * and is safe to repurpose. KVM stores it in vcpu->arch.arch_compat + * when userspace requests an unsupported compatibility mode (e.g., + * Power11 PVR on a Power11 host booted in Power10 compat). + * kvmppc_sanity_check() detects this and prevents the vCPU from + * running with an unsupported arch_compat. + */ +#define PVR_ARCH_INVALID 0xffffffff /* Macros for setting and retrieving special purpose registers */ #ifndef __ASSEMBLER__ 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/serial.h b/arch/powerpc/include/asm/serial.h index cd6c18d0e66e..534f0bb97ba9 100644 --- a/arch/powerpc/include/asm/serial.h +++ b/arch/powerpc/include/asm/serial.h @@ -1,6 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - */ #ifndef _ASM_POWERPC_SERIAL_H #define _ASM_POWERPC_SERIAL_H @@ -9,8 +7,8 @@ * through the device tree. */ -/* Default baud base if not found in device-tree */ -#define BASE_BAUD ( 1843200 / 16 ) +/* Provides BASE_BAUD, used as fallback if not found in device tree. */ +#include <asm-generic/serial.h> #ifdef CONFIG_PPC_UDBG_16550 extern void find_legacy_serial_ports(void); @@ -18,4 +16,4 @@ extern void find_legacy_serial_ports(void); #define find_legacy_serial_ports() do { } while (0) #endif -#endif /* _PPC64_SERIAL_H */ +#endif /* _ASM_POWERPC_SERIAL_H */ 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/string.h b/arch/powerpc/include/asm/string.h index 60ba22770f51..1981bd4036b5 100644 --- a/arch/powerpc/include/asm/string.h +++ b/arch/powerpc/include/asm/string.h @@ -5,7 +5,6 @@ #ifdef __KERNEL__ #ifndef CONFIG_KASAN -#define __HAVE_ARCH_STRNCPY #define __HAVE_ARCH_STRNCMP #define __HAVE_ARCH_MEMCHR #define __HAVE_ARCH_MEMCMP @@ -18,7 +17,6 @@ #define __HAVE_ARCH_MEMCPY_FLUSHCACHE extern char * strcpy(char *,const char *); -extern char * strncpy(char *,const char *, __kernel_size_t); extern __kernel_size_t strlen(const char *); extern int strcmp(const char *,const char *); extern int strncmp(const char *, const char *, __kernel_size_t); diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h index 0d3ccb34adfb..d0e9765dee28 100644 --- a/arch/powerpc/include/asm/synch.h +++ b/arch/powerpc/include/asm/synch.h @@ -37,8 +37,12 @@ static inline void ppc_after_tlbiel_barrier(void) * accelerators mapped will use tlbie (which does invalidate the copy) * to invalidate translations. It's not possible to limit POWER10 this * way due to local copy-paste. + * + * POWER12 does not need it. */ - asm volatile(ASM_FTR_IFSET(PPC_CP_ABORT, "", %0) : : "i" (CPU_FTR_ARCH_31) : "memory"); + asm volatile(ASM_FTR_IF(PPC_CP_ABORT, "", %0, %1) : + : "i" (CPU_FTR_ARCH_31|CPU_FTR_ARCH_32), "i" (CPU_FTR_ARCH_31) + : "memory"); } #endif /* __ASSEMBLER__ */ diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h index 4b3c52ed6e9d..32be22b995cc 100644 --- a/arch/powerpc/include/asm/syscall.h +++ b/arch/powerpc/include/asm/syscall.h @@ -98,6 +98,12 @@ static inline void syscall_set_return_value(struct task_struct *task, regs->gpr[3] = val; } } + /* + * Mark that a return value has been explicitly set by seccomp or + * ptrace so that system_call_exception() can skip the syscall + * unconditionally, even when the user requested syscall(-1). + */ + set_thread_flag(TIF_SYSCALL_RET); } static inline void syscall_get_arguments(struct task_struct *task, diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 97f35f9b1a96..1e069a2e7ce8 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -57,6 +57,8 @@ struct thread_info { #ifdef CONFIG_SMP unsigned int cpu; #endif + unsigned long exit_flags; /* Exit Flags for entry/exit */ + unsigned long syscall_work; /* SYSCALL_WORK_ flags */ unsigned long local_flags; /* private flags for thread */ #ifdef CONFIG_LIVEPATCH_64 unsigned long *livepatch_sp; @@ -118,6 +120,7 @@ void arch_setup_new_exec(void); #endif #define TIF_POLLING_NRFLAG 19 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_32BIT 20 /* 32 bit binary */ +#define TIF_SYSCALL_RET 21 /* syscall error value set */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) diff --git a/arch/powerpc/include/asm/timex.h b/arch/powerpc/include/asm/timex.h index 14b4489de52c..b48b78e47958 100644 --- a/arch/powerpc/include/asm/timex.h +++ b/arch/powerpc/include/asm/timex.h @@ -11,8 +11,6 @@ #include <asm/cputable.h> #include <asm/vdso/timebase.h> -#define CLOCK_TICK_RATE 1024000 /* Underlying HZ */ - typedef unsigned long cycles_t; static inline cycles_t get_cycles(void) diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 66ed5fe1b718..44ec416fa489 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -135,6 +135,13 @@ struct cpumask *cpu_coregroup_mask(int cpu); const struct cpumask *cpu_die_mask(int cpu); int cpu_die_id(int cpu); +/* + * Points to where the LLC is. On power9 this will point at CACHE + * domain, On others it will point to SMT domain. In all cases + * cpu_l2_cache_mask points to where LLC is + */ +#define arch_llc_mask(cpu) cpu_l2_cache_mask(cpu) + #ifdef CONFIG_PPC64 #include <asm/smp.h> diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index e98c628e3899..49039074b33f 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. * @@ -511,7 +537,7 @@ static inline void __user *mask_user_address(const void __user *ptr) if (IS_ENABLED(CONFIG_PPC64)) return mask_user_address_simple(ptr); - if (IS_ENABLED(CONFIG_E500)) + if (IS_ENABLED(CONFIG_PPC_E500)) return mask_user_address_isel(ptr); if (TASK_SIZE <= UL(SZ_2G) && border >= UL(SZ_2G)) return mask_user_address_simple(ptr); diff --git a/arch/powerpc/include/asm/vga.h b/arch/powerpc/include/asm/vga.h index f2dc40e1c52a..e45063b02b45 100644 --- a/arch/powerpc/include/asm/vga.h +++ b/arch/powerpc/include/asm/vga.h @@ -14,7 +14,7 @@ #include <asm/io.h> -#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_MDA_CONSOLE) +#ifdef CONFIG_VGA_CONSOLE #define VT_BUF_HAVE_RW /* @@ -40,7 +40,7 @@ static inline void scr_memsetw(u16 *s, u16 v, unsigned int n) memset16(s, cpu_to_le16(v), n / 2); } -#endif /* !CONFIG_VGA_CONSOLE && !CONFIG_MDA_CONSOLE */ +#endif /* !CONFIG_VGA_CONSOLE */ #ifdef __powerpc64__ #define VGA_MAP_MEM(x,s) ((unsigned long) ioremap((x), s)) diff --git a/arch/powerpc/include/asm/xive.h b/arch/powerpc/include/asm/xive.h index efb0f5effcc6..4e3e3358993c 100644 --- a/arch/powerpc/include/asm/xive.h +++ b/arch/powerpc/include/asm/xive.h @@ -91,7 +91,7 @@ static inline bool xive_enabled(void) { return __xive_enabled; } bool xive_spapr_init(void); bool xive_native_init(void); -void xive_smp_probe(void); +int xive_smp_probe(void); int xive_smp_prepare_cpu(unsigned int cpu); void xive_smp_setup_cpu(void); void xive_smp_disable_cpu(void); @@ -153,7 +153,7 @@ static inline bool xive_enabled(void) { return false; } static inline bool xive_spapr_init(void) { return false; } static inline bool xive_native_init(void) { return false; } -static inline void xive_smp_probe(void) { } +static inline int xive_smp_probe(void) { return -EINVAL; } static inline int xive_smp_prepare_cpu(unsigned int cpu) { return -EINVAL; } static inline void xive_smp_setup_cpu(void) { } static inline void xive_smp_disable_cpu(void) { } diff --git a/arch/powerpc/include/uapi/asm/cputable.h b/arch/powerpc/include/uapi/asm/cputable.h index 731b97dc2d15..68215b7ce67e 100644 --- a/arch/powerpc/include/uapi/asm/cputable.h +++ b/arch/powerpc/include/uapi/asm/cputable.h @@ -52,6 +52,8 @@ #define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000 /* TM w/out suspended state */ #define PPC_FEATURE2_ARCH_3_1 0x00040000 /* ISA 3.1 */ #define PPC_FEATURE2_MMA 0x00020000 /* Matrix Multiply Assist */ +#define PPC_FEATURE2_ARCH_3_2 0x00010000 /* ISA 3.2 */ +#define PPC_FEATURE2_DMF 0x00008000 /* Dense Math Facility */ /* * IMPORTANT! diff --git a/arch/powerpc/include/uapi/asm/fcntl.h b/arch/powerpc/include/uapi/asm/fcntl.h index 65ce08322a89..003bc5ea78e1 100644 --- a/arch/powerpc/include/uapi/asm/fcntl.h +++ b/arch/powerpc/include/uapi/asm/fcntl.h @@ -2,10 +2,10 @@ #ifndef _ASM_FCNTL_H #define _ASM_FCNTL_H -#define O_DIRECTORY 040000 /* must be a directory */ -#define O_NOFOLLOW 0100000 /* don't follow links */ -#define O_LARGEFILE 0200000 -#define O_DIRECT 0400000 /* direct disk access hint */ +#define O_DIRECTORY (1 << 14) /* must be a directory */ +#define O_NOFOLLOW (1 << 15) /* don't follow links */ +#define O_LARGEFILE (1 << 16) +#define O_DIRECT (1 << 17) /* direct disk access hint */ #include <asm-generic/fcntl.h> diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h index 077c5437f521..913a64b901a3 100644 --- a/arch/powerpc/include/uapi/asm/kvm.h +++ b/arch/powerpc/include/uapi/asm/kvm.h @@ -437,6 +437,24 @@ struct kvm_ppc_cpu_char { __u64 behaviour_mask; /* valid bits in behaviour */ }; +/* For KVM_PPC_GET_COMPAT_CAPS */ +struct kvm_ppc_compat_caps { + __u64 size; /* Size of this structure */ + __u64 flags; /* Reserved for future use */ + __u64 compat_capabilities; /* Capabilities supported by the host */ +}; +#define KVM_PPC_COMPAT_CAPS_SIZE_VER0 24 /* sizeof first published struct */ + +/* + * Capability bits for compat_capabilities field in kvm_ppc_compat_caps. + * These bits indicate which processor compatibility modes are supported. + */ +#define KVM_PPC_COMPAT_CAP_POWER9 (1ULL << 62) +#define KVM_PPC_COMPAT_CAP_POWER10 (1ULL << 61) +#define KVM_PPC_COMPAT_CAP_POWER11 (1ULL << 60) +#define KVM_PPC_COMPAT_BITMASK (KVM_PPC_COMPAT_CAP_POWER9 | \ + KVM_PPC_COMPAT_CAP_POWER10 | \ + KVM_PPC_COMPAT_CAP_POWER11) /* * Values for character and character_mask. * These are identical to the values used by H_GET_CPU_CHARACTERISTICS. diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c index 90d51d9b3ed2..cb0933061006 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 = @@ -689,7 +690,8 @@ show_shared_cpumap(struct kobject *k, struct kobj_attribute *attr, char *buf, bo mask = &cache->shared_cpu_map; - return cpumap_print_to_pagebuf(list, buf, mask); + return sysfs_emit(buf, list ? "%*pbl\n" : "%*pb\n", + cpumask_pr_args(mask)); } static ssize_t shared_cpu_map_show(struct kobject *k, struct kobj_attribute *attr, char *buf) diff --git a/arch/powerpc/kernel/cpu_setup_power.c b/arch/powerpc/kernel/cpu_setup_power.c index 98bd4e6c1770..5de704ac031d 100644 --- a/arch/powerpc/kernel/cpu_setup_power.c +++ b/arch/powerpc/kernel/cpu_setup_power.c @@ -286,3 +286,46 @@ void __restore_cpu_power10(void) init_HFSCR(); init_PMU_HV(); } + +void __setup_cpu_power12(unsigned long offset, struct cpu_spec *t) +{ + init_FSCR_power10(); + init_PMU(); + init_PMU_ISA31(); + + if (!init_hvmode_206(t)) + return; + + mtspr(SPRN_PSSCR, 0); + mtspr(SPRN_LPID, 0); + mtspr(SPRN_PID, 0); + mtspr(SPRN_AMOR, ~0); + mtspr(SPRN_PCR, PCR_MASK); + init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ + LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); + init_HFSCR(); + init_PMU_HV(); +} + +void __restore_cpu_power12(void) +{ + u64 msr; + + init_FSCR_power10(); + init_PMU(); + init_PMU_ISA31(); + + msr = mfmsr(); + if (!(msr & MSR_HV)) + return; + + mtspr(SPRN_PSSCR, 0); + mtspr(SPRN_LPID, 0); + mtspr(SPRN_PID, 0); + mtspr(SPRN_AMOR, ~0); + mtspr(SPRN_PCR, PCR_MASK); + init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ + LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); + init_HFSCR(); + init_PMU_HV(); +} diff --git a/arch/powerpc/kernel/cpu_specs_book3s_64.h b/arch/powerpc/kernel/cpu_specs_book3s_64.h index 98d4274a1b6b..26fa40aa34db 100644 --- a/arch/powerpc/kernel/cpu_specs_book3s_64.h +++ b/arch/powerpc/kernel/cpu_specs_book3s_64.h @@ -63,6 +63,11 @@ #define COMMON_USER_POWER11 COMMON_USER_POWER10 #define COMMON_USER2_POWER11 COMMON_USER2_POWER10 +#define COMMON_USER_POWER12 COMMON_USER_POWER10 +#define COMMON_USER2_POWER12 (COMMON_USER2_POWER10 | \ + PPC_FEATURE2_ARCH_3_2) + + static struct cpu_spec cpu_specs[] __initdata = { { /* PPC970 */ .pvr_mask = 0xffff0000, @@ -298,6 +303,20 @@ static struct cpu_spec cpu_specs[] __initdata = { .cpu_restore = __restore_cpu_power10, .platform = "power11", }, + { /* 3.2-compliant processor, i.e. Power12 "architected" mode */ + .pvr_mask = 0xffffffff, + .pvr_value = 0x0f000008, + .cpu_name = "Power12 (architected)", + .cpu_features = CPU_FTRS_POWER12, + .cpu_user_features = COMMON_USER_POWER12, + .cpu_user_features2 = COMMON_USER2_POWER12, + .mmu_features = MMU_FTRS_POWER12, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power12, + .cpu_restore = __restore_cpu_power12, + .platform = "power12", + }, { /* Power7 */ .pvr_mask = 0xffff0000, .pvr_value = 0x003f0000, @@ -485,6 +504,23 @@ static struct cpu_spec cpu_specs[] __initdata = { .machine_check_early = __machine_check_early_realmode_p10, .platform = "power11", }, + { /* Power12 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00830000, + .cpu_name = "Power12 (raw)", + .cpu_features = CPU_FTRS_POWER12, + .cpu_user_features = COMMON_USER_POWER12, + .cpu_user_features2 = COMMON_USER2_POWER12, + .mmu_features = MMU_FTRS_POWER12, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, + .cpu_setup = __setup_cpu_power12, + .cpu_restore = __restore_cpu_power12, + .machine_check_early = __machine_check_early_realmode_p10, + .platform = "power12", + }, { /* Cell Broadband Engine */ .pvr_mask = 0xffff0000, .pvr_value = 0x00700000, diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index 8b4de508d2eb..1f8b5a0f69be 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -67,7 +67,7 @@ bool arch_dma_unmap_sg_direct(struct device *dev, struct scatterlist *sg, } bool arch_dma_alloc_direct(struct device *dev) { - if (dev->dma_ops_bypass && dev->bus_dma_limit) + if (dev_dma_ops_bypass(dev) && dev->bus_dma_limit) return true; return false; @@ -75,7 +75,7 @@ bool arch_dma_alloc_direct(struct device *dev) bool arch_dma_free_direct(struct device *dev, dma_addr_t dma_handle) { - if (!dev->dma_ops_bypass || !dev->bus_dma_limit) + if (!dev_dma_ops_bypass(dev) || !dev->bus_dma_limit) return false; return is_direct_handle(dev, dma_handle); @@ -164,7 +164,7 @@ int dma_iommu_dma_supported(struct device *dev, u64 mask) * fixed ops will be used for RAM. This is limited by * bus_dma_limit which is set when RAM is pre-mapped. */ - dev->dma_ops_bypass = true; + dev_set_dma_ops_bypass(dev); dev_info(dev, "iommu: 64-bit OK but direct DMA is limited by %llx\n", dev->bus_dma_limit); return 1; @@ -185,7 +185,7 @@ int dma_iommu_dma_supported(struct device *dev, u64 mask) } dev_dbg(dev, "iommu: not 64-bit, using default ops\n"); - dev->dma_ops_bypass = false; + dev_clear_dma_ops_bypass(dev); return 1; } diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c index 3af6c06af02f..a87b22f555b2 100644 --- a/arch/powerpc/kernel/dt_cpu_ftrs.c +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c @@ -26,6 +26,7 @@ /* Device-tree visible constants follow */ #define ISA_V3_0B 3000 #define ISA_V3_1 3100 +#define ISA_V3_2 3200 #define USABLE_PR (1U << 0) #define USABLE_OS (1U << 1) @@ -90,8 +91,6 @@ static void __restore_cpu_cpufeatures(void) init_pmu_registers(); } -static char dt_cpu_name[64]; - static struct cpu_spec __initdata base_cpu_spec = { .cpu_name = NULL, .cpu_features = CPU_FTRS_DT_CPU_BASE, @@ -466,6 +465,35 @@ static int __init feat_enable_mce_power11(struct dt_cpu_feature *f) return 1; } +static void init_pmu_power12(void) +{ + init_pmu_power10(); +} + +static int __init feat_enable_pmu_power12(struct dt_cpu_feature *f) +{ + hfscr_pmu_enable(); + + init_pmu_power12(); + init_pmu_registers = init_pmu_power12; + + cur_cpu_spec->cpu_features |= CPU_FTR_MMCRA; + cur_cpu_spec->cpu_user_features |= PPC_FEATURE_PSERIES_PERFMON_COMPAT; + + cur_cpu_spec->num_pmcs = 6; + cur_cpu_spec->pmc_type = PPC_PMC_IBM; + + return 1; +} + +static int __init feat_enable_mce_power12(struct dt_cpu_feature *f) +{ + cur_cpu_spec->platform = "power12"; + cur_cpu_spec->machine_check_early = __machine_check_early_realmode_p10; + + return 1; +} + static int __init feat_enable_tm(struct dt_cpu_feature *f) { #ifdef CONFIG_PPC_TRANSACTIONAL_MEM @@ -657,9 +685,11 @@ static struct dt_cpu_feature_match __initdata {"machine-check-power9", feat_enable_mce_power9, 0}, {"machine-check-power10", feat_enable_mce_power10, 0}, {"machine-check-power11", feat_enable_mce_power11, 0}, + {"machine-check-power12", feat_enable_mce_power12, 0}, {"performance-monitor-power9", feat_enable_pmu_power9, 0}, {"performance-monitor-power10", feat_enable_pmu_power10, 0}, {"performance-monitor-power11", feat_enable_pmu_power10, 0}, + {"performance-monitor-power12", feat_enable_pmu_power12, 0}, {"event-based-branch-v3", feat_enable, 0}, {"random-number-generator", feat_enable, 0}, {"system-call-vectored", feat_disable, 0}, @@ -704,6 +734,20 @@ static void __init cpufeatures_setup_start(u32 isa) if (isa >= ISA_V3_1) { cur_cpu_spec->cpu_features |= CPU_FTR_ARCH_31; cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_ARCH_3_1; + + /* + * CPU_FTR_P11_PVR is a kernel-internal flag to identify + * Power11 and later processors. While ISA v3.1 is supported + * by Power10+, this flag specifically indicates Power11+ + * for code that needs to distinguish between P10 and P11. + */ + if (PVR_VER(mfspr(SPRN_PVR)) >= PVR_POWER11) + cur_cpu_spec->cpu_features |= CPU_FTR_P11_PVR; + } + + if (isa >= ISA_V3_2) { + cur_cpu_spec->cpu_features |= CPU_FTR_ARCH_32; + cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_ARCH_3_2; } } @@ -1069,6 +1113,7 @@ static int __init count_cpufeatures_subnodes(unsigned long node, static int __init dt_cpu_ftrs_scan_callback(unsigned long node, const char *uname, int depth, void *data) { + static char dt_cpu_name[64]; const __be32 *prop; int count, i; u32 isa; @@ -1106,8 +1151,8 @@ static int __init dt_cpu_ftrs_scan_callback(unsigned long node, const char } prop = of_get_flat_dt_prop(node, "display-name", NULL); - if (prop && strlen((char *)prop) != 0) { - strscpy(dt_cpu_name, (char *)prop, sizeof(dt_cpu_name)); + if (prop && *(char *)prop != 0) { + strscpy(dt_cpu_name, (char *)prop); cur_cpu_spec->cpu_name = dt_cpu_name; } diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 028f69158532..d64cce17a4e0 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -533,9 +533,7 @@ static void eeh_rmv_device(struct eeh_dev *edev, void *userdata) if (rmv_data) list_add(&edev->rmv_entry, &rmv_data->removed_vf_list); } else { - pci_lock_rescan_remove(); pci_stop_and_remove_bus_device(dev); - pci_unlock_rescan_remove(); } } 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/head_64.S b/arch/powerpc/kernel/head_64.S index 63432a33ec49..a54f6f979173 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -713,14 +713,18 @@ p_end: .8byte _end - copy_to_here _GLOBAL(copy_and_flush) addi r5,r5,-8 addi r6,r6,-8 -4: li r0,8 /* Use the smallest common */ - /* denominator cache line */ - /* size. This results in */ - /* extra cache line flushes */ - /* but operation is correct. */ - /* Can't get cache line size */ - /* from NACA as it is being */ - /* moved too. */ +4: li r0,8 /* r0 is the number of 8-byte words */ + /* to copy per cache sync iteration. */ + /* 8 words * 8 bytes = 64 bytes. 64B is */ + /* the current default cache line size. */ + /* This is a loop count, not a byte */ + /* count. Increasing it may skip */ + /* dcbst/icbi for lines in between and */ + /* leave stale instructions in icache. */ + /* This results in extra cache line */ + /* flushes but operation is correct. */ + /* Can't get cache line size from NACA */ + /* as it is being moved too. */ mtctr r0 /* put # words/line in ctr */ 3: addi r6,r6,8 /* copy a cache line */ diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c index e63bfde13e03..55f9c0c9922a 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 @@ -270,17 +92,14 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, 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); + /* Clear exit_flags so only flags set during this exit are visible */ + current->thread_info.exit_flags = 0; ti_flags = read_thread_flags(); - if (unlikely(r3 >= (unsigned long)-MAX_ERRNO) && is_not_scv) { if (likely(!(ti_flags & (_TIF_NOERROR | _TIF_RESTOREALL)))) { r3 = -r3; @@ -299,13 +118,23 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, } if (unlikely(ti_flags & _TIF_SYSCALL_DOTRACE)) { - do_syscall_trace_leave(regs); ret |= _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); + ret |= current->thread_info.exit_flags; #ifdef CONFIG_PPC64 regs->exit_result = ret; #endif @@ -316,6 +145,8 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, #ifdef CONFIG_PPC64 notrace unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *regs) { + unsigned long ret; + /* * This is called when detecting a soft-pending interrupt as well as * an alternate-return interrupt. So we can't just have the alternate @@ -330,13 +161,19 @@ 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); + ret = current_thread_info()->exit_flags & _TIF_RESTOREALL; + current_thread_info()->exit_flags &= ~_TIF_RESTOREALL; + regs->exit_result |= ret; return regs->exit_result; } @@ -347,8 +184,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. @@ -356,10 +192,23 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs) */ kuap_assert_locked(); - local_irq_disable(); + /* Clear exit_flags so only flags set during this exit are visible */ + current_thread_info()->exit_flags = 0; - ret = interrupt_exit_user_prepare_main(0, regs); + local_irq_disable(); +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 = current_thread_info()->exit_flags & _TIF_RESTOREALL; #ifdef CONFIG_PPC64 regs->exit_result = ret; #endif @@ -396,17 +245,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 +321,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..1ae8384637b5 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, @@ -1075,7 +1076,7 @@ int iommu_tce_check_ioba(unsigned long page_shift, if (ioba < offset) return -EINVAL; - if ((ioba + 1) > (offset + size)) + if ((ioba + npages < ioba) || (ioba - offset + npages > size)) return -EINVAL; return 0; diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index a0e8b998c9b5..15a3c3fd8e70 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -217,8 +217,12 @@ static __always_inline void call_do_softirq(const void *sp) [sp] "b" (sp), [offset] "i" (THREAD_SIZE - STACK_FRAME_MIN_SIZE), [callee] "i" (__do_softirq) : // Clobbers - "lr", "xer", "ctr", "memory", "cr0", "cr1", "cr5", "cr6", - "cr7", "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "lr", "xer", "ctr", "memory", "cr0", "cr1", "cr5", "cr6", "cr7", "r0", + /* r2 may be clobbered by the callee when using PCREL mode in the ELFv2 ABI. */ +#ifdef CONFIG_PPC_KERNEL_PCREL + "r2", +#endif + "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -275,8 +279,12 @@ static __always_inline void call_do_irq(struct pt_regs *regs, void *sp) [sp] "b" (sp), [offset] "i" (THREAD_SIZE - STACK_FRAME_MIN_SIZE), [callee] "i" (__do_irq) : // Clobbers - "lr", "xer", "ctr", "memory", "cr0", "cr1", "cr5", "cr6", - "cr7", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "lr", "xer", "ctr", "memory", "cr0", "cr1", "cr5", "cr6", "cr7", "r0", + /* r2 may be clobbered by the callee when using PCREL mode in the ELFv2 ABI. */ +#ifdef CONFIG_PPC_KERNEL_PCREL + "r2", +#endif + "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -370,10 +378,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/pci-common.c b/arch/powerpc/kernel/pci-common.c index 8efe95a0c4ff..4fc52c21fe5d 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -254,7 +254,7 @@ resource_size_t pcibios_default_alignment(void) } #ifdef CONFIG_PCI_IOV -resource_size_t pcibios_iov_resource_alignment(struct pci_dev *pdev, int resno) +resource_size_t pcibios_iov_resource_alignment(const struct pci_dev *pdev, int resno) { if (ppc_md.pcibios_iov_resource_alignment) return ppc_md.pcibios_iov_resource_alignment(pdev, resno); @@ -626,19 +626,14 @@ int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size) return -ENXIO; addr = hose->io_base_virt + port; - /* WARNING: The generic code is idiotic. It gets passed a pointer - * to what can be a 1, 2 or 4 byte quantity and always reads that - * as a u32, which means that we have to correct the location of - * the data read within those 32 bits for size 1 and 2 - */ switch(size) { case 1: - out_8(addr, val >> 24); + out_8(addr, val); return 1; case 2: if (port & 1) return -EINVAL; - out_le16(addr, val >> 16); + out_le16(addr, val); return 2; case 4: if (port & 3) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 9ed9dde7d231..d218c8cc1f73 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -824,7 +824,6 @@ void __init early_init_devtree(void *params) fadump_append_bootargs(); /* Scan memory nodes and rebuild MEMBLOCKs */ - early_init_dt_scan_root(); early_init_dt_scan_memory_ppc(); /* diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index f26e80cbc615..eb9f556b0937 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -86,6 +86,12 @@ */ #define ADDR(x) (u32)(unsigned long)(x) +/* + * Current Power system firmware caps the PVR list array size at 16 entries + * during CAS (Client Architecture Support) negotiation. + */ +#define CAS_MAX_PVR_ENTRIES 16 + #ifdef CONFIG_PPC64 #define OF_WORKAROUNDS 0 #else @@ -947,7 +953,7 @@ struct option_vector7 { } __packed; struct ibm_arch_vec { - struct { __be32 mask, val; } pvrs[16]; + struct { __be32 mask, val; } pvrs[18]; u8 num_vectors; @@ -980,6 +986,10 @@ static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = { .val = cpu_to_be32(0x003a0000), }, { + .mask = cpu_to_be32(0xffffffff), /* all 2.04-compliant and earlier */ + .val = cpu_to_be32(0x0f000001), + }, + { .mask = cpu_to_be32(0xffff0000), /* POWER6 */ .val = cpu_to_be32(0x003e0000), }, @@ -1012,6 +1022,14 @@ static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = { .val = cpu_to_be32(0x00820000), }, { + .mask = cpu_to_be32(0xffff0000), /* POWER12 */ + .val = cpu_to_be32(0x00830000), + }, + { + .mask = cpu_to_be32(0xffffffff), /* all 3.2-compliant */ + .val = cpu_to_be32(0x0f000008), + }, + { .mask = cpu_to_be32(0xffffffff), /* P11 compliant */ .val = cpu_to_be32(0x0f000007), }, @@ -1032,13 +1050,9 @@ static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = { .val = cpu_to_be32(0x0f000003), }, { - .mask = cpu_to_be32(0xffffffff), /* all 2.05-compliant */ + .mask = cpu_to_be32(0xfffffffd), /* all 2.05-compliant */ .val = cpu_to_be32(0x0f000002), }, - { - .mask = cpu_to_be32(0xfffffffe), /* all 2.04-compliant and earlier */ - .val = cpu_to_be32(0x0f000001), - }, }, .num_vectors = NUM_VECTORS(6), @@ -1048,7 +1062,7 @@ static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = { .byte1 = 0, .arch_versions = OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 | OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06 | OV1_PPC_2_07, - .arch_versions3 = OV1_PPC_3_00 | OV1_PPC_3_1, + .arch_versions3 = OV1_PPC_3_00 | OV1_PPC_3_1 | OV1_PPC_3_2, }, .vec2_len = VECTOR_LENGTH(sizeof(struct option_vector2)), @@ -1061,7 +1075,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) */ @@ -1403,6 +1417,22 @@ static void __init prom_send_capabilities(void) ihandle root; prom_arg_t ret; u32 cores; + int start_index = 0; + + /* + * Ensure that when running on Power11 or below hardware, the number + * of PVR entries passed during CAS negotiation does not exceed the + * firmware-imposed limit of 16. + * + * Compute the start_index to skip the oldest leading pvrs[] entries + * when running on Power11 or below hardware, so that the pointer + * passed to ibm,client-architecture-support points to + * ibm_architecture_vec.pvrs[start_index], presenting exactly 16 + * entries to firmware. + */ + if ((ARRAY_SIZE(ibm_architecture_vec_template.pvrs) > CAS_MAX_PVR_ENTRIES) && + (PVR_VER(mfspr(SPRN_PVR)) <= PVR_POWER11)) + start_index = ARRAY_SIZE(ibm_architecture_vec_template.pvrs) - CAS_MAX_PVR_ENTRIES; /* Check ibm,arch-vec-5-platform-support and fixup vec5 if required */ prom_check_platform_support(); @@ -1427,7 +1457,7 @@ static void __init prom_send_capabilities(void) if (call_prom_ret("call-method", 3, 2, &ret, ADDR("ibm,client-architecture-support"), root, - ADDR(&ibm_architecture_vec)) == 0) { + ADDR(&ibm_architecture_vec.pvrs[start_index])) == 0) { /* the call exists... */ if (ret) prom_printf("\nWARNING: ibm,client-architecture" diff --git a/arch/powerpc/kernel/ptrace/ptrace.c b/arch/powerpc/kernel/ptrace/ptrace.c index c6997df63287..6cd180bc36ab 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); /* diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 583dc16e9d3c..722dbfb6fbf8 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -394,30 +394,23 @@ static ssize_t manage_flash_write(struct file *file, const char __user *buf, size_t count, loff_t *off) { struct rtas_manage_flash_t *const args_buf = &rtas_manage_flash_data; - static const char reject_str[] = "0"; - static const char commit_str[] = "1"; - char stkbuf[10]; - int op; + unsigned int op; + char cmd; guard(mutex)(&rtas_manage_flash_mutex); if ((args_buf->status == MANAGE_AUTH) || (count == 0)) return count; - op = -1; - if (buf) { - if (count > 9) count = 9; - if (copy_from_user (stkbuf, buf, count)) - return -EFAULT; - if (strncmp(stkbuf, reject_str, strlen(reject_str)) == 0) - op = RTAS_REJECT_TMP_IMG; - else if (strncmp(stkbuf, commit_str, strlen(commit_str)) == 0) - op = RTAS_COMMIT_TMP_IMG; - } - - if (op == -1) { /* buf is empty, or contains invalid string */ + if (get_user(cmd, buf)) + return -EFAULT; + + if (cmd == '0') + op = RTAS_REJECT_TMP_IMG; + else if (cmd == '1') + op = RTAS_COMMIT_TMP_IMG; + else return -EINVAL; - } manage_flash(args_buf, op); return count; diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index fccf96e897f6..206c825225c2 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c @@ -54,6 +54,10 @@ int rtas_pci_dn_read_config(struct pci_dn *pdn, int where, int size, u32 *val) if (!config_access_valid(pdn, where)) return PCIBIOS_BAD_REGISTER_NUMBER; #ifdef CONFIG_EEH + if (pdn->edev && + (pdn->edev->mode & EEH_DEV_REMOVED)) + return PCIBIOS_DEVICE_NOT_FOUND; + if (pdn->edev && pdn->edev->pe && (pdn->edev->pe->state & EEH_PE_CFG_BLOCKED)) return PCIBIOS_SET_FAILED; @@ -105,6 +109,10 @@ int rtas_pci_dn_write_config(struct pci_dn *pdn, int where, int size, u32 val) if (!config_access_valid(pdn, where)) return PCIBIOS_BAD_REGISTER_NUMBER; #ifdef CONFIG_EEH + if (pdn->edev && + (pdn->edev->mode & EEH_DEV_REMOVED)) + return PCIBIOS_DEVICE_NOT_FOUND; + if (pdn->edev && pdn->edev->pe && (pdn->edev->pe->state & EEH_PE_CFG_BLOCKED)) return PCIBIOS_SET_FAILED; diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c index 6336ec9aedd0..fd40864bdb70 100644 --- a/arch/powerpc/kernel/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c @@ -10,6 +10,7 @@ #include <linux/sched.h> #include <linux/kernel.h> #include <linux/of.h> +#include <linux/overflow.h> #include <linux/poll.h> #include <linux/proc_fs.h> #include <linux/init.h> @@ -160,25 +161,17 @@ static void printk_log_rtas(char *buf, int len) static int log_rtas_len(char * buf) { - int len; + size_t len; struct rtas_error_log *err; - uint32_t extended_log_length; + u32 extended_log_length; - /* rtas fixed header */ - len = 8; err = (struct rtas_error_log *)buf; - extended_log_length = rtas_error_extended_log_length(err); - if (rtas_error_extended(err) && extended_log_length) { - - /* extended header */ - len += extended_log_length; - } + extended_log_length = rtas_error_extended(err) ? rtas_error_extended_log_length(err) : 0; + len = struct_size(err, buffer, extended_log_length); if (rtas_error_log_max == 0) rtas_error_log_max = rtas_get_error_log_max(); - - if (len > rtas_error_log_max) - len = rtas_error_log_max; + len = min(len, rtas_error_log_max); return len; } 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..4afaba19b586 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" @@ -303,6 +304,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) break; case 0x004e: /* POWER9 bits 12-15 give chip type */ case 0x0080: /* POWER10 bit 12 gives SMT8/4 */ + case 0x0083: /* POWER12 bit 12 gives SMT8/4 */ maj = (pvr >> 8) & 0x0F; min = pvr & 0xFF; break; @@ -323,7 +325,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 +333,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 +744,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..cc6498501610 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); + current_thread_info()->exit_flags |= _TIF_RESTOREALL; + do_signal(current); +} diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 3467f86fd78f..6a5a5469aaae 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -289,6 +289,9 @@ void smp_muxed_ipi_set_message(int cpu, int msg) void smp_muxed_ipi_message_pass(int cpu, int msg) { + if (!smp_ops->cause_ipi) + return; + smp_muxed_ipi_set_message(cpu, msg); /* diff --git a/arch/powerpc/kernel/syscall.c b/arch/powerpc/kernel/syscall.c index b762677f8737..fbefe1927b10 100644 --- a/arch/powerpc/kernel/syscall.c +++ b/arch/powerpc/kernel/syscall.c @@ -2,7 +2,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 +18,15 @@ 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(); - - 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; + if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0))) { + clear_thread_flag(TIF_SYSCALL_RET); + return syscall_get_error(current, regs); } -#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]; + if (unlikely(test_and_clear_thread_flag(TIF_SYSCALL_RET))) + return syscall_get_error(current, regs); - } 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/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl index 4fcc7c58a105..cfbb70039ff0 100644 --- a/arch/powerpc/kernel/syscalls/syscall.tbl +++ b/arch/powerpc/kernel/syscalls/syscall.tbl @@ -562,3 +562,4 @@ 469 common file_setattr sys_file_setattr 470 common listns sys_listns 471 nospu rseq_slice_yield sys_rseq_slice_yield +472 common fchroot sys_fchroot 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/time.c b/arch/powerpc/kernel/time.c index 4bbeb8644d3d..11145c40183d 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -376,6 +376,47 @@ void vtime_task_switch(struct task_struct *prev) acct->starttime = acct0->starttime; } } + +/** + * vtime_reset - Fast forward vtime entry clocks + * + * Called from dynticks idle IRQ entry to fast-forward the clocks to current time + * so that the IRQ time is still accounted by vtime while nohz cputime is paused. + */ +void vtime_reset(void) +{ + struct cpu_accounting_data *acct = get_accounting(current); + + acct->starttime = mftb(); +#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME + acct->startspurr = read_spurr(acct->starttime); +#endif +} + +#ifdef CONFIG_NO_HZ_COMMON +/** + * vtime_dyntick_start - Inform vtime about entry to idle-dynticks + * + * Called when idle enters in dyntick mode. The idle cputime that elapsed so far + * is accumulated and the tick subsystem takes over the idle cputime accounting. + */ +void vtime_dyntick_start(void) +{ + vtime_account_idle(current); +} + +/** + * vtime_dyntick_stop - Inform vtime about exit from idle-dynticks + * + * Called when idle exits from dyntick mode. The vtime entry clocks are + * fast-forward to current time so that idle accounting restarts elapsing from + * now. + */ +void vtime_dyntick_stop(void) +{ + vtime_reset(); +} +#endif /* CONFIG_NO_HZ_COMMON */ #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ void __no_kcsan __delay(unsigned long loops) @@ -458,6 +499,10 @@ DEFINE_PER_CPU(u8, irq_work_pending); #endif /* 32 vs 64 bit */ +/* + * Must be called with preemption disabled since it updates + * per-CPU irq_work state and programs the local CPU decrementer. + */ void arch_irq_work_raise(void) { /* @@ -471,10 +516,8 @@ void arch_irq_work_raise(void) * which could get tangled up if we're messing with the same state * here. */ - preempt_disable(); set_irq_work_pending_flag(); set_dec(1); - preempt_enable(); } static void set_dec_or_work(u64 val) @@ -890,6 +933,7 @@ static void __init set_decrementer_max(void) static void __init init_decrementer_clockevent(void) { register_decrementer_clockevent(smp_processor_id()); + vtime_reset(); } void secondary_cpu_time_init(void) @@ -905,6 +949,7 @@ void secondary_cpu_time_init(void) /* FIME: Should make unrelated change to move snapshot_timebase * call here ! */ register_decrementer_clockevent(smp_processor_id()); + vtime_reset(); } /* 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/vdso/Makefile b/arch/powerpc/kernel/vdso/Makefile index 8834dfe9d727..368759f81708 100644 --- a/arch/powerpc/kernel/vdso/Makefile +++ b/arch/powerpc/kernel/vdso/Makefile @@ -62,6 +62,12 @@ CC32FLAGSREMOVE += -fno-stack-clash-protection # 32-bit one. clang validates the values passed to these arguments during # parsing, even when -fno-stack-protector is passed afterwards. CC32FLAGSREMOVE += -mstack-protector-guard% +# ftrace is disabled for the vdso but arch/powerpc/Makefile adds this define to +# KBUILD_CPPFLAGS, which enables use of the 'patchable_function_entry' +# attribute in the 'inline' define via 'notrace'. This attribute is not +# supported for the powerpcle target, resulting in many instances of +# -Wunknown-attributes. +CC32FLAGSREMOVE += -DCC_USING_PATCHABLE_FUNCTION_ENTRY endif LD32FLAGS := -Wl,-soname=linux-vdso32.so.1 AS32FLAGS := -D__VDSO32__ diff --git a/arch/powerpc/kernel/vdso/gettimeofday.S b/arch/powerpc/kernel/vdso/gettimeofday.S index 1c8e51691bf8..c635cd1e77be 100644 --- a/arch/powerpc/kernel/vdso/gettimeofday.S +++ b/arch/powerpc/kernel/vdso/gettimeofday.S @@ -67,9 +67,11 @@ * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); * */ +#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME) V_FUNCTION_BEGIN(__kernel_gettimeofday) cvdso_call __c_kernel_gettimeofday V_FUNCTION_END(__kernel_gettimeofday) +#endif /* * Exact prototype of clock_gettime() @@ -77,9 +79,11 @@ V_FUNCTION_END(__kernel_gettimeofday) * int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); * */ +#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME) V_FUNCTION_BEGIN(__kernel_clock_gettime) cvdso_call __c_kernel_clock_gettime V_FUNCTION_END(__kernel_clock_gettime) +#endif /* * Exact prototype of clock_gettime64() @@ -99,9 +103,11 @@ V_FUNCTION_END(__kernel_clock_gettime64) * int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); * */ +#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME) V_FUNCTION_BEGIN(__kernel_clock_getres) cvdso_call __c_kernel_clock_getres V_FUNCTION_END(__kernel_clock_getres) +#endif /* * Exact prototype of clock_getres_time64() @@ -122,6 +128,8 @@ V_FUNCTION_END(__kernel_clock_getres_time64) * time_t time(time *t); * */ +#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME) V_FUNCTION_BEGIN(__kernel_time) cvdso_call __c_kernel_time call_time=1 V_FUNCTION_END(__kernel_time) +#endif diff --git a/arch/powerpc/kernel/vdso/vdso32.lds.S b/arch/powerpc/kernel/vdso/vdso32.lds.S index 3f384a2526ae..5e87c18fd282 100644 --- a/arch/powerpc/kernel/vdso/vdso32.lds.S +++ b/arch/powerpc/kernel/vdso/vdso32.lds.S @@ -119,13 +119,15 @@ VERSION { VDSO_VERSION_STRING { global: - __kernel_get_syscall_map; +#ifdef CONFIG_COMPAT_32BIT_TIME __kernel_gettimeofday; __kernel_clock_gettime; - __kernel_clock_gettime64; __kernel_clock_getres; - __kernel_clock_getres_time64; __kernel_time; +#endif /* CONFIG_COMPAT_32BIT_TIME */ + __kernel_get_syscall_map; + __kernel_clock_gettime64; + __kernel_clock_getres_time64; __kernel_get_tbfreq; __kernel_sync_dicache; __kernel_sigtramp32; diff --git a/arch/powerpc/kernel/vdso/vgettimeofday.c b/arch/powerpc/kernel/vdso/vgettimeofday.c index 3c194e1ab562..4b712fb01a3f 100644 --- a/arch/powerpc/kernel/vdso/vgettimeofday.c +++ b/arch/powerpc/kernel/vdso/vgettimeofday.c @@ -18,23 +18,25 @@ int __c_kernel_clock_getres(clockid_t clock_id, struct __kernel_timespec *res, return __cvdso_clock_getres_data(vd, clock_id, res); } #else +#ifdef CONFIG_COMPAT_32BIT_TIME int __c_kernel_clock_gettime(clockid_t clock, struct old_timespec32 *ts, const struct vdso_time_data *vd) { return __cvdso_clock_gettime32_data(vd, clock, ts); } -int __c_kernel_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts, - const struct vdso_time_data *vd) -{ - return __cvdso_clock_gettime_data(vd, clock, ts); -} - int __c_kernel_clock_getres(clockid_t clock_id, struct old_timespec32 *res, const struct vdso_time_data *vd) { return __cvdso_clock_getres_time32_data(vd, clock_id, res); } +#endif /* CONFIG_COMPAT_32BIT_TIME */ + +int __c_kernel_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts, + const struct vdso_time_data *vd) +{ + return __cvdso_clock_gettime_data(vd, clock, ts); +} int __c_kernel_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec *res, const struct vdso_time_data *vd) @@ -43,6 +45,7 @@ int __c_kernel_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec } #endif +#if defined(__powerpc64__) || defined(CONFIG_COMPAT_32BIT_TIME) int __c_kernel_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz, const struct vdso_time_data *vd) { @@ -53,3 +56,4 @@ __kernel_old_time_t __c_kernel_time(__kernel_old_time_t *time, const struct vdso { return __cvdso_time_data(vd, time); } +#endif 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/Makefile b/arch/powerpc/kexec/Makefile index 470eb0453e17..ec7a0eed75dc 100644 --- a/arch/powerpc/kexec/Makefile +++ b/arch/powerpc/kexec/Makefile @@ -16,4 +16,4 @@ GCOV_PROFILE_core_$(BITS).o := n KCOV_INSTRUMENT_core_$(BITS).o := n UBSAN_SANITIZE_core_$(BITS).o := n KASAN_SANITIZE_core.o := n -KASAN_SANITIZE_core_$(BITS) := n +KASAN_SANITIZE_core_$(BITS).o := n 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/kexec/crash.c b/arch/powerpc/kexec/crash.c index e6539f213b3d..775895f31037 100644 --- a/arch/powerpc/kexec/crash.c +++ b/arch/powerpc/kexec/crash.c @@ -493,7 +493,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify * struct crash_mem *cmem = NULL; struct kexec_segment *ksegment; void *ptr, *mem, *elfbuf = NULL; - unsigned long elfsz, memsz, base_addr, size; + unsigned long elfsz, memsz, base_addr, size, end; ksegment = &image->segment[image->elfcorehdr_index]; mem = (void *) ksegment->mem; @@ -502,7 +502,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify * ret = get_crash_memory_ranges(&cmem); if (ret) { pr_err("Failed to get crash mem range\n"); - return; + goto out; } /* @@ -512,7 +512,8 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify * if (image->hp_action == KEXEC_CRASH_HP_REMOVE_MEMORY) { base_addr = PFN_PHYS(mn->start_pfn); size = mn->nr_pages * PAGE_SIZE; - ret = remove_mem_range(&cmem, base_addr, size); + end = base_addr + size - 1; + ret = arch_crash_exclude_mem_range(&cmem, base_addr, end); if (ret) { pr_err("Failed to remove hot-unplugged memory from crash memory ranges\n"); goto out; diff --git a/arch/powerpc/kexec/elf_64.c b/arch/powerpc/kexec/elf_64.c index ea50a072debf..d9a466cd602e 100644 --- a/arch/powerpc/kexec/elf_64.c +++ b/arch/powerpc/kexec/elf_64.c @@ -94,6 +94,8 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, cmdline = modified_cmdline; } + kexec_dprintk("Command line: %s", cmdline ? cmdline : ""); + if (initrd != NULL) { kbuf.buffer = initrd; kbuf.bufsz = kbuf.memsz = initrd_len; diff --git a/arch/powerpc/kexec/file_load.c b/arch/powerpc/kexec/file_load.c index 4284f76cbef5..597998235136 100644 --- a/arch/powerpc/kexec/file_load.c +++ b/arch/powerpc/kexec/file_load.c @@ -36,25 +36,19 @@ char *setup_kdump_cmdline(struct kimage *image, char *cmdline, unsigned long cmdline_len) { - int elfcorehdr_strlen; char *cmdline_ptr; - cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL); + cmdline_ptr = kmalloc(COMMAND_LINE_SIZE, GFP_KERNEL); if (!cmdline_ptr) return NULL; - elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ", - image->elf_load_addr); - - if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) { - pr_err("Appending elfcorehdr=<addr> exceeds cmdline size\n"); + if (snprintf(cmdline_ptr, COMMAND_LINE_SIZE, "elfcorehdr=0x%lx %s", + image->elf_load_addr, cmdline_len ? cmdline : "") >= COMMAND_LINE_SIZE) { + pr_err("Prepending elfcorehdr=<addr> exceeds cmdline size\n"); kfree(cmdline_ptr); return NULL; } - memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len); - // Ensure it's nul terminated - cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0'; return cmdline_ptr; } diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c index 8c72e12ea44e..bd80c5fb1b1f 100644 --- a/arch/powerpc/kexec/file_load_64.c +++ b/arch/powerpc/kexec/file_load_64.c @@ -57,7 +57,7 @@ int arch_check_excluded_range(struct kimage *image, unsigned long start, emem = image->arch.exclude_ranges; for (i = 0; i < emem->nr_ranges; i++) - if (start < emem->ranges[i].end && end > emem->ranges[i].start) + if (start <= emem->ranges[i].end && end >= emem->ranges[i].start) return 1; return 0; @@ -113,7 +113,7 @@ static int add_usable_mem(struct umem_info *um_info, u64 base, u64 end) loc_end = um_info->ranges[i].end; if (loc_base >= base && loc_end <= end) add = true; - else if (base < loc_end && end > loc_base) { + else if (base <= loc_end && end >= loc_base) { if (loc_base < base) loc_base = base; if (loc_end > end) @@ -377,16 +377,12 @@ static int load_backup_segment(struct kimage *image, struct kexec_buf *kbuf) static unsigned int kdump_extra_elfcorehdr_size(struct crash_mem *cmem) { #if defined(CONFIG_CRASH_HOTPLUG) && defined(CONFIG_MEMORY_HOTPLUG) - unsigned int extra_sz = 0; - if (CONFIG_CRASH_MAX_MEMORY_RANGES > (unsigned int)PN_XNUM) pr_warn("Number of Phdrs %u exceeds max\n", CONFIG_CRASH_MAX_MEMORY_RANGES); else if (cmem->nr_ranges >= CONFIG_CRASH_MAX_MEMORY_RANGES) pr_warn("Configured crash mem ranges may not be enough\n"); else - extra_sz = (CONFIG_CRASH_MAX_MEMORY_RANGES - cmem->nr_ranges) * sizeof(Elf64_Phdr); - - return extra_sz; + return (CONFIG_CRASH_MAX_MEMORY_RANGES - cmem->nr_ranges) * sizeof(Elf64_Phdr); #endif return 0; } @@ -664,7 +660,7 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem * extra_size += (cpu_nodes - boot_cpu_node_count) * cpu_node_size(); /* Consider extra space for reserved memory ranges if any */ - if (rmem->nr_ranges > 0) + if (rmem && rmem->nr_ranges > 0) extra_size += sizeof(struct fdt_reserve_entry) * rmem->nr_ranges; return extra_size + kdump_extra_fdt_size_ppc64(image, cpu_nodes); diff --git a/arch/powerpc/kexec/ranges.c b/arch/powerpc/kexec/ranges.c index 867135560e5c..539061d14a77 100644 --- a/arch/powerpc/kexec/ranges.c +++ b/arch/powerpc/kexec/ranges.c @@ -21,6 +21,7 @@ #include <linux/of.h> #include <linux/slab.h> #include <linux/memblock.h> +#include <linux/minmax.h> #include <linux/crash_core.h> #include <asm/sections.h> #include <asm/kexec_ranges.h> @@ -105,19 +106,16 @@ static void __merge_memory_ranges(struct crash_mem *mem_rngs) struct range *ranges; int i, idx; - if (!mem_rngs) + if (!mem_rngs || mem_rngs->nr_ranges <= 1) return; idx = 0; - ranges = &(mem_rngs->ranges[0]); + ranges = mem_rngs->ranges; for (i = 1; i < mem_rngs->nr_ranges; i++) { - if (ranges[i].start <= (ranges[i-1].end + 1)) - ranges[idx].end = ranges[i].end; + if (ranges[i].start <= (ranges[idx].end + 1)) + ranges[idx].end = max(ranges[idx].end, ranges[i].end); else { idx++; - if (i == idx) - continue; - ranges[idx] = ranges[i]; } } @@ -553,9 +551,9 @@ out: #endif /* CONFIG_KEXEC_FILE */ #ifdef CONFIG_CRASH_DUMP -static int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges, - unsigned long long mstart, - unsigned long long mend) +int arch_crash_exclude_mem_range(struct crash_mem **mem_ranges, + unsigned long long mstart, + unsigned long long mend) { struct crash_mem *tmem = *mem_ranges; @@ -604,18 +602,10 @@ int get_crash_memory_ranges(struct crash_mem **mem_ranges) sort_memory_ranges(*mem_ranges, true); } - /* Exclude crashkernel region */ - ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_res.start, crashk_res.end); + ret = crash_exclude_core_ranges(mem_ranges); if (ret) goto out; - for (i = 0; i < crashk_cma_cnt; ++i) { - ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_cma_ranges[i].start, - crashk_cma_ranges[i].end); - if (ret) - goto out; - } - /* * FIXME: For now, stay in parity with kexec-tools but if RTAS/OPAL * regions are exported to save their context at the time of @@ -641,89 +631,4 @@ out: pr_err("Failed to setup crash memory ranges\n"); return ret; } - -/** - * remove_mem_range - Removes the given memory range from the range list. - * @mem_ranges: Range list to remove the memory range to. - * @base: Base address of the range to remove. - * @size: Size of the memory range to remove. - * - * (Re)allocates memory, if needed. - * - * Returns 0 on success, negative errno on error. - */ -int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size) -{ - u64 end; - int ret = 0; - unsigned int i; - u64 mstart, mend; - struct crash_mem *mem_rngs = *mem_ranges; - - if (!size) - return 0; - - /* - * Memory range are stored as start and end address, use - * the same format to do remove operation. - */ - end = base + size - 1; - - for (i = 0; i < mem_rngs->nr_ranges; i++) { - mstart = mem_rngs->ranges[i].start; - mend = mem_rngs->ranges[i].end; - - /* - * Memory range to remove is not part of this range entry - * in the memory range list - */ - if (!(base >= mstart && end <= mend)) - continue; - - /* - * Memory range to remove is equivalent to this entry in the - * memory range list. Remove the range entry from the list. - */ - if (base == mstart && end == mend) { - for (; i < mem_rngs->nr_ranges - 1; i++) { - mem_rngs->ranges[i].start = mem_rngs->ranges[i+1].start; - mem_rngs->ranges[i].end = mem_rngs->ranges[i+1].end; - } - mem_rngs->nr_ranges--; - goto out; - } - /* - * Start address of the memory range to remove and the - * current memory range entry in the list is same. Just - * move the start address of the current memory range - * entry in the list to end + 1. - */ - else if (base == mstart) { - mem_rngs->ranges[i].start = end + 1; - goto out; - } - /* - * End address of the memory range to remove and the - * current memory range entry in the list is same. - * Just move the end address of the current memory - * range entry in the list to base - 1. - */ - else if (end == mend) { - mem_rngs->ranges[i].end = base - 1; - goto out; - } - /* - * Memory range to remove is not at the edge of current - * memory range entry. Split the current memory entry into - * two half. - */ - else { - size = mem_rngs->ranges[i].end - end + 1; - mem_rngs->ranges[i].end = base - 1; - ret = add_mem_range(mem_ranges, end + 1, size); - } - } -out: - return ret; -} #endif /* CONFIG_CRASH_DUMP */ diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index 9a0d1c1aca6c..b6bc2fc86dca 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig @@ -22,6 +22,7 @@ config KVM select KVM_COMMON select KVM_VFIO select HAVE_KVM_IRQ_BYPASS + select VIRT_XFER_TO_GUEST_WORK config KVM_BOOK3S_HANDLER bool diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 61dbeea317f3..dbac3573b2c8 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -388,7 +388,7 @@ static void kvmppc_set_pvr_hv(struct kvm_vcpu *vcpu, u32 pvr) } /* Dummy value used in computing PCR value below */ -#define PCR_ARCH_31 (PCR_ARCH_300 << 1) +#define PCR_ARCH_32 (PCR_ARCH_31 << 1) static inline unsigned long map_pcr_to_cap(unsigned long pcr) { @@ -417,7 +417,9 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) struct kvmppc_vcore *vc = vcpu->arch.vcore; /* We can (emulate) our own architecture version and anything older */ - if (cpu_has_feature(CPU_FTR_P11_PVR) || cpu_has_feature(CPU_FTR_ARCH_31)) + if (cpu_has_feature(CPU_FTR_ARCH_32)) + host_pcr_bit = PCR_ARCH_32; + else if (cpu_has_feature(CPU_FTR_P11_PVR) || cpu_has_feature(CPU_FTR_ARCH_31)) host_pcr_bit = PCR_ARCH_31; else if (cpu_has_feature(CPU_FTR_ARCH_300)) host_pcr_bit = PCR_ARCH_300; @@ -446,9 +448,24 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) guest_pcr_bit = PCR_ARCH_300; break; case PVR_ARCH_31: + guest_pcr_bit = PCR_ARCH_31; + break; case PVR_ARCH_31_P11: + /* + * Need to check this for ISA 3.1, as Power10 and + * Power11 share the same PCR. For any subsequent ISA + * versions, this will be taken care of by the guest vs + * host PCR comparison below. + */ + if (!cpu_has_feature(CPU_FTR_P11_PVR)) { + arch_compat = PVR_ARCH_INVALID; + goto out; + } guest_pcr_bit = PCR_ARCH_31; break; + case PVR_ARCH_32: + guest_pcr_bit = PCR_ARCH_32; + break; default: return -EINVAL; } @@ -469,6 +486,7 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) return -EINVAL; } +out: spin_lock(&vc->lock); vc->arch_compat = arch_compat; kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_LOGICAL_PVR); @@ -479,7 +497,7 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) vc->pcr = (host_pcr_bit - guest_pcr_bit) | PCR_MASK; spin_unlock(&vc->lock); - return 0; + return kvmppc_sanity_check(vcpu); } static void kvmppc_dump_regs(struct kvm_vcpu *vcpu) @@ -3853,7 +3871,8 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) */ local_irq_disable(); hard_irq_disable(); - if (lazy_irq_pending() || need_resched() || + xfer_to_guest_mode_prepare(); + if (lazy_irq_pending() || xfer_to_guest_mode_work_pending() || recheck_signals_and_mmu(&core_info)) { local_irq_enable(); vc->vcore_state = VCORE_INACTIVE; @@ -4824,10 +4843,16 @@ static int kvmppc_run_vcpu(struct kvm_vcpu *vcpu) vc->runner = vcpu; if (n_ceded == vc->n_runnable) { kvmppc_vcore_blocked(vc); - } else if (need_resched()) { + } else if (__xfer_to_guest_mode_work_pending()) { kvmppc_vcore_preempt(vc); - /* Let something else run */ - cond_resched_lock(&vc->lock); + /* + * Let something else run. The raw helper is used as + * signal exits are accounted by this path already; + * it may schedule(), so drop the vcore lock. + */ + spin_unlock(&vc->lock); + xfer_to_guest_mode_handle_work(); + spin_lock(&vc->lock); if (vc->vcore_state == VCORE_PREEMPT) kvmppc_vcore_end_preempt(vc); } else { @@ -4895,12 +4920,16 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, run->exit_reason = KVM_EXIT_FAIL_ENTRY; run->fail_entry.hardware_entry_failure_reason = 0; vcpu->arch.ret = r; - return r; + goto done; } } - if (need_resched()) - cond_resched(); + r = kvm_xfer_to_guest_mode_handle_work(vcpu); + if (r) { + /* -EINTR: signal pending, exit to userspace (KVM_EXIT_INTR) */ + vcpu->arch.ret = r; + goto done; + } kvmppc_update_vpas(vcpu); @@ -4914,9 +4943,13 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, vcpu->arch.state = KVMPPC_VCPU_RUNNABLE; - if (signal_pending(current)) - goto sigpend; - if (need_resched() || !kvm->arch.mmu_ready) + xfer_to_guest_mode_prepare(); + + /* + * IRQs are disabled here, so on pending work bail to the outer loop, + * which handles it via kvm_xfer_to_guest_mode_handle_work() above. + */ + if (xfer_to_guest_mode_work_pending() || !kvm->arch.mmu_ready) goto out; vcpu->cpu = pcpu; @@ -5068,10 +5101,6 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, return vcpu->arch.ret; - sigpend: - vcpu->stat.signal_exits++; - run->exit_reason = KVM_EXIT_INTR; - vcpu->arch.ret = -EINTR; out: vcpu->cpu = -1; vcpu->arch.thread_cpu = -1; @@ -6111,12 +6140,12 @@ static int kvmppc_irq_bypass_add_producer_hv(struct irq_bypass_consumer *cons, struct kvm_kernel_irqfd *irqfd = container_of(cons, struct kvm_kernel_irqfd, consumer); - irqfd->producer = prod; - ret = kvmppc_set_passthru_irq(irqfd->kvm, prod->irq, irqfd->gsi); if (ret) pr_info("kvmppc_set_passthru_irq (irq %d, gsi %d) fails: %d\n", prod->irq, irqfd->gsi, ret); + else + irqfd->producer = prod; return ret; } @@ -6510,6 +6539,61 @@ static bool kvmppc_hash_v3_possible(void) return true; } +static int kvmppc_map_compat_capabilities(u32 cpu_version, + unsigned long *capabilities) +{ + switch (cpu_version) { + case PVR_ARCH_31_P11: + *capabilities |= KVM_PPC_COMPAT_CAP_POWER11; + fallthrough; + case PVR_ARCH_31: + *capabilities |= KVM_PPC_COMPAT_CAP_POWER10; + fallthrough; + case PVR_ARCH_300: + *capabilities |= KVM_PPC_COMPAT_CAP_POWER9; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps) +{ + struct device_node *np; + unsigned long capabilities = 0; + long rc = -EINVAL; + u32 cpu_version = 0; + + if (kvmhv_on_pseries()) { + if (kvmhv_is_nestedv2()) { + WARN_ON_ONCE(!nested_capabilities); + capabilities = nested_capabilities; + rc = 0; + } else { + for_each_node_by_type(np, "cpu") { + if (!of_property_read_u32(np, "cpu-version", + &cpu_version)) { + of_node_put(np); + break; + } + } + if (!cpu_version) + return -EINVAL; + rc = kvmppc_map_compat_capabilities(cpu_version, + &capabilities); + } + } + + if (rc < 0) + return rc; + + host_caps->compat_capabilities = capabilities & KVM_PPC_COMPAT_BITMASK; + + return rc; +} + static struct kvmppc_ops kvm_ops_hv = { .get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv, .set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv, @@ -6552,6 +6636,7 @@ static struct kvmppc_ops kvm_ops_hv = { .hash_v3_possible = kvmppc_hash_v3_possible, .create_vcpu_debugfs = kvmppc_arch_create_vcpu_debugfs_hv, .create_vm_debugfs = kvmppc_arch_create_vm_debugfs_hv, + .get_compat_caps = kvmppc_get_compat_caps, }; static int kvm_init_subcore_bitmap(void) diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 22e616662255..a6ff42d7666c 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -1204,8 +1204,10 @@ static void kvmhv_emulate_tlbie_all_lpid(struct kvm_vcpu *vcpu, int ric) spin_lock(&kvm->mmu_lock); idr_for_each_entry(&kvm->arch.kvm_nested_guest_idr, gp, lpid) { + ++gp->refcnt; spin_unlock(&kvm->mmu_lock); kvmhv_emulate_tlbie_lpid(vcpu, gp, ric); + kvmhv_put_nested(gp); spin_lock(&kvm->mmu_lock); } spin_unlock(&kvm->mmu_lock); diff --git a/arch/powerpc/kvm/book3s_hv_uvmem.c b/arch/powerpc/kvm/book3s_hv_uvmem.c index 5fbb95d90e99..463aef870c4e 100644 --- a/arch/powerpc/kvm/book3s_hv_uvmem.c +++ b/arch/powerpc/kvm/book3s_hv_uvmem.c @@ -779,8 +779,11 @@ static int kvmppc_svm_page_in(struct vm_area_struct *vma, if (spage) { ret = uv_page_in(kvm->arch.lpid, pfn << page_shift, gpa, 0, page_shift); - if (ret) + if (ret) { + unlock_page(dpage); + put_page(dpage); goto out_finalize; + } } } diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 2ba2dd26a7ea..ecfb88bf6464 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -639,27 +639,24 @@ static void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr) */ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) { - struct kvm_host_map map; u64 hpage_offset; u32 *page; - int i, r; + int i; - r = kvm_vcpu_map(vcpu, pte->raddr >> PAGE_SHIFT, &map); - if (r) + CLASS(kvm_vcpu_map_local, m)(vcpu, pte->raddr >> PAGE_SHIFT); + if (m.ret) return; hpage_offset = pte->raddr & ~PAGE_MASK; hpage_offset &= ~0xFFFULL; hpage_offset /= 4; - page = map.hva; + page = m.map.hva; /* patch dcbz into reserved instruction, so we trap */ for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++) if ((be32_to_cpu(page[i]) & 0xff0007ff) == INS_DCBZ) page[i] &= cpu_to_be32(0xfffffff7); - - kvm_vcpu_unmap(vcpu, &map); } static bool kvmppc_visible_gpa(struct kvm_vcpu *vcpu, gpa_t gpa) diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index f3ddb24ece74..13ad4cf5fa71 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -598,7 +598,7 @@ static unsigned long watchdog_next_timeout(struct kvm_vcpu *vcpu) if (do_div(nr_jiffies, tb_ticks_per_jiffy)) nr_jiffies++; - return min_t(unsigned long long, nr_jiffies, TIMER_NEXT_MAX_DELTA); + return min(nr_jiffies, TIMER_NEXT_MAX_DELTA); } static void arm_next_watchdog(struct kvm_vcpu *vcpu) @@ -722,6 +722,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu) if (vcpu->arch.shared->msr & MSR_WE) { local_irq_enable(); kvm_vcpu_halt(vcpu); + local_irq_disable(); hard_irq_disable(); kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS); diff --git a/arch/powerpc/kvm/mpic.c b/arch/powerpc/kvm/mpic.c index 3070f36d9fb8..fb5f9e65e02e 100644 --- a/arch/powerpc/kvm/mpic.c +++ b/arch/powerpc/kvm/mpic.c @@ -1833,7 +1833,8 @@ int kvm_set_routing_entry(struct kvm *kvm, e->set = mpic_set_irq; e->irqchip.irqchip = ue->u.irqchip.irqchip; e->irqchip.pin = ue->u.irqchip.pin; - if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) + if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS || + e->irqchip.irqchip >= KVM_NR_IRQCHIPS) goto out; break; case KVM_IRQ_ROUTING_MSI: diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 00302399fc37..9194cf492d1c 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -81,23 +81,41 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) int r; WARN_ON(irqs_disabled()); + /* + * local_irq_disable() first: on 32-bit, hard_irq_disable() alone is a + * raw MSR[EE] clear that bypasses the lockdep/irq-tracing state, and + * the xfer_to_guest_mode helpers assert IRQs are seen as disabled. + */ + local_irq_disable(); hard_irq_disable(); while (true) { - if (need_resched()) { + xfer_to_guest_mode_prepare(); + + if (xfer_to_guest_mode_work_pending()) { + /* + * The helper must run with IRQs enabled and may + * schedule(). On a pending signal it returns -EINTR + * with run->exit_reason and vcpu->stat.signal_exits + * already set, so just return to userspace. + */ local_irq_enable(); - cond_resched(); + r = kvm_xfer_to_guest_mode_handle_work(vcpu); + local_irq_disable(); hard_irq_disable(); + if (r) { + /* + * The generic helper does not set the exit + * type; record it for the E500 + * CONFIG_KVM_EXIT_TIMING histogram (a no-op + * otherwise). + */ + kvmppc_set_exit_type(vcpu, SIGNAL_EXITS); + break; + } continue; } - if (signal_pending(current)) { - kvmppc_account_exit(vcpu, SIGNAL_EXITS); - vcpu->run->exit_reason = KVM_EXIT_INTR; - r = -EINTR; - break; - } - vcpu->mode = IN_GUEST_MODE; /* @@ -116,6 +134,7 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) local_irq_enable(); trace_kvm_check_requests(vcpu); r = kvmppc_core_check_requests(vcpu); + local_irq_disable(); hard_irq_disable(); if (r > 0) continue; @@ -258,6 +277,12 @@ int kvmppc_sanity_check(struct kvm_vcpu *vcpu) if (!vcpu->arch.pvr) goto out; +#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) + if (vcpu->arch.vcore && + vcpu->arch.vcore->arch_compat == PVR_ARCH_INVALID) + goto out; +#endif + /* PAPR only works with book3s_64 */ if ((vcpu->arch.cpu_type != KVM_CPU_3S_64) && vcpu->arch.papr_enabled) goto out; @@ -635,9 +660,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) * implementations just count online CPUs. */ if (hv_enabled) - r = min_t(unsigned int, num_present_cpus(), KVM_MAX_VCPUS); + r = min(num_present_cpus(), KVM_MAX_VCPUS); else - r = min_t(unsigned int, num_online_cpus(), KVM_MAX_VCPUS); + r = min(num_online_cpus(), KVM_MAX_VCPUS); break; case KVM_CAP_MAX_VCPUS: r = KVM_MAX_VCPUS; @@ -697,6 +722,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) } } break; +#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) + case KVM_CAP_PPC_COMPAT_CAPS: + r = 0; + if (hv_enabled && kvmhv_on_pseries()) + r = 1; + break; +#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ default: r = 0; break; @@ -2463,6 +2495,77 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) r = kvm->arch.kvm_ops->svm_off(kvm); break; } + case KVM_PPC_GET_COMPAT_CAPS: { + struct kvm_ppc_compat_caps host_caps = {}; + u64 usize; + + /* + * Read the size field first to drive copy_struct_from_user. + * size must be the first field of the struct. + */ + r = -EFAULT; + if (get_user(usize, (__u64 __user *)argp)) + goto out; + + r = -E2BIG; + if (unlikely(usize > PAGE_SIZE)) + goto out; + + /* + * Enforce a minimum: reject buffers smaller than the initial + * struct version (VER0). This allows old userspace compiled + * against the original struct to still work on a newer kernel + * that has grown the struct with appended fields. + */ + r = -EINVAL; + if (usize < KVM_PPC_COMPAT_CAPS_SIZE_VER0) + goto out; + + /* + * copy_struct_from_user() handles forward/backward compat: + * usize == ksize: verbatim copy + * usize < ksize: zero-pad trailing (old userspace, new kernel) + * usize > ksize: succeed iff trailing bytes are zero, else -E2BIG + */ + r = copy_struct_from_user(&host_caps, sizeof(host_caps), + argp, usize); + if (r) { + /* + * New userspace with a larger struct called an older + * kernel. Write back ksize in host_caps.size so + * userspace knows which older struct to retry with, + * then fail with -E2BIG. + */ + if (r == -E2BIG) + if (put_user((__u64)sizeof(host_caps), + (__u64 __user *)argp)) + r = -EFAULT; + goto out; + } + + /* Reserved fields must be zero */ + r = -EINVAL; + if (host_caps.flags) + goto out; + + r = -ENOTTY; + if (!kvm->arch.kvm_ops->get_compat_caps) + goto out; + + r = kvm->arch.kvm_ops->get_compat_caps(&host_caps); + if (r) + goto out; + + /* + * Report the number of bytes actually populated by the kernel, + * not usize: if new userspace passed a larger struct with zero + * trailing bytes, we only filled sizeof(host_caps) bytes. + */ + host_caps.size = min_t(u64, usize, sizeof(host_caps)); + r = copy_struct_to_user(argp, usize, &host_caps, + sizeof(host_caps), NULL); + break; + } default: { struct kvm *kvm = filp->private_data; r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg); diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index f84e0337cc02..44ff9f684bef 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -60,9 +60,6 @@ struct patch_context { static DEFINE_PER_CPU(struct patch_context, cpu_patching_context); -static int map_patch_area(void *addr, unsigned long text_poke_addr); -static void unmap_patch_area(unsigned long addr); - static bool mm_patch_enabled(void) { return IS_ENABLED(CONFIG_SMP) && radix_enabled(); @@ -117,11 +114,11 @@ static int text_area_cpu_up(unsigned int cpu) // Map/unmap the area to ensure all page tables are pre-allocated addr = (unsigned long)area->addr; - err = map_patch_area(empty_zero_page, addr); + err = map_kernel_page(addr, __pa_symbol(empty_zero_page), PAGE_KERNEL_RO); if (err) return err; - unmap_patch_area(addr); + unmap_kernel_page(addr); this_cpu_write(cpu_patching_context.area, area); this_cpu_write(cpu_patching_context.addr, addr); @@ -233,51 +230,6 @@ static unsigned long get_patch_pfn(void *addr) return __pa_symbol(addr) >> PAGE_SHIFT; } -/* - * This can be called for kernel text or a module. - */ -static int map_patch_area(void *addr, unsigned long text_poke_addr) -{ - unsigned long pfn = get_patch_pfn(addr); - - return map_kernel_page(text_poke_addr, (pfn << PAGE_SHIFT), PAGE_KERNEL); -} - -static void unmap_patch_area(unsigned long addr) -{ - pte_t *ptep; - pmd_t *pmdp; - pud_t *pudp; - p4d_t *p4dp; - pgd_t *pgdp; - - pgdp = pgd_offset_k(addr); - if (WARN_ON(pgd_none(*pgdp))) - return; - - p4dp = p4d_offset(pgdp, addr); - if (WARN_ON(p4d_none(*p4dp))) - return; - - pudp = pud_offset(p4dp, addr); - if (WARN_ON(pud_none(*pudp))) - return; - - pmdp = pmd_offset(pudp, addr); - if (WARN_ON(pmd_none(*pmdp))) - return; - - ptep = pte_offset_kernel(pmdp, addr); - if (WARN_ON(pte_none(*ptep))) - return; - - /* - * In hash, pte_clear flushes the tlb, in radix, we have to - */ - pte_clear(&init_mm, addr, ptep); - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); -} - static int __do_patch_mem_mm(void *addr, unsigned long val, bool is_dword) { int err; diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S index daa72061dc0c..c3f5e7d31ee7 100644 --- a/arch/powerpc/lib/string.S +++ b/arch/powerpc/lib/string.S @@ -10,28 +10,6 @@ .text -/* This clears out any unused part of the destination buffer, - just as the libc version does. -- paulus */ -_GLOBAL(strncpy) - PPC_LCMPI 0,r5,0 - beqlr - mtctr r5 - addi r6,r3,-1 - addi r4,r4,-1 - .balign IFETCH_ALIGN_BYTES -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r6) - bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ - bnelr /* if we didn't hit a null char, we're done */ - mfctr r5 - PPC_LCMPI 0,r5,0 /* any space left in destination buffer? */ - beqlr /* we know r0 == 0 here */ -2: stbu r0,1(r6) /* clear it out if so */ - bdnz 2b - blr -EXPORT_SYMBOL(strncpy) - _GLOBAL(strncmp) PPC_LCMPI 0,r5,0 beq- 2f diff --git a/arch/powerpc/lib/vmx-helper.c b/arch/powerpc/lib/vmx-helper.c index 554b248002b4..cc9fb72cb4eb 100644 --- a/arch/powerpc/lib/vmx-helper.c +++ b/arch/powerpc/lib/vmx-helper.c @@ -46,13 +46,20 @@ int exit_vmx_usercopy(void) * set and we are preemptible. The hack here is to schedule a * decrementer to fire here and reschedule for us if necessary. */ - if (need_irq_preemption() && need_resched()) + if (need_resched()) set_dec(1); return 0; } EXPORT_SYMBOL(exit_vmx_usercopy); -int enter_vmx_ops(void) +/* + * Can be called from kexec copy_page() path with MMU off. The kexec + * code sets preempt_count to HARDIRQ_OFFSET so we return early here. + * Since in_interrupt() is always inline, __no_sanitize_address on this + * function is sufficient to avoid KASAN shadow memory accesses in real + * mode. + */ +int __no_sanitize_address enter_vmx_ops(void) { if (in_interrupt()) return 0; diff --git a/arch/powerpc/mm/book3s64/hash_native.c b/arch/powerpc/mm/book3s64/hash_native.c index e9e2dd70c060..ab2a80e59011 100644 --- a/arch/powerpc/mm/book3s64/hash_native.c +++ b/arch/powerpc/mm/book3s64/hash_native.c @@ -184,9 +184,14 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize) va |= ssize << 8; sllp = get_sllp_encoding(apsize); va |= sllp << 5; - asm volatile(ASM_FTR_IFSET("tlbiel %0", PPC_TLBIEL_v205(%0, 0), %1) - : : "r" (va), "i" (CPU_FTR_ARCH_206) - : "memory"); + + if (cpu_has_feature(CPU_FTR_ARCH_32)) { + asm volatile(PPC_TLBIEL(%0, %1, 0, 0, 0) : : "r"(va), "r"(0) : "memory"); + } else { + asm volatile(ASM_FTR_IFSET("tlbiel %0", PPC_TLBIEL_v205(%0, 0), %1) + : : "r" (va), "i" (CPU_FTR_ARCH_206) + : "memory"); + } break; default: /* We need 14 to 14 + i bits of va */ @@ -203,9 +208,14 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize) */ va |= (vpn & 0xfe); va |= 1; /* L */ - asm volatile(ASM_FTR_IFSET("tlbiel %0", PPC_TLBIEL_v205(%0, 1), %1) - : : "r" (va), "i" (CPU_FTR_ARCH_206) - : "memory"); + + if (cpu_has_feature(CPU_FTR_ARCH_32)) { + asm volatile(PPC_TLBIEL(%0, %1, 0, 0, 0) : : "r"(va), "r"(0) : "memory"); + } else { + asm volatile(ASM_FTR_IFSET("tlbiel %0", PPC_TLBIEL_v205(%0, 1), %1) + : : "r" (va), "i" (CPU_FTR_ARCH_206) + : "memory"); + } break; } trace_tlbie(0, 1, va, 0, 0, 0, 0); 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/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c index 10aced261cff..cf692b2b5f7b 100644 --- a/arch/powerpc/mm/book3s64/radix_pgtable.c +++ b/arch/powerpc/mm/book3s64/radix_pgtable.c @@ -1314,7 +1314,6 @@ int __meminit vmemmap_populate_compound_pages(unsigned long start_pfn, * covering out both edges. */ unsigned long addr; - unsigned long addr_pfn = start_pfn; unsigned long next; pgd_t *pgd; p4d_t *p4d; @@ -1335,7 +1334,6 @@ int __meminit vmemmap_populate_compound_pages(unsigned long start_pfn, if (pmd_leaf(READ_ONCE(*pmd))) { /* existing huge mapping. Skip the range */ - addr_pfn += (PMD_SIZE >> PAGE_SHIFT); next = pmd_addr_end(addr, end); continue; } @@ -1348,11 +1346,11 @@ int __meminit vmemmap_populate_compound_pages(unsigned long start_pfn, * page whose VMEMMAP_RESERVE_NR pages were mapped and * this request fall in those pages. */ - addr_pfn += 1; next = addr + PAGE_SIZE; continue; } else { unsigned long nr_pages = pgmap_vmemmap_nr(pgmap); + unsigned long addr_pfn = page_to_pfn((struct page *)addr); unsigned long pfn_offset = addr_pfn - ALIGN_DOWN(addr_pfn, nr_pages); pte_t *tail_page_pte; @@ -1376,7 +1374,6 @@ int __meminit vmemmap_populate_compound_pages(unsigned long start_pfn, if (!pte) return -ENOMEM; - addr_pfn += 2; next = addr + 2 * PAGE_SIZE; continue; } @@ -1392,7 +1389,6 @@ int __meminit vmemmap_populate_compound_pages(unsigned long start_pfn, return -ENOMEM; vmemmap_verify(pte, node, addr, addr + PAGE_SIZE); - addr_pfn += 1; next = addr + PAGE_SIZE; continue; } @@ -1402,7 +1398,6 @@ int __meminit vmemmap_populate_compound_pages(unsigned long start_pfn, return -ENOMEM; vmemmap_verify(pte, node, addr, addr + PAGE_SIZE); - addr_pfn += 1; next = addr + PAGE_SIZE; continue; } diff --git a/arch/powerpc/mm/book3s64/slice.c b/arch/powerpc/mm/book3s64/slice.c index 28bec5bc7879..82127e31dca6 100644 --- a/arch/powerpc/mm/book3s64/slice.c +++ b/arch/powerpc/mm/book3s64/slice.c @@ -659,7 +659,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned int psize; if (radix_enabled()) - return generic_get_unmapped_area(filp, addr, len, pgoff, flags, vm_flags); + return generic_get_unmapped_area(filp, addr, len, pgoff, flags, + legacy_to_vma_flags(vm_flags)); if (filp && is_file_hugepages(filp)) psize = file_to_psize(filp); @@ -679,7 +680,8 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp, unsigned int psize; if (radix_enabled()) - return generic_get_unmapped_area_topdown(filp, addr0, len, pgoff, flags, vm_flags); + return generic_get_unmapped_area_topdown(filp, addr0, len, + pgoff, flags, legacy_to_vma_flags(vm_flags)); if (filp && is_file_hugepages(filp)) psize = file_to_psize(filp); diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 558fafb82b8a..a298746dc143 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -104,17 +104,14 @@ void __init pseries_add_gpage(u64 addr, u64 page_size, unsigned long number_of_p } } -static int __init pseries_alloc_bootmem_huge_page(struct hstate *hstate) +static __init void *pseries_alloc_bootmem_huge_page(struct hstate *hstate) { - struct huge_bootmem_page *m; + void *m; if (nr_gpages == 0) - return 0; + return NULL; m = phys_to_virt(gpage_freearray[--nr_gpages]); gpage_freearray[nr_gpages] = 0; - list_add(&m->list, &huge_boot_pages[0]); - m->hstate = hstate; - m->flags = 0; - return 1; + return m; } bool __init hugetlb_node_alloc_supported(void) @@ -124,7 +121,7 @@ bool __init hugetlb_node_alloc_supported(void) #endif -int __init alloc_bootmem_huge_page(struct hstate *h, int nid) +void *__init arch_alloc_bootmem_huge_page(struct hstate *h, int nid) { #ifdef CONFIG_PPC_BOOK3S_64 diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index b6f3ae03ca9e..0e777d7dc332 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -41,7 +41,6 @@ #include <linux/libfdt.h> #include <linux/memremap.h> #include <linux/memory.h> -#include <linux/bootmem_info.h> #include <asm/pgalloc.h> #include <asm/page.h> @@ -388,13 +387,6 @@ void __ref vmemmap_free(unsigned long start, unsigned long end, #endif -#ifdef CONFIG_HAVE_BOOTMEM_INFO_NODE -void register_page_bootmem_memmap(unsigned long section_nr, - struct page *start_page, unsigned long size) -{ -} -#endif /* CONFIG_HAVE_BOOTMEM_INFO_NODE */ - #endif /* CONFIG_SPARSEMEM_VMEMMAP */ #ifdef CONFIG_PPC_BOOK3S_64 @@ -636,7 +628,9 @@ void __init mmu_early_init_devtree(void) of_scan_flat_dt(dt_scan_mmu_pid_width, NULL); if (hvmode && !mmu_lpid_bits) { - if (early_cpu_has_feature(CPU_FTR_ARCH_207S)) + if (early_cpu_has_feature(CPU_FTR_ARCH_32)) + mmu_lpid_bits = 16; /* POWER12 */ + else if (early_cpu_has_feature(CPU_FTR_ARCH_207S)) mmu_lpid_bits = 12; /* POWER8-10 */ else mmu_lpid_bits = 10; /* POWER7 */ diff --git a/arch/powerpc/mm/kasan/init_book3e_64.c b/arch/powerpc/mm/kasan/init_book3e_64.c index 0d3a73d6d4b0..0ed372fb8b09 100644 --- a/arch/powerpc/mm/kasan/init_book3e_64.c +++ b/arch/powerpc/mm/kasan/init_book3e_64.c @@ -68,9 +68,6 @@ static void __init kasan_init_phys_region(void *start, void *end) unsigned long k_start, k_end, k_cur; void *va; - if (start >= end) - return; - k_start = ALIGN_DOWN((unsigned long)kasan_mem_to_shadow(start), PAGE_SIZE); k_end = ALIGN((unsigned long)kasan_mem_to_shadow(end), PAGE_SIZE); diff --git a/arch/powerpc/mm/kasan/init_book3s_64.c b/arch/powerpc/mm/kasan/init_book3s_64.c index dcafa641804c..ccfbfb894637 100644 --- a/arch/powerpc/mm/kasan/init_book3s_64.c +++ b/arch/powerpc/mm/kasan/init_book3s_64.c @@ -24,9 +24,6 @@ static void __init kasan_init_phys_region(void *start, void *end) unsigned long k_start, k_end, k_cur; void *va; - if (start >= end) - return; - k_start = ALIGN_DOWN((unsigned long)kasan_mem_to_shadow(start), PAGE_SIZE); k_end = ALIGN((unsigned long)kasan_mem_to_shadow(end), PAGE_SIZE); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 648d0c5602ec..b617b69452cd 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -158,12 +158,13 @@ int __ref arch_add_memory(int nid, u64 start, u64 size, return rc; } -void __ref arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap) +void __ref arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap, + struct dev_pagemap *pgmap) { unsigned long start_pfn = start >> PAGE_SHIFT; unsigned long nr_pages = size >> PAGE_SHIFT; - __remove_pages(start_pfn, nr_pages, altmap); + __remove_pages(start_pfn, nr_pages, altmap, pgmap); arch_remove_linear_mapping(start, size); } #endif @@ -370,12 +371,6 @@ int devmem_is_allowed(unsigned long pfn) } #endif /* CONFIG_STRICT_DEVMEM */ -/* - * This is defined in kernel/resource.c but only powerpc needs to export it, for - * the EHEA driver. Drop this when drivers/net/ethernet/ibm/ehea is removed. - */ -EXPORT_SYMBOL_GPL(walk_system_ram_range); - #ifdef CONFIG_EXECMEM static struct execmem_info execmem_info __ro_after_init; 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 53ab97ad6074..7b07b43575f1 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c @@ -295,7 +295,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr alloclen = proglen + FUNCTION_DESCR_SIZE + fixup_len + extable_len; fhdr = bpf_jit_binary_pack_alloc(alloclen, &fimage, 4, &hdr, &image, - bpf_jit_fill_ill_insns); + bpf_jit_fill_ill_insns, bpf_prog_was_classic(fp)); if (!fhdr) goto out_err; @@ -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); @@ -583,7 +588,7 @@ bool bpf_jit_inlines_helper_call(s32 imm) void *arch_alloc_bpf_trampoline(unsigned int size) { - return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns); + return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns, false); } void arch_free_bpf_trampoline(void *image, unsigned int size) @@ -597,22 +602,22 @@ int arch_protect_bpf_trampoline(void *image, unsigned int size) } static int invoke_bpf_prog(u32 *image, u32 *ro_image, struct codegen_context *ctx, - struct bpf_tramp_link *l, int regs_off, int retval_off, + struct bpf_tramp_node *n, int regs_off, int retval_off, int run_ctx_off, bool save_ret) { - struct bpf_prog *p = l->link.prog; + struct bpf_prog *p = n->link->prog; ppc_inst_t branch_insn; u32 jmp_idx; int ret = 0; /* Save cookie */ if (IS_ENABLED(CONFIG_PPC64)) { - PPC_LI64(_R3, l->cookie); + PPC_LI64(_R3, n->cookie); EMIT(PPC_RAW_STD(_R3, _R1, run_ctx_off + offsetof(struct bpf_tramp_run_ctx, bpf_cookie))); } else { - PPC_LI32(_R3, l->cookie >> 32); - PPC_LI32(_R4, l->cookie); + PPC_LI32(_R3, n->cookie >> 32); + PPC_LI32(_R4, n->cookie); EMIT(PPC_RAW_STW(_R3, _R1, run_ctx_off + offsetof(struct bpf_tramp_run_ctx, bpf_cookie))); EMIT(PPC_RAW_STW(_R4, _R1, @@ -679,7 +684,7 @@ static int invoke_bpf_prog(u32 *image, u32 *ro_image, struct codegen_context *ct } static int invoke_bpf_mod_ret(u32 *image, u32 *ro_image, struct codegen_context *ctx, - struct bpf_tramp_links *tl, int regs_off, int retval_off, + struct bpf_tramp_nodes *tn, int regs_off, int retval_off, int run_ctx_off, u32 *branches) { int i; @@ -690,8 +695,8 @@ static int invoke_bpf_mod_ret(u32 *image, u32 *ro_image, struct codegen_context */ EMIT(PPC_RAW_LI(_R3, 0)); EMIT(PPC_RAW_STL(_R3, _R1, retval_off)); - for (i = 0; i < tl->nr_links; i++) { - if (invoke_bpf_prog(image, ro_image, ctx, tl->links[i], regs_off, retval_off, + for (i = 0; i < tn->nr_nodes; i++) { + if (invoke_bpf_prog(image, ro_image, ctx, tn->nodes[i], regs_off, retval_off, run_ctx_off, true)) return -EINVAL; @@ -807,18 +812,18 @@ static void bpf_trampoline_restore_args_stack(u32 *image, struct codegen_context static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_image, void *rw_image_end, void *ro_image, const struct btf_func_model *m, u32 flags, - struct bpf_tramp_links *tlinks, + struct bpf_tramp_nodes *tnodes, void *func_addr) { int regs_off, func_meta_off, ip_off, run_ctx_off, retval_off; int nvr_off, alt_lr_off, r4_off = 0; - struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN]; - struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; - struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT]; + struct bpf_tramp_nodes *fmod_ret = &tnodes[BPF_TRAMP_MODIFY_RETURN]; + struct bpf_tramp_nodes *fentry = &tnodes[BPF_TRAMP_FENTRY]; + struct bpf_tramp_nodes *fexit = &tnodes[BPF_TRAMP_FEXIT]; int i, ret, nr_regs, retaddr_off, bpf_frame_size = 0; struct codegen_context codegen_ctx, *ctx; int cookie_off, cookie_cnt, cookie_ctx_off; - int fsession_cnt = bpf_fsession_cnt(tlinks); + int fsession_cnt = bpf_fsession_cnt(tnodes); u64 func_meta; u32 *image = (u32 *)rw_image; ppc_inst_t branch_insn; @@ -893,7 +898,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im /* room for session cookies */ cookie_off = bpf_frame_size; - cookie_cnt = bpf_fsession_cookie_cnt(tlinks); + cookie_cnt = bpf_fsession_cookie_cnt(tnodes); bpf_frame_size += cookie_cnt * 8; /* Room for IP address argument */ @@ -1030,21 +1035,21 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im cookie_ctx_off = (regs_off - cookie_off) / 8; - for (i = 0; i < fentry->nr_links; i++) { - if (bpf_prog_calls_session_cookie(fentry->links[i])) { + for (i = 0; i < fentry->nr_nodes; i++) { + if (bpf_prog_calls_session_cookie(fentry->nodes[i])) { u64 meta = func_meta | (cookie_ctx_off << BPF_TRAMP_COOKIE_INDEX_SHIFT); store_func_meta(image, ctx, meta, func_meta_off); cookie_ctx_off--; } - if (invoke_bpf_prog(image, ro_image, ctx, fentry->links[i], regs_off, retval_off, + if (invoke_bpf_prog(image, ro_image, ctx, fentry->nodes[i], regs_off, retval_off, run_ctx_off, flags & BPF_TRAMP_F_RET_FENTRY_RET)) return -EINVAL; } - if (fmod_ret->nr_links) { - branches = kcalloc(fmod_ret->nr_links, sizeof(u32), GFP_KERNEL); + if (fmod_ret->nr_nodes) { + branches = kcalloc(fmod_ret->nr_nodes, sizeof(u32), GFP_KERNEL); if (!branches) return -ENOMEM; @@ -1093,7 +1098,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im } /* Update branches saved in invoke_bpf_mod_ret with address of do_fexit */ - for (i = 0; i < fmod_ret->nr_links && image; i++) { + for (i = 0; i < fmod_ret->nr_nodes && image; i++) { if (create_cond_branch(&branch_insn, &image[branches[i]], (unsigned long)&image[ctx->idx], COND_NE << 16)) { ret = -EINVAL; @@ -1110,15 +1115,15 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im cookie_ctx_off = (regs_off - cookie_off) / 8; - for (i = 0; i < fexit->nr_links; i++) { - if (bpf_prog_calls_session_cookie(fexit->links[i])) { + for (i = 0; i < fexit->nr_nodes; i++) { + if (bpf_prog_calls_session_cookie(fexit->nodes[i])) { u64 meta = func_meta | (cookie_ctx_off << BPF_TRAMP_COOKIE_INDEX_SHIFT); store_func_meta(image, ctx, meta, func_meta_off); cookie_ctx_off--; } - if (invoke_bpf_prog(image, ro_image, ctx, fexit->links[i], regs_off, retval_off, + if (invoke_bpf_prog(image, ro_image, ctx, fexit->nodes[i], regs_off, retval_off, run_ctx_off, false)) { ret = -EINVAL; goto cleanup; @@ -1185,18 +1190,18 @@ cleanup: } int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, - struct bpf_tramp_links *tlinks, void *func_addr) + struct bpf_tramp_nodes *tnodes, void *func_addr) { struct bpf_tramp_image im; int ret; - ret = __arch_prepare_bpf_trampoline(&im, NULL, NULL, NULL, m, flags, tlinks, func_addr); + ret = __arch_prepare_bpf_trampoline(&im, NULL, NULL, NULL, m, flags, tnodes, func_addr); return ret; } int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, const struct btf_func_model *m, u32 flags, - struct bpf_tramp_links *tlinks, + struct bpf_tramp_nodes *tnodes, void *func_addr) { u32 size = image_end - image; @@ -1212,7 +1217,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i return -ENOMEM; ret = __arch_prepare_bpf_trampoline(im, rw_image, rw_image + size, image, m, - flags, tlinks, func_addr); + flags, tnodes, func_addr); if (ret < 0) goto out; diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index db364d9083e7..fc9db691e820 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -451,10 +451,26 @@ 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; /* bpf to bpf call, func is not known in the initial pass. Emit 5 nops as a placeholder */ if (!func) { @@ -469,6 +485,8 @@ int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context * } #ifdef CONFIG_PPC_KERNEL_PCREL + long reladdr; + reladdr = func_addr - local_paca->kernelbase; /* @@ -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()); + int 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..84ecf6fa7f5d --- /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 CFUNC(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/Makefile b/arch/powerpc/perf/Makefile index 78dd7e25219e..bcc804c41338 100644 --- a/arch/powerpc/perf/Makefile +++ b/arch/powerpc/perf/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_PPC_PERF_CTRS) += core-book3s.o obj64-$(CONFIG_PPC_PERF_CTRS) += ppc970-pmu.o power5-pmu.o \ power5+-pmu.o power6-pmu.o power7-pmu.o \ isa207-common.o power8-pmu.o power9-pmu.o \ - generic-compat-pmu.o power10-pmu.o bhrb.o + generic-compat-pmu.o power10-pmu.o bhrb.o power12-pmu.o obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o obj-$(CONFIG_PPC_POWERNV) += imc-pmu.o diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 8b0081441f85..10ded865583c 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 = { @@ -2242,6 +2243,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, const u64 last_period = event->hw.last_period; s64 prev, delta, left; int record = 0; + int mark_event = regs->dsisr & MMCRA_SAMPLE_ENABLE; if (event->hw.state & PERF_HES_STOPPED) { write_pmc(event->hw.idx, 0); @@ -2304,9 +2306,9 @@ static void record_and_restart(struct perf_event *event, unsigned long val, * In ISA v3.0 and before values "0" and "7" are considered reserved. * In ISA v3.1, value "7" has been used to indicate "larx/stcx". * Drop the sample if "type" has reserved values for this field with a - * ISA version check. + * ISA version check for marked events. */ - if (event->attr.sample_type & PERF_SAMPLE_DATA_SRC && + if (mark_event && event->attr.sample_type & PERF_SAMPLE_DATA_SRC && ppmu->get_mem_data_src) { val = (regs->dar & SIER_TYPE_MASK) >> SIER_TYPE_SHIFT; if (val == 0 || (val == 7 && !cpu_has_feature(CPU_FTR_ARCH_31))) { @@ -2482,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"); /* @@ -2611,6 +2613,8 @@ static int __init init_ppc64_pmu(void) return 0; else if (!init_power11_pmu()) return 0; + else if (!init_power12_pmu()) + return 0; else if (!init_ppc970_pmu()) return 0; else 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..b0eedf185960 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> @@ -428,25 +429,25 @@ static char *memdup_to_str(char *maybe_str, int max_len, gfp_t gfp) static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, char *buf) { - return cpumap_print_to_pagebuf(true, buf, &hv_24x7_cpumask); + return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(&hv_24x7_cpumask)); } 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 5cac2cf3bd1e..76495744f52a 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,13 +94,13 @@ 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, struct device_attribute *attr, char *buf) { - return cpumap_print_to_pagebuf(true, buf, &hv_gpci_cpumask); + return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(&hv_gpci_cpumask)); } /* Interface attribute array index to store system information */ @@ -210,7 +211,7 @@ static ssize_t processor_bus_topology_show(struct device *dev, struct device_att 0, 0, buf, &n, arg); if (!ret) - return n; + goto out_success; if (ret != H_PARAMETER) goto out; @@ -244,12 +245,14 @@ static ssize_t processor_bus_topology_show(struct device *dev, struct device_att starting_index, 0, buf, &n, arg); if (!ret) - return n; + goto out_success; if (ret != H_PARAMETER) goto out; } +out_success: + put_cpu_var(hv_gpci_reqb); return n; out: @@ -278,7 +281,7 @@ static ssize_t processor_config_show(struct device *dev, struct device_attribute 0, 0, buf, &n, arg); if (!ret) - return n; + goto out_success; if (ret != H_PARAMETER) goto out; @@ -312,12 +315,14 @@ static ssize_t processor_config_show(struct device *dev, struct device_attribute starting_index, 0, buf, &n, arg); if (!ret) - return n; + goto out_success; if (ret != H_PARAMETER) goto out; } +out_success: + put_cpu_var(hv_gpci_reqb); return n; out: @@ -346,7 +351,7 @@ static ssize_t affinity_domain_via_virtual_processor_show(struct device *dev, 0, 0, buf, &n, arg); if (!ret) - return n; + goto out_success; if (ret != H_PARAMETER) goto out; @@ -382,12 +387,14 @@ static ssize_t affinity_domain_via_virtual_processor_show(struct device *dev, starting_index, secondary_index, buf, &n, arg); if (!ret) - return n; + goto out_success; if (ret != H_PARAMETER) goto out; } +out_success: + put_cpu_var(hv_gpci_reqb); return n; out: @@ -416,7 +423,7 @@ static ssize_t affinity_domain_via_domain_show(struct device *dev, struct device 0, 0, buf, &n, arg); if (!ret) - return n; + goto out_success; if (ret != H_PARAMETER) goto out; @@ -448,12 +455,14 @@ static ssize_t affinity_domain_via_domain_show(struct device *dev, struct device starting_index, 0, buf, &n, arg); if (!ret) - return n; + goto out_success; if (ret != H_PARAMETER) goto out; } +out_success: + put_cpu_var(hv_gpci_reqb); return n; out: diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index c1563b4eaa94..f401181d8669 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -117,7 +117,7 @@ static ssize_t imc_pmu_cpumask_get_attr(struct device *dev, return 0; } - return cpumap_print_to_pagebuf(true, buf, active_mask); + return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(active_mask)); } static DEVICE_ATTR(cpumask, S_IRUGO, imc_pmu_cpumask_get_attr, NULL); @@ -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)) { @@ -1025,10 +1023,7 @@ static int thread_imc_event_init(struct perf_event *event) static bool is_thread_imc_pmu(struct perf_event *event) { - if (!strncmp(event->pmu->name, "thread_imc", strlen("thread_imc"))) - return true; - - return false; + return strstarts(event->pmu->name, "thread_imc"); } static __be64 *get_event_base_addr(struct perf_event *event) diff --git a/arch/powerpc/perf/internal.h b/arch/powerpc/perf/internal.h index a70ac471a5a5..84d6ca209c49 100644 --- a/arch/powerpc/perf/internal.h +++ b/arch/powerpc/perf/internal.h @@ -11,4 +11,5 @@ int __init init_power8_pmu(void); int __init init_power9_pmu(void); int __init init_power10_pmu(void); int __init init_power11_pmu(void); +int __init init_power12_pmu(void); int __init init_generic_compat_pmu(void); 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/power12-events-list.h b/arch/powerpc/perf/power12-events-list.h new file mode 100644 index 000000000000..cc26796d418b --- /dev/null +++ b/arch/powerpc/perf/power12-events-list.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Performance counter support for POWER12 processors. + * + * Copyright 2026 Athira Rajeev, IBM Corporation. + */ + +/* + * Power12 event codes. + */ +EVENT(PM_CYC, 0x600f4); +EVENT(PM_DISP_STALL_CYC, 0x100f8); +EVENT(PM_EXEC_STALL, 0x30008); +EVENT(PM_INST_CMPL, 0x500fa); +EVENT(PM_BR_CMPL, 0x4d05e); +EVENT(PM_BR_MPRED_CMPL, 0x400f6); +EVENT(PM_BR_FIN, 0x10068); +EVENT(PM_MPRED_BR_FIN, 0x27098); +EVENT(PM_LD_DEMAND_MISS_L1_FIN, 0x400f0); + +/* All L1 D cache load references counted at finish, gated by reject */ +EVENT(PM_LD_REF_L1, 0x100fc); +/* Load Missed L1 */ +EVENT(PM_LD_MISS_L1, 0x3e054); +/* Store Missed L1 */ +EVENT(PM_ST_MISS_L1, 0x300f0); +/* L1 cache data prefetches */ +EVENT(PM_LD_PREFETCH_CACHE_LINE_MISS, 0x1002c); +/* Demand iCache Miss */ +EVENT(PM_L1_ICACHE_MISS, 0x200fc); +/* Instruction fetches from L1 */ +EVENT(PM_INST_FROM_L1, 0x04080); +/* Instruction Demand sectors writtent into IL1 */ +EVENT(PM_INST_FROM_L1MISS, 0x03F00000001C040); +/* Instruction prefetch written into IL1 */ +EVENT(PM_IC_PREF_REQ, 0x040a0); +/* The data cache was reloaded from local core's L3 due to a demand load */ +EVENT(PM_DATA_FROM_L3, 0x10340000003C040); +/* Demand LD - L3 Miss (not L2 hit and not L3 hit) */ +EVENT(PM_DATA_FROM_L3MISS, 0x300fe); +/* All successful D-side store dispatches for this thread */ +EVENT(PM_L2_ST, 0x010000046080); +/* All successful D-side store dispatches for this thread that were L2 Miss */ +EVENT(PM_L2_ST_MISS, 0x26880); +/* Total HW L3 prefetches(Load+store) */ +EVENT(PM_L3_PF_MISS_L3, 0x100000016080); +/* Data PTEG reload */ +EVENT(PM_DTLB_MISS, 0x300fc); +/* ITLB Reloaded */ +EVENT(PM_ITLB_MISS, 0x400fc); + +EVENT(PM_CYC_ALT, 0x0001e); +EVENT(PM_INST_CMPL_ALT, 0x00002); + +/* + * Memory Access Events + * + * Primary PMU event used here is PM_MRK_INST_CMPL (0x401e0) + * To enable capturing of memory profiling, these MMCRA bits + * needs to be programmed and corresponding raw event format + * encoding. + * + * MMCRA bits encoding needed are + * SM (Sampling Mode) + * EM (Eligibility for Random Sampling) + * TECE (Threshold Event Counter Event) + * TS (Threshold Start Event) + * TE (Threshold End Event) + * + * Corresponding Raw Encoding bits: + * sample [EM,SM] + * thresh_sel (TECE) + * thresh start (TS) + * thresh end (TE) + */ + +EVENT(MEM_LOADS, 0x35340401e0); +EVENT(MEM_STORES, 0x353c0401e0); diff --git a/arch/powerpc/perf/power12-pmu.c b/arch/powerpc/perf/power12-pmu.c new file mode 100644 index 000000000000..89cc704b8324 --- /dev/null +++ b/arch/powerpc/perf/power12-pmu.c @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Performance counter support for Power12 processors. + * + * Copyright 2026 Athira Rajeev, IBM Corporation. + */ + +#define pr_fmt(fmt) "power12-pmu: " fmt + +#include "isa207-common.h" + +/* + * Raw event encoding for Power12: + * + * 60 56 52 48 44 40 36 32 + * | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | + * | | [ ] [ src_match ] [ src_mask ] | [ ] [ l2l3_sel ] [ thresh_ctl ] + * | | | | | | + * | | *- IFM (Linux) | | thresh start/stop -* + * | *- BHRB (Linux) | src_sel + * *- EBB (Linux) *invert_bit + * + * 28 24 20 16 12 8 4 0 + * | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | + * [ ] [ sample ] [ ] [ ] [ pmc ] [unit ] [ ] | m [ pmcxsel ] + * | | | | | | | + * | | | | | | *- mark + * | | | *- L1/L2/L3 cache_sel | |*-radix_scope_qual + * | | sdar_mode | + * | *- sampling mode for marked events *- combine + * | + * *- thresh_sel + * + * Below uses IBM bit numbering. + * + * MMCR1[x:y] = unit (PMCxUNIT) + * MMCR1[24] = pmc1combine[0] + * MMCR1[25] = pmc1combine[1] + * MMCR1[26] = pmc2combine[0] + * MMCR1[27] = pmc2combine[1] + * MMCR1[28] = pmc3combine[0] + * MMCR1[29] = pmc3combine[1] + * MMCR1[30] = pmc4combine[0] + * MMCR1[31] = pmc4combine[1] + * + * if pmc == 3 and unit == 0 and pmcxsel[0:6] == 0b0101011 + * MMCR1[20:27] = thresh_ctl + * else if pmc == 4 and unit == 0xf and pmcxsel[0:6] == 0b0101001 + * MMCR1[20:27] = thresh_ctl + * else + * MMCRA[48:55] = thresh_ctl (THRESH START/END) + * + * if thresh_sel: + * MMCRA[45:47] = thresh_sel + * + * if l2l3_sel: + * MMCR2[56:60] = l2l3_sel[0:4] + * + * MMCR1[16] = cache_sel[0] + * MMCR1[17] = cache_sel[1] + * MMCR1[18] = radix_scope_qual + * + * if mark: + * MMCRA[63] = 1 (SAMPLE_ENABLE) + * MMCRA[57:59] = sample[0:2] (RAND_SAMP_ELIG) + * MMCRA[61:62] = sample[3:4] (RAND_SAMP_MODE) + * + * if EBB and BHRB: + * MMCRA[32:33] = IFM + * + * MMCRA[SDAR_MODE] = sdar_mode[0:1] + */ + +/* + * Some power12 event codes. + */ +#define EVENT(_name, _code) enum{_name = _code} + +#include "power12-events-list.h" + +#undef EVENT + +/* MMCRA IFM bits - POWER12 */ +#define POWER12_MMCRA_IFM1 0x0000000040000000UL +#define POWER12_MMCRA_IFM2 0x0000000080000000UL +#define POWER12_MMCRA_IFM3 0x00000000C0000000UL +#define POWER12_MMCRA_BHRB_MASK 0x00000000C0000000UL + +extern u64 PERF_REG_EXTENDED_MASK; + +/* Table of alternatives, sorted by column 0 */ +static const unsigned int power12_event_alternatives[][MAX_ALT] = { + { PM_INST_CMPL_ALT, PM_INST_CMPL }, + { PM_CYC_ALT, PM_CYC }, +}; + +static int power12_get_alternatives(u64 event, unsigned int flags, u64 alt[]) +{ + int num_alt = 0; + + num_alt = isa207_get_alternatives(event, alt, + ARRAY_SIZE(power12_event_alternatives), flags, + power12_event_alternatives); + + return num_alt; +} + +static int power12_check_attr_config(struct perf_event *ev) +{ + u64 val; + u64 event = ev->attr.config; + + val = (event >> EVENT_SAMPLE_SHIFT) & EVENT_SAMPLE_MASK; + if (val == 0x10 || isa3XX_check_attr_config(ev)) + return -EINVAL; + + return 0; +} + +GENERIC_EVENT_ATTR(cpu-cycles, PM_CYC); +GENERIC_EVENT_ATTR(instructions, PM_INST_CMPL); +GENERIC_EVENT_ATTR(branch-instructions, PM_BR_FIN); +GENERIC_EVENT_ATTR(branch-misses, PM_MPRED_BR_FIN); +GENERIC_EVENT_ATTR(cache-references, PM_LD_REF_L1); +GENERIC_EVENT_ATTR(cache-misses, PM_LD_DEMAND_MISS_L1_FIN); +GENERIC_EVENT_ATTR(mem-loads, MEM_LOADS); +GENERIC_EVENT_ATTR(mem-stores, MEM_STORES); + +CACHE_EVENT_ATTR(L1-dcache-load-misses, PM_LD_MISS_L1); +CACHE_EVENT_ATTR(L1-dcache-loads, PM_LD_REF_L1); +CACHE_EVENT_ATTR(L1-dcache-prefetches, PM_LD_PREFETCH_CACHE_LINE_MISS); +CACHE_EVENT_ATTR(L1-dcache-store-misses, PM_ST_MISS_L1); +CACHE_EVENT_ATTR(L1-icache-load-misses, PM_L1_ICACHE_MISS); +CACHE_EVENT_ATTR(L1-icache-loads, PM_INST_FROM_L1); +CACHE_EVENT_ATTR(L1-icache-prefetches, PM_IC_PREF_REQ); +CACHE_EVENT_ATTR(LLC-load-misses, PM_DATA_FROM_L3MISS); +CACHE_EVENT_ATTR(LLC-loads, PM_DATA_FROM_L3); +CACHE_EVENT_ATTR(LLC-prefetches, PM_L3_PF_MISS_L3); +CACHE_EVENT_ATTR(LLC-store-misses, PM_L2_ST_MISS); +CACHE_EVENT_ATTR(LLC-stores, PM_L2_ST); +CACHE_EVENT_ATTR(branch-load-misses, PM_BR_MPRED_CMPL); +CACHE_EVENT_ATTR(branch-loads, PM_BR_CMPL); +CACHE_EVENT_ATTR(dTLB-load-misses, PM_DTLB_MISS); +CACHE_EVENT_ATTR(iTLB-load-misses, PM_ITLB_MISS); + +static struct attribute *power12_events_attr[] = { + GENERIC_EVENT_PTR(PM_CYC), + GENERIC_EVENT_PTR(PM_INST_CMPL), + GENERIC_EVENT_PTR(PM_BR_FIN), + GENERIC_EVENT_PTR(PM_MPRED_BR_FIN), + GENERIC_EVENT_PTR(PM_LD_REF_L1), + GENERIC_EVENT_PTR(PM_LD_DEMAND_MISS_L1_FIN), + GENERIC_EVENT_PTR(MEM_LOADS), + GENERIC_EVENT_PTR(MEM_STORES), + CACHE_EVENT_PTR(PM_LD_MISS_L1), + CACHE_EVENT_PTR(PM_LD_REF_L1), + CACHE_EVENT_PTR(PM_LD_PREFETCH_CACHE_LINE_MISS), + CACHE_EVENT_PTR(PM_ST_MISS_L1), + CACHE_EVENT_PTR(PM_L1_ICACHE_MISS), + CACHE_EVENT_PTR(PM_INST_FROM_L1), + CACHE_EVENT_PTR(PM_IC_PREF_REQ), + CACHE_EVENT_PTR(PM_DATA_FROM_L3MISS), + CACHE_EVENT_PTR(PM_DATA_FROM_L3), + CACHE_EVENT_PTR(PM_L3_PF_MISS_L3), + CACHE_EVENT_PTR(PM_L2_ST_MISS), + CACHE_EVENT_PTR(PM_L2_ST), + CACHE_EVENT_PTR(PM_BR_MPRED_CMPL), + CACHE_EVENT_PTR(PM_BR_CMPL), + CACHE_EVENT_PTR(PM_DTLB_MISS), + CACHE_EVENT_PTR(PM_ITLB_MISS), + NULL +}; + +static const struct attribute_group power12_pmu_events_group = { + .name = "events", + .attrs = power12_events_attr, +}; + +PMU_FORMAT_ATTR(event, "config:0-59"); +PMU_FORMAT_ATTR(pmcxsel, "config:0-7"); +PMU_FORMAT_ATTR(mark, "config:8"); +PMU_FORMAT_ATTR(combine, "config:10-11"); +PMU_FORMAT_ATTR(unit, "config:12-15"); +PMU_FORMAT_ATTR(pmc, "config:16-19"); +PMU_FORMAT_ATTR(cache_sel, "config:20-21"); +PMU_FORMAT_ATTR(sdar_mode, "config:22-23"); +PMU_FORMAT_ATTR(sample_mode, "config:24-28"); +PMU_FORMAT_ATTR(thresh_sel, "config:29-31"); +PMU_FORMAT_ATTR(thresh_stop, "config:32-35"); +PMU_FORMAT_ATTR(thresh_start, "config:36-39"); +PMU_FORMAT_ATTR(l2l3_sel, "config:40-44"); +PMU_FORMAT_ATTR(src_sel, "config:45-46"); +PMU_FORMAT_ATTR(invert_bit, "config:47"); +PMU_FORMAT_ATTR(src_mask, "config:48-53"); +PMU_FORMAT_ATTR(src_match, "config:54-59"); +PMU_FORMAT_ATTR(radix_scope, "config:9"); +PMU_FORMAT_ATTR(thresh_cmp, "config1:0-17"); + +static struct attribute *power12_pmu_format_attr[] = { + &format_attr_event.attr, + &format_attr_pmcxsel.attr, + &format_attr_mark.attr, + &format_attr_combine.attr, + &format_attr_unit.attr, + &format_attr_pmc.attr, + &format_attr_cache_sel.attr, + &format_attr_sdar_mode.attr, + &format_attr_sample_mode.attr, + &format_attr_thresh_sel.attr, + &format_attr_thresh_stop.attr, + &format_attr_thresh_start.attr, + &format_attr_l2l3_sel.attr, + &format_attr_src_sel.attr, + &format_attr_invert_bit.attr, + &format_attr_src_mask.attr, + &format_attr_src_match.attr, + &format_attr_radix_scope.attr, + &format_attr_thresh_cmp.attr, + NULL, +}; + +static const struct attribute_group power12_pmu_format_group = { + .name = "format", + .attrs = power12_pmu_format_attr, +}; + +static const struct attribute_group *power12_pmu_attr_groups[] = { + &power12_pmu_format_group, + &power12_pmu_events_group, + NULL, +}; + +static int power12_generic_events[] = { + [PERF_COUNT_HW_CPU_CYCLES] = PM_CYC, + [PERF_COUNT_HW_INSTRUCTIONS] = PM_INST_CMPL, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = PM_BR_FIN, + [PERF_COUNT_HW_BRANCH_MISSES] = PM_MPRED_BR_FIN, + [PERF_COUNT_HW_CACHE_REFERENCES] = PM_LD_REF_L1, + [PERF_COUNT_HW_CACHE_MISSES] = PM_LD_DEMAND_MISS_L1_FIN, +}; + +static u64 power12_bhrb_filter_map(u64 branch_sample_type) +{ + u64 pmu_bhrb_filter = 0; + + /* BHRB and regular PMU events share the same privilege state + * filter configuration. BHRB is always recorded along with a + * regular PMU event. As the privilege state filter is handled + * in the basic PMC configuration of the accompanying regular + * PMU event, we ignore any separate BHRB specific request. + */ + + /* No branch filter requested */ + if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY) + return pmu_bhrb_filter; + + /* Invalid branch filter options - HW does not support */ + if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_RETURN) + return -1; + + if (branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL) { + pmu_bhrb_filter |= POWER12_MMCRA_IFM2; + return pmu_bhrb_filter; + } + + if (branch_sample_type & PERF_SAMPLE_BRANCH_COND) { + pmu_bhrb_filter |= POWER12_MMCRA_IFM3; + return pmu_bhrb_filter; + } + + if (branch_sample_type & PERF_SAMPLE_BRANCH_CALL) + return -1; + + if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) { + pmu_bhrb_filter |= POWER12_MMCRA_IFM1; + return pmu_bhrb_filter; + } + + /* Every thing else is unsupported */ + return -1; +} + +static void power12_config_bhrb(u64 pmu_bhrb_filter) +{ + pmu_bhrb_filter &= POWER12_MMCRA_BHRB_MASK; + + /* Enable BHRB filter in PMU */ + mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter)); +} + +#define C(x) PERF_COUNT_HW_CACHE_##x + +/* + * Table of generalized cache-related events. + * 0 means not supported, -1 means nonsensical, other values + * are event codes. + */ +static u64 power12_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { + [C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = PM_LD_REF_L1, + [C(RESULT_MISS)] = PM_LD_MISS_L1, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = PM_ST_MISS_L1, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = PM_LD_PREFETCH_CACHE_LINE_MISS, + [C(RESULT_MISS)] = 0, + }, + }, + [C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = PM_INST_FROM_L1, + [C(RESULT_MISS)] = PM_L1_ICACHE_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = PM_INST_FROM_L1MISS, + [C(RESULT_MISS)] = -1, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = PM_IC_PREF_REQ, + [C(RESULT_MISS)] = 0, + }, + }, + [C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = PM_DATA_FROM_L3, + [C(RESULT_MISS)] = PM_DATA_FROM_L3MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = PM_L2_ST, + [C(RESULT_MISS)] = PM_L2_ST_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = PM_L3_PF_MISS_L3, + [C(RESULT_MISS)] = 0, + }, + }, + [C(DTLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = PM_DTLB_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + }, + [C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = 0, + [C(RESULT_MISS)] = PM_ITLB_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + }, + [C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = PM_BR_CMPL, + [C(RESULT_MISS)] = PM_BR_MPRED_CMPL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = -1, + [C(RESULT_MISS)] = -1, + }, + }, +}; + +#undef C + +/* + * Set the MMCR0[CC56RUN] bit to enable counting for + * PMC5 and PMC6 regardless of the state of CTRL[RUN], + * so that we can use counters 5 and 6 as PM_INST_CMPL and + * PM_CYC. + */ +static int power12_compute_mmcr(u64 event[], int n_ev, + unsigned int hwc[], struct mmcr_regs *mmcr, + struct perf_event *pevents[], u32 flags) +{ + int ret; + + ret = isa207_compute_mmcr(event, n_ev, hwc, mmcr, pevents, flags); + if (!ret) + mmcr->mmcr0 |= MMCR0_C56RUN; + return ret; +} + +static struct power_pmu power12_pmu = { + .name = "Power12", + .n_counter = MAX_PMU_COUNTERS, + .add_fields = ISA207_ADD_FIELDS, + .test_adder = ISA207_TEST_ADDER, + .group_constraint_mask = CNST_CACHE_PMC4_MASK, + .group_constraint_val = CNST_CACHE_PMC4_VAL, + .compute_mmcr = power12_compute_mmcr, + .config_bhrb = power12_config_bhrb, + .bhrb_filter_map = power12_bhrb_filter_map, + .get_constraint = isa207_get_constraint, + .get_alternatives = power12_get_alternatives, + .get_mem_data_src = isa207_get_mem_data_src, + .get_mem_weight = isa207_get_mem_weight, + .disable_pmc = isa207_disable_pmc, + .flags = PPMU_HAS_SIER | PPMU_ARCH_207S | + PPMU_ARCH_31 | PPMU_HAS_ATTR_CONFIG1 | + PPMU_P10, + .n_generic = ARRAY_SIZE(power12_generic_events), + .generic_events = power12_generic_events, + .cache_events = &power12_cache_events, + .attr_groups = power12_pmu_attr_groups, + .bhrb_nr = 32, + .capabilities = PERF_PMU_CAP_EXTENDED_REGS, + .check_attr_config = power12_check_attr_config, +}; + +int __init init_power12_pmu(void) +{ + unsigned int pvr; + int rc; + + pvr = mfspr(SPRN_PVR); + if (PVR_VER(pvr) != PVR_POWER12) + return -ENODEV; + + /* Set the PERF_REG_EXTENDED_MASK here */ + PERF_REG_EXTENDED_MASK = PERF_REG_PMU_MASK_31; + + rc = register_power_pmu(&power12_pmu); + if (rc) + return rc; + + /* Tell userspace that EBB is supported */ + cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_EBB; + + return 0; +} 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/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index fc79f8466933..150813cea945 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -227,13 +227,6 @@ config PPC44x_SIMPLE help This option enables the simple PowerPC 44x platform support. -config PPC4xx_GPIO - bool "PPC4xx GPIO support" - depends on 44x - select GPIOLIB - help - Enable gpiolib support for ppc440 based boards - # 44x specific CPU modules, selected based on the board above. config 440EP bool diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index ca7b1bb442d9..4598d8b89bf4 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile @@ -15,4 +15,4 @@ obj-$(CONFIG_FSP2) += fsp2.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_PPC4xx_HSTA_MSI) += hsta_msi.o obj-$(CONFIG_PPC4xx_CPM) += cpm.o -obj-$(CONFIG_PPC4xx_GPIO) += gpio.o + diff --git a/arch/powerpc/platforms/44x/gpio.c b/arch/powerpc/platforms/44x/gpio.c deleted file mode 100644 index aea0d913b59d..000000000000 --- a/arch/powerpc/platforms/44x/gpio.c +++ /dev/null @@ -1,210 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * PPC4xx gpio driver - * - * Copyright (c) 2008 Harris Corporation - * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix - * Copyright (c) MontaVista Software, Inc. 2008. - * - * Author: Steve Falco <sfalco@harris.com> - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/gpio/driver.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/platform_device.h> - -#define GPIO_MASK(gpio) (0x80000000 >> (gpio)) -#define GPIO_MASK2(gpio) (0xc0000000 >> ((gpio) * 2)) - -/* Physical GPIO register layout */ -struct ppc4xx_gpio { - __be32 or; - __be32 tcr; - __be32 osrl; - __be32 osrh; - __be32 tsrl; - __be32 tsrh; - __be32 odr; - __be32 ir; - __be32 rr1; - __be32 rr2; - __be32 rr3; - __be32 reserved1; - __be32 isr1l; - __be32 isr1h; - __be32 isr2l; - __be32 isr2h; - __be32 isr3l; - __be32 isr3h; -}; - -struct ppc4xx_gpio_chip { - struct gpio_chip gc; - void __iomem *regs; - spinlock_t lock; -}; - -/* - * GPIO LIB API implementation for GPIOs - * - * There are a maximum of 32 gpios in each gpio controller. - */ - -static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio) -{ - struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); - struct ppc4xx_gpio __iomem *regs = chip->regs; - - return !!(in_be32(®s->ir) & GPIO_MASK(gpio)); -} - -static inline void -__ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); - struct ppc4xx_gpio __iomem *regs = chip->regs; - - if (val) - setbits32(®s->or, GPIO_MASK(gpio)); - else - clrbits32(®s->or, GPIO_MASK(gpio)); -} - -static int ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); - unsigned long flags; - - spin_lock_irqsave(&chip->lock, flags); - - __ppc4xx_gpio_set(gc, gpio, val); - - spin_unlock_irqrestore(&chip->lock, flags); - - pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); - - return 0; -} - -static int ppc4xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) -{ - struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); - struct ppc4xx_gpio __iomem *regs = chip->regs; - unsigned long flags; - - spin_lock_irqsave(&chip->lock, flags); - - /* Disable open-drain function */ - clrbits32(®s->odr, GPIO_MASK(gpio)); - - /* Float the pin */ - clrbits32(®s->tcr, GPIO_MASK(gpio)); - - /* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */ - if (gpio < 16) { - clrbits32(®s->osrl, GPIO_MASK2(gpio)); - clrbits32(®s->tsrl, GPIO_MASK2(gpio)); - } else { - clrbits32(®s->osrh, GPIO_MASK2(gpio)); - clrbits32(®s->tsrh, GPIO_MASK2(gpio)); - } - - spin_unlock_irqrestore(&chip->lock, flags); - - return 0; -} - -static int -ppc4xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc); - struct ppc4xx_gpio __iomem *regs = chip->regs; - unsigned long flags; - - spin_lock_irqsave(&chip->lock, flags); - - /* First set initial value */ - __ppc4xx_gpio_set(gc, gpio, val); - - /* Disable open-drain function */ - clrbits32(®s->odr, GPIO_MASK(gpio)); - - /* Drive the pin */ - setbits32(®s->tcr, GPIO_MASK(gpio)); - - /* Bits 0-15 use TSRL, bits 16-31 use TSRH */ - if (gpio < 16) { - clrbits32(®s->osrl, GPIO_MASK2(gpio)); - clrbits32(®s->tsrl, GPIO_MASK2(gpio)); - } else { - clrbits32(®s->osrh, GPIO_MASK2(gpio)); - clrbits32(®s->tsrh, GPIO_MASK2(gpio)); - } - - spin_unlock_irqrestore(&chip->lock, flags); - - pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); - - return 0; -} - -static int ppc4xx_gpio_probe(struct platform_device *ofdev) -{ - struct device *dev = &ofdev->dev; - struct device_node *np = dev->of_node; - struct ppc4xx_gpio_chip *chip; - struct gpio_chip *gc; - - chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - spin_lock_init(&chip->lock); - - gc = &chip->gc; - - gc->base = -1; - gc->ngpio = 32; - gc->direction_input = ppc4xx_gpio_dir_in; - gc->direction_output = ppc4xx_gpio_dir_out; - gc->get = ppc4xx_gpio_get; - gc->set = ppc4xx_gpio_set; - - gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np); - if (!gc->label) - return -ENOMEM; - - chip->regs = devm_of_iomap(dev, np, 0, NULL); - if (IS_ERR(chip->regs)) - return PTR_ERR(chip->regs); - - return devm_gpiochip_add_data(dev, gc, chip); -} - -static const struct of_device_id ppc4xx_gpio_match[] = { - { - .compatible = "ibm,ppc4xx-gpio", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, ppc4xx_gpio_match); - -static struct platform_driver ppc4xx_gpio_driver = { - .probe = ppc4xx_gpio_probe, - .driver = { - .name = "ppc4xx-gpio", - .of_match_table = ppc4xx_gpio_match, - }, -}; - -static int __init ppc4xx_gpio_init(void) -{ - return platform_driver_register(&ppc4xx_gpio_driver); -} -arch_initcall(ppc4xx_gpio_init); diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index a5001d32f978..6f674f86dc85 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c @@ -293,6 +293,8 @@ static int pika_dtm_thread(void __iomem *fpga) schedule_timeout(HZ); } + put_device(&client->dev); + return 0; } diff --git a/arch/powerpc/platforms/82xx/km82xx.c b/arch/powerpc/platforms/82xx/km82xx.c index 99f0f0f41876..4ad223525e89 100644 --- a/arch/powerpc/platforms/82xx/km82xx.c +++ b/arch/powerpc/platforms/82xx/km82xx.c @@ -27,8 +27,8 @@ static void __init km82xx_pic_init(void) { - struct device_node *np __free(device_node); - np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic"); + struct device_node *np __free(device_node) = of_find_compatible_node(NULL, + NULL, "fsl,pq2-pic"); if (!np) { pr_err("PIC init: can not find cpm-pic node\n"); diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index 9b693594a5f7..3908c9b0725c 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -8,13 +8,13 @@ */ #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/device.h> #include <linux/mutex.h> #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 +77,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/85xx/common.c b/arch/powerpc/platforms/85xx/common.c index 757811155587..c11deb2f50ed 100644 --- a/arch/powerpc/platforms/85xx/common.c +++ b/arch/powerpc/platforms/85xx/common.c @@ -42,6 +42,8 @@ static const struct of_device_id mpc85xx_common_ids[] __initconst = { { .compatible = "fsl,qoriq-pcie-v2.3", }, { .compatible = "fsl,qoriq-pcie-v2.2", }, { .compatible = "fsl,fman", }, + /* IFC NAND and NOR controllers */ + { .compatible = "fsl,ifc", }, {}, }; diff --git a/arch/powerpc/platforms/86xx/common.c b/arch/powerpc/platforms/86xx/common.c index a4a550527609..57cb65be7e0f 100644 --- a/arch/powerpc/platforms/86xx/common.c +++ b/arch/powerpc/platforms/86xx/common.c @@ -4,7 +4,6 @@ */ #include <linux/init.h> -#include <linux/mod_devicetable.h> #include <linux/of_platform.h> #include <asm/reg.h> #include <asm/synch.h> diff --git a/arch/powerpc/platforms/8xx/cpm1.c b/arch/powerpc/platforms/8xx/cpm1.c index 7433be7d66ee..b31376bf6778 100644 --- a/arch/powerpc/platforms/8xx/cpm1.c +++ b/arch/powerpc/platforms/8xx/cpm1.c @@ -472,12 +472,24 @@ 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; struct cpm1_gpio16_chip *cpm1_gc; struct gpio_chip *gc; - u16 mask; + u32 mask; cpm1_gc = devm_kzalloc(dev, sizeof(*cpm1_gc), GFP_KERNEL); if (!cpm1_gc) @@ -485,7 +497,7 @@ int cpm1_gpiochip_add16(struct device *dev) spin_lock_init(&cpm1_gc->lock); - if (!of_property_read_u16(np, "fsl,cpm1-gpio-irq-mask", &mask)) { + if (!of_property_read_u32(np, "fsl,cpm1-gpio-irq-mask", &mask)) { int i, j; for (i = 0, j = 0; i < 16; i++) @@ -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/Kconfig b/arch/powerpc/platforms/Kconfig index c4e61843d9d9..2f797ac6f1b3 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -228,14 +228,6 @@ config TAU_AVERAGE If in doubt, say N here. -config QE_GPIO - bool "QE GPIO support" - depends on QUICC_ENGINE - select GPIOLIB - help - Say Y here if you're going to use hardware that connects to the - QE GPIOs. - config CPM2 bool "Enable support for the CPM2 (Communications Processor Module)" depends on (FSL_SOC_BOOKE && PPC32) || PPC_82xx diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index bac02c83bb3e..f0adbf7ecb7f 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -87,6 +87,7 @@ config PPC_BOOK3S_64 select ARCH_ENABLE_HUGEPAGE_MIGRATION if HUGETLB_PAGE && MIGRATION select ARCH_ENABLE_SPLIT_PMD_PTLOCK select ARCH_SUPPORTS_HUGETLBFS + select ARCH_HAS_PTE_PROTNONE select ARCH_SUPPORTS_NUMA_BALANCING select HAVE_MOVE_PMD select HAVE_MOVE_PUD @@ -112,7 +113,7 @@ config PPC_THP depends on PPC_RADIX_MMU || (PPC_64S_HASH_MMU && PAGE_SIZE_64KB) select HAVE_ARCH_TRANSPARENT_HUGEPAGE select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD - select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE + select ARCH_HAS_PMD_SOFTLEAVES if TRANSPARENT_HUGEPAGE choice prompt "CPU selection" 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/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 10fa9b844fcc..de7494748fec 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -268,10 +268,12 @@ static int spufs_mem_mmap_access(struct vm_area_struct *vma, if (write && !(vma->vm_flags & VM_WRITE)) return -EACCES; + if (offset >= LS_SIZE) + return -EFAULT; if (spu_acquire(ctx)) return -EINTR; - if ((offset + len) > vma->vm_end) - len = vma->vm_end - offset; + if ((offset + len) > LS_SIZE) + len = LS_SIZE - offset; local_store = ctx->ops->get_ls(ctx); if (write) memcpy_toio(local_store + offset, buf, len); @@ -1430,7 +1432,7 @@ static int spufs_mfc_open(struct inode *inode, struct file *file) if (ctx->owner != current->mm) return -EINVAL; - if (icount_read(inode) != 1) + if (icount_read_once(inode) != 1) return -EBUSY; mutex_lock(&ctx->mapping_lock); diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index 60f990a336c4..2df955274652 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -272,13 +272,12 @@ void __init pas_pci_init(void) { struct device_node *root = of_find_node_by_path("/"); struct device_node *np; - int res; pci_set_flags(PCI_SCAN_ALL_PCIE_DEVS); np = of_find_compatible_node(root, NULL, "pasemi,rootbus"); if (np) { - res = pas_add_bridge(np); + pas_add_bridge(np); of_node_put(np); } of_node_put(root); diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index d03b41336901..45792ecd5dfd 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -165,6 +165,8 @@ static int __init pas_setup_mce_regs(void) while (dev && reg < MAX_MCE_REGS) { mce_regs[reg].name = kasprintf(GFP_KERNEL, "mc%d_mcdebug_errsta", reg); + if (!mce_regs[reg].name) + return -ENOMEM; mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x730); dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, dev); reg++; diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index 72eb99aba40f..abceae91dfde 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -284,9 +284,7 @@ static void __init bootx_scan_dt_build_struct(unsigned long base, dt_push_token(OF_DT_BEGIN_NODE, mem_end); /* get the node's full name */ - namep = np->full_name ? (char *)(base + np->full_name) : NULL; - if (namep == NULL) - namep = ""; + namep = np->full_name ? (char *)(base + np->full_name) : ""; l = strlen(namep); DBG("* struct: %s\n", namep); diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index 73b7f4e8c047..a175a32a222b 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -1058,40 +1058,6 @@ int pmac_i2c_match_adapter(struct device_node *dev, struct i2c_adapter *adapter) } EXPORT_SYMBOL_GPL(pmac_i2c_match_adapter); -int pmac_low_i2c_lock(struct device_node *np) -{ - struct pmac_i2c_bus *bus, *found = NULL; - - list_for_each_entry(bus, &pmac_i2c_busses, link) { - if (np == bus->controller) { - found = bus; - break; - } - } - if (!found) - return -ENODEV; - return pmac_i2c_open(bus, 0); -} -EXPORT_SYMBOL_GPL(pmac_low_i2c_lock); - -int pmac_low_i2c_unlock(struct device_node *np) -{ - struct pmac_i2c_bus *bus, *found = NULL; - - list_for_each_entry(bus, &pmac_i2c_busses, link) { - if (np == bus->controller) { - found = bus; - break; - } - } - if (!found) - return -ENODEV; - pmac_i2c_close(bus); - return 0; -} -EXPORT_SYMBOL_GPL(pmac_low_i2c_unlock); - - int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled) { int rc; @@ -1505,7 +1471,7 @@ static int __init pmac_i2c_create_platform_devices(void) if (bus->platform_dev == NULL) return -ENOMEM; bus->platform_dev->dev.platform_data = bus; - bus->platform_dev->dev.of_node = bus->busnode; + platform_device_set_of_node(bus->platform_dev, bus->busnode); platform_device_add(bus->platform_dev); } 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/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 32ecbc46e74b..728a5610d167 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -1623,15 +1623,13 @@ int64_t pnv_opal_pci_msi_eoi(struct irq_data *d) return opal_pci_msi_eoi(phb->opal_id, d->parent_data->hwirq); } -static struct irq_chip pnv_pci_msi_irq_chip; - /* * Returns true iff chip is something that we could call * pnv_opal_pci_msi_eoi for. */ bool is_pnv_opal_msi(struct irq_chip *chip) { - return chip == &pnv_pci_msi_irq_chip; + return chip && chip->name && str_has_prefix(chip->name, "PNV-"); } EXPORT_SYMBOL_GPL(is_pnv_opal_msi); @@ -1728,7 +1726,7 @@ static const struct msi_parent_ops pnv_msi_parent_ops = { .chip_flags = MSI_CHIP_FLAG_SET_EOI, .bus_select_token = DOMAIN_BUS_NEXUS, .bus_select_mask = MATCH_PCI_MSI, - .prefix = "PNV-", + .prefix = "PNV-", /* Note: is_pnv_opal_msi() uses this */ .init_dev_msi_info = pnv_init_dev_msi_info, }; diff --git a/arch/powerpc/platforms/powernv/pci-sriov.c b/arch/powerpc/platforms/powernv/pci-sriov.c index 7105a573aec4..8652078801f2 100644 --- a/arch/powerpc/platforms/powernv/pci-sriov.c +++ b/arch/powerpc/platforms/powernv/pci-sriov.c @@ -244,8 +244,8 @@ void pnv_pci_ioda_fixup_iov(struct pci_dev *pdev) } } -resource_size_t pnv_pci_iov_resource_alignment(struct pci_dev *pdev, - int resno) +resource_size_t pnv_pci_iov_resource_alignment(const struct pci_dev *pdev, + int resno) { resource_size_t align = pci_iov_resource_size(pdev, resno); struct pnv_phb *phb = pci_bus_to_pnvhb(pdev->bus); diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 42075501663b..3ac718d471c2 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -251,13 +251,14 @@ struct pnv_iov_data { struct resource holes[PCI_SRIOV_NUM_BARS]; }; -static inline struct pnv_iov_data *pnv_iov_get(struct pci_dev *pdev) +static inline struct pnv_iov_data *pnv_iov_get(const struct pci_dev *pdev) { return pdev->dev.archdata.iov_data; } void pnv_pci_ioda_fixup_iov(struct pci_dev *pdev); -resource_size_t pnv_pci_iov_resource_alignment(struct pci_dev *pdev, int resno); +resource_size_t pnv_pci_iov_resource_alignment(const struct pci_dev *pdev, + int resno); int pnv_pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs); int pnv_pcibios_sriov_disable(struct pci_dev *pdev); diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 4dbb47ddbdcc..2af92e7ba4ee 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -312,7 +312,7 @@ static void __noreturn pnv_restart(char *cmd) pnv_prepare_going_down(); do { - if (!cmd || !strlen(cmd)) + if (!cmd || *cmd == '\0') rc = opal_cec_reboot(); else if (strcmp(cmd, "full") == 0) rc = opal_cec_reboot2(OPAL_REBOOT_FULL_IPL, NULL); @@ -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/smp.c b/arch/powerpc/platforms/powernv/smp.c index 8f41ef364fc6..b1201dbafcaf 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -332,10 +332,12 @@ static void pnv_cause_ipi(int cpu) static void __init pnv_smp_probe(void) { - if (xive_enabled()) - xive_smp_probe(); - else + if (xive_enabled()) { + if (xive_smp_probe() < 0) + return; + } else { xics_smp_probe(); + } if (cpu_has_feature(CPU_FTR_DBELL)) { ic_cause_ipi = smp_ops->cause_ipi; 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/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index 12c473768c39..9109c218a060 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -950,8 +950,6 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) static int __init ps3_register_devices(void) { - int result; - if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) return -ENODEV; @@ -959,7 +957,7 @@ static int __init ps3_register_devices(void) /* ps3_repository_dump_bus_info(); */ - result = ps3_start_probe_thread(PS3_BUS_TYPE_STORAGE); + ps3_start_probe_thread(PS3_BUS_TYPE_STORAGE); ps3_register_vuart_devices(); diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 20fc5b68faee..315a32fd75b1 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -615,6 +615,7 @@ static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, fail_map: for (iopage--; 0 <= iopage; iopage--) { + offset = (1 << r->page_size) * iopage; lv1_put_iopte(0, c->bus_addr + offset, c->lpar_addr + offset, diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index b8c030eab138..0cc755ac3e7f 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -6,6 +6,8 @@ * Copyright 2006 Sony Corp. */ +#include <linux/minmax.h> + #include <asm/lv1call.h> #include "platform.h" @@ -74,8 +76,9 @@ static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, static u64 make_first_field(const char *text, u64 index) { u64 n = 0; + size_t len = min(strlen(text), sizeof(n)); - memcpy((char *)&n, text, strnlen(text, sizeof(n))); + memcpy(&n, text, len); return PS3_VENDOR_ID_NONE + (n >> 32) + index; } 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/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index e4e0b45e1b9d..33a676fa3d6c 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -13,6 +13,7 @@ #include <linux/export.h> #include <linux/io.h> #include <linux/mm.h> +#include <linux/processor.h> #include <asm/spu.h> #include <asm/spu_priv1.h> @@ -191,8 +192,6 @@ static void spu_unmap(struct spu *spu) static int __init setup_areas(struct spu *spu) { - struct table {char* name; unsigned long addr; unsigned long size;}; - spu_pdata(spu)->shadow = ioremap_prot(spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow), pgprot_noncached_wc(PAGE_KERNEL_RO)); @@ -363,12 +362,9 @@ static int __init ps3_create_spu(struct spu *spu, void *data) if (result) goto fail_enable; - /* Make sure the spu is in SPE_EX_STATE_EXECUTED. */ - - /* need something better here!!! */ - while (in_be64(&spu_pdata(spu)->shadow->spe_execution_status) - != SPE_EX_STATE_EXECUTED) - (void)0; + while (in_be64(&spu_pdata(spu)->shadow->spe_execution_status) != + SPE_EX_STATE_EXECUTED) + cpu_relax(); return result; diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index f7052b131a4c..74910ce3a541 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -154,6 +154,7 @@ config HV_PERF_CTRS config VPA_PMU tristate "VPA PMU events" depends on KVM_BOOK3S_64_HV && HV_PERF_CTRS + default m help Enable access to the VPA PMU counters via perf. This enables code that support measurement for KVM on PowerVM(KoP) feature. diff --git a/arch/powerpc/platforms/pseries/cc_platform.c b/arch/powerpc/platforms/pseries/cc_platform.c index e8021af83a19..46e110a5a717 100644 --- a/arch/powerpc/platforms/pseries/cc_platform.c +++ b/arch/powerpc/platforms/pseries/cc_platform.c @@ -17,6 +17,7 @@ bool cc_platform_has(enum cc_attr attr) { switch (attr) { case CC_ATTR_MEM_ENCRYPT: + case CC_ATTR_GUEST_MEM_ENCRYPT: return is_secure_guest(); default: 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/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index b2f14db59034..94f3b57054b6 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -164,13 +164,7 @@ static int update_lmb_associativity_index(struct drmem_lmb *lmb) static struct memory_block *lmb_to_memblock(struct drmem_lmb *lmb) { - unsigned long section_nr; - struct memory_block *mem_block; - - section_nr = pfn_to_section_nr(PFN_DOWN(lmb->base_addr)); - - mem_block = find_memory_block(section_nr); - return mem_block; + return memory_block_get(phys_to_block_id(lmb->base_addr)); } static int get_lmb_range(u32 drc_index, int n_lmbs, @@ -213,14 +207,14 @@ static int dlpar_change_lmb_state(struct drmem_lmb *lmb, bool online) return -EINVAL; } - if (online && mem_block->dev.offline) + if (online && dev_offline(&mem_block->dev)) rc = device_online(&mem_block->dev); - else if (!online && !mem_block->dev.offline) + else if (!online && !dev_offline(&mem_block->dev)) rc = device_offline(&mem_block->dev); else rc = 0; - put_device(&mem_block->dev); + memory_block_put(mem_block); return rc; } @@ -319,12 +313,12 @@ static int dlpar_remove_lmb(struct drmem_lmb *lmb) rc = dlpar_offline_lmb(lmb); if (rc) { - put_device(&mem_block->dev); + memory_block_put(mem_block); return rc; } __remove_memory(lmb->base_addr, memory_block_size); - put_device(&mem_block->dev); + memory_block_put(mem_block); /* Update memory regions for memory remove */ memblock_remove(lmb->base_addr, memory_block_size); diff --git a/arch/powerpc/platforms/pseries/htmdump.c b/arch/powerpc/platforms/pseries/htmdump.c index 742ec52c9d4d..f33941b80ada 100644 --- a/arch/powerpc/platforms/pseries/htmdump.c +++ b/arch/powerpc/platforms/pseries/htmdump.c @@ -16,6 +16,7 @@ static void *htm_buf; static void *htm_status_buf; static void *htm_info_buf; static void *htm_caps_buf; +static void *htm_mem_buf; static u32 nodeindex; static u32 nodalchipindex; static u32 coreindexonchip; @@ -86,7 +87,7 @@ static ssize_t htm_return_check(long rc) static ssize_t htmdump_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) { - void *htm_buf = filp->private_data; + void *htm_buf_data = filp->private_data; unsigned long page, read_size, available; loff_t offset; long rc, ret; @@ -100,7 +101,7 @@ static ssize_t htmdump_read(struct file *filp, char __user *ubuf, * - last three values are address, size and offset */ rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip, - htmtype, H_HTM_OP_DUMP_DATA, virt_to_phys(htm_buf), + htmtype, H_HTM_OP_DUMP_DATA, virt_to_phys(htm_buf_data), PAGE_SIZE, page); ret = htm_return_check(rc); @@ -112,7 +113,61 @@ static ssize_t htmdump_read(struct file *filp, char __user *ubuf, available = PAGE_SIZE; read_size = min(count, available); *ppos += read_size; - return simple_read_from_buffer(ubuf, count, &offset, htm_buf, available); + return simple_read_from_buffer(ubuf, count, &offset, htm_buf_data, available); +} + +static ssize_t htmsystem_mem_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *ppos) +{ + void *htm_mem_data = filp->private_data; + long rc, ret; + u64 *num_entries; + u64 to_copy = 0; + loff_t offset = 0; + u64 mem_offset = 0; + + /* + * Invoke H_HTM call with: + * - operation as htm status (H_HTM_OP_STATUS) + * - last three values as addr, size and offset. "offset" + * is value from output buffer header that points to next + * entry to dump. 0 is the first entry to dump. next entry + * is read from the output bufferbyte offset 0x8. + * + * When first time hcall is invoked, mem_offset should be + * zero because zero is the first entry. + * In the next hcall, offset of next entry to read from is + * picked from output buffer header itself. So don't fill + * mem_offset for first read. + * + * If there is no further data to read in next iteration, + * offset value from output buffer header will point to -1. + */ + if (*ppos) { + mem_offset = *(u64 *)(htm_mem_data + 0x8); + if (mem_offset == -1) + return 0; + } + rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip, + htmtype, H_HTM_OP_DUMP_SYSMEM_CONF, virt_to_phys(htm_mem_data), + PAGE_SIZE, be64_to_cpu(mem_offset)); + ret = htm_return_check(rc); + if (ret <= 0) { + pr_debug("H_HTM hcall returned for op: H_HTM_OP_DUMP_SYSMEM_CONF with hcall returning %ld\n", ret); + return ret; + } + + /* + * HTM system mem buffer, start of buffer + 0x10 gives the + * number of HTM entries in the buffer. + * So total count to copy is: + * 32 bytes (for first 5 fields) + (number of HTM entries * entry size) + */ + num_entries = htm_mem_data + 0x10; + to_copy = 32 + (be64_to_cpu(*num_entries) * 32); + + *ppos += to_copy; + return simple_read_from_buffer(ubuf, count, &offset, htm_mem_data, to_copy); } static const struct file_operations htmdump_fops = { @@ -121,6 +176,12 @@ static const struct file_operations htmdump_fops = { .open = simple_open, }; +static const struct file_operations htmsystem_mem_fops = { + .llseek = NULL, + .read = htmsystem_mem_read, + .open = simple_open, +}; + static int htmconfigure_set(void *data, u64 val) { long rc, ret; @@ -226,20 +287,31 @@ static int htmstart_get(void *data, u64 *val) static ssize_t htmstatus_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) { - void *htm_status_buf = filp->private_data; + void *htm_status_data = filp->private_data; long rc, ret; u64 *num_entries; u64 to_copy; int htmstatus_flag; + loff_t offset = 0; + u64 status_offset = 0; /* * Invoke H_HTM call with: * - operation as htm status (H_HTM_OP_STATUS) - * - last three values as addr, size and offset + * - last three values as addr, size and offset. + * "offset" is value from output buffer header + * that points to next entry to dump. 0 is the first + * entry to dump. next entry is read from the output + * bufferbyte offset 0x8. */ + if (*ppos) { + status_offset = *(u64 *)(htm_status_data + 0x8); + if (status_offset == -1) + return 0; + } rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip, - htmtype, H_HTM_OP_STATUS, virt_to_phys(htm_status_buf), - PAGE_SIZE, 0); + htmtype, H_HTM_OP_STATUS, virt_to_phys(htm_status_data), + PAGE_SIZE, be64_to_cpu(status_offset)); ret = htm_return_check(rc); if (ret <= 0) { @@ -255,13 +327,15 @@ static ssize_t htmstatus_read(struct file *filp, char __user *ubuf, * So total count to copy is: * 32 bytes (for first 7 fields) + (number of HTM entries * entry size) */ - num_entries = htm_status_buf + 0x10; + num_entries = htm_status_data + 0x10; if (htmtype == 0x2) htmstatus_flag = 0x8; else htmstatus_flag = 0x6; to_copy = 32 + (be64_to_cpu(*num_entries) * htmstatus_flag); - return simple_read_from_buffer(ubuf, count, ppos, htm_status_buf, to_copy); + *ppos += to_copy; + + return simple_read_from_buffer(ubuf, count, &offset, htm_status_data, to_copy); } static const struct file_operations htmstatus_fops = { @@ -273,19 +347,30 @@ static const struct file_operations htmstatus_fops = { static ssize_t htminfo_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) { - void *htm_info_buf = filp->private_data; + void *htm_info_data = filp->private_data; long rc, ret; u64 *num_entries; u64 to_copy; + loff_t offset = 0; + u64 info_offset = 0; /* * Invoke H_HTM call with: * - operation as htm status (H_HTM_OP_STATUS) * - last three values as addr, size and offset + * "offset" is value from output buffer header + * that points to next entry to dump. 0 is the first + * entry to dump. next entry is read from the output + * bufferbyte offset 0x8. */ + if (*ppos) { + info_offset = *(u64 *)(htm_info_data + 0x8); + if (info_offset == -1) + return 0; + } rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip, - htmtype, H_HTM_OP_DUMP_SYSPROC_CONF, virt_to_phys(htm_info_buf), - PAGE_SIZE, 0); + htmtype, H_HTM_OP_DUMP_SYSPROC_CONF, virt_to_phys(htm_info_data), + PAGE_SIZE, be64_to_cpu(info_offset)); ret = htm_return_check(rc); if (ret <= 0) { @@ -301,15 +386,17 @@ static ssize_t htminfo_read(struct file *filp, char __user *ubuf, * So total count to copy is: * 32 bytes (for first 5 fields) + (number of HTM entries * entry size) */ - num_entries = htm_info_buf + 0x10; + num_entries = htm_info_data + 0x10; to_copy = 32 + (be64_to_cpu(*num_entries) * 16); - return simple_read_from_buffer(ubuf, count, ppos, htm_info_buf, to_copy); + + *ppos += to_copy; + return simple_read_from_buffer(ubuf, count, &offset, htm_info_data, to_copy); } static ssize_t htmcaps_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) { - void *htm_caps_buf = filp->private_data; + void *htm_caps_data = filp->private_data; long rc, ret; /* @@ -319,7 +406,7 @@ static ssize_t htmcaps_read(struct file *filp, char __user *ubuf, * and zero */ rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip, - htmtype, H_HTM_OP_CAPABILITIES, virt_to_phys(htm_caps_buf), + htmtype, H_HTM_OP_CAPABILITIES, virt_to_phys(htm_caps_data), 0x80, 0); ret = htm_return_check(rc); @@ -328,7 +415,7 @@ static ssize_t htmcaps_read(struct file *filp, char __user *ubuf, return ret; } - return simple_read_from_buffer(ubuf, count, ppos, htm_caps_buf, 0x80); + return simple_read_from_buffer(ubuf, count, ppos, htm_caps_data, 0x80); } static const struct file_operations htminfo_fops = { @@ -440,28 +527,47 @@ static int htmdump_init_debugfs(void) htm_status_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!htm_status_buf) { pr_err("Failed to allocate htmstatus buf\n"); - return -ENOMEM; + goto htm_status_buf_err; } /* Debugfs interface file to present System Processor Configuration */ htm_info_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!htm_info_buf) { pr_err("Failed to allocate htm info buf\n"); - return -ENOMEM; + goto htm_info_buf_err; } /* Debugfs interface file to present HTM capabilities */ htm_caps_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!htm_caps_buf) { pr_err("Failed to allocate htm caps buf\n"); - return -ENOMEM; + goto htm_caps_buf_err; + } + + /* Memory to present HTM system memory configuration */ + htm_mem_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!htm_mem_buf) { + pr_err("Failed to allocate htm mem buf\n"); + goto htm_mem_buf_err; } debugfs_create_file("htmstatus", 0400, htmdump_debugfs_dir, htm_status_buf, &htmstatus_fops); debugfs_create_file("htminfo", 0400, htmdump_debugfs_dir, htm_info_buf, &htminfo_fops); debugfs_create_file("htmcaps", 0400, htmdump_debugfs_dir, htm_caps_buf, &htmcaps_fops); + debugfs_create_file("htmsystem_mem", 0400, htmdump_debugfs_dir, htm_mem_buf, &htmsystem_mem_fops); return 0; + +htm_mem_buf_err: + kfree(htm_caps_buf); +htm_caps_buf_err: + kfree(htm_info_buf); +htm_info_buf_err: + kfree(htm_status_buf); +htm_status_buf_err: + debugfs_remove_recursive(htmdump_debugfs_dir); + kfree(htm_buf); + return -ENOMEM; } static int __init htmdump_init(void) @@ -482,6 +588,10 @@ static void __exit htmdump_exit(void) { debugfs_remove_recursive(htmdump_debugfs_dir); kfree(htm_buf); + kfree(htm_status_buf); + kfree(htm_info_buf); + kfree(htm_caps_buf); + kfree(htm_mem_buf); } module_init(htmdump_init); 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/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 3e1f915fe4f6..272e9aab66d4 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -812,18 +812,11 @@ static struct device_node *pci_dma_find(struct device_node *dn, /* parse DMA window property. During normal system boot, only default * DMA window is passed in OF. But, for kdump, a dedicated adapter might - * have both default and DDW in FDT. In this scenario, DDW takes precedence - * over default window. + * have both default and DDW in FDT. In this scenario, default window + * takes precedence over DDW. For a dedicated adapter, default window will + * potentially have more unused TCEs. */ - if (ddw_win) { - struct dynamic_dma_window_prop *p; - - p = (struct dynamic_dma_window_prop *)ddw_prop; - prop->liobn = p->liobn; - prop->dma_base = p->dma_base; - prop->tce_shift = p->tce_shift; - prop->window_shift = p->window_shift; - } else if (default_win) { + if (default_win) { unsigned long offset, size, liobn; of_parse_dma_window(rdn, default_prop, &liobn, &offset, &size); @@ -832,6 +825,14 @@ static struct device_node *pci_dma_find(struct device_node *dn, prop->dma_base = cpu_to_be64(offset); prop->tce_shift = cpu_to_be32(IOMMU_PAGE_SHIFT_4K); prop->window_shift = cpu_to_be32(order_base_2(size)); + } else { + struct dynamic_dma_window_prop *p; + + p = (struct dynamic_dma_window_prop *)ddw_prop; + prop->liobn = p->liobn; + prop->dma_base = p->dma_base; + prop->tce_shift = p->tce_shift; + prop->window_shift = p->window_shift; } return rdn; diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c index 431be156ca9b..29f7c97ff193 100644 --- a/arch/powerpc/platforms/pseries/kexec.c +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -20,12 +20,15 @@ void pseries_kexec_cpu_down(int crash_shutdown, int secondary) { /* - * Don't risk a hypervisor call if we're crashing - * XXX: Why? The hypervisor is not crashing. It might be better - * to at least attempt unregister to avoid the hypervisor stepping - * on our memory. + * Ensure vpa/slb_shadow/dtl cleanup even while we are crashing. + * Why? The hypervisor is not crashing so at least attempt unregister to + * avoid the hypervisor stepping on our memory. If hypervisor or kexec + * kernel steps on the old memory allocated to these areas before the + * new kexec-kernel happens to allocate and register new areas, + * the hypervisor will see invalid content which may cause + * unexpected behavior. */ - if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { + if (firmware_has_feature(FW_FEATURE_SPLPAR)) { int ret; int cpu = smp_processor_id(); int hwcpu = hard_smp_processor_id(); diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c index 8821c378bfff..3280b7968cab 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); @@ -697,7 +699,7 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, if (!firmware_has_feature(FW_FEATURE_SPLPAR)) return -EINVAL; - if (count > sizeof(kbuf)) + if (count == 0 || count > sizeof(kbuf)) return -EINVAL; if (copy_from_user(kbuf, buf, count)) diff --git a/arch/powerpc/platforms/pseries/papr-hvpipe.c b/arch/powerpc/platforms/pseries/papr-hvpipe.c index 14ae480d060a..0c40bdde45e2 100644 --- a/arch/powerpc/platforms/pseries/papr-hvpipe.c +++ b/arch/powerpc/platforms/pseries/papr-hvpipe.c @@ -190,33 +190,34 @@ static int hvpipe_rtas_recv_msg(char __user *buf, int size) return -ENOMEM; } - ret = rtas_ibm_receive_hvpipe_msg(work_area, &srcID, - &bytes_written); - if (!ret) { - /* - * Recv HVPIPE RTAS is successful. - * When releasing FD or no one is waiting on the - * specific source, issue recv HVPIPE RTAS call - * so that pipe is not blocked - this func is called - * with NULL buf. - */ - if (buf) { - if (size < bytes_written) { - pr_err("Received the payload size = %d, but the buffer size = %d\n", - bytes_written, size); - bytes_written = size; - } - ret = copy_to_user(buf, - rtas_work_area_raw_buf(work_area), - bytes_written); - if (!ret) - ret = bytes_written; - } - } else { - pr_err("ibm,receive-hvpipe-msg failed with %d\n", - ret); + /* + * Recv HVPIPE RTAS is successful. + * When releasing FD or no one is waiting on the + * specific source, issue recv HVPIPE RTAS call + * so that pipe is not blocked - this func is called + * with NULL buf. + */ + ret = rtas_ibm_receive_hvpipe_msg(work_area, &srcID, &bytes_written); + if (ret) { + pr_err("ibm,receive-hvpipe-msg failed with %d\n", ret); + goto out; } + if (!buf) + goto out; + + if (size < bytes_written) { + pr_err("Received the payload size = %d, but the buffer size = %d\n", + bytes_written, size); + bytes_written = size; + } + + if (copy_to_user(buf, rtas_work_area_raw_buf(work_area), bytes_written)) + ret = -EFAULT; + else + ret = bytes_written; + +out: rtas_work_area_free(work_area); return ret; } @@ -327,8 +328,8 @@ static ssize_t papr_hvpipe_handle_read(struct file *file, { struct hvpipe_source_info *src_info = file->private_data; - struct papr_hvpipe_hdr hdr; - long ret; + struct papr_hvpipe_hdr hdr = {}; + ssize_t ret = 0; /* * Return -ENXIO during migration @@ -376,7 +377,7 @@ static ssize_t papr_hvpipe_handle_read(struct file *file, ret = copy_to_user(buf, &hdr, HVPIPE_HDR_LEN); if (ret) - return ret; + return -EFAULT; /* * Message event has payload, so get the payload with @@ -385,19 +386,23 @@ static ssize_t papr_hvpipe_handle_read(struct file *file, if (hdr.flags & HVPIPE_MSG_AVAILABLE) { ret = hvpipe_rtas_recv_msg(buf + HVPIPE_HDR_LEN, size - HVPIPE_HDR_LEN); - if (ret > 0) { + /* + * Always clear MSG_AVAILABLE once the RTAS call has drained + * the message, regardless of whether copy_to_user succeeded. + */ + if (ret >= 0 || ret == -EFAULT) src_info->hvpipe_status &= ~HVPIPE_MSG_AVAILABLE; - ret += HVPIPE_HDR_LEN; - } } else if (hdr.flags & HVPIPE_LOST_CONNECTION) { /* * Hypervisor is closing the pipe for the specific * source. So notify user space. */ src_info->hvpipe_status &= ~HVPIPE_LOST_CONNECTION; - ret = HVPIPE_HDR_LEN; } + if (ret >= 0) + ret += HVPIPE_HDR_LEN; + return ret; } @@ -444,16 +449,18 @@ static int papr_hvpipe_handle_release(struct inode *inode, struct file *file) { struct hvpipe_source_info *src_info; + unsigned long flags; /* * Hold the lock, remove source from src_list, reset the * hvpipe status and release the lock to prevent any race * with message event IRQ. */ - spin_lock(&hvpipe_src_list_lock); + spin_lock_irqsave(&hvpipe_src_list_lock, flags); src_info = file->private_data; list_del(&src_info->list); file->private_data = NULL; + spin_unlock_irqrestore(&hvpipe_src_list_lock, flags); /* * If the pipe for this specific source has any pending * payload, issue recv HVPIPE RTAS so that pipe will not @@ -461,10 +468,8 @@ static int papr_hvpipe_handle_release(struct inode *inode, */ if (src_info->hvpipe_status & HVPIPE_MSG_AVAILABLE) { src_info->hvpipe_status = 0; - spin_unlock(&hvpipe_src_list_lock); hvpipe_rtas_recv_msg(NULL, 0); - } else - spin_unlock(&hvpipe_src_list_lock); + } kfree(src_info); return 0; @@ -479,50 +484,53 @@ static const struct file_operations papr_hvpipe_handle_ops = { static int papr_hvpipe_dev_create_handle(u32 srcID) { - struct hvpipe_source_info *src_info __free(kfree) = NULL; - - spin_lock(&hvpipe_src_list_lock); - /* - * Do not allow more than one process communicates with - * each source. - */ - src_info = hvpipe_find_source(srcID); - if (src_info) { - spin_unlock(&hvpipe_src_list_lock); - pr_err("pid(%d) is already using the source(%d)\n", - src_info->tsk->pid, srcID); - return -EALREADY; - } - spin_unlock(&hvpipe_src_list_lock); + struct hvpipe_source_info *src_info; + int fd; + unsigned long flags; src_info = kzalloc_obj(*src_info, GFP_KERNEL_ACCOUNT); if (!src_info) return -ENOMEM; src_info->srcID = srcID; - src_info->tsk = current; init_waitqueue_head(&src_info->recv_wqh); - FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC, - anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops, - (void *)src_info, O_RDWR)); - if (fdf.err) - return fdf.err; - - retain_and_null_ptr(src_info); - spin_lock(&hvpipe_src_list_lock); /* - * If two processes are executing ioctl() for the same - * source ID concurrently, prevent the second process to - * acquire FD. + * Do not allow more than one process communicates with + * each source. */ + spin_lock_irqsave(&hvpipe_src_list_lock, flags); if (hvpipe_find_source(srcID)) { - spin_unlock(&hvpipe_src_list_lock); + spin_unlock_irqrestore(&hvpipe_src_list_lock, flags); + pr_err("pid(%s:%d) could not get the source(%d)\n", + current->comm, task_pid_nr(current), srcID); + kfree(src_info); return -EALREADY; } list_add(&src_info->list, &hvpipe_src_list); - spin_unlock(&hvpipe_src_list_lock); - return fd_publish(fdf); + spin_unlock_irqrestore(&hvpipe_src_list_lock, flags); + + fd = FD_ADD(O_RDONLY | O_CLOEXEC, + anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops, + (void *)src_info, O_RDWR)); + if (fd < 0) { + spin_lock_irqsave(&hvpipe_src_list_lock, flags); + list_del(&src_info->list); + spin_unlock_irqrestore(&hvpipe_src_list_lock, flags); + /* + * if we fail to add FD, that means no userspace program is + * polling. In that case if there is a msg pending because the + * interrupt was fired after the src_info was added to the + * global list, then let's consume it here, to unblock the + * hvpipe + */ + if (src_info->hvpipe_status & HVPIPE_MSG_AVAILABLE) + hvpipe_rtas_recv_msg(NULL, 0); + kfree(src_info); + return fd; + } + + return fd; } /* @@ -685,20 +693,19 @@ static int __init enable_hvpipe_IRQ(void) struct device_node *np; hvpipe_check_exception_token = rtas_function_token(RTAS_FN_CHECK_EXCEPTION); - if (hvpipe_check_exception_token == RTAS_UNKNOWN_SERVICE) + if (hvpipe_check_exception_token == RTAS_UNKNOWN_SERVICE) return -ENODEV; /* hvpipe events */ np = of_find_node_by_path("/event-sources/ibm,hvpipe-msg-events"); - if (np != NULL) { - request_event_sources_irqs(np, hvpipe_event_interrupt, - "HPIPE_EVENT"); - of_node_put(np); - } else { - pr_err("Can not enable hvpipe event IRQ\n"); + if (!np) { + pr_err("No device node found, could not enable hvpipe event IRQ\n"); return -ENODEV; } + request_event_sources_irqs(np, hvpipe_event_interrupt, "HPIPE_EVENT"); + of_node_put(np); + return 0; } @@ -775,23 +782,29 @@ static int __init papr_hvpipe_init(void) } ret = enable_hvpipe_IRQ(); - if (!ret) { - ret = set_hvpipe_sys_param(1); - if (!ret) - ret = misc_register(&papr_hvpipe_dev); - } + if (ret) + goto out_wq; - if (!ret) { - pr_info("hvpipe feature is enabled\n"); - hvpipe_feature = true; - return 0; - } + ret = misc_register(&papr_hvpipe_dev); + if (ret) + goto out_wq; - pr_err("hvpipe feature is not enabled %d\n", ret); + ret = set_hvpipe_sys_param(1); + if (ret) + goto out_misc; + + pr_info("hvpipe feature is enabled\n"); + hvpipe_feature = true; + return 0; + +out_misc: + misc_deregister(&papr_hvpipe_dev); +out_wq: destroy_workqueue(papr_hvpipe_wq); out: kfree(papr_hvpipe_work); papr_hvpipe_work = NULL; + pr_err("hvpipe feature is not enabled %d\n", ret); return ret; } machine_device_initcall(pseries, papr_hvpipe_init); diff --git a/arch/powerpc/platforms/pseries/papr-hvpipe.h b/arch/powerpc/platforms/pseries/papr-hvpipe.h index c343f4230865..4bdf7bb2fc4d 100644 --- a/arch/powerpc/platforms/pseries/papr-hvpipe.h +++ b/arch/powerpc/platforms/pseries/papr-hvpipe.h @@ -21,7 +21,6 @@ struct hvpipe_source_info { u32 srcID; u32 hvpipe_status; wait_queue_head_t recv_wqh; /* wake up poll() waitq */ - struct task_struct *tsk; }; /* diff --git a/arch/powerpc/platforms/pseries/papr-phy-attest.c b/arch/powerpc/platforms/pseries/papr-phy-attest.c index 20a0e1581302..350ba26e5962 100644 --- a/arch/powerpc/platforms/pseries/papr-phy-attest.c +++ b/arch/powerpc/platforms/pseries/papr-phy-attest.c @@ -230,10 +230,17 @@ static long papr_phy_attest_create_handle(struct papr_phy_attest_io_block __user return -ENOMEM; if (copy_from_user(¶ms->cmd, ulc, - sizeof(struct papr_phy_attest_io_block))) + sizeof(struct papr_phy_attest_io_block))) { + kfree(params); return -EFAULT; + } params->cmd_len = be32_to_cpu(params->cmd.length); + if (params->cmd_len == 0 || params->cmd_len > sizeof(params->cmd)) { + kfree(params); + return -EINVAL; + } + seq = (struct papr_rtas_sequence) { .begin = phy_attest_sequence_begin, .end = phy_attest_sequence_end, @@ -246,6 +253,9 @@ static long papr_phy_attest_create_handle(struct papr_phy_attest_io_block __user &papr_phy_attest_handle_ops, "[papr-physical-attestation]"); + if (fd < 0) + kfree(params); + return fd; } diff --git a/arch/powerpc/platforms/pseries/papr_platform_attributes.c b/arch/powerpc/platforms/pseries/papr_platform_attributes.c index c6159870de0e..aacdaa1ebf63 100644 --- a/arch/powerpc/platforms/pseries/papr_platform_attributes.c +++ b/arch/powerpc/platforms/pseries/papr_platform_attributes.c @@ -271,11 +271,9 @@ retry: esi_buf_size = ESI_HDR_SIZE + (CURR_MAX_ESI_ATTRS * max_esi_attrs); temp_esi_buf = krealloc(esi_buf, esi_buf_size, GFP_KERNEL); - if (temp_esi_buf) - esi_buf = temp_esi_buf; - else - return -ENOMEM; - + if (!temp_esi_buf) + goto out_free_esi_buf; + esi_buf = temp_esi_buf; goto retry; } @@ -325,12 +323,8 @@ retry: } for (idx = 0; idx < num_attrs; idx++) { - bool show_val_desc = true; - /* Do not add the value desc attr if it does not exist */ - if (strnlen(esi_attrs[idx].value_desc, - sizeof(esi_attrs[idx].value_desc)) == 0) - show_val_desc = false; + bool show_val_desc = *esi_attrs[idx].value_desc != '\0'; if (add_attr_group(be64_to_cpu(esi_attrs[idx].id), &papr_groups[idx], 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/pci.c b/arch/powerpc/platforms/pseries/pci.c index 84e4ffe957a8..6fc13f4a79a3 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -132,11 +132,14 @@ static int pseries_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs) /* First integer stores max config */ max_config_vfs = of_read_number(&max_vfs[0], 1); - if (max_config_vfs < num_vfs && num_vfs > MAX_VFS_FOR_MAP_PE) { - dev_err(&pdev->dev, - "Num VFs %x > %x Configurable VFs\n", - num_vfs, (num_vfs > MAX_VFS_FOR_MAP_PE) ? - MAX_VFS_FOR_MAP_PE : max_config_vfs); + if (max_config_vfs < num_vfs) { + dev_err(&pdev->dev, "Num VFs %x > %x Configurable VFs\n", + num_vfs, max_config_vfs); + return -EINVAL; + } + if (num_vfs > MAX_VFS_FOR_MAP_PE) { + dev_err(&pdev->dev, "Num VFs %x > %x PE mapping limit\n", + num_vfs, MAX_VFS_FOR_MAP_PE); return -EINVAL; } 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/ras.c b/arch/powerpc/platforms/pseries/ras.c index adafd593d9d3..7b8713bdd978 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -7,6 +7,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/of.h> +#include <linux/overflow.h> #include <linux/fs.h> #include <linux/reboot.h> #include <linux/irq_work.h> @@ -440,6 +441,8 @@ static __be64 *fwnmi_get_savep(struct pt_regs *regs) static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) { struct rtas_error_log *h; + u32 extended_log_length; + size_t len; __be64 *savep; savep = fwnmi_get_savep(regs); @@ -449,17 +452,12 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */ h = (struct rtas_error_log *)&savep[1]; + extended_log_length = rtas_error_extended(h) ? rtas_error_extended_log_length(h) : 0; + len = struct_size(h, buffer, extended_log_length); + len = min(len, RTAS_ERROR_LOG_MAX); /* Use the per cpu buffer from paca to store rtas error log */ memset(local_paca->mce_data_buf, 0, RTAS_ERROR_LOG_MAX); - if (!rtas_error_extended(h)) { - memcpy(local_paca->mce_data_buf, h, sizeof(__u64)); - } else { - int len, error_log_length; - - error_log_length = 8 + rtas_error_extended_log_length(h); - len = min_t(int, error_log_length, RTAS_ERROR_LOG_MAX); - memcpy(local_paca->mce_data_buf, h, len); - } + memcpy(local_paca->mce_data_buf, h, len); return (struct rtas_error_log *)local_paca->mce_data_buf; } diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 7faebcffc9df..18e3f1a036e3 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -307,7 +307,7 @@ static int do_remove_property(char *buf, size_t bufsize) if (tmp) *tmp = '\0'; - if (strlen(buf) == 0) + if (*buf == '\0') return -EINVAL; return of_remove_property(np, of_find_property(np, buf, NULL)); @@ -330,7 +330,7 @@ static int do_update_property(char *buf, size_t bufsize) if (!next_prop) return -EINVAL; - if (!strlen(name)) + if (*name == '\0') return -ENODEV; newprop = new_property(name, length, value, NULL); 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/setup.c b/arch/powerpc/platforms/pseries/setup.c index 50b26ed8432d..f29e7547c995 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -77,6 +77,7 @@ #include <asm/dtl.h> #include <asm/hvconsole.h> #include <asm/setup.h> +#include <asm/papr-watchdog.h> #include "pseries.h" @@ -185,14 +186,37 @@ static void __init fwnmi_init(void) #endif } +static void pseries_crash_stop_watchdogs(void) +{ + long rc; + + rc = plpar_hcall_norets_notrace(H_WATCHDOG, PSERIES_WDTF_OP_STOP, + PSERIES_WDT_NUM_ALL); + if (rc != H_SUCCESS && rc != H_NOOP) + pr_warn("Could not stop watchdogs before kdump rc=%ld\n", rc); +} + /* * Affix a device for the first timer to the platform bus if * we have firmware support for the H_WATCHDOG hypercall. */ static __init int pseries_wdt_init(void) { - if (firmware_has_feature(FW_FEATURE_WATCHDOG)) - platform_device_register_simple("pseries-wdt", 0, NULL, 0); + struct platform_device *pdev; + + if (!firmware_has_feature(FW_FEATURE_WATCHDOG)) + return 0; + + pdev = platform_device_register_simple("pseries-wdt", 0, NULL, 0); + + if (IS_ERR(pdev)) { + pr_err("Failed to register pseries-wdt platform device\n"); + return PTR_ERR(pdev); + } + + if (crash_shutdown_register(pseries_crash_stop_watchdogs)) + pr_warn("Could not register watchdog crash shutdown handler\n"); + return 0; } machine_subsys_initcall(pseries, pseries_wdt_init); @@ -658,7 +682,8 @@ enum get_iov_fw_value_index { WDW_SIZE = 3 /* Get Window Size */ }; -static resource_size_t pseries_get_iov_fw_value(struct pci_dev *dev, int resno, +static resource_size_t pseries_get_iov_fw_value(const struct pci_dev *dev, + int resno, enum get_iov_fw_value_index value) { const int *indexes; @@ -788,7 +813,7 @@ static void pseries_pci_fixup_iov_resources(struct pci_dev *pdev) pseries_disable_sriov_resources(pdev); } -static resource_size_t pseries_pci_iov_resource_alignment(struct pci_dev *pdev, +static resource_size_t pseries_pci_iov_resource_alignment(const struct pci_dev *pdev, int resno) { const __be32 *reg; diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index db99725e752b..9e1bed383e33 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -128,7 +128,12 @@ static void smp_setup_cpu(int cpu) else if (cpu != boot_cpuid) xics_setup_cpu(); - if (firmware_has_feature(FW_FEATURE_SPLPAR)) + /* + * Initialize VPA on non-boot cpus since boot-cpu vpa was + * already initialized in pSeries_setup_arch() + */ + if (firmware_has_feature(FW_FEATURE_SPLPAR) && + cpu != boot_cpuid) vpa_init(cpu); cpumask_clear_cpu(cpu, of_spin_mask); @@ -194,10 +199,12 @@ static int pseries_cause_nmi_ipi(int cpu) static __init void pSeries_smp_probe(void) { - if (xive_enabled()) - xive_smp_probe(); - else + if (xive_enabled()) { + if (xive_smp_probe() < 0) + return; + } else { xics_smp_probe(); + } /* No doorbell facility, must use the interrupt controller for IPIs */ if (!cpu_has_feature(CPU_FTR_DBELL)) 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/svm.c b/arch/powerpc/platforms/pseries/svm.c index 384c9dc1899a..7a403dbd35ee 100644 --- a/arch/powerpc/platforms/pseries/svm.c +++ b/arch/powerpc/platforms/pseries/svm.c @@ -29,7 +29,7 @@ static int __init init_svm(void) * need to use the SWIOTLB buffer for DMA even if dma_capable() says * otherwise. */ - ppc_swiotlb_flags |= SWIOTLB_ANY | SWIOTLB_FORCE; + ppc_swiotlb_flags |= SWIOTLB_ANY; /* Share the SWIOTLB buffer with the host. */ swiotlb_update_mem_attributes(); 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/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index 07ea605ab0e6..b5d200e3ad68 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c @@ -181,6 +181,18 @@ static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) return 0; } +static int cpm2_gpio32_get_direction(struct gpio_chip *gc, unsigned int gpio) +{ + struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc); + struct cpm2_ioports __iomem *iop = cpm2_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 cpm2_gpiochip_add32(struct device *dev) { struct device_node *np = dev->of_node; @@ -199,6 +211,7 @@ int cpm2_gpiochip_add32(struct device *dev) gc->ngpio = 32; gc->direction_input = cpm2_gpio32_dir_in; gc->direction_output = cpm2_gpio32_dir_out; + gc->get_direction = cpm2_gpio32_get_direction; gc->get = cpm2_gpio32_get; gc->set = cpm2_gpio32_set; gc->parent = dev; diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c index 839cf5adc7d9..eea5ed0ce26e 100644 --- a/arch/powerpc/sysdev/fsl_lbc.c +++ b/arch/powerpc/sysdev/fsl_lbc.c @@ -24,7 +24,6 @@ #include <linux/sched.h> #include <linux/platform_device.h> #include <linux/interrupt.h> -#include <linux/mod_devicetable.h> #include <linux/syscore_ops.h> #include <asm/fsl_lbc.h> 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/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c index 9f6dd11c1344..03955a85bed8 100644 --- a/arch/powerpc/sysdev/fsl_pmc.c +++ b/arch/powerpc/sysdev/fsl_pmc.c @@ -13,7 +13,6 @@ #include <linux/export.h> #include <linux/suspend.h> #include <linux/delay.h> -#include <linux/mod_devicetable.h> #include <linux/of_address.h> #include <linux/platform_device.h> diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c index 456a4f64ae0a..2f38d4b41ad3 100644 --- a/arch/powerpc/sysdev/msi_bitmap.c +++ b/arch/powerpc/sysdev/msi_bitmap.c @@ -21,7 +21,7 @@ int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num) offset = bitmap_find_next_zero_area(bmp->bitmap, bmp->irq_count, 0, num, (1 << order) - 1); - if (offset > bmp->irq_count) + if (offset >= bmp->irq_count) goto err; bitmap_set(bmp->bitmap, offset, num); diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index c120be73d149..ed3d3e26c136 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -74,6 +74,8 @@ static struct xive_ipi_desc { */ static unsigned int xive_ipi_cpu_to_irq(unsigned int cpu) { + if (!xive_ipis) + return XIVE_BAD_IRQ; return xive_ipis[early_cpu_to_node(cpu)].irq; } #endif @@ -564,6 +566,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; } @@ -1131,8 +1134,7 @@ static int __init xive_init_ipis(void) if (!ipi_domain) goto out_free_fwnode; - xive_ipis = kzalloc_objs(*xive_ipis, nr_node_ids, - GFP_KERNEL | __GFP_NOFAIL); + xive_ipis = kzalloc_objs(*xive_ipis, nr_node_ids); if (!xive_ipis) goto out_free_domain; @@ -1157,6 +1159,7 @@ static int __init xive_init_ipis(void) out_free_xive_ipis: kfree(xive_ipis); + xive_ipis = NULL; out_free_domain: irq_domain_remove(ipi_domain); out_free_fwnode: @@ -1189,6 +1192,9 @@ static int xive_setup_cpu_ipi(unsigned int cpu) pr_debug("Setting up IPI for CPU %d\n", cpu); + if (xive_ipi_irq == XIVE_BAD_IRQ) + return -EIO; + xc = per_cpu(xive_cpu, cpu); /* Check if we are already setup */ @@ -1233,6 +1239,9 @@ noinstr static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc) /* Disable the IPI and free the IRQ data */ + if (xive_ipi_irq == XIVE_BAD_IRQ) + return; + /* Already cleaned up ? */ if (xc->hw_ipi == XIVE_BAD_IRQ) return; @@ -1256,15 +1265,23 @@ noinstr static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc) xive_ops->put_ipi(cpu, xc); } -void __init xive_smp_probe(void) +int __init xive_smp_probe(void) { - smp_ops->cause_ipi = xive_cause_ipi; + int ret; /* Register the IPI */ - xive_init_ipis(); + ret = xive_init_ipis(); + if (ret < 0) + return ret; /* Allocate and setup IPI for the boot CPU */ - xive_setup_cpu_ipi(smp_processor_id()); + ret = xive_setup_cpu_ipi(smp_processor_id()); + if (ret < 0) + return ret; + + smp_ops->cause_ipi = xive_cause_ipi; + + return 0; } #endif /* CONFIG_SMP */ |
