summaryrefslogtreecommitdiff
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/Kconfig7
-rw-r--r--arch/powerpc/Kconfig.debug3
-rw-r--r--arch/powerpc/Makefile7
-rw-r--r--arch/powerpc/boot/dts/Makefile73
-rw-r--r--arch/powerpc/boot/dts/fsl/Makefile43
-rw-r--r--arch/powerpc/boot/dts/mpc8308_p1m.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8308rdb.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8315erdb.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc836x_rdk.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8377_rdb.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8377_wlan.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8378_rdb.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8379_rdb.dts1
-rw-r--r--arch/powerpc/boot/hack-coff.c2
-rw-r--r--arch/powerpc/boot/rs6000.h84
-rw-r--r--arch/powerpc/boot/serial.c1
-rw-r--r--arch/powerpc/boot/simpleboot.c2
-rw-r--r--arch/powerpc/boot/stdio.c11
-rw-r--r--arch/powerpc/boot/stdio.h3
-rw-r--r--arch/powerpc/boot/string.S13
-rw-r--r--arch/powerpc/boot/string.h1
-rw-r--r--arch/powerpc/boot/treeboot-akebono.c2
-rw-r--r--arch/powerpc/boot/treeboot-currituck.c2
-rwxr-xr-xarch/powerpc/boot/wrapper1
-rw-r--r--arch/powerpc/configs/44x/akebono_defconfig1
-rw-r--r--arch/powerpc/configs/44x/bamboo_defconfig1
-rw-r--r--arch/powerpc/configs/44x/currituck_defconfig1
-rw-r--r--arch/powerpc/configs/44x/ebony_defconfig1
-rw-r--r--arch/powerpc/configs/44x/eiger_defconfig1
-rw-r--r--arch/powerpc/configs/44x/fsp2_defconfig1
-rw-r--r--arch/powerpc/configs/44x/icon_defconfig1
-rw-r--r--arch/powerpc/configs/44x/iss476-smp_defconfig1
-rw-r--r--arch/powerpc/configs/44x/katmai_defconfig1
-rw-r--r--arch/powerpc/configs/44x/rainier_defconfig1
-rw-r--r--arch/powerpc/configs/44x/redwood_defconfig1
-rw-r--r--arch/powerpc/configs/44x/sequoia_defconfig1
-rw-r--r--arch/powerpc/configs/44x/taishan_defconfig1
-rw-r--r--arch/powerpc/configs/44x/warp_defconfig2
-rw-r--r--arch/powerpc/configs/52xx/cm5200_defconfig1
-rw-r--r--arch/powerpc/configs/52xx/motionpro_defconfig1
-rw-r--r--arch/powerpc/configs/52xx/tqm5200_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/asp8347_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc8313_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc8315_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc832x_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_itx_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc837x_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/85xx-hw.config1
-rw-r--r--arch/powerpc/configs/amigaone_defconfig2
-rw-r--r--arch/powerpc/configs/cell_defconfig1
-rw-r--r--arch/powerpc/configs/chrp32_defconfig2
-rw-r--r--arch/powerpc/configs/ep8248e_defconfig1
-rw-r--r--arch/powerpc/configs/fsl-emb-nonhw.config1
-rw-r--r--arch/powerpc/configs/g5_defconfig4
-rw-r--r--arch/powerpc/configs/linkstation_defconfig1
-rw-r--r--arch/powerpc/configs/mgcoge_defconfig1
-rw-r--r--arch/powerpc/configs/mpc83xx_defconfig1
-rw-r--r--arch/powerpc/configs/mvme5100_defconfig1
-rw-r--r--arch/powerpc/configs/pasemi_defconfig1
-rw-r--r--arch/powerpc/configs/pmac32_defconfig1
-rw-r--r--arch/powerpc/configs/powernv_defconfig2
-rw-r--r--arch/powerpc/configs/ppc44x_defconfig3
-rw-r--r--arch/powerpc/configs/ppc64_defconfig3
-rw-r--r--arch/powerpc/configs/ppc64e_defconfig2
-rw-r--r--arch/powerpc/configs/ppc6xx_defconfig11
-rw-r--r--arch/powerpc/configs/ps3_defconfig1
-rw-r--r--arch/powerpc/configs/skiroot_defconfig1
-rw-r--r--arch/powerpc/crypto/aes-spe-glue.c9
-rw-r--r--arch/powerpc/crypto/aes_cbc.c6
-rw-r--r--arch/powerpc/include/asm/Kbuild1
-rw-r--r--arch/powerpc/include/asm/book3s/64/pgtable.h10
-rw-r--r--arch/powerpc/include/asm/cpu_setup.h2
-rw-r--r--arch/powerpc/include/asm/cputable.h17
-rw-r--r--arch/powerpc/include/asm/entry-common.h537
-rw-r--r--arch/powerpc/include/asm/hw_irq.h4
-rw-r--r--arch/powerpc/include/asm/interrupt.h387
-rw-r--r--arch/powerpc/include/asm/jump_label.h23
-rw-r--r--arch/powerpc/include/asm/kasan.h15
-rw-r--r--arch/powerpc/include/asm/kexec_ranges.h1
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h1
-rw-r--r--arch/powerpc/include/asm/machdep.h2
-rw-r--r--arch/powerpc/include/asm/mmu.h1
-rw-r--r--arch/powerpc/include/asm/papr-watchdog.h64
-rw-r--r--arch/powerpc/include/asm/pci.h2
-rw-r--r--arch/powerpc/include/asm/pmac_low_i2c.h4
-rw-r--r--arch/powerpc/include/asm/preempt.h16
-rw-r--r--arch/powerpc/include/asm/prom.h7
-rw-r--r--arch/powerpc/include/asm/ptrace.h3
-rw-r--r--arch/powerpc/include/asm/reg.h17
-rw-r--r--arch/powerpc/include/asm/rtas-types.h5
-rw-r--r--arch/powerpc/include/asm/serial.h8
-rw-r--r--arch/powerpc/include/asm/signal.h1
-rw-r--r--arch/powerpc/include/asm/stacktrace.h6
-rw-r--r--arch/powerpc/include/asm/string.h2
-rw-r--r--arch/powerpc/include/asm/synch.h6
-rw-r--r--arch/powerpc/include/asm/syscall.h6
-rw-r--r--arch/powerpc/include/asm/thread_info.h3
-rw-r--r--arch/powerpc/include/asm/timex.h2
-rw-r--r--arch/powerpc/include/asm/topology.h7
-rw-r--r--arch/powerpc/include/asm/uaccess.h28
-rw-r--r--arch/powerpc/include/asm/vga.h4
-rw-r--r--arch/powerpc/include/asm/xive.h4
-rw-r--r--arch/powerpc/include/uapi/asm/cputable.h2
-rw-r--r--arch/powerpc/include/uapi/asm/fcntl.h8
-rw-r--r--arch/powerpc/include/uapi/asm/kvm.h18
-rw-r--r--arch/powerpc/kernel/cacheinfo.c16
-rw-r--r--arch/powerpc/kernel/cpu_setup_power.c43
-rw-r--r--arch/powerpc/kernel/cpu_specs_book3s_64.h36
-rw-r--r--arch/powerpc/kernel/dma-iommu.c8
-rw-r--r--arch/powerpc/kernel/dt_cpu_ftrs.c53
-rw-r--r--arch/powerpc/kernel/eeh_driver.c2
-rw-r--r--arch/powerpc/kernel/eeh_sysfs.c8
-rw-r--r--arch/powerpc/kernel/fadump.c14
-rw-r--r--arch/powerpc/kernel/head_64.S20
-rw-r--r--arch/powerpc/kernel/interrupt.c253
-rw-r--r--arch/powerpc/kernel/iommu.c5
-rw-r--r--arch/powerpc/kernel/irq.c21
-rw-r--r--arch/powerpc/kernel/pci-common.c11
-rw-r--r--arch/powerpc/kernel/prom.c1
-rw-r--r--arch/powerpc/kernel/prom_init.c48
-rw-r--r--arch/powerpc/kernel/ptrace/ptrace.c141
-rw-r--r--arch/powerpc/kernel/rtas_flash.c27
-rw-r--r--arch/powerpc/kernel/rtas_pci.c8
-rw-r--r--arch/powerpc/kernel/rtasd.c19
-rw-r--r--arch/powerpc/kernel/security.c13
-rw-r--r--arch/powerpc/kernel/setup-common.c16
-rw-r--r--arch/powerpc/kernel/signal.c25
-rw-r--r--arch/powerpc/kernel/smp.c3
-rw-r--r--arch/powerpc/kernel/syscall.c123
-rw-r--r--arch/powerpc/kernel/syscalls/syscall.tbl1
-rw-r--r--arch/powerpc/kernel/sysfs.c23
-rw-r--r--arch/powerpc/kernel/time.c49
-rw-r--r--arch/powerpc/kernel/traps.c2
-rw-r--r--arch/powerpc/kernel/vdso/Makefile6
-rw-r--r--arch/powerpc/kernel/vdso/gettimeofday.S8
-rw-r--r--arch/powerpc/kernel/vdso/vdso32.lds.S8
-rw-r--r--arch/powerpc/kernel/vdso/vgettimeofday.c16
-rw-r--r--arch/powerpc/kernel/watchdog.c2
-rw-r--r--arch/powerpc/kexec/Makefile2
-rw-r--r--arch/powerpc/kexec/core_64.c4
-rw-r--r--arch/powerpc/kexec/crash.c7
-rw-r--r--arch/powerpc/kexec/elf_64.c2
-rw-r--r--arch/powerpc/kexec/file_load.c14
-rw-r--r--arch/powerpc/kexec/file_load_64.c12
-rw-r--r--arch/powerpc/kexec/ranges.c113
-rw-r--r--arch/powerpc/kvm/Kconfig1
-rw-r--r--arch/powerpc/kvm/book3s_hv.c123
-rw-r--r--arch/powerpc/kvm/book3s_hv_nested.c2
-rw-r--r--arch/powerpc/kvm/book3s_hv_uvmem.c5
-rw-r--r--arch/powerpc/kvm/book3s_pr.c11
-rw-r--r--arch/powerpc/kvm/booke.c3
-rw-r--r--arch/powerpc/kvm/mpic.c3
-rw-r--r--arch/powerpc/kvm/powerpc.c125
-rw-r--r--arch/powerpc/lib/code-patching.c52
-rw-r--r--arch/powerpc/lib/string.S22
-rw-r--r--arch/powerpc/lib/vmx-helper.c11
-rw-r--r--arch/powerpc/mm/book3s64/hash_native.c22
-rw-r--r--arch/powerpc/mm/book3s64/hash_utils.c4
-rw-r--r--arch/powerpc/mm/book3s64/radix_pgtable.c7
-rw-r--r--arch/powerpc/mm/book3s64/slice.c6
-rw-r--r--arch/powerpc/mm/hugetlbpage.c13
-rw-r--r--arch/powerpc/mm/init_64.c12
-rw-r--r--arch/powerpc/mm/kasan/init_book3e_64.c3
-rw-r--r--arch/powerpc/mm/kasan/init_book3s_64.c3
-rw-r--r--arch/powerpc/mm/mem.c11
-rw-r--r--arch/powerpc/net/Makefile4
-rw-r--r--arch/powerpc/net/bpf_jit_comp.c63
-rw-r--r--arch/powerpc/net/bpf_jit_comp64.c62
-rw-r--r--arch/powerpc/net/bpf_timed_may_goto.S57
-rw-r--r--arch/powerpc/perf/Makefile2
-rw-r--r--arch/powerpc/perf/core-book3s.c12
-rw-r--r--arch/powerpc/perf/core-fsl-emb.c3
-rw-r--r--arch/powerpc/perf/hv-24x7.c20
-rw-r--r--arch/powerpc/perf/hv-gpci.c31
-rw-r--r--arch/powerpc/perf/imc-pmu.c13
-rw-r--r--arch/powerpc/perf/internal.h1
-rw-r--r--arch/powerpc/perf/kvm-hv-pmu.c3
-rw-r--r--arch/powerpc/perf/power12-events-list.h78
-rw-r--r--arch/powerpc/perf/power12-pmu.c466
-rw-r--r--arch/powerpc/perf/vpa-pmu.c3
-rw-r--r--arch/powerpc/platforms/44x/Kconfig7
-rw-r--r--arch/powerpc/platforms/44x/Makefile2
-rw-r--r--arch/powerpc/platforms/44x/gpio.c210
-rw-r--r--arch/powerpc/platforms/44x/warp.c2
-rw-r--r--arch/powerpc/platforms/82xx/km82xx.c4
-rw-r--r--arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c4
-rw-r--r--arch/powerpc/platforms/85xx/common.c2
-rw-r--r--arch/powerpc/platforms/86xx/common.c1
-rw-r--r--arch/powerpc/platforms/8xx/cpm1.c30
-rw-r--r--arch/powerpc/platforms/Kconfig8
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype3
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c5
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c8
-rw-r--r--arch/powerpc/platforms/pasemi/pci.c3
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c2
-rw-r--r--arch/powerpc/platforms/powermac/bootx_init.c4
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c36
-rw-r--r--arch/powerpc/platforms/powernv/idle.c3
-rw-r--r--arch/powerpc/platforms/powernv/opal-dump.c11
-rw-r--r--arch/powerpc/platforms/powernv/opal-elog.c9
-rw-r--r--arch/powerpc/platforms/powernv/opal-flash.c4
-rw-r--r--arch/powerpc/platforms/powernv/opal-powercap.c12
-rw-r--r--arch/powerpc/platforms/powernv/opal-psr.c12
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c6
-rw-r--r--arch/powerpc/platforms/powernv/pci-sriov.c4
-rw-r--r--arch/powerpc/platforms/powernv/pci.h5
-rw-r--r--arch/powerpc/platforms/powernv/setup.c5
-rw-r--r--arch/powerpc/platforms/powernv/smp.c8
-rw-r--r--arch/powerpc/platforms/powernv/subcore.c3
-rw-r--r--arch/powerpc/platforms/ps3/device-init.c4
-rw-r--r--arch/powerpc/platforms/ps3/mm.c1
-rw-r--r--arch/powerpc/platforms/ps3/repository.c5
-rw-r--r--arch/powerpc/platforms/ps3/setup.c3
-rw-r--r--arch/powerpc/platforms/ps3/spu.c12
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig1
-rw-r--r--arch/powerpc/platforms/pseries/cc_platform.c1
-rw-r--r--arch/powerpc/platforms/pseries/cmm.c5
-rw-r--r--arch/powerpc/platforms/pseries/dlpar.c3
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c18
-rw-r--r--arch/powerpc/platforms/pseries/htmdump.c150
-rw-r--r--arch/powerpc/platforms/pseries/ibmebus.c5
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c23
-rw-r--r--arch/powerpc/platforms/pseries/kexec.c13
-rw-r--r--arch/powerpc/platforms/pseries/lparcfg.c26
-rw-r--r--arch/powerpc/platforms/pseries/papr-hvpipe.c181
-rw-r--r--arch/powerpc/platforms/pseries/papr-hvpipe.h1
-rw-r--r--arch/powerpc/platforms/pseries/papr-phy-attest.c12
-rw-r--r--arch/powerpc/platforms/pseries/papr_platform_attributes.c14
-rw-r--r--arch/powerpc/platforms/pseries/papr_scm.c5
-rw-r--r--arch/powerpc/platforms/pseries/pci.c13
-rw-r--r--arch/powerpc/platforms/pseries/power.c3
-rw-r--r--arch/powerpc/platforms/pseries/pseries_energy.c3
-rw-r--r--arch/powerpc/platforms/pseries/ras.c16
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c4
-rw-r--r--arch/powerpc/platforms/pseries/rtas-fadump.c80
-rw-r--r--arch/powerpc/platforms/pseries/rtas-fadump.h6
-rw-r--r--arch/powerpc/platforms/pseries/setup.c33
-rw-r--r--arch/powerpc/platforms/pseries/smp.c15
-rw-r--r--arch/powerpc/platforms/pseries/suspend.c3
-rw-r--r--arch/powerpc/platforms/pseries/svm.c2
-rw-r--r--arch/powerpc/platforms/pseries/vas-sysfs.c3
-rw-r--r--arch/powerpc/platforms/pseries/vio.c29
-rw-r--r--arch/powerpc/sysdev/cpm_common.c13
-rw-r--r--arch/powerpc/sysdev/fsl_lbc.c1
-rw-r--r--arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c3
-rw-r--r--arch/powerpc/sysdev/fsl_pmc.c1
-rw-r--r--arch/powerpc/sysdev/msi_bitmap.c2
-rw-r--r--arch/powerpc/sysdev/xive/common.c29
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, &current_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, &current_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(&regs->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(&regs->or, GPIO_MASK(gpio));
- else
- clrbits32(&regs->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(&regs->odr, GPIO_MASK(gpio));
-
- /* Float the pin */
- clrbits32(&regs->tcr, GPIO_MASK(gpio));
-
- /* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */
- if (gpio < 16) {
- clrbits32(&regs->osrl, GPIO_MASK2(gpio));
- clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
- } else {
- clrbits32(&regs->osrh, GPIO_MASK2(gpio));
- clrbits32(&regs->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(&regs->odr, GPIO_MASK(gpio));
-
- /* Drive the pin */
- setbits32(&regs->tcr, GPIO_MASK(gpio));
-
- /* Bits 0-15 use TSRL, bits 16-31 use TSRH */
- if (gpio < 16) {
- clrbits32(&regs->osrl, GPIO_MASK2(gpio));
- clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
- } else {
- clrbits32(&regs->osrh, GPIO_MASK2(gpio));
- clrbits32(&regs->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(&params->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 */