Merge tag 'dlm-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 13 Oct 2020 15:59:39 +0000 (08:59 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 13 Oct 2020 15:59:39 +0000 (08:59 -0700)
Pull dlm updates from David Teigland:
 "This set continues the ongoing rework of the low level communication
  layer in the dlm.

  The focus here is on improvements to connection handling, and
  reworking the receiving of messages"

* tag 'dlm-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm:
  fs: dlm: fix race in nodeid2con
  fs: dlm: rework receive handling
  fs: dlm: disallow buffer size below default
  fs: dlm: handle range check as callback
  fs: dlm: fix mark per nodeid setting
  fs: dlm: remove lock dependency warning
  fs: dlm: use free_con to free connection
  fs: dlm: handle possible othercon writequeues
  fs: dlm: move free writequeue into con free
  fs: dlm: fix configfs memory leak
  fs: dlm: fix dlm_local_addr memory leak
  fs: dlm: make connection hash lockless
  fs: dlm: synchronize dlm before shutdown

3561 files changed:
.clang-format
.gitignore
.mailmap
Documentation/ABI/stable/sysfs-kernel-notes [new file with mode: 0644]
Documentation/PCI/index.rst
Documentation/PCI/sysfs-pci.rst [moved from Documentation/filesystems/sysfs-pci.rst with 100% similarity]
Documentation/RCU/lockdep.rst
Documentation/admin-guide/README.rst
Documentation/admin-guide/bcache.rst
Documentation/admin-guide/blockdev/ramdisk.rst
Documentation/admin-guide/cgroup-v1/cpusets.rst
Documentation/admin-guide/cgroup-v2.rst
Documentation/admin-guide/device-mapper/dm-crypt.rst
Documentation/admin-guide/devices.txt
Documentation/admin-guide/dynamic-debug-howto.rst
Documentation/admin-guide/kdump/kdump.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/laptops/thinkpad-acpi.rst
Documentation/admin-guide/perf/arm-cmn.rst [new file with mode: 0644]
Documentation/admin-guide/perf/index.rst
Documentation/admin-guide/pm/cpuidle.rst
Documentation/admin-guide/pm/intel_pstate.rst
Documentation/admin-guide/svga.rst
Documentation/admin-guide/sysctl/abi.rst
Documentation/admin-guide/tainted-kernels.rst
Documentation/arm/sunxi.rst
Documentation/arm/uefi.rst
Documentation/arm64/amu.rst
Documentation/arm64/cpu-feature-registers.rst
Documentation/arm64/elf_hwcaps.rst
Documentation/arm64/index.rst
Documentation/arm64/memory-tagging-extension.rst [new file with mode: 0644]
Documentation/bpf/ringbuf.rst
Documentation/conf.py
Documentation/core-api/cpu_hotplug.rst
Documentation/crypto/userspace-if.rst
Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
Documentation/devicetree/bindings/crypto/ti,sa2ul.yaml
Documentation/devicetree/bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml
Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml
Documentation/devicetree/bindings/edac/amazon,al-mc-edac.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/mstar,mst-intc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/snps,dw-apb-ictl.txt
Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt [deleted file]
Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt [deleted file]
Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/leds/cznic,turris-omnia-leds.yaml
Documentation/devicetree/bindings/media/i2c/imx274.txt [deleted file]
Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
Documentation/devicetree/bindings/mmc/mtk-sd.txt
Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt
Documentation/devicetree/bindings/net/dsa/dsa.txt
Documentation/devicetree/bindings/net/renesas,ravb.txt
Documentation/devicetree/bindings/perf/arm,cmn.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rng/ingenic,trng.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rng/xiphera,xip8001b-trng.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt
Documentation/devicetree/bindings/timer/renesas,cmt.yaml
Documentation/devicetree/bindings/trivial-devices.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/doc-guide/kernel-doc.rst
Documentation/doc-guide/sphinx.rst
Documentation/driver-api/dma-buf.rst
Documentation/driver-api/fpga/fpga-bridge.rst
Documentation/driver-api/fpga/fpga-mgr.rst
Documentation/driver-api/fpga/fpga-programming.rst
Documentation/driver-api/fpga/fpga-region.rst
Documentation/driver-api/gpio/driver.rst
Documentation/driver-api/iio/core.rst
Documentation/driver-api/nvdimm/index.rst
Documentation/driver-api/soundwire/stream.rst
Documentation/fault-injection/nvme-fault-injection.rst
Documentation/fb/fbcon.rst
Documentation/fb/matroxfb.rst
Documentation/fb/sstfb.rst
Documentation/fb/vesafb.rst
Documentation/features/debug/debug-vm-pgtable/arch-support.txt
Documentation/filesystems/affs.rst
Documentation/filesystems/index.rst
Documentation/filesystems/mount_api.rst
Documentation/filesystems/seq_file.rst
Documentation/filesystems/sysfs.rst
Documentation/filesystems/ubifs-authentication.rst
Documentation/firmware-guide/acpi/index.rst
Documentation/hwmon/abituguru-datasheet.rst
Documentation/hwmon/abituguru.rst
Documentation/hwmon/abituguru3.rst
Documentation/hwmon/index.rst
Documentation/ia64/index.rst
Documentation/ia64/xen.rst [deleted file]
Documentation/iio/iio_configfs.rst
Documentation/kbuild/llvm.rst
Documentation/kbuild/makefiles.rst
Documentation/locking/lockdep-design.rst
Documentation/locking/locktypes.rst
Documentation/locking/seqlock.rst
Documentation/maintainer/index.rst
Documentation/maintainer/maintainer-entry-profile.rst
Documentation/maintainer/modifying-patches.rst [new file with mode: 0644]
Documentation/memory-barriers.txt
Documentation/networking/dsa/configuration.rst
Documentation/networking/ethtool-netlink.rst
Documentation/networking/index.rst
Documentation/networking/sysfs-tagging.rst [moved from Documentation/filesystems/sysfs-tagging.rst with 100% similarity]
Documentation/powerpc/syscall64-abi.rst
Documentation/process/2.Process.rst
Documentation/process/changes.rst
Documentation/process/deprecated.rst
Documentation/process/email-clients.rst
Documentation/process/programming-language.rst
Documentation/process/submit-checklist.rst
Documentation/process/submitting-drivers.rst
Documentation/process/submitting-patches.rst
Documentation/scheduler/sched-capacity.rst
Documentation/scheduler/sched-energy.rst
Documentation/security/credentials.rst
Documentation/security/keys/trusted-encrypted.rst
Documentation/sound/cards/audigy-mixer.rst
Documentation/sound/cards/sb-live-mixer.rst
Documentation/sound/designs/timestamping.rst
Documentation/sphinx/automarkup.py
Documentation/trace/kprobetrace.rst
Documentation/trace/ring-buffer-design.rst
Documentation/translations/it_IT/process/deprecated.rst
Documentation/translations/ko_KR/howto.rst
Documentation/translations/ko_KR/memory-barriers.txt
Documentation/translations/zh_CN/arm64/amu.rst [new file with mode: 0644]
Documentation/translations/zh_CN/arm64/index.rst [new file with mode: 0644]
Documentation/translations/zh_CN/filesystems/sysfs.txt
Documentation/translations/zh_CN/index.rst
Documentation/userspace-api/media/v4l/buffer.rst
Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst
Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst
Documentation/virt/index.rst
Documentation/virt/kvm/amd-memory-encryption.rst
Documentation/virt/kvm/api.rst
Documentation/virt/kvm/arm/hyp-abi.rst
Documentation/virt/kvm/cpuid.rst
Documentation/virt/uml/user_mode_linux.rst [deleted file]
Documentation/virt/uml/user_mode_linux_howto_v2.rst [new file with mode: 0644]
Documentation/vm/hmm.rst
Documentation/vm/index.rst
Documentation/vm/page_migration.rst
Documentation/watch_queue.rst
Documentation/x86/boot.rst
Documentation/x86/cpuinfo.rst [new file with mode: 0644]
Documentation/x86/index.rst
Documentation/x86/resctrl_ui.rst
Documentation/x86/sva.rst [new file with mode: 0644]
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/include/asm/checksum.h
arch/alpha/kernel/module.c
arch/alpha/kernel/signal.c
arch/alpha/kernel/traps.c
arch/alpha/kernel/vmlinux.lds.S
arch/alpha/lib/csum_partial_copy.c
arch/arc/boot/dts/hsdk.dts
arch/arc/include/asm/pgalloc.h
arch/arc/kernel/disasm.c
arch/arc/kernel/kprobes.c
arch/arc/kernel/perf_event.c
arch/arc/kernel/signal.c
arch/arc/kernel/troubleshoot.c
arch/arc/kernel/unwind.c
arch/arc/kernel/vmlinux.lds.S
arch/arc/mm/init.c
arch/arc/plat-eznps/include/plat/ctop.h
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/vmlinux.lds.S
arch/arm/boot/dts/at91-sama5d2_icp.dts
arch/arm/boot/dts/bcm-hr2.dtsi
arch/arm/boot/dts/bcm-nsp.dtsi
arch/arm/boot/dts/bcm2835-rpi.dtsi
arch/arm/boot/dts/bcm5301x.dtsi
arch/arm/boot/dts/imx6q-logicpd.dts
arch/arm/boot/dts/imx6q-prtwd2.dts
arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
arch/arm/boot/dts/imx6sx-pinfunc.h
arch/arm/boot/dts/imx7d-zii-rmu2.dts
arch/arm/boot/dts/imx7ulp.dtsi
arch/arm/boot/dts/logicpd-som-lv-baseboard.dtsi
arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi
arch/arm/boot/dts/ls1021a.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/socfpga_arria10.dtsi
arch/arm/boot/dts/vfxxx.dtsi
arch/arm/configs/integrator_defconfig
arch/arm/crypto/aes-neonbs-core.S
arch/arm/crypto/aes-neonbs-glue.c
arch/arm/crypto/curve25519-glue.c
arch/arm/crypto/poly1305-glue.c
arch/arm/crypto/sha256-armv4.pl
arch/arm/crypto/sha256-core.S_shipped
arch/arm/crypto/sha512-armv4.pl
arch/arm/crypto/sha512-core.S_shipped
arch/arm/include/asm/checksum.h
arch/arm/include/asm/efi.h
arch/arm/include/asm/hardirq.h
arch/arm/include/asm/smp.h
arch/arm/include/asm/vmlinux.lds.h [moved from arch/arm/kernel/vmlinux.lds.h with 84% similarity]
arch/arm/kernel/hw_breakpoint.c
arch/arm/kernel/irq.c
arch/arm/kernel/signal.c
arch/arm/kernel/smp.c
arch/arm/kernel/topology.c
arch/arm/kernel/vmlinux-xip.lds.S
arch/arm/kernel/vmlinux.lds.S
arch/arm/lib/csumpartialcopy.S
arch/arm/lib/csumpartialcopygeneric.S
arch/arm/lib/csumpartialcopyuser.S
arch/arm/mach-ep93xx/crunch.c
arch/arm/mach-imx/cpuidle-imx6q.c
arch/arm/mach-mmp/pm-mmp2.c
arch/arm/mach-mmp/pm-pxa910.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/omap-iommu.c
arch/arm/mach-omap2/omap_device.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-orion5x/dns323-setup.c
arch/arm/mach-rpc/riscpc.c
arch/arm/mach-tegra/reset.c
arch/arm/mm/alignment.c
arch/arm/mm/proc-v7-bugs.c
arch/arm/plat-omap/dma.c
arch/arm/probes/decode.c
arch/arm/probes/kprobes/core.c
arch/arm/xen/enlighten.c
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi
arch/arm64/boot/dts/freescale/Makefile
arch/arm64/boot/dts/freescale/imx8mp.dtsi
arch/arm64/boot/dts/freescale/imx8mq.dtsi
arch/arm64/boot/dts/mediatek/mt7622.dtsi
arch/arm64/boot/dts/nvidia/tegra186.dtsi
arch/arm64/boot/dts/nvidia/tegra194.dtsi
arch/arm64/boot/dts/nvidia/tegra210.dtsi
arch/arm64/boot/dts/ti/k3-am65-main.dtsi
arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi
arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-am654-base-board.dts
arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi
arch/arm64/boot/dts/xilinx/zynqmp.dtsi
arch/arm64/configs/defconfig
arch/arm64/crypto/aes-neonbs-core.S
arch/arm64/crypto/ghash-ce-glue.c
arch/arm64/crypto/sha1-ce-glue.c
arch/arm64/crypto/sha2-ce-glue.c
arch/arm64/include/asm/arch_gicv3.h
arch/arm64/include/asm/archrandom.h
arch/arm64/include/asm/boot.h
arch/arm64/include/asm/compat.h
arch/arm64/include/asm/compiler.h
arch/arm64/include/asm/cpu_ops.h
arch/arm64/include/asm/cpucaps.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/efi.h
arch/arm64/include/asm/esr.h
arch/arm64/include/asm/exception.h
arch/arm64/include/asm/extable.h
arch/arm64/include/asm/fpsimd.h
arch/arm64/include/asm/fpsimdmacros.h
arch/arm64/include/asm/hardirq.h
arch/arm64/include/asm/hwcap.h
arch/arm64/include/asm/insn.h
arch/arm64/include/asm/irq_work.h
arch/arm64/include/asm/irqflags.h
arch/arm64/include/asm/kernel-pgtable.h
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/mman.h
arch/arm64/include/asm/mmu.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/mte.h [new file with mode: 0644]
arch/arm64/include/asm/numa.h
arch/arm64/include/asm/page-def.h
arch/arm64/include/asm/page.h
arch/arm64/include/asm/pci.h
arch/arm64/include/asm/perf_event.h
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pgtable-prot.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/ptrace.h
arch/arm64/include/asm/smp.h
arch/arm64/include/asm/spectre.h [new file with mode: 0644]
arch/arm64/include/asm/stacktrace.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/thread_info.h
arch/arm64/include/asm/tlbflush.h
arch/arm64/include/asm/traps.h
arch/arm64/include/asm/unistd32.h
arch/arm64/include/uapi/asm/hwcap.h
arch/arm64/include/uapi/asm/kvm.h
arch/arm64/include/uapi/asm/mman.h
arch/arm64/include/uapi/asm/ptrace.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/acpi.c
arch/arm64/kernel/cpu-reset.S
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/debug-monitors.c
arch/arm64/kernel/entry-common.c
arch/arm64/kernel/entry-fpsimd.S
arch/arm64/kernel/entry.S
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/head.S
arch/arm64/kernel/hibernate.c
arch/arm64/kernel/hw_breakpoint.c
arch/arm64/kernel/image-vars.h
arch/arm64/kernel/image.h
arch/arm64/kernel/insn.c
arch/arm64/kernel/irq.c
arch/arm64/kernel/module-plts.c
arch/arm64/kernel/module.c
arch/arm64/kernel/mte.c [new file with mode: 0644]
arch/arm64/kernel/paravirt.c
arch/arm64/kernel/perf_callchain.c
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/perf_regs.c
arch/arm64/kernel/probes/decode-insn.c
arch/arm64/kernel/probes/kprobes.c
arch/arm64/kernel/process.c
arch/arm64/kernel/proton-pack.c [new file with mode: 0644]
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/relocate_kernel.S
arch/arm64/kernel/return_address.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/signal.c
arch/arm64/kernel/smccc-call.S
arch/arm64/kernel/smp.c
arch/arm64/kernel/smp_spin_table.c
arch/arm64/kernel/ssbd.c [deleted file]
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/suspend.c
arch/arm64/kernel/syscall.c
arch/arm64/kernel/topology.c
arch/arm64/kernel/traps.c
arch/arm64/kernel/vdso.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/Kconfig
arch/arm64/kvm/arm.c
arch/arm64/kvm/handle_exit.c
arch/arm64/kvm/hyp/Makefile
arch/arm64/kvm/hyp/entry.S
arch/arm64/kvm/hyp/hyp-entry.S
arch/arm64/kvm/hyp/include/hyp/debug-sr.h
arch/arm64/kvm/hyp/include/hyp/switch.h
arch/arm64/kvm/hyp/nvhe/switch.c
arch/arm64/kvm/hyp/nvhe/tlb.c
arch/arm64/kvm/hyp/vgic-v3-sr.c
arch/arm64/kvm/hyp/vhe/switch.c
arch/arm64/kvm/hypercalls.c
arch/arm64/kvm/mmu.c
arch/arm64/kvm/pmu-emul.c
arch/arm64/kvm/psci.c
arch/arm64/kvm/pvtime.c
arch/arm64/kvm/reset.c
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/trace_arm.h
arch/arm64/kvm/trace_handle_exit.h
arch/arm64/kvm/vgic/vgic-mmio-v3.c
arch/arm64/lib/Makefile
arch/arm64/lib/mte.S [new file with mode: 0644]
arch/arm64/mm/Makefile
arch/arm64/mm/context.c
arch/arm64/mm/copypage.c
arch/arm64/mm/extable.c
arch/arm64/mm/fault.c
arch/arm64/mm/mmu.c
arch/arm64/mm/mteswap.c [new file with mode: 0644]
arch/arm64/mm/numa.c
arch/arm64/mm/pageattr.c
arch/arm64/mm/proc.S
arch/arm64/mm/ptdump.c [moved from arch/arm64/mm/dump.c with 97% similarity]
arch/arm64/net/bpf_jit_comp.c
arch/c6x/include/asm/checksum.h
arch/c6x/kernel/signal.c
arch/c6x/lib/csum_64plus.S
arch/csky/kernel/probes/kprobes.c
arch/csky/kernel/signal.c
arch/csky/kernel/vmlinux.lds.S
arch/h8300/kernel/signal.c
arch/hexagon/include/asm/checksum.h
arch/hexagon/kernel/module.c
arch/hexagon/kernel/signal.c
arch/hexagon/kernel/vmlinux.lds.S
arch/hexagon/lib/checksum.c
arch/ia64/Kconfig
arch/ia64/configs/bigsur_defconfig
arch/ia64/configs/generic_defconfig
arch/ia64/configs/gensparse_defconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/configs/zx1_defconfig
arch/ia64/include/asm/acpi.h
arch/ia64/include/asm/checksum.h
arch/ia64/include/asm/processor.h
arch/ia64/include/asm/switch_to.h
arch/ia64/kernel/Makefile
arch/ia64/kernel/crash.c
arch/ia64/kernel/ia64_ksyms.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/kprobes.c
arch/ia64/kernel/module.c
arch/ia64/kernel/perfmon.c [deleted file]
arch/ia64/kernel/process.c
arch/ia64/kernel/ptrace.c
arch/ia64/kernel/signal.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/syscalls/syscall.tbl
arch/ia64/kernel/unaligned.c
arch/ia64/kernel/unwind.c
arch/ia64/kernel/vmlinux.lds.S
arch/ia64/lib/Makefile
arch/ia64/lib/carta_random.S [deleted file]
arch/ia64/lib/csum_partial_copy.c
arch/ia64/mm/init.c
arch/ia64/oprofile/Makefile
arch/ia64/oprofile/init.c
arch/ia64/oprofile/perfmon.c [deleted file]
arch/m68k/Kconfig
arch/m68k/amiga/config.c
arch/m68k/atari/atakeyb.c
arch/m68k/configs/mac_defconfig
arch/m68k/configs/multi_defconfig
arch/m68k/include/asm/checksum.h
arch/m68k/include/asm/thread_info.h
arch/m68k/kernel/head.S
arch/m68k/kernel/signal.c
arch/m68k/kernel/traps.c
arch/m68k/lib/checksum.c
arch/m68k/mac/config.c
arch/m68k/mac/macboing.c
arch/m68k/mac/via.c
arch/m68k/mm/fault.c
arch/m68k/mm/mcfmmu.c
arch/m68k/mm/motorola.c
arch/microblaze/include/asm/Kbuild
arch/microblaze/kernel/signal.c
arch/microblaze/mm/init.c
arch/mips/Kconfig
arch/mips/bcm47xx/setup.c
arch/mips/include/asm/checksum.h
arch/mips/include/asm/compat.h
arch/mips/include/asm/cpu-type.h
arch/mips/include/asm/irqflags.h
arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h
arch/mips/include/asm/mach-loongson64/irq.h
arch/mips/include/asm/mach-loongson64/mmzone.h
arch/mips/include/asm/unroll.h
arch/mips/kernel/kprobes.c
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/syscalls/syscall_n32.tbl
arch/mips/kernel/syscalls/syscall_o32.tbl
arch/mips/kernel/traps.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/kvm/mips.c
arch/mips/lib/csum_partial.S
arch/mips/loongson2ef/Platform
arch/mips/loongson64/cop2-ex.c
arch/mips/mm/c-r4k.c
arch/mips/oprofile/op_model_mipsxx.c
arch/mips/sni/a20r.c
arch/nds32/include/asm/irqflags.h
arch/nds32/kernel/fpu.c
arch/nds32/kernel/signal.c
arch/nds32/kernel/vmlinux.lds.S
arch/nios2/include/asm/checksum.h
arch/nios2/kernel/vmlinux.lds.S
arch/openrisc/include/asm/uaccess.h
arch/openrisc/kernel/setup.c
arch/openrisc/kernel/signal.c
arch/openrisc/kernel/vmlinux.lds.S
arch/openrisc/mm/cache.c
arch/parisc/boot/compressed/vmlinux.lds.S
arch/parisc/include/asm/checksum.h
arch/parisc/include/asm/compat.h
arch/parisc/kernel/kprobes.c
arch/parisc/kernel/signal.c
arch/parisc/kernel/syscalls/syscall.tbl
arch/parisc/kernel/traps.c
arch/parisc/kernel/vmlinux.lds.S
arch/parisc/lib/checksum.c
arch/parisc/mm/fault.c
arch/powerpc/Kconfig
arch/powerpc/configs/pasemi_defconfig
arch/powerpc/configs/ppc6xx_defconfig
arch/powerpc/crypto/crc-vpmsum_test.c
arch/powerpc/include/asm/book3s/64/mmu.h
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/include/asm/checksum.h
arch/powerpc/include/asm/compat.h
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/mman.h
arch/powerpc/include/asm/nohash/64/pgtable.h
arch/powerpc/include/asm/string.h
arch/powerpc/include/asm/uaccess.h
arch/powerpc/include/uapi/asm/mman.h
arch/powerpc/kernel/dma-iommu.c
arch/powerpc/kernel/dt_cpu_ftrs.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/kprobes.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/syscalls/syscall.tbl
arch/powerpc/kernel/vdso32/Makefile
arch/powerpc/kernel/vdso32/vdso32.lds.S
arch/powerpc/kernel/vdso64/Makefile
arch/powerpc/kernel/vdso64/vdso64.lds.S
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/lib/Makefile
arch/powerpc/lib/checksum_32.S
arch/powerpc/lib/checksum_64.S
arch/powerpc/lib/checksum_wrappers.c
arch/powerpc/lib/copy_mc_64.S [moved from arch/powerpc/lib/memcpy_mcsafe_64.S with 98% similarity]
arch/powerpc/mm/book3s64/hash_utils.c
arch/powerpc/mm/book3s64/radix_pgtable.c
arch/powerpc/mm/init_64.c
arch/powerpc/net/bpf_jit_comp.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/imc-pmu.c
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/powernv/idle.c
arch/powerpc/platforms/pseries/papr_scm.c
arch/riscv/Kconfig
arch/riscv/boot/dts/kendryte/k210.dtsi
arch/riscv/include/asm/clint.h [new file with mode: 0644]
arch/riscv/include/asm/ftrace.h
arch/riscv/include/asm/stackprotector.h
arch/riscv/include/asm/timex.h
arch/riscv/kernel/ftrace.c
arch/riscv/kernel/signal.c
arch/riscv/kernel/vmlinux.lds.S
arch/riscv/mm/init.c
arch/riscv/net/bpf_jit_comp32.c
arch/s390/Kconfig
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/include/asm/checksum.h
arch/s390/include/asm/compat.h
arch/s390/include/asm/percpu.h
arch/s390/include/asm/pgtable.h
arch/s390/kernel/entry.h
arch/s390/kernel/idle.c
arch/s390/kernel/kprobes.c
arch/s390/kernel/pgm_check.S
arch/s390/kernel/setup.c
arch/s390/kernel/stacktrace.c
arch/s390/kernel/syscalls/syscall.tbl
arch/s390/kernel/vmlinux.lds.S
arch/s390/mm/fault.c
arch/s390/mm/vmem.c
arch/s390/pci/pci.c
arch/s390/pci/pci_event.c
arch/sh/drivers/platform_early.c
arch/sh/include/asm/checksum_32.h
arch/sh/include/asm/smp.h
arch/sh/kernel/disassemble.c
arch/sh/kernel/entry-common.S
arch/sh/kernel/kgdb.c
arch/sh/kernel/kprobes.c
arch/sh/kernel/ptrace_32.c
arch/sh/kernel/signal_32.c
arch/sh/kernel/vmlinux.lds.S
arch/sh/lib/checksum.S
arch/sparc/Kconfig
arch/sparc/include/asm/checksum.h
arch/sparc/include/asm/checksum_32.h
arch/sparc/include/asm/checksum_64.h
arch/sparc/include/asm/compat.h
arch/sparc/kernel/auxio_64.c
arch/sparc/kernel/central.c
arch/sparc/kernel/kgdb_32.c
arch/sparc/kernel/kgdb_64.c
arch/sparc/kernel/kprobes.c
arch/sparc/kernel/pcr.c
arch/sparc/kernel/prom_32.c
arch/sparc/kernel/signal32.c
arch/sparc/kernel/signal_32.c
arch/sparc/kernel/signal_64.c
arch/sparc/kernel/syscalls/syscall.tbl
arch/sparc/kernel/vmlinux.lds.S
arch/sparc/lib/checksum_32.S
arch/sparc/lib/csum_copy.S
arch/sparc/lib/csum_copy_from_user.S
arch/sparc/lib/csum_copy_to_user.S
arch/sparc/math-emu/math_32.c
arch/sparc/mm/fault_32.c
arch/sparc/net/bpf_jit_comp_32.c
arch/um/kernel/dyn.lds.S
arch/um/kernel/signal.c
arch/um/kernel/uml.lds.S
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/Makefile
arch/x86/boot/cmdline.c
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/head_32.S
arch/x86/boot/compressed/head_64.S
arch/x86/boot/compressed/kaslr.c
arch/x86/boot/compressed/misc.h
arch/x86/boot/compressed/mkpiggy.c
arch/x86/boot/compressed/vmlinux.lds.S
arch/x86/boot/setup.ld
arch/x86/boot/tools/build.c
arch/x86/configs/i386_defconfig
arch/x86/configs/x86_64_defconfig
arch/x86/crypto/blake2s-glue.c
arch/x86/crypto/chacha_glue.c
arch/x86/crypto/crc32c-intel_glue.c
arch/x86/crypto/curve25519-x86_64.c
arch/x86/crypto/nhpoly1305-avx2-glue.c
arch/x86/crypto/nhpoly1305-sse2-glue.c
arch/x86/crypto/poly1305-x86_64-cryptogams.pl
arch/x86/crypto/poly1305_glue.c
arch/x86/entry/calling.h
arch/x86/entry/common.c
arch/x86/entry/entry_64.S
arch/x86/entry/syscall_x32.c
arch/x86/entry/syscalls/syscall_32.tbl
arch/x86/entry/syscalls/syscall_64.tbl
arch/x86/entry/thunk_32.S
arch/x86/entry/vdso/vdso32/vclock_gettime.c
arch/x86/events/amd/ibs.c
arch/x86/events/amd/iommu.c
arch/x86/events/amd/uncore.c
arch/x86/events/core.c
arch/x86/events/intel/core.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/lbr.c
arch/x86/events/intel/uncore.c
arch/x86/events/intel/uncore.h
arch/x86/events/intel/uncore_snb.c
arch/x86/events/intel/uncore_snbep.c
arch/x86/events/msr.c
arch/x86/events/perf_event.h
arch/x86/events/rapl.c
arch/x86/hyperv/hv_init.c
arch/x86/hyperv/hv_spinlock.c
arch/x86/include/asm/acpi.h
arch/x86/include/asm/apic.h
arch/x86/include/asm/asm-prototypes.h
arch/x86/include/asm/asm.h
arch/x86/include/asm/checksum.h
arch/x86/include/asm/checksum_32.h
arch/x86/include/asm/checksum_64.h
arch/x86/include/asm/compat.h
arch/x86/include/asm/copy_mc_test.h [new file with mode: 0644]
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/debugreg.h
arch/x86/include/asm/disabled-features.h
arch/x86/include/asm/entry-common.h
arch/x86/include/asm/extable.h
arch/x86/include/asm/fixmap.h
arch/x86/include/asm/fpu/api.h
arch/x86/include/asm/fpu/internal.h
arch/x86/include/asm/fpu/types.h
arch/x86/include/asm/fpu/xstate.h
arch/x86/include/asm/frame.h
arch/x86/include/asm/fsgsbase.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/hyperv-tlfs.h
arch/x86/include/asm/idtentry.h
arch/x86/include/asm/io.h
arch/x86/include/asm/irq_remapping.h
arch/x86/include/asm/irq_stack.h
arch/x86/include/asm/irqdomain.h
arch/x86/include/asm/kprobes.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/mcsafe_test.h [deleted file]
arch/x86/include/asm/mmu.h
arch/x86/include/asm/mpspec.h
arch/x86/include/asm/msi.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/pgtable-3level_types.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_64_types.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/required-features.h
arch/x86/include/asm/segment.h
arch/x86/include/asm/special_insns.h
arch/x86/include/asm/static_call.h [new file with mode: 0644]
arch/x86/include/asm/string_64.h
arch/x86/include/asm/sync_core.h
arch/x86/include/asm/text-patching.h
arch/x86/include/asm/traps.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/uaccess_64.h
arch/x86/include/asm/uv/bios.h
arch/x86/include/asm/uv/uv.h
arch/x86/include/asm/uv/uv_bau.h [deleted file]
arch/x86/include/asm/uv/uv_hub.h
arch/x86/include/asm/uv/uv_mmrs.h
arch/x86/include/asm/x86_init.h
arch/x86/kernel/Makefile
arch/x86/kernel/alternative.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/msi.c
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/apic/probe_64.c
arch/x86/kernel/apic/vector.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/cpu/cacheinfo.c
arch/x86/kernel/cpu/centaur.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpuid-deps.c
arch/x86/kernel/cpu/mce/amd.c
arch/x86/kernel/cpu/mce/core.c
arch/x86/kernel/cpu/mce/dev-mcelog.c
arch/x86/kernel/cpu/mce/inject.c
arch/x86/kernel/cpu/mce/intel.c
arch/x86/kernel/cpu/mce/internal.h
arch/x86/kernel/cpu/mce/severity.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/cpu/mtrr/cyrix.c
arch/x86/kernel/cpu/resctrl/core.c
arch/x86/kernel/cpu/resctrl/ctrlmondata.c
arch/x86/kernel/cpu/resctrl/internal.h
arch/x86/kernel/cpu/resctrl/monitor.c
arch/x86/kernel/cpu/resctrl/rdtgroup.c
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/devicetree.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/fpu/init.c
arch/x86/kernel/fpu/xstate.c
arch/x86/kernel/hw_breakpoint.c
arch/x86/kernel/idt.c
arch/x86/kernel/irq.c
arch/x86/kernel/irq_64.c
arch/x86/kernel/kgdb.c
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/kprobes/opt.c
arch/x86/kernel/kvm.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/msr.c
arch/x86/kernel/nmi.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/paravirt_patch.c
arch/x86/kernel/process.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/quirks.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/signal.c
arch/x86/kernel/signal_compat.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/stacktrace.c
arch/x86/kernel/static_call.c [new file with mode: 0644]
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kernel/umip.c
arch/x86/kernel/uprobes.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kernel/x86_init.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/emulate.c
arch/x86/kvm/hyperv.c
arch/x86/kvm/irq_comm.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/sev.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/x86.c
arch/x86/lib/Makefile
arch/x86/lib/checksum_32.S
arch/x86/lib/cmdline.c
arch/x86/lib/copy_mc.c [new file with mode: 0644]
arch/x86/lib/copy_mc_64.S [new file with mode: 0644]
arch/x86/lib/copy_user_64.S
arch/x86/lib/csum-copy_64.S
arch/x86/lib/csum-wrappers_64.c
arch/x86/lib/getuser.S
arch/x86/lib/insn-eval.c
arch/x86/lib/memcpy_64.S
arch/x86/lib/putuser.S
arch/x86/lib/usercopy_64.c
arch/x86/math-emu/errors.c
arch/x86/math-emu/fpu_trig.c
arch/x86/mm/extable.c
arch/x86/mm/fault.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/numa_emulation.c
arch/x86/mm/pat/set_memory.c
arch/x86/mm/tlb.c
arch/x86/pci/common.c
arch/x86/pci/init.c
arch/x86/pci/xen.c
arch/x86/platform/efi/efi.c
arch/x86/platform/uv/Makefile
arch/x86/platform/uv/bios_uv.c
arch/x86/platform/uv/tlb_uv.c [deleted file]
arch/x86/platform/uv/uv_irq.c
arch/x86/platform/uv/uv_nmi.c
arch/x86/platform/uv/uv_time.c
arch/x86/um/asm/checksum.h
arch/x86/um/asm/checksum_32.h
arch/x86/xen/enlighten_pv.c
arch/x86/xen/mmu_pv.c
arch/xtensa/include/asm/checksum.h
arch/xtensa/kernel/signal.c
arch/xtensa/lib/checksum.S
block/badblocks.c
block/bfq-cgroup.c
block/bfq-iosched.c
block/bfq-iosched.h
block/bfq-wf2q.c
block/bio.c
block/blk-cgroup.c
block/blk-core.c
block/blk-iocost.c
block/blk-merge.c
block/blk-mq-sched.c
block/blk-mq-sched.h
block/blk-mq.c
block/blk-settings.c
block/blk-stat.c
block/blk-wbt.c
block/bsg-lib.c
block/ioprio.c
block/partitions/core.c
block/partitions/ibm.c
block/scsi_ioctl.c
crypto/Kconfig
crypto/Makefile
crypto/af_alg.c
crypto/ahash.c
crypto/algif_aead.c
crypto/algif_rng.c
crypto/algif_skcipher.c
crypto/arc4.c
crypto/asymmetric_keys/public_key.c
crypto/asymmetric_keys/x509_cert_parser.c
crypto/asymmetric_keys/x509_public_key.c
crypto/cbc.c
crypto/crc32c_generic.c
crypto/crct10dif_generic.c
crypto/crypto_engine.c
crypto/drbg.c
crypto/ecrdsa.c
crypto/internal.h
crypto/jitterentropy-kcapi.c
crypto/proc.c
crypto/rsa-pkcs1pad.c
crypto/sm2.c [new file with mode: 0644]
crypto/sm2signature.asn1 [new file with mode: 0644]
crypto/sm3_generic.c
crypto/tcrypt.c
crypto/tcrypt.h
crypto/testmgr.c
crypto/testmgr.h
crypto/xor.c
drivers/accessibility/braille/braille_console.c
drivers/accessibility/speakup/Kconfig
drivers/accessibility/speakup/Makefile
drivers/accessibility/speakup/serialio.c
drivers/accessibility/speakup/spk_priv.h
drivers/accessibility/speakup/spk_ttyio.c
drivers/accessibility/speakup/spk_types.h
drivers/accessibility/speakup/synth.c
drivers/acpi/acpi_apd.c
drivers/acpi/arm64/iort.c
drivers/acpi/osl.c
drivers/acpi/processor_idle.c
drivers/ata/ahci.c
drivers/ata/ahci_brcm.c
drivers/ata/libahci_platform.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/pata_atp867x.c
drivers/ata/pata_serverworks.c
drivers/ata/sata_mv.c
drivers/ata/sata_promise.c
drivers/ata/sata_sx4.c
drivers/atm/eni.c
drivers/atm/firestream.c
drivers/atm/fore200e.c
drivers/atm/he.c
drivers/atm/idt77105.c
drivers/atm/lanai.c
drivers/atm/zatm.c
drivers/auxdisplay/arm-charlcd.c
drivers/auxdisplay/panel.c
drivers/base/core.c
drivers/base/firmware_loader/fallback.c
drivers/base/firmware_loader/firmware.h
drivers/base/firmware_loader/main.c
drivers/base/node.c
drivers/base/power/main.c
drivers/base/regmap/internal.h
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap.c
drivers/block/aoe/aoecmd.c
drivers/block/ataflop.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/null_blk_main.c
drivers/block/paride/pd.c
drivers/block/pktcdvd.c
drivers/block/rbd.c
drivers/block/rnbd/rnbd-srv.c
drivers/block/rsxx/core.c
drivers/block/skd_main.c
drivers/block/virtio_blk.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkback/xenbus.c
drivers/block/xen-blkfront.c
drivers/bus/ti-sysc.c
drivers/char/agp/ali-agp.c
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/cctrng.c
drivers/char/hw_random/imx-rngc.c
drivers/char/hw_random/ingenic-rng.c
drivers/char/hw_random/ingenic-trng.c [new file with mode: 0644]
drivers/char/hw_random/intel-rng.c
drivers/char/hw_random/iproc-rng200.c
drivers/char/hw_random/mxc-rnga.c
drivers/char/hw_random/npcm-rng.c
drivers/char/hw_random/optee-rng.c
drivers/char/hw_random/stm32-rng.c
drivers/char/hw_random/xiphera-trng.c [new file with mode: 0644]
drivers/char/ipmi/kcs_bmc.c
drivers/char/lp.c
drivers/char/mem.c
drivers/char/nvram.c
drivers/char/tpm/Kconfig
drivers/char/tpm/Makefile
drivers/char/tpm/tpm-sysfs.c
drivers/char/tpm/tpm_tis_core.c
drivers/char/tpm/tpm_tis_core.h
drivers/char/tpm/tpm_tis_synquacer.c [new file with mode: 0644]
drivers/clk/bcm/Kconfig
drivers/clk/davinci/pll.c
drivers/clk/qcom/lpasscorecc-sc7180.c
drivers/clk/rockchip/clk-rk3228.c
drivers/clk/samsung/clk-exynos4.c
drivers/clk/samsung/clk-exynos5420.c
drivers/clk/socfpga/clk-s10.c
drivers/clk/tegra/clk-pll.c
drivers/clk/tegra/clk-tegra210-emc.c
drivers/clk/versatile/clk-impd1.c
drivers/clocksource/h8300_timer8.c
drivers/clocksource/mps2-timer.c
drivers/clocksource/timer-armada-370-xp.c
drivers/clocksource/timer-cadence-ttc.c
drivers/clocksource/timer-clint.c
drivers/clocksource/timer-gx6605s.c
drivers/clocksource/timer-sp.h
drivers/clocksource/timer-sp804.c
drivers/clocksource/timer-ti-dm-systimer.c
drivers/counter/microchip-tcb-capture.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/p4-clockmod.c
drivers/cpufreq/speedstep-lib.c
drivers/cpufreq/tegra194-cpufreq.c
drivers/cpufreq/ti-cpufreq.c
drivers/cpuidle/cpuidle-psci.c
drivers/cpuidle/cpuidle-pseries.c
drivers/cpuidle/cpuidle.c
drivers/crypto/Kconfig
drivers/crypto/allwinner/Kconfig
drivers/crypto/allwinner/sun4i-ss/sun4i-ss-hash.c
drivers/crypto/allwinner/sun8i-ce/Makefile
drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c
drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c
drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c [new file with mode: 0644]
drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c [new file with mode: 0644]
drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c [new file with mode: 0644]
drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h
drivers/crypto/allwinner/sun8i-ss/Makefile
drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c
drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c
drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c [new file with mode: 0644]
drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c [new file with mode: 0644]
drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h
drivers/crypto/amcc/crypto4xx_alg.c
drivers/crypto/amcc/crypto4xx_core.h
drivers/crypto/amlogic/amlogic-gxl-cipher.c
drivers/crypto/amlogic/amlogic-gxl-core.c
drivers/crypto/atmel-aes.c
drivers/crypto/atmel-tdes.c
drivers/crypto/axis/artpec6_crypto.c
drivers/crypto/bcm/cipher.c
drivers/crypto/bcm/cipher.h
drivers/crypto/bcm/spu.c
drivers/crypto/bcm/spu.h
drivers/crypto/bcm/spu2.c
drivers/crypto/bcm/spu2.h
drivers/crypto/caam/Kconfig
drivers/crypto/caam/Makefile
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamalg_desc.c
drivers/crypto/caam/caamalg_qi.c
drivers/crypto/caam/caamalg_qi2.c
drivers/crypto/caam/caamalg_qi2.h
drivers/crypto/caam/ctrl.c
drivers/crypto/caam/debugfs.c [new file with mode: 0644]
drivers/crypto/caam/debugfs.h [new file with mode: 0644]
drivers/crypto/caam/dpseci-debugfs.c
drivers/crypto/caam/intern.h
drivers/crypto/caam/jr.c
drivers/crypto/caam/qi.c
drivers/crypto/cavium/cpt/cptvf_algs.c
drivers/crypto/cavium/cpt/cptvf_reqmanager.c
drivers/crypto/cavium/nitrox/nitrox_main.c
drivers/crypto/cavium/zip/zip_main.c
drivers/crypto/ccp/ccp-ops.c
drivers/crypto/ccree/cc_cipher.c
drivers/crypto/ccree/cc_crypto_ctx.h
drivers/crypto/ccree/cc_driver.c
drivers/crypto/ccree/cc_driver.h
drivers/crypto/ccree/cc_pm.c
drivers/crypto/chelsio/chcr_core.c
drivers/crypto/chelsio/chcr_ktls.c
drivers/crypto/hifn_795x.c
drivers/crypto/hisilicon/hpre/hpre.h
drivers/crypto/hisilicon/hpre/hpre_crypto.c
drivers/crypto/hisilicon/hpre/hpre_main.c
drivers/crypto/hisilicon/qm.c
drivers/crypto/hisilicon/qm.h
drivers/crypto/hisilicon/sec2/sec_crypto.c
drivers/crypto/hisilicon/sec2/sec_main.c
drivers/crypto/hisilicon/zip/zip.h
drivers/crypto/hisilicon/zip/zip_crypto.c
drivers/crypto/hisilicon/zip/zip_main.c
drivers/crypto/img-hash.c
drivers/crypto/inside-secure/safexcel.c
drivers/crypto/inside-secure/safexcel.h
drivers/crypto/inside-secure/safexcel_cipher.c
drivers/crypto/inside-secure/safexcel_hash.c
drivers/crypto/inside-secure/safexcel_ring.c
drivers/crypto/ixp4xx_crypto.c
drivers/crypto/marvell/cesa/cesa.c
drivers/crypto/marvell/cesa/cesa.h
drivers/crypto/marvell/cesa/cipher.c
drivers/crypto/marvell/cesa/hash.c
drivers/crypto/marvell/cesa/tdma.c
drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
drivers/crypto/marvell/octeontx/otx_cptvf_reqmgr.c
drivers/crypto/mediatek/mtk-aes.c
drivers/crypto/mediatek/mtk-platform.c
drivers/crypto/mediatek/mtk-sha.c
drivers/crypto/n2_core.c
drivers/crypto/omap-sham.c
drivers/crypto/padlock-aes.c
drivers/crypto/picoxcell_crypto.c
drivers/crypto/qat/qat_c3xxx/adf_drv.c
drivers/crypto/qat/qat_c3xxxvf/adf_drv.c
drivers/crypto/qat/qat_c62x/adf_drv.c
drivers/crypto/qat/qat_c62xvf/adf_drv.c
drivers/crypto/qat/qat_common/adf_accel_devices.h
drivers/crypto/qat/qat_common/adf_admin.c
drivers/crypto/qat/qat_common/adf_aer.c
drivers/crypto/qat/qat_common/adf_cfg.c
drivers/crypto/qat/qat_common/adf_common_drv.h
drivers/crypto/qat/qat_common/adf_ctl_drv.c
drivers/crypto/qat/qat_common/adf_dev_mgr.c
drivers/crypto/qat/qat_common/adf_pf2vf_msg.c
drivers/crypto/qat/qat_common/adf_sriov.c
drivers/crypto/qat/qat_common/adf_transport_debug.c
drivers/crypto/qat/qat_common/qat_algs.c
drivers/crypto/qat/qat_common/qat_hal.c
drivers/crypto/qat/qat_common/qat_uclo.c
drivers/crypto/qat/qat_dh895xcc/adf_drv.c
drivers/crypto/qat/qat_dh895xccvf/adf_drv.c
drivers/crypto/qce/core.c
drivers/crypto/qce/sha.c
drivers/crypto/qce/skcipher.c
drivers/crypto/qcom-rng.c
drivers/crypto/rockchip/rk3288_crypto.c
drivers/crypto/rockchip/rk3288_crypto.h
drivers/crypto/rockchip/rk3288_crypto_ahash.c
drivers/crypto/rockchip/rk3288_crypto_skcipher.c
drivers/crypto/s5p-sss.c
drivers/crypto/sa2ul.c
drivers/crypto/sahara.c
drivers/crypto/stm32/Kconfig
drivers/crypto/stm32/stm32-crc32.c
drivers/crypto/stm32/stm32-cryp.c
drivers/crypto/stm32/stm32-hash.c
drivers/crypto/talitos.c
drivers/crypto/ux500/cryp/cryp.c
drivers/crypto/ux500/cryp/cryp_core.c
drivers/crypto/ux500/hash/hash_core.c
drivers/crypto/virtio/Kconfig
drivers/crypto/xilinx/zynqmp-aes-gcm.c
drivers/dax/device.c
drivers/dax/super.c
drivers/devfreq/devfreq.c
drivers/devfreq/tegra30-devfreq.c
drivers/dma-buf/dma-buf.c
drivers/dma-buf/dma-fence-chain.c
drivers/dma/acpi-dma.c
drivers/dma/amba-pl08x.c
drivers/dma/at_hdmac.c
drivers/dma/dma-jz4780.c
drivers/dma/dmatest.c
drivers/dma/dw-edma/dw-edma-core.c
drivers/dma/fsldma.c
drivers/dma/fsldma.h
drivers/dma/idxd/device.c
drivers/dma/idxd/irq.c
drivers/dma/imx-dma.c
drivers/dma/iop-adma.h
drivers/dma/nbpfaxi.c
drivers/dma/of-dma.c
drivers/dma/pl330.c
drivers/dma/sh/shdma-base.c
drivers/dma/ti/k3-udma.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/al_mc_edac.c [new file with mode: 0644]
drivers/edac/amd64_edac.c
drivers/edac/aspeed_edac.c
drivers/edac/e752x_edac.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/ghes_edac.c
drivers/edac/i5100_edac.c
drivers/edac/i5400_edac.c
drivers/edac/i7300_edac.c
drivers/edac/i7core_edac.c
drivers/edac/ie31200_edac.c
drivers/edac/mce_amd.c
drivers/edac/pnd2_edac.c
drivers/edac/sb_edac.c
drivers/edac/thunderx_edac.c
drivers/edac/ti_edac.c
drivers/firewire/core-device.c
drivers/firewire/core-iso.c
drivers/firewire/core-topology.c
drivers/firewire/core-transaction.c
drivers/firewire/ohci.c
drivers/firmware/arm_sdei.c
drivers/firmware/efi/Kconfig
drivers/firmware/efi/Makefile
drivers/firmware/efi/cper.c
drivers/firmware/efi/efi-init.c [moved from drivers/firmware/efi/arm-init.c with 99% similarity]
drivers/firmware/efi/efi-pstore.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/efibc.c
drivers/firmware/efi/efivars.c
drivers/firmware/efi/embedded-firmware.c
drivers/firmware/efi/libstub/Makefile
drivers/firmware/efi/libstub/arm32-stub.c
drivers/firmware/efi/libstub/arm64-stub.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/firmware/efi/libstub/efi-stub.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/fdt.c
drivers/firmware/efi/libstub/file.c
drivers/firmware/efi/libstub/hidden.h [deleted file]
drivers/firmware/efi/libstub/relocate.c
drivers/firmware/efi/libstub/string.c
drivers/firmware/efi/libstub/vsprintf.c
drivers/firmware/efi/mokvar-table.c [new file with mode: 0644]
drivers/firmware/efi/vars.c
drivers/firmware/google/Kconfig
drivers/firmware/google/gsmi.c
drivers/firmware/ti_sci.c
drivers/gpio/gpio-amd-fch.c
drivers/gpio/gpio-aspeed-sgpio.c
drivers/gpio/gpio-aspeed.c
drivers/gpio/gpio-ath79.c
drivers/gpio/gpio-eic-sprd.c
drivers/gpio/gpio-mockup.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-siox.c
drivers/gpio/gpio-sprd.c
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-tc3589x.c
drivers/gpio/gpio-tegra186.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-cdev.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10_3.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
drivers/gpu/drm/amd/amdgpu/nv.c
drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
drivers/gpu/drm/amd/amdgpu/si_dpm.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c
drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_events.c
drivers/gpu/drm/amd/amdkfd/kfd_events.h
drivers/gpu/drm/amd/amdkfd/kfd_iommu.c
drivers/gpu/drm/amd/amdkfd/kfd_pasid.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/amdkfd/kfd_process.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/dc_stream.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn30/Makefile
drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.h
drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c
drivers/gpu/drm/amd/display/modules/power/power_helpers.c
drivers/gpu/drm/amd/display/modules/power/power_helpers.h
drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_default.h
drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_offset.h
drivers/gpu/drm/amd/include/asic_reg/gc/gc_10_3_0_sh_mask.h
drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_3_0_0_sh_mask.h
drivers/gpu/drm/amd/include/kgd_kfd_interface.h
drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega20_thermal.c
drivers/gpu/drm/amd/powerplay/navi10_ppt.c
drivers/gpu/drm/amd/powerplay/renoir_ppt.c
drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c
drivers/gpu/drm/arm/malidp_hw.c
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/bridge/nwl-dsi.c
drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
drivers/gpu/drm/bridge/ti-sn65dsi86.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_color_mgmt.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_mode_object.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_plane.c
drivers/gpu/drm/etnaviv/etnaviv_gpu.c
drivers/gpu/drm/etnaviv/etnaviv_sched.c
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_gem.h
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
drivers/gpu/drm/i915/display/icl_dsi.c
drivers/gpu/drm/i915/display/intel_bios.c
drivers/gpu/drm/i915/display/intel_cdclk.c
drivers/gpu/drm/i915/display/intel_combo_phy.c
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_dpll_mgr.c
drivers/gpu/drm/i915/display/intel_hdcp.c
drivers/gpu/drm/i915/display/intel_panel.c
drivers/gpu/drm/i915/display/intel_sdvo.c
drivers/gpu/drm/i915/display/intel_sprite.c
drivers/gpu/drm/i915/display/intel_tc.c
drivers/gpu/drm/i915/gem/i915_gem_context.c
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gem/i915_gem_mman.c
drivers/gpu/drm/i915/gem/i915_gem_object.h
drivers/gpu/drm/i915/gem/i915_gem_pages.c
drivers/gpu/drm/i915/gem/i915_gem_stolen.c
drivers/gpu/drm/i915/gem/i915_gem_userptr.c
drivers/gpu/drm/i915/gem/selftests/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gt/intel_engine_cs.c
drivers/gpu/drm/i915/gt/intel_ggtt.c
drivers/gpu/drm/i915/gt/intel_lrc.c
drivers/gpu/drm/i915/gt/intel_ring_submission.c
drivers/gpu/drm/i915/gvt/handlers.c
drivers/gpu/drm/i915/gvt/vgpu.c
drivers/gpu/drm/i915/i915_active.c
drivers/gpu/drm/i915/i915_cmd_parser.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_pmu.c
drivers/gpu/drm/i915/i915_request.c
drivers/gpu/drm/i915/i915_sw_fence.c
drivers/gpu/drm/i915/selftests/mock_gem_device.c
drivers/gpu/drm/imx/ipuv3-plane.c
drivers/gpu/drm/ingenic/ingenic-drm-drv.c
drivers/gpu/drm/mediatek/mtk_drm_crtc.c
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
drivers/gpu/drm/mediatek/mtk_drm_drv.c
drivers/gpu/drm/mediatek/mtk_dsi.c
drivers/gpu/drm/mediatek/mtk_hdmi.c
drivers/gpu/drm/meson/meson_osd_afbcd.c
drivers/gpu/drm/meson/meson_overlay.c
drivers/gpu/drm/msm/adreno/a2xx_gpu.c
drivers/gpu/drm/msm/adreno/a3xx_gpu.c
drivers/gpu/drm/msm/adreno/a4xx_gpu.c
drivers/gpu/drm/msm/adreno/a5xx_gpu.c
drivers/gpu/drm/msm/adreno/a5xx_gpu.h
drivers/gpu/drm/msm/adreno/a5xx_preempt.c
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h
drivers/gpu/drm/msm/adreno/adreno_device.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/msm/msm_ringbuffer.c
drivers/gpu/drm/nouveau/dispnv50/core507d.c
drivers/gpu/drm/nouveau/dispnv50/crcc37d.c
drivers/gpu/drm/nouveau/dispnv50/disp.c
drivers/gpu/drm/nouveau/include/nvif/push507c.h
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/omapdrm/dss/venc.c
drivers/gpu/drm/omapdrm/omap_crtc.c
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/uvd_v1_0.c
drivers/gpu/drm/savage/savage_state.c
drivers/gpu/drm/sti/sti_hdmi.c
drivers/gpu/drm/sun4i/sun4i_backend.c
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
drivers/gpu/drm/sun4i/sun8i_csc.h
drivers/gpu/drm/sun4i/sun8i_mixer.c
drivers/gpu/drm/sun4i/sun8i_vi_layer.c
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tilcdc/tilcdc_crtc.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/tve200/tve200_display.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/via/via_dmablit.c
drivers/gpu/drm/virtio/virtgpu_display.c
drivers/gpu/drm/virtio/virtgpu_drv.h
drivers/gpu/drm/virtio/virtgpu_object.c
drivers/gpu/drm/virtio/virtgpu_plane.c
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
drivers/gpu/drm/vmwgfx/vmwgfx_thp.c
drivers/gpu/drm/xen/xen_drm_front.c
drivers/gpu/drm/xen/xen_drm_front_gem.c
drivers/gpu/drm/xlnx/Kconfig
drivers/gpu/ipu-v3/ipu-dc.c
drivers/hid/hid-core.c
drivers/hid/hid-cougar.c
drivers/hid/hid-elan.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-lg-g15.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-macally.c
drivers/hid/hid-microsoft.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-quirks.c
drivers/hid/hid-rmi.c
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-uclogic-params.c
drivers/hid/hid-wiimote-core.c
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hiddev.c
drivers/hid/usbhid/usbhid.h
drivers/hid/wacom_wac.c
drivers/hsi/clients/ssi_protocol.c
drivers/hsi/controllers/omap_ssi_core.c
drivers/hv/channel_mgmt.c
drivers/hv/hv_kvp.c
drivers/hv/hv_util.c
drivers/hv/vmbus_drv.c
drivers/hwmon/adt7462.c
drivers/hwmon/applesmc.c
drivers/hwmon/emc1403.c
drivers/hwmon/f71882fg.c
drivers/hwmon/gsc-hwmon.c
drivers/hwmon/hwmon-vid.c
drivers/hwmon/ina3221.c
drivers/hwmon/nct6775.c
drivers/hwmon/nct7904.c
drivers/hwmon/occ/common.c
drivers/hwmon/pmbus/isl68137.c
drivers/hwmon/w83627hf.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83795.c
drivers/hwtracing/coresight/coresight-cpu-debug.c
drivers/hwtracing/coresight/coresight-etm4x.c
drivers/hwtracing/coresight/coresight-tmc.c
drivers/hwtracing/intel_th/sth.c
drivers/i2c/algos/i2c-algo-pca.c
drivers/i2c/busses/i2c-aspeed.c
drivers/i2c/busses/i2c-bcm-iproc.c
drivers/i2c/busses/i2c-cpm.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-meson.c
drivers/i2c/busses/i2c-mt65xx.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-npcm7xx.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-opal.c
drivers/i2c/busses/i2c-owl.c
drivers/i2c/busses/i2c-rcar.c
drivers/i2c/i2c-core-acpi.c
drivers/i2c/i2c-core-base.c
drivers/i2c/i2c-core.h
drivers/i3c/master/dw-i3c-master.c
drivers/ide/Kconfig
drivers/ide/hpt366.c
drivers/ide/ide-cd.c
drivers/ide/ide-floppy.c
drivers/ide/ide-probe.c
drivers/ide/ide-taskfile.c
drivers/ide/macide.c
drivers/ide/sis5513.c
drivers/idle/intel_idle.c
drivers/iio/accel/bmc150-accel-core.c
drivers/iio/accel/kxsd9.c
drivers/iio/accel/mma7455_core.c
drivers/iio/accel/mma8452.c
drivers/iio/adc/Kconfig
drivers/iio/adc/ab8500-gpadc.c
drivers/iio/adc/ad7124.c
drivers/iio/adc/cpcap-adc.c
drivers/iio/adc/ina2xx-adc.c
drivers/iio/adc/max1118.c
drivers/iio/adc/mcp3422.c
drivers/iio/adc/meson_saradc.c
drivers/iio/adc/qcom-spmi-adc5.c
drivers/iio/adc/ti-adc081c.c
drivers/iio/adc/ti-adc084s021.c
drivers/iio/adc/ti-ads1015.c
drivers/iio/chemical/ccs811.c
drivers/iio/chemical/sps30.c
drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
drivers/iio/dac/ad5592r-base.c
drivers/iio/dac/dpot-dac.c
drivers/iio/health/max30102.c
drivers/iio/imu/adis.c
drivers/iio/industrialio-core.c
drivers/iio/light/ltr501.c
drivers/iio/light/max44000.c
drivers/iio/light/si1145.c
drivers/iio/magnetometer/ak8974.c
drivers/iio/magnetometer/ak8975.c
drivers/iio/proximity/mb1232.c
drivers/infiniband/core/cache.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/cq.c
drivers/infiniband/core/device.c
drivers/infiniband/core/roce_gid_mgmt.c
drivers/infiniband/core/rw.c
drivers/infiniband/core/ucma.c
drivers/infiniband/core/uverbs_ioctl.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/bnxt_re/ib_verbs.c
drivers/infiniband/hw/bnxt_re/main.c
drivers/infiniband/hw/bnxt_re/qplib_fp.c
drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
drivers/infiniband/hw/bnxt_re/qplib_sp.c
drivers/infiniband/hw/bnxt_re/qplib_sp.h
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/hfi1/pio_copy.c
drivers/infiniband/hw/i40iw/i40iw_cm.c
drivers/infiniband/hw/i40iw/i40iw_ctrl.c
drivers/infiniband/hw/i40iw/i40iw_hw.c
drivers/infiniband/hw/i40iw/i40iw_main.c
drivers/infiniband/hw/i40iw/i40iw_puda.c
drivers/infiniband/hw/i40iw/i40iw_utils.c
drivers/infiniband/hw/i40iw/i40iw_verbs.c
drivers/infiniband/hw/mlx4/cq.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/mcg.c
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mlx5/cq.c
drivers/infiniband/hw/mlx5/mad.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/mthca/mthca_av.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/qedr/verbs.c
drivers/infiniband/hw/qib/qib_iba6120.c
drivers/infiniband/hw/qib/qib_iba7220.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_mad.c
drivers/infiniband/hw/qib/qib_rc.c
drivers/infiniband/hw/qib/qib_sdma.c
drivers/infiniband/hw/qib/qib_uc.c
drivers/infiniband/hw/qib/qib_verbs.c
drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c
drivers/infiniband/sw/rdmavt/qp.c
drivers/infiniband/sw/rxe/rxe.c
drivers/infiniband/sw/rxe/rxe.h
drivers/infiniband/sw/rxe/rxe_comp.c
drivers/infiniband/sw/rxe/rxe_mr.c
drivers/infiniband/sw/rxe/rxe_sysfs.c
drivers/infiniband/sw/rxe/rxe_task.c
drivers/infiniband/sw/rxe/rxe_verbs.c
drivers/infiniband/sw/siw/siw_cm.c
drivers/infiniband/sw/siw/siw_qp_rx.c
drivers/infiniband/sw/siw/siw_qp_tx.c
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/iser/iser_verbs.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c
drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c
drivers/infiniband/ulp/rtrs/rtrs-srv.c
drivers/input/joystick/fsia6b.c
drivers/input/joystick/gamecon.c
drivers/input/mouse/trackpoint.c
drivers/input/mouse/trackpoint.h
drivers/input/serio/i8042-x86ia64io.h
drivers/input/tablet/wacom_serial4.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/wm831x-ts.c
drivers/interconnect/core.c
drivers/interconnect/qcom/bcm-voter.c
drivers/iommu/amd/Kconfig
drivers/iommu/amd/amd_iommu.h
drivers/iommu/amd/init.c
drivers/iommu/amd/iommu.c
drivers/iommu/amd/iommu_v2.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
drivers/iommu/exynos-iommu.c
drivers/iommu/hyperv-iommu.c
drivers/iommu/intel/dmar.c
drivers/iommu/intel/iommu.c
drivers/iommu/intel/irq_remapping.c
drivers/iommu/intel/pasid.c
drivers/iommu/intel/pasid.h
drivers/iommu/intel/svm.c
drivers/iommu/iommu.c
drivers/iommu/irq_remapping.c
drivers/iommu/irq_remapping.h
drivers/iommu/virtio-iommu.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-armada-370-xp.c
drivers/irqchip/irq-bcm2836.c
drivers/irqchip/irq-dw-apb-ictl.c
drivers/irqchip/irq-gic-common.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-hip04.c
drivers/irqchip/irq-imx-gpcv2.c
drivers/irqchip/irq-imx-intmux.c
drivers/irqchip/irq-imx-irqsteer.c
drivers/irqchip/irq-ingenic.c
drivers/irqchip/irq-loongson-htvec.c
drivers/irqchip/irq-mips-gic.c
drivers/irqchip/irq-mst-intc.c [new file with mode: 0644]
drivers/irqchip/irq-mtk-cirq.c
drivers/irqchip/irq-mtk-sysirq.c
drivers/irqchip/irq-owl-sirq.c [new file with mode: 0644]
drivers/irqchip/irq-pruss-intc.c [new file with mode: 0644]
drivers/irqchip/irq-stm32-exti.c
drivers/irqchip/irq-ti-sci-inta.c
drivers/irqchip/irq-ti-sci-intr.c
drivers/irqchip/irq-vic.c
drivers/irqchip/irqchip.c
drivers/irqchip/qcom-pdc.c
drivers/isdn/hardware/mISDN/avmfritz.c
drivers/isdn/hardware/mISDN/hfc_multi_8xx.h
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/isdn/hardware/mISDN/hfcsusb.c
drivers/isdn/hardware/mISDN/isdnhdlc.c
drivers/isdn/hardware/mISDN/mISDNinfineon.c
drivers/isdn/hardware/mISDN/mISDNisar.c
drivers/isdn/mISDN/stack.c
drivers/lightnvm/pblk-core.c
drivers/macintosh/adbhid.c
drivers/macintosh/smu.c
drivers/md/bcache/journal.c
drivers/md/bcache/util.c
drivers/md/dm-cache-metadata.c
drivers/md/dm-crypt.c
drivers/md/dm-integrity.c
drivers/md/dm-mpath.c
drivers/md/dm-table.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-writecache.c
drivers/md/dm.c
drivers/md/md-autodetect.c
drivers/md/md-bitmap.c
drivers/md/persistent-data/dm-block-manager.c
drivers/md/raid5.c
drivers/media/cec/core/cec-adap.c
drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
drivers/media/common/videobuf2/videobuf2-core.c
drivers/media/common/videobuf2/videobuf2-dma-contig.c
drivers/media/common/videobuf2/videobuf2-dma-sg.c
drivers/media/common/videobuf2/videobuf2-v4l2.c
drivers/media/dvb-core/dvb_net.c
drivers/media/dvb-core/dvb_vb2.c
drivers/media/dvb-frontends/bcm3510.c
drivers/media/dvb-frontends/dib0090.c
drivers/media/dvb-frontends/dib3000mb.c
drivers/media/dvb-frontends/dib7000p.c
drivers/media/dvb-frontends/drx39xyj/drxj.c
drivers/media/dvb-frontends/drxd_hard.c
drivers/media/dvb-frontends/drxk_hard.c
drivers/media/dvb-frontends/lgdt3306a.c
drivers/media/dvb-frontends/mt352.c
drivers/media/dvb-frontends/mxl5xx.c
drivers/media/dvb-frontends/or51132.c
drivers/media/dvb-frontends/s5h1411.c
drivers/media/dvb-frontends/zl10353.c
drivers/media/i2c/Kconfig
drivers/media/pci/cx23885/cx23885-cards.c
drivers/media/pci/ddbridge/ddbridge-core.c
drivers/media/pci/meye/meye.c
drivers/media/pci/ttpci/av7110.c
drivers/media/pci/ttpci/av7110_hw.c
drivers/media/pci/ttpci/av7110_ipack.c
drivers/media/pci/ttpci/budget-av.c
drivers/media/pci/ttpci/budget.c
drivers/media/platform/sh_vou.c
drivers/media/platform/ti-vpe/cal.h
drivers/media/radio/radio-si476x.c
drivers/media/radio/tea575x.c
drivers/media/rc/bpf-lirc.c
drivers/media/rc/gpio-ir-tx.c
drivers/media/rc/ir-rc6-decoder.c
drivers/media/rc/ir-sony-decoder.c
drivers/media/rc/mceusb.c
drivers/media/rc/rc-main.c
drivers/media/test-drivers/vicodec/vicodec-core.c
drivers/media/tuners/xc5000.c
drivers/media/usb/b2c2/flexcop-usb.c
drivers/media/usb/cpia2/cpia2_core.c
drivers/media/usb/cx231xx/cx231xx-video.c
drivers/media/usb/dvb-usb/dib0700_devices.c
drivers/media/usb/dvb-usb/dw2102.c
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
drivers/media/v4l2-core/v4l2-ctrls.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/videobuf-core.c
drivers/memory/omap-gpmc.c
drivers/memstick/core/memstick.c
drivers/memstick/core/ms_block.c
drivers/memstick/host/jmb38x_ms.c
drivers/memstick/host/tifm_ms.c
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptscsih.c
drivers/mfd/db8500-prcmu.c
drivers/mfd/iqs62x.c
drivers/mfd/mfd-core.c
drivers/mfd/mxs-lradc.c
drivers/mfd/omap-usb-host.c
drivers/mfd/rave-sp.c
drivers/mfd/syscon.c
drivers/misc/eeprom/at24.c
drivers/misc/eeprom/at25.c
drivers/misc/habanalabs/common/command_buffer.c
drivers/misc/habanalabs/common/command_submission.c
drivers/misc/habanalabs/common/debugfs.c
drivers/misc/habanalabs/common/device.c
drivers/misc/habanalabs/common/firmware_if.c
drivers/misc/habanalabs/common/habanalabs.h
drivers/misc/habanalabs/common/memory.c
drivers/misc/habanalabs/common/mmu.c
drivers/misc/habanalabs/common/pci.c
drivers/misc/habanalabs/common/sysfs.c
drivers/misc/habanalabs/gaudi/gaudi.c
drivers/misc/habanalabs/gaudi/gaudiP.h
drivers/misc/habanalabs/gaudi/gaudi_coresight.c
drivers/misc/habanalabs/goya/goya.c
drivers/misc/habanalabs/goya/goya_coresight.c
drivers/misc/habanalabs/include/gaudi/gaudi_masks.h
drivers/misc/mei/hdcp/mei_hdcp.c
drivers/misc/mic/scif/scif_api.c
drivers/misc/mic/scif/scif_rma.c
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-gru/grukservices.c
drivers/misc/sgi-xp/xp.h
drivers/misc/sgi-xp/xp_main.c
drivers/misc/sgi-xp/xp_uv.c
drivers/misc/sgi-xp/xpc_main.c
drivers/misc/sgi-xp/xpc_partition.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/misc/sgi-xp/xpnet.c
drivers/misc/uacce/uacce.c
drivers/mmc/core/host.c
drivers/mmc/core/queue.c
drivers/mmc/core/sdio_ops.c
drivers/mmc/host/Kconfig
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/dw_mmc-k3.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/meson-mx-sdio.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/renesas_sdhi_core.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-sprd.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci-xenon-phy.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/tifm_sd.c
drivers/mmc/host/usdhi6rol0.c
drivers/mtd/spi-nor/core.c
drivers/mtd/spi-nor/core.h
drivers/mux/adgs1408.c
drivers/net/appletalk/cops.c
drivers/net/arcnet/arc-rimi.c
drivers/net/arcnet/com20020-isa.c
drivers/net/arcnet/com90io.c
drivers/net/arcnet/com90xx.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/can/at91_can.c
drivers/net/can/peak_canfd/peak_pciefd_main.c
drivers/net/can/sja1000/sja1000_platform.c
drivers/net/can/slcan.c
drivers/net/can/spi/mcp251x.c
drivers/net/can/usb/peak_usb/pcan_usb.c
drivers/net/can/usb/peak_usb/pcan_usb_core.c
drivers/net/can/usb/peak_usb/pcan_usb_pro.c
drivers/net/dsa/b53/b53_common.c
drivers/net/dsa/b53/b53_serdes.c
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/microchip/ksz8795.c
drivers/net/dsa/microchip/ksz9477.c
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/microchip/ksz_common.h
drivers/net/dsa/mt7530.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/ocelot/felix.c
drivers/net/dsa/ocelot/felix_vsc9959.c
drivers/net/dsa/ocelot/seville_vsc9953.c
drivers/net/dsa/rtl8366.c
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/ethernet/3com/3c509.c
drivers/net/ethernet/3com/3c574_cs.c
drivers/net/ethernet/3com/typhoon.c
drivers/net/ethernet/3com/typhoon.h
drivers/net/ethernet/8390/axnet_cs.c
drivers/net/ethernet/8390/pcnet_cs.c
drivers/net/ethernet/alacritech/slicoss.c
drivers/net/ethernet/alteon/acenic.c
drivers/net/ethernet/amd/amd8111e.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
drivers/net/ethernet/aquantia/atlantic/Makefile
drivers/net/ethernet/arc/emac_mdio.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bgmac-bcma.c
drivers/net/ethernet/broadcom/bgmac-platform.c
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/genet/bcmmii.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/brocade/bna/bfa_ioc.c
drivers/net/ethernet/brocade/bna/bna_enet.c
drivers/net/ethernet/brocade/bna/bna_tx_rx.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/cadence/macb_ptp.c
drivers/net/ethernet/cavium/liquidio/lio_main.c
drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
drivers/net/ethernet/chelsio/cxgb3/l2t.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c
drivers/net/ethernet/chelsio/cxgb4/l2t.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/cortina/gemini.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/dec/tulip/de2104x.c
drivers/net/ethernet/dec/tulip/de4x5.c
drivers/net/ethernet/dec/tulip/tulip_core.c
drivers/net/ethernet/dec/tulip/winbond-840.c
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h
drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
drivers/net/ethernet/freescale/enetc/enetc_pf.c
drivers/net/ethernet/freescale/fman/fman_memac.c
drivers/net/ethernet/freescale/fman/fman_port.c
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/freescale/xgmac_mdio.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
drivers/net/ethernet/hisilicon/hns/hns_enet.c
drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/huawei/hinic/Kconfig
drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
drivers/net/ethernet/huawei/hinic/hinic_main.c
drivers/net/ethernet/huawei/hinic/hinic_port.c
drivers/net/ethernet/huawei/hinic/hinic_rx.c
drivers/net/ethernet/huawei/hinic/hinic_sriov.c
drivers/net/ethernet/huawei/hinic/hinic_tx.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/ibm/emac/core.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/ice/ice_common.c
drivers/net/ethernet/intel/ice/ice_fw_update.c
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_lib.h
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igc/igc.h
drivers/net/ethernet/intel/igc/igc_ptp.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/lantiq_xrx200.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
drivers/net/ethernet/marvell/octeontx2/af/mbox.c
drivers/net/ethernet/marvell/octeontx2/af/mbox.h
drivers/net/ethernet/marvell/octeontx2/af/rvu.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/mellanox/mlx4/mr.c
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c
drivers/net/ethernet/mellanox/mlx5/core/en/port.c
drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h
drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_stats.c
drivers/net/ethernet/mellanox/mlx5/core/en_fs.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c
drivers/net/ethernet/mellanox/mlxsw/core.c
drivers/net/ethernet/mellanox/mlxsw/core_env.c
drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
drivers/net/ethernet/microchip/lan743x_ethtool.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/mscc/ocelot_net.c
drivers/net/ethernet/mscc/ocelot_vsc7514.c
drivers/net/ethernet/natsemi/natsemi.c
drivers/net/ethernet/neterion/vxge/vxge-config.c
drivers/net/ethernet/netronome/nfp/crypto/tls.c
drivers/net/ethernet/netronome/nfp/flower/action.c
drivers/net/ethernet/netronome/nfp/flower/cmsg.c
drivers/net/ethernet/netronome/nfp/flower/offload.c
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
drivers/net/ethernet/netronome/nfp/nfp_asm.c
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c
drivers/net/ethernet/packetengines/yellowfin.c
drivers/net/ethernet/pensando/ionic/ionic_txrx.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
drivers/net/ethernet/qlogic/qed/qed_cxt.c
drivers/net/ethernet/qlogic/qed/qed_dev.c
drivers/net/ethernet/qlogic/qed/qed_l2.c
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/qlogic/qed/qed_mcp.c
drivers/net/ethernet/qlogic/qed/qed_sriov.c
drivers/net/ethernet/qlogic/qede/qede_filter.c
drivers/net/ethernet/qlogic/qede/qede_main.c
drivers/net/ethernet/qlogic/qla3xxx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/rocker/rocker_main.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
drivers/net/ethernet/sfc/ef100.c
drivers/net/ethernet/sfc/ef100_rx.c
drivers/net/ethernet/sfc/falcon/ethtool.c
drivers/net/ethernet/sfc/falcon/farch.c
drivers/net/ethernet/sfc/farch.c
drivers/net/ethernet/sfc/mcdi_filters.c
drivers/net/ethernet/sfc/mcdi_port_common.c
drivers/net/ethernet/sfc/rx.c
drivers/net/ethernet/sis/sis900.c
drivers/net/ethernet/smsc/smc911x.c
drivers/net/ethernet/socionext/netsec.c
drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
drivers/net/ethernet/sun/cassini.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/sun/sungem.c
drivers/net/ethernet/sun/sunvnet_common.c
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/ethernet/ti/cpsw-phy-sel.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/cpsw_new.c
drivers/net/ethernet/ti/cpsw_priv.c
drivers/net/ethernet/ti/tlan.c
drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
drivers/net/ethernet/toshiba/spider_net.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/ethernet/xircom/xirc2ps_cs.c
drivers/net/fddi/skfp/pcmplc.c
drivers/net/fjes/fjes_main.c
drivers/net/geneve.c
drivers/net/gtp.c
drivers/net/hamradio/baycom_epp.c
drivers/net/hamradio/mkiss.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/ieee802154/adf7242.c
drivers/net/ieee802154/ca8210.c
drivers/net/ipa/ipa_table.c
drivers/net/macsec.c
drivers/net/macvlan.c
drivers/net/mii.c
drivers/net/netdevsim/bus.c
drivers/net/netdevsim/fib.c
drivers/net/phy/Kconfig
drivers/net/phy/adin.c
drivers/net/phy/dp83640.c
drivers/net/phy/dp83867.c
drivers/net/phy/dp83869.c
drivers/net/phy/fixed_phy.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/phy/phylink.c
drivers/net/phy/realtek.c
drivers/net/phy/sfp-bus.c
drivers/net/phy/sfp.c
drivers/net/plip/plip.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/usb/Kconfig
drivers/net/usb/aqc111.c
drivers/net/usb/asix_common.c
drivers/net/usb/ax88179_178a.c
drivers/net/usb/catc.c
drivers/net/usb/cdc-phonet.c
drivers/net/usb/dm9601.c
drivers/net/usb/lan78xx.c
drivers/net/usb/pegasus.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/usb/rndis_host.c
drivers/net/usb/rtl8150.c
drivers/net/usb/usbnet.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_ethtool.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/wan/hdlc.c
drivers/net/wan/hdlc_cisco.c
drivers/net/wan/hdlc_fr.c
drivers/net/wan/hdlc_ppp.c
drivers/net/wan/lapbether.c
drivers/net/wan/sdla.c
drivers/net/wan/x25_asy.c
drivers/net/wimax/i2400m/control.c
drivers/net/wimax/i2400m/usb-fw.c
drivers/net/wimax/i2400m/usb-tx.c
drivers/net/wimax/i2400m/usb.c
drivers/net/wireguard/noise.c
drivers/net/wireguard/peerlookup.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/intel/ipw2x00/Kconfig
drivers/net/wireless/intersil/hostap/Kconfig
drivers/net/wireless/marvell/mwifiex/fw.h
drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
drivers/net/wireless/mediatek/mt76/mt7615/init.c
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
drivers/net/wireless/mediatek/mt76/mt7915/init.c
drivers/net/wireless/mediatek/mt76/mt7915/mac.c
drivers/net/wireless/quantenna/qtnfmac/core.c
drivers/net/wireless/ti/wlcore/cmd.h
drivers/net/wireless/ti/wlcore/main.c
drivers/net/xen-netback/hash.c
drivers/net/xen-netback/xenbus.c
drivers/net/xen-netfront.c
drivers/nfc/pn533/pn533.c
drivers/nfc/st21nfca/dep.c
drivers/nfc/st95hf/core.c
drivers/nfc/trf7970a.c
drivers/ntb/ntb_transport.c
drivers/nvdimm/claim.c
drivers/nvdimm/dimm_devs.c
drivers/nvdimm/pmem.c
drivers/nvme/host/Kconfig
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.c
drivers/nvme/host/fc.c
drivers/nvme/host/hwmon.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/nvme/target/configfs.c
drivers/nvme/target/core.c
drivers/nvme/target/fc.c
drivers/nvme/target/fcloop.c
drivers/nvme/target/io-cmd-bdev.c
drivers/nvme/target/loop.c
drivers/nvme/target/passthru.c
drivers/nvme/target/rdma.c
drivers/nvme/target/tcp.c
drivers/opp/core.c
drivers/opp/opp.h
drivers/oprofile/buffer_sync.c
drivers/parport/ieee1284.c
drivers/parport/parport_pc.c
drivers/pci/Kconfig
drivers/pci/controller/Kconfig
drivers/pci/controller/dwc/pci-imx6.c
drivers/pci/controller/pci-hyperv.c
drivers/pci/controller/pci-rcar-gen2.c
drivers/pci/controller/pcie-rockchip-host.c
drivers/pci/controller/vmd.c
drivers/pci/hotplug/ibmphp_res.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/shpchp_ctrl.c
drivers/pci/msi.c
drivers/pci/pci.c
drivers/pci/proc.c
drivers/pci/quirks.c
drivers/pci/setup-bus.c
drivers/pci/xen-pcifront.c
drivers/pcmcia/db1xxx_ss.c
drivers/perf/Kconfig
drivers/perf/Makefile
drivers/perf/arm-ccn.c
drivers/perf/arm-cmn.c [new file with mode: 0644]
drivers/perf/arm_dsu_pmu.c
drivers/perf/arm_pmu.c
drivers/perf/arm_spe_pmu.c
drivers/perf/hisilicon/hisi_uncore_pmu.h
drivers/perf/thunderx2_pmu.c
drivers/perf/xgene_pmu.c
drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c
drivers/phy/qualcomm/phy-qcom-qmp.c
drivers/phy/qualcomm/phy-qcom-qmp.h
drivers/phy/qualcomm/phy-qcom-usb-hs.c
drivers/phy/rockchip/phy-rockchip-inno-usb2.c
drivers/phy/ti/phy-am654-serdes.c
drivers/phy/ti/phy-omap-usb2.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
drivers/pinctrl/mvebu/pinctrl-armada-xp.c
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-sm8250.c
drivers/platform/olpc/olpc-ec.c
drivers/platform/olpc/olpc-xo175-ec.c
drivers/platform/x86/Kconfig
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/asus-wmi.h
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/intel-vbtn.c
drivers/platform/x86/intel_pmc_core_pltdrv.c
drivers/platform/x86/mlx-platform.c
drivers/platform/x86/pcengines-apuv2.c
drivers/platform/x86/surfacepro3_button.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/power/supply/ab8500_charger.c
drivers/power/supply/ab8500_fg.c
drivers/power/supply/abx500_chargalg.c
drivers/power/supply/axp20x_usb_power.c
drivers/power/supply/cros_usbpd-charger.c
drivers/power/supply/max8925_power.c
drivers/power/supply/sbs-battery.c
drivers/power/supply/wm831x_power.c
drivers/power/supply/wm8350_power.c
drivers/powercap/intel_rapl_common.c
drivers/ps3/ps3av.c
drivers/ps3/ps3av_cmd.c
drivers/rapidio/Kconfig
drivers/rapidio/devices/rio_mport_cdev.c
drivers/ras/cec.c
drivers/regulator/axp20x-regulator.c
drivers/regulator/core.c
drivers/regulator/cros-ec-regulator.c
drivers/regulator/fixed.c
drivers/regulator/pwm-regulator.c
drivers/regulator/slg51000-regulator.c
drivers/regulator/twl6030-regulator.c
drivers/remoteproc/omap_remoteproc.c
drivers/reset/reset-imx7.c
drivers/rpmsg/qcom_glink_native.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-pcf85063.c
drivers/rtc/rtc-pcf8523.c
drivers/rtc/rtc-stmp3xxx.c
drivers/s390/block/dasd_fba.c
drivers/s390/crypto/zcrypt_api.c
drivers/s390/crypto/zcrypt_ccamisc.c
drivers/s390/net/ctcm_fsms.c
drivers/s390/net/ctcm_mpc.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_ethtool.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/scsi/53c700.c
drivers/scsi/BusLogic.c
drivers/scsi/FlashPoint.c
drivers/scsi/NCR5380.c
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aic7xxx/aic79xx_core.c
drivers/scsi/aic7xxx/aic79xx_osm.c
drivers/scsi/aic7xxx/aic7xxx_core.c
drivers/scsi/aic94xx/aic94xx_scb.c
drivers/scsi/aic94xx/aic94xx_tmf.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/arm/fas216.c
drivers/scsi/be2iscsi/be_iscsi.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/bfa/bfa_fcpim.c
drivers/scsi/bfa/bfa_fcs_lport.c
drivers/scsi/bfa/bfa_fcs_rport.c
drivers/scsi/bfa/bfa_ioc.c
drivers/scsi/bfa/bfa_svc.c
drivers/scsi/bnx2fc/bnx2fc_hwi.c
drivers/scsi/csiostor/csio_hw.c
drivers/scsi/csiostor/csio_lnode.c
drivers/scsi/csiostor/csio_wr.c
drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
drivers/scsi/cxgbi/libcxgbi.c
drivers/scsi/cxlflash/main.c
drivers/scsi/cxlflash/superpipe.c
drivers/scsi/device_handler/scsi_dh_hp_sw.c
drivers/scsi/esas2r/esas2r_flash.c
drivers/scsi/esas2r/esas2r_init.c
drivers/scsi/esp_scsi.c
drivers/scsi/fcoe/fcoe_ctlr.c
drivers/scsi/g_NCR5380.c
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hpsa.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
drivers/scsi/imm.c
drivers/scsi/isci/phy.c
drivers/scsi/isci/remote_device.c
drivers/scsi/isci/remote_node_context.c
drivers/scsi/isci/request.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/libfc/fc_disc.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/libiscsi.c
drivers/scsi/libiscsi_tcp.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/libsas/sas_discover.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_nvme.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/megaraid.c
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/mesh.c
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_ctl.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/myrb.c
drivers/scsi/ncr53c8xx.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/ppa.c
drivers/scsi/qedf/qedf_main.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/qlogicpti.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_lib.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/sd_zbc.c
drivers/scsi/sg.c
drivers/scsi/smartpqi/smartpqi_init.c
drivers/scsi/sr.c
drivers/scsi/st.c
drivers/scsi/sun3_scsi.c
drivers/scsi/sym53c8xx_2/sym_fw.c
drivers/scsi/sym53c8xx_2/sym_hipd.c
drivers/scsi/sym53c8xx_2/sym_nvram.c
drivers/scsi/ufs/ufs_bsg.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/virtio_scsi.c
drivers/scsi/vmw_pvscsi.c
drivers/scsi/wd33c93.c
drivers/scsi/xen-scsifront.c
drivers/soc/qcom/socinfo.c
drivers/soc/tegra/pmc.c
drivers/soundwire/bus.c
drivers/soundwire/stream.c
drivers/spi/spi-bcm-qspi.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm2835aux.c
drivers/spi/spi-cadence-quadspi.c
drivers/spi/spi-fsl-cpm.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-fsl-espi.c
drivers/spi/spi-loopback-test.c
drivers/spi/spi-sprd-adi.c
drivers/spi/spi-stm32.c
drivers/spi/spi.c
drivers/ssb/driver_chipcommon.c
drivers/ssb/driver_mipscore.c
drivers/ssb/scan.c
drivers/staging/greybus/audio_helper.c
drivers/staging/greybus/audio_topology.c
drivers/staging/media/atomisp/pci/atomisp_cmd.c
drivers/staging/media/atomisp/pci/atomisp_compat_css20.c
drivers/staging/media/atomisp/pci/atomisp_ioctl.c
drivers/staging/media/atomisp/pci/atomisp_v4l2.c
drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
drivers/staging/media/atomisp/pci/sh_css.c
drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c
drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c
drivers/staging/media/imx/imx-media-csi.c
drivers/staging/media/sunxi/cedrus/cedrus.c
drivers/staging/media/usbvision/usbvision-i2c.c
drivers/staging/rtl8192e/Kconfig
drivers/staging/rtl8192e/rtllib_crypt_tkip.c
drivers/staging/rtl8192e/rtllib_crypt_wep.c
drivers/staging/rtl8192u/Kconfig
drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c
drivers/staging/wlan-ng/hfa384x_usb.c
drivers/staging/wlan-ng/prism2usb.c
drivers/target/iscsi/cxgbit/cxgbit_main.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_login.h
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/target_core_pr.c
drivers/target/target_core_sbc.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tfc_cmd.c
drivers/thermal/qcom/qcom-spmi-temp-alarm.c
drivers/thermal/qcom/tsens-v0_1.c
drivers/thermal/qcom/tsens-v1.c
drivers/thermal/thermal_core.c
drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
drivers/thunderbolt/ctl.c
drivers/thunderbolt/eeprom.c
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb.h
drivers/thunderbolt/tunnel.c
drivers/tty/hvc/hvc_xen.c
drivers/tty/mips_ejtag_fdc.c
drivers/tty/n_gsm.c
drivers/tty/n_hdlc.c
drivers/tty/n_r3964.c
drivers/tty/serial/8250/8250_em.c
drivers/tty/serial/8250/8250_exar.c
drivers/tty/serial/8250/8250_fintek.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/8250/8250_uniphier.c
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/omap-serial.c
drivers/tty/serial/qcom_geni_serial.c
drivers/tty/serial/rda-uart.c
drivers/tty/serial/samsung_tty.c
drivers/tty/serial/serial-tegra.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/stm32-usart.c
drivers/tty/serial/sunsu.c
drivers/tty/serial/sunzilog.c
drivers/tty/serial/xilinx_uartps.c
drivers/tty/tty_ioctl.c
drivers/tty/vt/vt.c
drivers/tty/vt/vt_ioctl.c
drivers/usb/c67x00/c67x00-sched.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/usblp.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/sysfs.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/dwc3-meson-g12a.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/f_mass_storage.c
drivers/usb/gadget/function/f_ncm.c
drivers/usb/gadget/function/f_tcm.c
drivers/usb/gadget/u_f.h
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/fsl_udc_core.c
drivers/usb/gadget/udc/pxa25x_udc.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/ohci-exynos.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/xhci-dbgcap.c
drivers/usb/host/xhci-debugfs.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci-renesas.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci-tegra.c
drivers/usb/host/xhci.c
drivers/usb/misc/lvstest.c
drivers/usb/misc/yurex.c
drivers/usb/musb/cppi_dma.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/musb_gadget_ep0.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_virthub.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/phy/phy-jz4770.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/storage/sddr55.c
drivers/usb/storage/uas.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/unusual_uas.h
drivers/usb/typec/mux/intel_pmc_mux.c
drivers/usb/typec/tcpm/tcpci.c
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/ucsi/displayport.c
drivers/usb/typec/ucsi/ucsi.c
drivers/usb/typec/ucsi/ucsi_acpi.c
drivers/vdpa/Kconfig
drivers/vdpa/ifcvf/ifcvf_base.h
drivers/vdpa/ifcvf/ifcvf_main.c
drivers/vdpa/mlx5/net/mlx5_vnet.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/iotlb.c
drivers/vhost/vdpa.c
drivers/vhost/vhost.c
drivers/video/backlight/adp8860_bl.c
drivers/video/console/Kconfig
drivers/video/console/newport_con.c
drivers/video/console/vgacon.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/Makefile
drivers/video/fbdev/acornfb.c
drivers/video/fbdev/amba-clcd.c [new file with mode: 0644]
drivers/video/fbdev/arcfb.c
drivers/video/fbdev/atmel_lcdfb.c
drivers/video/fbdev/aty/radeon_pm.c
drivers/video/fbdev/cirrusfb.c
drivers/video/fbdev/controlfb.c
drivers/video/fbdev/core/bitblit.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbcon.h
drivers/video/fbdev/core/fbcon_ccw.c
drivers/video/fbdev/core/fbcon_cw.c
drivers/video/fbdev/core/fbcon_rotate.c
drivers/video/fbdev/core/fbcon_ud.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/core/tileblit.c
drivers/video/fbdev/fsl-diu-fb.c
drivers/video/fbdev/gxt4500.c
drivers/video/fbdev/hyperv_fb.c
drivers/video/fbdev/i740fb.c
drivers/video/fbdev/mmp/fb/mmpfb.c
drivers/video/fbdev/nvidia/nv_hw.c
drivers/video/fbdev/offb.c
drivers/video/fbdev/omap/lcdc.c
drivers/video/fbdev/omap/omapfb_main.c
drivers/video/fbdev/omap2/omapfb/dss/dispc.c
drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
drivers/video/fbdev/omap2/omapfb/omapfb-main.c
drivers/video/fbdev/pm2fb.c
drivers/video/fbdev/pxa168fb.c
drivers/video/fbdev/pxafb.c
drivers/video/fbdev/riva/fbdev.c
drivers/video/fbdev/s3c-fb.c
drivers/video/fbdev/sa1100fb.c
drivers/video/fbdev/savage/savagefb_driver.c
drivers/video/fbdev/sh_mobile_lcdcfb.c
drivers/video/fbdev/sis/sis_main.c
drivers/video/fbdev/sm501fb.c
drivers/video/fbdev/stifb.c
drivers/video/fbdev/tdfxfb.c
drivers/video/fbdev/vga16fb.c
drivers/video/fbdev/via/lcd.c
drivers/video/fbdev/xen-fbfront.c
drivers/watchdog/sc1200wdt.c
drivers/watchdog/wdrtas.c
drivers/xen/Kconfig
drivers/xen/Makefile
drivers/xen/balloon.c
drivers/xen/events/events_base.c
drivers/xen/grant-table.c
drivers/xen/privcmd.c
drivers/xen/pvcalls-front.c
drivers/xen/unpopulated-alloc.c [new file with mode: 0644]
drivers/xen/xen-acpi-memhotplug.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xen-scsiback.c
drivers/xen/xenbus/xenbus_client.c
drivers/xen/xenbus/xenbus_probe_frontend.c
drivers/xen/xlate_mmu.c
drivers/zorro/zorro.c
fs/9p/vfs_file.c
fs/Makefile
fs/adfs/dir_f.c
fs/affs/amigaffs.c
fs/affs/file.c
fs/affs/inode.c
fs/affs/super.c
fs/afs/cmservice.c
fs/afs/file.c
fs/afs/flock.c
fs/afs/fs_probe.c
fs/afs/fsclient.c
fs/afs/inode.c
fs/afs/internal.h
fs/afs/misc.c
fs/afs/proc.c
fs/afs/rotate.c
fs/afs/rxrpc.c
fs/afs/vl_list.c
fs/afs/vl_probe.c
fs/afs/vl_rotate.c
fs/afs/vlclient.c
fs/afs/write.c
fs/afs/yfsclient.c
fs/aio.c
fs/autofs/waitq.c
fs/binfmt_flat.c
fs/btrfs/block-group.c
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/free-space-tree.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/print-tree.c
fs/btrfs/scrub.c
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/transaction.c
fs/btrfs/tree-checker.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/buffer.c
fs/ceph/caps.c
fs/ceph/debugfs.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.h
fs/ceph/quota.c
fs/ceph/super.h
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/inode.c
fs/cifs/sess.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/compat.c [deleted file]
fs/configfs/dir.c
fs/crypto/crypto.c
fs/crypto/fname.c
fs/crypto/fscrypt_private.h
fs/crypto/hooks.c
fs/crypto/inline_crypt.c
fs/crypto/keyring.c
fs/crypto/keysetup.c
fs/crypto/keysetup_v1.c
fs/crypto/policy.c
fs/dax.c
fs/debugfs/file.c
fs/dlm/lock.c
fs/efivarfs/super.c
fs/erofs/zmap.c
fs/eventpoll.c
fs/exfat/cache.c
fs/exfat/exfat_fs.h
fs/exfat/inode.c
fs/exfat/namei.c
fs/exfat/super.c
fs/ext2/file.c
fs/ext2/inode.c
fs/ext2/super.c
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/super.c
fs/f2fs/data.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/namei.c
fs/f2fs/node.c
fs/f2fs/segment.c
fs/f2fs/super.c
fs/fcntl.c
fs/fs-writeback.c
fs/fs_context.c
fs/fsopen.c
fs/fuse/file.c
fs/gfs2/bmap.c
fs/gfs2/log.c
fs/gfs2/quota.c
fs/gfs2/trans.c
fs/hfsplus/wrapper.c
fs/internal.h
fs/io-wq.c
fs/io_uring.c
fs/iomap/seek.c
fs/jffs2/fs.c
fs/jffs2/readinode.c
fs/libfs.c
fs/locks.c
fs/namespace.c
fs/nfs/blocklayout/blocklayout.c
fs/nfs/dir.c
fs/nfs/filelayout/filelayout.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/fs_context.c
fs/nfs/nfs3acl.c
fs/nfs/nfs42proc.c
fs/nfs/nfs4file.c
fs/nfs/nfs4idmap.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs_common/nfsacl.c
fs/nfsd/blocklayout.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfsfh.c
fs/nfsd/nfsproc.c
fs/nfsd/nfssvc.c
fs/nfsd/vfs.c
fs/nilfs2/bmap.c
fs/nilfs2/recovery.c
fs/nilfs2/segment.c
fs/notify/fanotify/fanotify_user.c
fs/ocfs2/cluster/quorum.c
fs/pipe.c
fs/proc/page.c
fs/proc/task_mmu.c
fs/pstore/zone.c
fs/quota/Kconfig
fs/quota/Makefile
fs/quota/compat.c [deleted file]
fs/quota/compat.h [new file with mode: 0644]
fs/quota/quota.c
fs/read_write.c
fs/seq_file.c
fs/signalfd.c
fs/splice.c
fs/ubifs/dir.c
fs/ubifs/lprops.c
fs/udf/symlink.c
fs/ufs/util.h
fs/vboxsf/super.c
fs/vboxsf/utils.c
fs/xfs/libxfs/xfs_attr_leaf.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_ialloc.c
fs/xfs/libxfs/xfs_trans_inode.c
fs/xfs/libxfs/xfs_trans_space.h
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_file.c
include/asm-generic/atomic-instrumented.h
include/asm-generic/bitops/instrumented-atomic.h
include/asm-generic/bitops/instrumented-lock.h
include/asm-generic/bitops/instrumented-non-atomic.h
include/asm-generic/checksum.h
include/asm-generic/compat.h
include/asm-generic/vmlinux.lds.h
include/clocksource/timer-sp804.h [deleted file]
include/crypto/algapi.h
include/crypto/cbc.h [deleted file]
include/crypto/hash.h
include/crypto/if_alg.h
include/crypto/internal/hash.h
include/crypto/public_key.h
include/crypto/sm2.h [new file with mode: 0644]
include/crypto/sm3.h
include/drm/drm_dsc.h
include/drm/drm_hdcp.h
include/drm/drm_modeset_lock.h
include/kvm/arm_pmu.h
include/linux/acpi.h
include/linux/amba/clcd-regs.h [new file with mode: 0644]
include/linux/amba/clcd.h [new file with mode: 0644]
include/linux/amd-iommu.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/bvec.h
include/linux/cacheinfo.h
include/linux/ceph/ceph_features.h
include/linux/compat.h
include/linux/compiler.h
include/linux/compiler_attributes.h
include/linux/compiler_types.h
include/linux/cper.h
include/linux/cpufreq.h
include/linux/cpuhotplug.h
include/linux/cpuidle.h
include/linux/dax.h
include/linux/dcache.h
include/linux/debugobjects.h
include/linux/device.h
include/linux/dynamic_debug.h
include/linux/efi.h
include/linux/efi_embedded_fw.h
include/linux/entry-common.h
include/linux/filter.h
include/linux/font.h
include/linux/fs.h
include/linux/fs_parser.h
include/linux/fscrypt.h
include/linux/ftrace.h
include/linux/hid.h
include/linux/hidden.h [new file with mode: 0644]
include/linux/i2c-algo-pca.h
include/linux/iio/iio.h
include/linux/instrumented.h
include/linux/intel-iommu.h
include/linux/intel-svm.h
include/linux/iommu.h
include/linux/irq.h
include/linux/irqdomain.h
include/linux/irqflags.h
include/linux/jhash.h
include/linux/kcsan-checks.h
include/linux/kernel-page-flags.h
include/linux/kernel.h
include/linux/khugepaged.h
include/linux/kprobes.h
include/linux/ksm.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/lockdep.h
include/linux/lockdep_types.h
include/linux/log2.h
include/linux/memremap.h
include/linux/memstick.h
include/linux/mlx5/driver.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mman.h
include/linux/mmu_context.h
include/linux/mmzone.h
include/linux/module.h
include/linux/mpi.h
include/linux/msi.h
include/linux/net.h
include/linux/netdev_features.h
include/linux/netdevice.h
include/linux/netfilter/nf_conntrack_sctp.h
include/linux/netfilter/nfnetlink.h
include/linux/nfs_xdr.h
include/linux/node.h
include/linux/notifier.h
include/linux/oid_registry.h
include/linux/page-flags.h
include/linux/pagemap.h
include/linux/pe.h
include/linux/percpu-rwsem.h
include/linux/perf/arm_pmu.h
include/linux/perf_event.h
include/linux/pgtable.h
include/linux/pipe_fs_i.h
include/linux/platform_data/gpio/gpio-amd-fch.h
include/linux/powercap.h
include/linux/qed/qed_if.h
include/linux/quotaops.h
include/linux/rbtree_latch.h
include/linux/refcount.h
include/linux/resctrl.h
include/linux/sched.h
include/linux/sched/mm.h
include/linux/sched/sd_flags.h [new file with mode: 0644]
include/linux/sched/topology.h
include/linux/seqlock.h
include/linux/serial_core.h
include/linux/signal.h
include/linux/skbuff.h
include/linux/soc/ti/ti_sci_protocol.h
include/linux/stackleak.h
include/linux/stacktrace.h
include/linux/static_call.h [new file with mode: 0644]
include/linux/static_call_types.h [new file with mode: 0644]
include/linux/string.h
include/linux/sunrpc/gss_krb5.h
include/linux/sunrpc/gss_krb5_enctypes.h
include/linux/syscalls.h
include/linux/timekeeping.h
include/linux/timer.h
include/linux/tracepoint-defs.h
include/linux/tracepoint.h
include/linux/uacce.h
include/linux/uaccess.h
include/linux/uio.h
include/linux/vm_event_item.h
include/linux/vmstat.h
include/linux/wait.h
include/linux/watch_queue.h
include/math-emu/op-common.h
include/media/videobuf2-core.h
include/net/act_api.h
include/net/af_rxrpc.h
include/net/checksum.h
include/net/flow.h
include/net/genetlink.h
include/net/ip.h
include/net/ndisc.h
include/net/netfilter/nf_tables.h
include/net/netlink.h
include/net/netns/nftables.h
include/net/sctp/structs.h
include/net/vxlan.h
include/net/xfrm.h
include/soc/mscc/ocelot.h
include/soc/mscc/ocelot_ana.h
include/soc/nps/common.h
include/sound/soc.h
include/trace/define_trace.h
include/trace/events/filelock.h
include/trace/events/mmflags.h
include/trace/events/rxrpc.h
include/trace/events/sched.h
include/trace/events/writeback.h
include/trace/events/xen.h
include/uapi/asm-generic/siginfo.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/elf.h
include/uapi/linux/ethtool_netlink.h
include/uapi/linux/fscrypt.h
include/uapi/linux/if_alg.h
include/uapi/linux/in.h
include/uapi/linux/kvm.h
include/uapi/linux/membarrier.h
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/prctl.h
include/uapi/linux/rxrpc.h
include/uapi/linux/snmp.h
include/uapi/linux/videodev2.h
include/xen/arm/page.h
include/xen/balloon.h
include/xen/xen.h
init/Kconfig
init/initramfs.c
init/main.c
ipc/ipc_sysctl.c
ipc/sem.c
ipc/shm.c
kernel/Makefile
kernel/auditfilter.c
kernel/bpf/cgroup.c
kernel/bpf/cpumap.c
kernel/bpf/hashtab.c
kernel/bpf/inode.c
kernel/bpf/syscall.c
kernel/bpf/sysfs_btf.c
kernel/bpf/verifier.c
kernel/capability.c
kernel/compat.c
kernel/cpu_pm.c
kernel/debug/gdbstub.c
kernel/debug/kdb/kdb_keyboard.c
kernel/debug/kdb/kdb_support.c
kernel/dma/pool.c
kernel/entry/common.c
kernel/events/core.c
kernel/fork.c
kernel/gcov/gcc_4_7.c
kernel/irq/chip.c
kernel/irq/debugfs.c
kernel/irq/handle.c
kernel/irq/internals.h
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/irq/matrix.c
kernel/irq/msi.c
kernel/irq/pm.c
kernel/irq/proc.c
kernel/irq/resend.c
kernel/irq/settings.h
kernel/jump_label.c
kernel/kallsyms.c
kernel/kcsan/core.c
kernel/kcsan/debugfs.c
kernel/kcsan/kcsan-test.c
kernel/kcsan/kcsan.h
kernel/kcsan/report.c
kernel/kcsan/selftest.c
kernel/kprobes.c
kernel/locking/lockdep.c
kernel/locking/lockdep_internals.h
kernel/locking/percpu-rwsem.c
kernel/module.c
kernel/notifier.c
kernel/padata.c
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/power.h
kernel/power/qos.c
kernel/power/suspend.c
kernel/power/user.c
kernel/rcu/rcu.h
kernel/rcu/tasks.h
kernel/rcu/tree.c
kernel/rcu/update.c
kernel/sched/core.c
kernel/sched/deadline.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/features.h
kernel/sched/idle.c
kernel/sched/membarrier.c
kernel/sched/topology.c
kernel/seccomp.c
kernel/signal.c
kernel/softirq.c
kernel/stackleak.c
kernel/stacktrace.c
kernel/static_call.c [new file with mode: 0644]
kernel/sys.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/time/alarmtimer.c
kernel/time/hrtimer.c
kernel/time/posix-timers.c
kernel/time/sched_clock.c
kernel/time/tick-broadcast.c
kernel/time/timekeeping.c
kernel/time/timer.c
kernel/trace/blktrace.c
kernel/trace/bpf_trace.c
kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_events_hist.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_output.c
kernel/trace/trace_preemptirq.c
kernel/trace/trace_printk.c
kernel/tracepoint.c
kernel/umh.c
kernel/workqueue.c
lib/Kconfig
lib/Kconfig.debug
lib/Kconfig.kcsan
lib/bootconfig.c
lib/checksum.c
lib/crypto/chacha20poly1305.c
lib/debugobjects.c
lib/dynamic_debug.c
lib/fonts/font_10x18.c
lib/fonts/font_6x10.c
lib/fonts/font_6x11.c
lib/fonts/font_7x14.c
lib/fonts/font_8x16.c
lib/fonts/font_8x8.c
lib/fonts/font_acorn_8x8.c
lib/fonts/font_mini_4x6.c
lib/fonts/font_pearl_8x8.c
lib/fonts/font_sun12x22.c
lib/fonts/font_sun8x16.c
lib/fonts/font_ter16x32.c
lib/glob.c
lib/iov_iter.c
lib/kobject.c
lib/locking-selftest.c
lib/memregion.c
lib/mpi/Makefile
lib/mpi/ec.c [new file with mode: 0644]
lib/mpi/mpi-add.c [new file with mode: 0644]
lib/mpi/mpi-bit.c
lib/mpi/mpi-cmp.c
lib/mpi/mpi-div.c [new file with mode: 0644]
lib/mpi/mpi-internal.h
lib/mpi/mpi-inv.c [new file with mode: 0644]
lib/mpi/mpi-mod.c [new file with mode: 0644]
lib/mpi/mpi-mul.c [new file with mode: 0644]
lib/mpi/mpicoder.c
lib/mpi/mpih-div.c
lib/mpi/mpih-mul.c
lib/mpi/mpiutil.c
lib/percpu_counter.c
lib/random32.c
lib/string.c
lib/test_firmware.c
lib/test_rhashtable.c
lib/vsprintf.c
lib/xz/xz_dec_lzma2.c
lib/xz/xz_dec_stream.c
lib/zstd/decompress.c
mm/Kconfig
mm/filemap.c
mm/gup.c
mm/huge_memory.c
mm/hugetlb.c
mm/khugepaged.c
mm/ksm.c
mm/madvise.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/memremap.c
mm/migrate.c
mm/mlock.c
mm/mmap.c
mm/mprotect.c
mm/nommu.c
mm/page_alloc.c
mm/page_io.c
mm/page_isolation.c
mm/percpu.c
mm/process_vm_access.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slub.c
mm/swap.c
mm/swapfile.c
mm/util.c
mm/vmscan.c
mm/vmstat.c
net/8021q/vlan_dev.c
net/9p/trans_xen.c
net/atm/common.c
net/atm/lec.c
net/atm/resources.c
net/batman-adv/bat_v_ogm.c
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/bridge_loop_avoidance.h
net/batman-adv/gateway_client.c
net/batman-adv/multicast.c
net/batman-adv/multicast.h
net/batman-adv/routing.c
net/batman-adv/soft-interface.c
net/bpf/test_run.c
net/bridge/br_arp_nd_proxy.c
net/bridge/br_fdb.c
net/bridge/br_netlink.c
net/bridge/br_vlan.c
net/caif/cfrfml.c
net/can/j1939/socket.c
net/can/j1939/transport.c
net/ceph/ceph_hash.c
net/ceph/crush/mapper.c
net/ceph/messenger.c
net/ceph/mon_client.c
net/ceph/osd_client.c
net/compat.c
net/core/dev.c
net/core/dev_addr_lists.c
net/core/dev_ioctl.c
net/core/devlink.c
net/core/drop_monitor.c
net/core/dst.c
net/core/fib_rules.c
net/core/filter.c
net/core/net_namespace.c
net/core/netpoll.c
net/core/pktgen.c
net/core/skbuff.c
net/core/skmsg.c
net/core/sock.c
net/dcb/dcbnl.c
net/dccp/ccids/ccid3.c
net/dccp/feat.c
net/dccp/input.c
net/dccp/options.c
net/dccp/output.c
net/dccp/proto.c
net/decnet/af_decnet.c
net/decnet/dn_nsp_in.c
net/decnet/dn_table.c
net/decnet/sysctl_net_decnet.c
net/dsa/slave.c
net/dsa/tag_ocelot.c
net/ethtool/netlink.c
net/ethtool/tunnels.c
net/hsr/hsr_netlink.c
net/ieee802154/6lowpan/reassembly.c
net/ieee802154/6lowpan/rx.c
net/ipv4/fib_frontend.c
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/inet_diag.c
net/ipv4/ip_output.c
net/ipv4/ip_tunnel_core.c
net/ipv4/ip_vti.c
net/ipv4/netfilter/nf_nat_pptp.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv6/Kconfig
net/ipv6/icmp.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_output.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/sysctl_net_ipv6.c
net/iucv/af_iucv.c
net/l3mdev/l3mdev.c
net/mac80211/airtime.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/util.c
net/mac80211/vht.c
net/mac802154/tx.c
net/mpls/af_mpls.c
net/mptcp/options.c
net/mptcp/pm_netlink.c
net/mptcp/protocol.c
net/mptcp/protocol.h
net/mptcp/subflow.c
net/ncsi/ncsi-manage.c
net/netfilter/ipvs/ip_vs_proto_tcp.c
net/netfilter/ipvs/ip_vs_proto_udp.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_pptp.c
net/netfilter/nf_conntrack_proto.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_proto_udp.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue.c
net/netfilter/nft_flow_offload.c
net/netfilter/nft_meta.c
net/netfilter/nft_payload.c
net/netfilter/nft_set_rbtree.c
net/netfilter/xt_recent.c
net/netlabel/netlabel_domainhash.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/netlink/policy.c
net/netrom/nr_in.c
net/netrom/nr_route.c
net/openvswitch/conntrack.c
net/openvswitch/flow.c
net/packet/af_packet.c
net/phonet/pep.c
net/qrtr/ns.c
net/qrtr/qrtr.c
net/rds/send.c
net/rose/rose_in.c
net/rose/rose_route.c
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-internal.h
net/rxrpc/call_accept.c
net/rxrpc/call_object.c
net/rxrpc/conn_client.c
net/rxrpc/conn_event.c
net/rxrpc/input.c
net/rxrpc/key.c
net/rxrpc/local_object.c
net/rxrpc/output.c
net/rxrpc/peer_event.c
net/rxrpc/peer_object.c
net/rxrpc/recvmsg.c
net/rxrpc/rtt.c
net/rxrpc/rxkad.c
net/rxrpc/sendmsg.c
net/sched/act_api.c
net/sched/act_bpf.c
net/sched/act_connmark.c
net/sched/act_csum.c
net/sched/act_ct.c
net/sched/act_ctinfo.c
net/sched/act_gact.c
net/sched/act_gate.c
net/sched/act_ife.c
net/sched/act_ipt.c
net/sched/act_mirred.c
net/sched/act_mpls.c
net/sched/act_nat.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_sample.c
net/sched/act_simple.c
net/sched/act_skbedit.c
net/sched/act_skbmod.c
net/sched/act_tunnel_key.c
net/sched/act_vlan.c
net/sched/cls_flower.c
net/sched/sch_cake.c
net/sched/sch_generic.c
net/sched/sch_red.c
net/sched/sch_taprio.c
net/sctp/auth.c
net/sctp/ipv6.c
net/sctp/outqueue.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
net/smc/smc_close.c
net/smc/smc_core.c
net/smc/smc_llc.c
net/socket.c
net/sunrpc/Kconfig
net/sunrpc/auth_gss/gss_krb5_crypto.c
net/sunrpc/auth_gss/gss_krb5_mech.c
net/sunrpc/auth_gss/gss_krb5_seal.c
net/sunrpc/auth_gss/gss_krb5_seqnum.c
net/sunrpc/auth_gss/gss_krb5_unseal.c
net/sunrpc/auth_gss/gss_krb5_wrap.c
net/sunrpc/auth_gss/trace.c
net/sunrpc/clnt.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/socklib.c
net/sunrpc/svcsock.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtsock.c
net/switchdev/switchdev.c
net/tipc/bearer.c
net/tipc/crypto.c
net/tipc/group.c
net/tipc/link.c
net/tipc/msg.c
net/tipc/socket.c
net/tls/tls_sw.c
net/unix/af_unix.c
net/wireless/Kconfig
net/wireless/chan.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/scan.c
net/wireless/sme.c
net/wireless/util.c
net/wireless/wext-compat.c
net/x25/x25_facilities.c
net/x25/x25_in.c
net/xdp/xdp_umem.c
net/xdp/xsk.c
net/xfrm/espintcp.c
net/xfrm/xfrm_interface.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
samples/bpf/hbm.c
samples/kprobes/kprobe_example.c
samples/kprobes/kretprobe_example.c
scripts/Makefile.kcsan
scripts/atomic/check-atomics.sh
scripts/atomic/gen-atomic-instrumented.sh
scripts/checkpatch.pl
scripts/coccinelle/api/device_attr_show.cocci
scripts/dtc/Makefile
scripts/kallsyms.c
scripts/kconfig/lkc.h
scripts/kconfig/lkc_proto.h
scripts/kconfig/nconf.c
scripts/kconfig/qconf.cc
scripts/kconfig/streamline_config.pl
scripts/kernel-doc
scripts/spelling.txt
scripts/tags.sh
security/apparmor/domain.c
security/apparmor/lib.c
security/device_cgroup.c
security/integrity/digsig_asymmetric.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template_lib.c
security/integrity/platform_certs/load_uefi.c
security/keys/compat.c
security/keys/internal.h
security/keys/keyctl.c
security/keys/process_keys.c
security/keys/request_key.c
security/selinux/hooks.c
security/selinux/ss/mls.c
security/smack/smack_lsm.c
security/tomoyo/common.c
security/tomoyo/file.c
sound/core/oss/mulaw.c
sound/core/timer.c
sound/firewire/amdtp-stream.c
sound/firewire/digi00x/digi00x.c
sound/firewire/tascam/tascam.c
sound/hda/hdac_device.c
sound/hda/intel-dsp-config.c
sound/pci/asihpi/asihpi.c
sound/pci/asihpi/hpioctl.c
sound/pci/ca0106/ca0106_main.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_tegra.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/riptide/riptide.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/ppc/snd_ps3.c
sound/soc/atmel/mchp-i2s-mcc.c
sound/soc/codecs/jz4770.c
sound/soc/codecs/max98373-sdw.c
sound/soc/codecs/pcm186x.c
sound/soc/codecs/pcm3168a.c
sound/soc/codecs/rt1308-sdw.c
sound/soc/codecs/rt700-sdw.c
sound/soc/codecs/rt711-sdw.c
sound/soc/codecs/rt715-sdw.c
sound/soc/codecs/tlv320adcx140.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm_hubs.c
sound/soc/codecs/wm_hubs.h
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_ssi.c
sound/soc/hisilicon/hi6210-i2s.c
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/baytrail/sst-baytrail-pcm.c
sound/soc/intel/boards/bytcht_es8316.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/skl_hda_dsp_generic.c
sound/soc/intel/boards/sof_maxim_common.c
sound/soc/intel/haswell/sst-haswell-dsp.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/meson/axg-tdm-interface.c
sound/soc/meson/axg-toddr.c
sound/soc/pxa/pxa-ssp.c
sound/soc/qcom/apq8016_sbc.c
sound/soc/qcom/apq8096.c
sound/soc/qcom/common.c
sound/soc/qcom/sdm845.c
sound/soc/qcom/storm.c
sound/soc/rockchip/rockchip_pdm.c
sound/soc/samsung/i2s.c
sound/soc/sh/siu_pcm.c
sound/soc/soc-core.c
sound/soc/soc-dai.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sof/intel/hda-dai.c
sound/soc/sof/pcm.c
sound/soc/ti/ams-delta.c
sound/soc/ti/davinci-i2s.c
sound/soc/ti/n810.c
sound/soc/ti/omap-dmic.c
sound/soc/ti/omap-mcpdm.c
sound/soc/ti/rx51.c
sound/soc/txx9/txx9aclc.c
sound/soc/zte/zx-i2s.c
sound/soc/zte/zx-spdif.c
sound/usb/midi.c
sound/usb/misc/ua101.c
sound/usb/mixer_maps.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/usbaudio.h
sound/x86/Kconfig
tools/arch/x86/include/asm/mcsafe_test.h [deleted file]
tools/arch/x86/lib/memcpy_64.S
tools/bootconfig/test-bootconfig.sh
tools/bpf/Makefile
tools/bpf/bpftool/Makefile
tools/bpf/resolve_btfids/Makefile
tools/include/linux/static_call_types.h [new file with mode: 0644]
tools/include/uapi/asm-generic/unistd.h
tools/include/uapi/linux/in.h
tools/include/uapi/linux/kvm.h
tools/include/uapi/linux/perf_event.h
tools/io_uring/io_uring-bench.c
tools/lib/bpf/Makefile
tools/lib/bpf/btf.c
tools/lib/bpf/libbpf.c
tools/lib/traceevent/event-parse.c
tools/memory-model/Documentation/cheatsheet.txt
tools/memory-model/Documentation/litmus-tests.txt [new file with mode: 0644]
tools/memory-model/Documentation/recipes.txt
tools/memory-model/Documentation/references.txt
tools/memory-model/Documentation/simple.txt [new file with mode: 0644]
tools/memory-model/README
tools/objtool/check.c
tools/objtool/check.h
tools/objtool/elf.c
tools/objtool/elf.h
tools/objtool/objtool.h
tools/objtool/orc_gen.c
tools/objtool/sync-check.sh
tools/perf/Documentation/perf-record.txt
tools/perf/Documentation/perf-stat.txt
tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
tools/perf/arch/s390/entry/syscalls/syscall.tbl
tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
tools/perf/bench/Build
tools/perf/bench/mem-memcpy-x86-64-lib.c [deleted file]
tools/perf/bench/sched-messaging.c
tools/perf/bench/synthesize.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/pmu-events/arch/x86/amdzen1/core.json
tools/perf/pmu-events/arch/x86/amdzen2/core.json
tools/perf/pmu-events/jevents.c
tools/perf/tests/attr/README
tools/perf/tests/attr/test-record-group2 [new file with mode: 0644]
tools/perf/tests/bp_signal.c
tools/perf/tests/bpf.c
tools/perf/tests/parse-events.c
tools/perf/tests/parse-metric.c
tools/perf/tests/pmu-events.c
tools/perf/tests/pmu.c
tools/perf/ui/browsers/hists.c
tools/perf/util/arm-spe-decoder/arm-spe-decoder.c
tools/perf/util/cs-etm.c
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/intel-pt.c
tools/perf/util/machine.c
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/metricgroup.c
tools/perf/util/parse-events.c
tools/perf/util/parse-events.y
tools/perf/util/pmu.c
tools/perf/util/pmu.h
tools/perf/util/record.c
tools/perf/util/session.c
tools/perf/util/stat-display.c
tools/perf/util/stat-shadow.c
tools/perf/util/stat.h
tools/perf/util/symbol.c
tools/perf/util/zstd.c
tools/power/pm-graph/sleepgraph.py
tools/testing/nvdimm/test/nfit.c
tools/testing/selftests/arm64/Makefile
tools/testing/selftests/arm64/fp/.gitignore [new file with mode: 0644]
tools/testing/selftests/arm64/fp/Makefile [new file with mode: 0644]
tools/testing/selftests/arm64/fp/README [new file with mode: 0644]
tools/testing/selftests/arm64/fp/asm-offsets.h [new file with mode: 0644]
tools/testing/selftests/arm64/fp/assembler.h [new file with mode: 0644]
tools/testing/selftests/arm64/fp/fpsimd-stress [new file with mode: 0755]
tools/testing/selftests/arm64/fp/fpsimd-test.S [new file with mode: 0644]
tools/testing/selftests/arm64/fp/sve-probe-vls.c [new file with mode: 0644]
tools/testing/selftests/arm64/fp/sve-ptrace-asm.S [new file with mode: 0644]
tools/testing/selftests/arm64/fp/sve-ptrace.c [new file with mode: 0644]
tools/testing/selftests/arm64/fp/sve-stress [new file with mode: 0755]
tools/testing/selftests/arm64/fp/sve-test.S [new file with mode: 0644]
tools/testing/selftests/arm64/fp/vlset.c [new file with mode: 0644]
tools/testing/selftests/arm64/mte/.gitignore [new file with mode: 0644]
tools/testing/selftests/arm64/mte/Makefile [new file with mode: 0644]
tools/testing/selftests/arm64/mte/check_buffer_fill.c [new file with mode: 0644]
tools/testing/selftests/arm64/mte/check_child_memory.c [new file with mode: 0644]
tools/testing/selftests/arm64/mte/check_ksm_options.c [new file with mode: 0644]
tools/testing/selftests/arm64/mte/check_mmap_options.c [new file with mode: 0644]
tools/testing/selftests/arm64/mte/check_tags_inclusion.c [new file with mode: 0644]
tools/testing/selftests/arm64/mte/check_user_mem.c [new file with mode: 0644]
tools/testing/selftests/arm64/mte/mte_common_util.c [new file with mode: 0644]
tools/testing/selftests/arm64/mte/mte_common_util.h [new file with mode: 0644]
tools/testing/selftests/arm64/mte/mte_def.h [new file with mode: 0644]
tools/testing/selftests/arm64/mte/mte_helper.S [new file with mode: 0644]
tools/testing/selftests/arm64/pauth/.gitignore [new file with mode: 0644]
tools/testing/selftests/arm64/pauth/Makefile [new file with mode: 0644]
tools/testing/selftests/arm64/pauth/exec_target.c [new file with mode: 0644]
tools/testing/selftests/arm64/pauth/helper.c [new file with mode: 0644]
tools/testing/selftests/arm64/pauth/helper.h [new file with mode: 0644]
tools/testing/selftests/arm64/pauth/pac.c [new file with mode: 0644]
tools/testing/selftests/arm64/pauth/pac_corruptor.S [new file with mode: 0644]
tools/testing/selftests/bpf/progs/bpf_iter_bpf_hash_map.c
tools/testing/selftests/bpf/test_maps.c
tools/testing/selftests/bpf/test_progs.c
tools/testing/selftests/kvm/x86_64/debug_regs.c
tools/testing/selftests/net/rtnetlink.sh
tools/testing/selftests/netfilter/nft_flowtable.sh
tools/testing/selftests/powerpc/copyloops/.gitignore
tools/testing/selftests/powerpc/copyloops/Makefile
tools/testing/selftests/powerpc/copyloops/copy_mc_64.S [new symlink]
tools/testing/selftests/powerpc/copyloops/memcpy_mcsafe_64.S [deleted symlink]
tools/testing/selftests/powerpc/mm/.gitignore
tools/testing/selftests/powerpc/mm/Makefile
tools/testing/selftests/powerpc/mm/prot_sao.c [new file with mode: 0644]
tools/testing/selftests/rseq/param_test.c
tools/testing/selftests/rseq/rseq-x86.h
tools/testing/selftests/rseq/run_param_test.sh
tools/testing/selftests/timers/Makefile
tools/testing/selftests/timers/settings [new file with mode: 0644]
tools/testing/selftests/vm/map_hugetlb.c
tools/testing/selftests/x86/fsgsbase.c
tools/testing/selftests/x86/test_vsyscall.c
tools/usb/Build [new file with mode: 0644]
tools/usb/Makefile
tools/vm/page-types.c
virt/kvm/kvm_main.c

index a0a9608..badfc1b 100644 (file)
@@ -111,6 +111,7 @@ ForEachMacros:
   - 'css_for_each_descendant_pre'
   - 'device_for_each_child_node'
   - 'dma_fence_chain_for_each'
+  - 'do_for_each_ftrace_op'
   - 'drm_atomic_crtc_for_each_plane'
   - 'drm_atomic_crtc_state_for_each_plane'
   - 'drm_atomic_crtc_state_for_each_plane_state'
@@ -136,6 +137,7 @@ ForEachMacros:
   - 'for_each_active_dev_scope'
   - 'for_each_active_drhd_unit'
   - 'for_each_active_iommu'
+  - 'for_each_aggr_pgid'
   - 'for_each_available_child_of_node'
   - 'for_each_bio'
   - 'for_each_board_func_rsrc'
@@ -234,6 +236,7 @@ ForEachMacros:
   - 'for_each_node_state'
   - 'for_each_node_with_cpus'
   - 'for_each_node_with_property'
+  - 'for_each_nonreserved_multicast_dest_pgid'
   - 'for_each_of_allnodes'
   - 'for_each_of_allnodes_from'
   - 'for_each_of_cpu_node'
@@ -256,6 +259,7 @@ ForEachMacros:
   - 'for_each_pci_dev'
   - 'for_each_pci_msi_entry'
   - 'for_each_pcm_streams'
+  - 'for_each_physmem_range'
   - 'for_each_populated_zone'
   - 'for_each_possible_cpu'
   - 'for_each_present_cpu'
@@ -265,6 +269,8 @@ ForEachMacros:
   - 'for_each_process_thread'
   - 'for_each_property_of_node'
   - 'for_each_registered_fb'
+  - 'for_each_requested_gpio'
+  - 'for_each_requested_gpio_in_range'
   - 'for_each_reserved_mem_region'
   - 'for_each_rtd_codec_dais'
   - 'for_each_rtd_codec_dais_rollback'
@@ -278,12 +284,17 @@ ForEachMacros:
   - 'for_each_sg'
   - 'for_each_sg_dma_page'
   - 'for_each_sg_page'
+  - 'for_each_sgtable_dma_page'
+  - 'for_each_sgtable_dma_sg'
+  - 'for_each_sgtable_page'
+  - 'for_each_sgtable_sg'
   - 'for_each_sibling_event'
   - 'for_each_subelement'
   - 'for_each_subelement_extid'
   - 'for_each_subelement_id'
   - '__for_each_thread'
   - 'for_each_thread'
+  - 'for_each_unicast_dest_pgid'
   - 'for_each_wakeup_source'
   - 'for_each_zone'
   - 'for_each_zone_zonelist'
@@ -464,6 +475,7 @@ ForEachMacros:
   - 'v4l2_m2m_for_each_src_buf'
   - 'v4l2_m2m_for_each_src_buf_safe'
   - 'virtio_device_for_each_vq'
+  - 'while_for_each_ftrace_op'
   - 'xa_for_each'
   - 'xa_for_each_marked'
   - 'xa_for_each_range'
index 162bd2b..d01cda8 100644 (file)
@@ -152,3 +152,6 @@ x509.genkey
 
 # Clang's compilation database file
 /compile_commands.json
+
+# Documentation toolchain
+sphinx_*/
index 332c783..e4ccac4 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -41,7 +41,8 @@ Andrew Murray <amurray@thegoodpenguin.co.uk> <andrew.murray@arm.com>
 Andrew Vasquez <andrew.vasquez@qlogic.com>
 Andrey Ryabinin <ryabinin.a.a@gmail.com> <a.ryabinin@samsung.com>
 Andy Adamson <andros@citi.umich.edu>
-Antoine Tenart <antoine.tenart@free-electrons.com>
+Antoine Tenart <atenart@kernel.org> <antoine.tenart@bootlin.com>
+Antoine Tenart <atenart@kernel.org> <antoine.tenart@free-electrons.com>
 Antonio Ospite <ao2@ao2.it> <ao2@amarulasolutions.com>
 Archit Taneja <archit@ti.com>
 Ard Biesheuvel <ardb@kernel.org> <ard.biesheuvel@linaro.org>
@@ -169,6 +170,10 @@ Juha Yrjola <juha.yrjola@solidboot.com>
 Julien Thierry <julien.thierry.kdev@gmail.com> <julien.thierry@arm.com>
 Kamil Konieczny <k.konieczny@samsung.com> <k.konieczny@partner.samsung.com>
 Kay Sievers <kay.sievers@vrfy.org>
+Kees Cook <keescook@chromium.org> <kees.cook@canonical.com>
+Kees Cook <keescook@chromium.org> <keescook@google.com>
+Kees Cook <keescook@chromium.org> <kees@outflux.net>
+Kees Cook <keescook@chromium.org> <kees@ubuntu.com>
 Kenneth W Chen <kenneth.w.chen@intel.com>
 Konstantin Khlebnikov <koct9i@gmail.com> <khlebnikov@yandex-team.ru>
 Konstantin Khlebnikov <koct9i@gmail.com> <k.khlebnikov@samsung.com>
@@ -184,6 +189,7 @@ Leon Romanovsky <leon@kernel.org> <leonro@nvidia.com>
 Linas Vepstas <linas@austin.ibm.com>
 Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch>
 Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@web.de>
+<linux-hardening@vger.kernel.org> <kernel-hardening@lists.openwall.com>
 Li Yang <leoyang.li@nxp.com> <leoli@freescale.com>
 Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org>
 Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com>
@@ -191,6 +197,7 @@ Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com>
 Marcin Nowakowski <marcin.nowakowski@mips.com> <marcin.nowakowski@imgtec.com>
 Marc Zyngier <maz@kernel.org> <marc.zyngier@arm.com>
 Mark Brown <broonie@sirena.org.uk>
+Mark Starovoytov <mstarovo@pm.me> <mstarovoitov@marvell.com>
 Mark Yao <markyao0591@gmail.com> <mark.yao@rock-chips.com>
 Martin Kepplinger <martink@posteo.de> <martin.kepplinger@ginzinger.com>
 Martin Kepplinger <martink@posteo.de> <martin.kepplinger@puri.sm>
@@ -308,6 +315,7 @@ Tony Luck <tony.luck@intel.com>
 TripleX Chung <xxx.phy@gmail.com> <triplex@zh-kernel.org>
 TripleX Chung <xxx.phy@gmail.com> <zhongyu@18mail.cn>
 Tsuneo Yoshioka <Tsuneo.Yoshioka@f-secure.com>
+Tycho Andersen <tycho@tycho.pizza> <tycho@tycho.ws>
 Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
 Uwe Kleine-König <ukl@pengutronix.de>
 Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
diff --git a/Documentation/ABI/stable/sysfs-kernel-notes b/Documentation/ABI/stable/sysfs-kernel-notes
new file mode 100644 (file)
index 0000000..2c76ee9
--- /dev/null
@@ -0,0 +1,5 @@
+What:          /sys/kernel/notes
+Date:          July 2009
+Contact:       <linux-kernel@vger.kernel.org>
+Description:   The /sys/kernel/notes file contains the binary representation
+               of the running vmlinux's .notes section.
index 8f66fea..c17c87a 100644 (file)
@@ -12,6 +12,7 @@ Linux PCI Bus Subsystem
    pciebus-howto
    pci-iov-howto
    msi-howto
+   sysfs-pci
    acpi-info
    pci-error-recovery
    pcieaer-howto
index f1fc8ae..cc860a0 100644 (file)
@@ -49,7 +49,7 @@ checking of rcu_dereference() primitives:
                is invoked by both RCU-sched readers and updaters.
        srcu_dereference_check(p, c):
                Use explicit check expression "c" along with
-               srcu_read_lock_held()().  This is useful in code that
+               srcu_read_lock_held().  This is useful in code that
                is invoked by both SRCU readers and updaters.
        rcu_dereference_raw(p):
                Don't check.  (Use sparingly, if at all.)
index 5aad534..95a28f4 100644 (file)
@@ -322,9 +322,9 @@ Compiling the kernel
    reboot, and enjoy!
 
    If you ever need to change the default root device, video mode,
-   ramdisk size, etc.  in the kernel image, use the ``rdev`` program (or
-   alternatively the LILO boot options when appropriate).  No need to
-   recompile the kernel to change these parameters.
+   etc. in the kernel image, use your bootloader's boot options
+   where appropriate.  No need to recompile the kernel to change
+   these parameters.
 
  - Reboot with the new kernel and enjoy.
 
index 1eccf95..8d3a2d0 100644 (file)
@@ -5,11 +5,14 @@ A block layer cache (bcache)
 Say you've got a big slow raid 6, and an ssd or three. Wouldn't it be
 nice if you could use them as cache... Hence bcache.
 
-Wiki and git repositories are at:
+The bcache wiki can be found at:
+  https://bcache.evilpiepirate.org
 
-  - https://bcache.evilpiepirate.org
-  - http://evilpiepirate.org/git/linux-bcache.git
-  - https://evilpiepirate.org/git/bcache-tools.git
+This is the git repository of bcache-tools:
+  https://git.kernel.org/pub/scm/linux/kernel/git/colyli/bcache-tools.git/
+
+The latest bcache kernel code can be found from mainline Linux kernel:
+  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/
 
 It's designed around the performance characteristics of SSDs - it only allocates
 in erase block sized buckets, and it uses a hybrid btree/log to track cached
@@ -41,17 +44,21 @@ in the cache it first disables writeback caching and waits for all dirty data
 to be flushed.
 
 Getting started:
-You'll need make-bcache from the bcache-tools repository. Both the cache device
+You'll need bcache util from the bcache-tools repository. Both the cache device
 and backing device must be formatted before use::
 
-  make-bcache -B /dev/sdb
-  make-bcache -C /dev/sdc
+  bcache make -B /dev/sdb
+  bcache make -C /dev/sdc
 
-make-bcache has the ability to format multiple devices at the same time - if
+`bcache make` has the ability to format multiple devices at the same time - if
 you format your backing devices and cache device at the same time, you won't
 have to manually attach::
 
-  make-bcache -B /dev/sda /dev/sdb -C /dev/sdc
+  bcache make -B /dev/sda /dev/sdb -C /dev/sdc
+
+If your bcache-tools is not updated to latest version and does not have the
+unified `bcache` utility, you may use the legacy `make-bcache` utility to format
+bcache device with same -B and -C parameters.
 
 bcache-tools now ships udev rules, and bcache devices are known to the kernel
 immediately.  Without udev, you can manually register devices like this::
@@ -188,7 +195,7 @@ D) Recovering data without bcache:
 If bcache is not available in the kernel, a filesystem on the backing
 device is still available at an 8KiB offset. So either via a loopdev
 of the backing device created with --offset 8K, or any value defined by
---data-offset when you originally formatted bcache with `make-bcache`.
+--data-offset when you originally formatted bcache with `bcache make`.
 
 For example::
 
@@ -210,7 +217,7 @@ E) Wiping a cache device
 
 After you boot back with bcache enabled, you recreate the cache and attach it::
 
-       host:~# make-bcache -C /dev/sdh2
+       host:~# bcache make -C /dev/sdh2
        UUID:                   7be7e175-8f4c-4f99-94b2-9c904d227045
        Set UUID:               5bc072a8-ab17-446d-9744-e247949913c1
        version:                0
@@ -318,7 +325,7 @@ want for getting the best possible numbers when benchmarking.
 
    The default metadata size in bcache is 8k.  If your backing device is
    RAID based, then be sure to align this by a multiple of your stride
-   width using `make-bcache --data-offset`. If you intend to expand your
+   width using `bcache make --data-offset`. If you intend to expand your
    disk array in the future, then multiply a series of primes by your
    raid stripe size to get the disk multiples that you would like.
 
index b7c2268..9ce6101 100644 (file)
@@ -6,7 +6,7 @@ Using the RAM disk block device with Linux
 
        1) Overview
        2) Kernel Command Line Parameters
-       3) Using "rdev -r"
+       3) Using "rdev"
        4) An Example of Creating a Compressed RAM Disk
 
 
@@ -59,51 +59,27 @@ default is 4096 (4 MB).
        rd_size
                See ramdisk_size.
 
-3) Using "rdev -r"
-------------------
+3) Using "rdev"
+---------------
 
-The usage of the word (two bytes) that "rdev -r" sets in the kernel image is
-as follows. The low 11 bits (0 -> 10) specify an offset (in 1 k blocks) of up
-to 2 MB (2^11) of where to find the RAM disk (this used to be the size). Bit
-14 indicates that a RAM disk is to be loaded, and bit 15 indicates whether a
-prompt/wait sequence is to be given before trying to read the RAM disk. Since
-the RAM disk dynamically grows as data is being written into it, a size field
-is not required. Bits 11 to 13 are not currently used and may as well be zero.
-These numbers are no magical secrets, as seen below::
+"rdev" is an obsolete, deprecated, antiquated utility that could be used
+to set the boot device in a Linux kernel image.
 
-  ./arch/x86/kernel/setup.c:#define RAMDISK_IMAGE_START_MASK     0x07FF
-  ./arch/x86/kernel/setup.c:#define RAMDISK_PROMPT_FLAG          0x8000
-  ./arch/x86/kernel/setup.c:#define RAMDISK_LOAD_FLAG            0x4000
+Instead of using rdev, just place the boot device information on the
+kernel command line and pass it to the kernel from the bootloader.
 
-Consider a typical two floppy disk setup, where you will have the
-kernel on disk one, and have already put a RAM disk image onto disk #2.
+You can also pass arguments to the kernel by setting FDARGS in
+arch/x86/boot/Makefile and specify in initrd image by setting FDINITRD in
+arch/x86/boot/Makefile.
 
-Hence you want to set bits 0 to 13 as 0, meaning that your RAM disk
-starts at an offset of 0 kB from the beginning of the floppy.
-The command line equivalent is: "ramdisk_start=0"
+Some of the kernel command line boot options that may apply here are::
 
-You want bit 14 as one, indicating that a RAM disk is to be loaded.
-The command line equivalent is: "load_ramdisk=1"
-
-You want bit 15 as one, indicating that you want a prompt/keypress
-sequence so that you have a chance to switch floppy disks.
-The command line equivalent is: "prompt_ramdisk=1"
-
-Putting that together gives 2^15 + 2^14 + 0 = 49152 for an rdev word.
-So to create disk one of the set, you would do::
-
-       /usr/src/linux# cat arch/x86/boot/zImage > /dev/fd0
-       /usr/src/linux# rdev /dev/fd0 /dev/fd0
-       /usr/src/linux# rdev -r /dev/fd0 49152
+  ramdisk_start=N
+  ramdisk_size=M
 
 If you make a boot disk that has LILO, then for the above, you would use::
 
-       append = "ramdisk_start=0 load_ramdisk=1 prompt_ramdisk=1"
-
-Since the default start = 0 and the default prompt = 1, you could use::
-
-       append = "load_ramdisk=1"
-
+       append = "ramdisk_start=N ramdisk_size=M"
 
 4) An Example of Creating a Compressed RAM Disk
 -----------------------------------------------
@@ -151,12 +127,9 @@ f) Put the RAM disk image onto the floppy, after the kernel. Use an offset
 
        dd if=/tmp/ram_image.gz of=/dev/fd0 bs=1k seek=400
 
-g) Use "rdev" to set the boot device, RAM disk offset, prompt flag, etc.
-   For prompt_ramdisk=1, load_ramdisk=1, ramdisk_start=400, one would
-   have 2^15 + 2^14 + 400 = 49552::
-
-       rdev /dev/fd0 /dev/fd0
-       rdev -r /dev/fd0 49552
+g) Make sure that you have already specified the boot information in
+   FDARGS and FDINITRD or that you use a bootloader to pass kernel
+   command line boot options to the kernel.
 
 That is it. You now have your boot/root compressed RAM disk floppy. Some
 users may wish to combine steps (d) and (f) by using a pipe.
@@ -167,11 +140,14 @@ users may wish to combine steps (d) and (f) by using a pipe.
 Changelog:
 ----------
 
+SEPT-2020 :
+
+                Removed usage of "rdev"
+
 10-22-04 :
                Updated to reflect changes in command line options, remove
                obsolete references, general cleanup.
                James Nelson (james4765@gmail.com)
 
-
 12-95 :
                Original Document
index 6be4378..baa07b3 100644 (file)
@@ -1324,15 +1324,26 @@ PAGE_SIZE multiple when read back.
          pgmajfault
                Number of major page faults incurred
 
-         workingset_refault
-               Number of refaults of previously evicted pages
+         workingset_refault_anon
+               Number of refaults of previously evicted anonymous pages.
 
-         workingset_activate
-               Number of refaulted pages that were immediately activated
+         workingset_refault_file
+               Number of refaults of previously evicted file pages.
 
-         workingset_restore
-               Number of restored pages which have been detected as an active
-               workingset before they got reclaimed.
+         workingset_activate_anon
+               Number of refaulted anonymous pages that were immediately
+               activated.
+
+         workingset_activate_file
+               Number of refaulted file pages that were immediately activated.
+
+         workingset_restore_anon
+               Number of restored anonymous pages which have been detected as
+               an active workingset before they got reclaimed.
+
+         workingset_restore_file
+               Number of restored file pages which have been detected as an
+               active workingset before they got reclaimed.
 
          workingset_nodereclaim
                Number of times a shadow node has been reclaimed
index 8f4a3f8..bc28a95 100644 (file)
@@ -67,7 +67,7 @@ Parameters::
     the value passed in <key_size>.
 
 <key_type>
-    Either 'logon' or 'user' kernel key type.
+    Either 'logon', 'user' or 'encrypted' kernel key type.
 
 <key_description>
     The kernel keyring key description crypt target should look for
@@ -121,6 +121,14 @@ submit_from_crypt_cpus
     thread because it benefits CFQ to have writes submitted using the
     same context.
 
+no_read_workqueue
+    Bypass dm-crypt internal workqueue and process read requests synchronously.
+
+no_write_workqueue
+    Bypass dm-crypt internal workqueue and process write requests synchronously.
+    This option is automatically enabled for host-managed zoned block devices
+    (e.g. host-managed SMR hard-disks).
+
 integrity:<bytes>:<type>
     The device requires additional <bytes> metadata per-sector stored
     in per-bio integrity structure. This metadata must by provided
index d336f3f..63fd4e6 100644 (file)
 
   98 block     User-mode virtual block device
                  0 = /dev/ubda         First user-mode block device
-                16 = /dev/udbb         Second user-mode block device
+                16 = /dev/ubdb         Second user-mode block device
                    ...
 
                Partitions are handled in the same way as for IDE
index e5a8def..6c04aea 100644 (file)
@@ -156,7 +156,6 @@ against.  Possible keywords are:::
   ``line-range`` cannot contain space, e.g.
   "1-30" is valid range but "1 - 30" is not.
 
-  ``module=foo`` combined keyword=value form is interchangably accepted
 
 The meanings of each keyword are:
 
index 2da65fe..75a9dd9 100644 (file)
@@ -509,9 +509,12 @@ ELF32-format headers using the --elf32-core-headers kernel option on the
 dump kernel.
 
 You can also use the Crash utility to analyze dump files in Kdump
-format. Crash is available on Dave Anderson's site at the following URL:
+format. Crash is available at the following URL:
 
-   http://people.redhat.com/~anderson/
+   https://github.com/crash-utility/crash
+
+Crash document can be found at:
+   https://crash-utility.github.io/
 
 Trigger Kdump on WARN()
 =======================
index a106874..0fa47dd 100644 (file)
                        loops can be debugged more effectively on production
                        systems.
 
-       clearcpuid=BITNUM [X86]
+       clearcpuid=BITNUM[,BITNUM...] [X86]
                        Disable CPUID feature X for the kernel. See
                        arch/x86/include/asm/cpufeatures.h for the valid bit
                        numbers. Note the Linux specific bits are not necessarily
                        some critical bits.
 
        cma=nn[MG]@[start[MG][-end[MG]]]
-                       [ARM,X86,KNL]
+                       [KNL,CMA]
                        Sets the size of kernel global memory area for
                        contiguous memory allocations and optionally the
                        placement constraint by the physical address range of
                        Arch Perfmon v4 (Skylake and newer).
 
        disable_ddw     [PPC/PSERIES]
-                       Disable Dynamic DMA Window support. Use this if
+                       Disable Dynamic DMA Window support. Use this
                        to workaround buggy firmware.
 
        disable_ipv6=   [IPV6]
                        what data is available or for reverse-engineering.
 
        dyndbg[="val"]          [KNL,DYNAMIC_DEBUG]
-       module.dyndbg[="val"]
+       <module>.dyndbg[="val"]
                        Enable debug messages at boot time.  See
                        Documentation/admin-guide/dynamic-debug-howto.rst
                        for details.
        nopku           [X86] Disable Memory Protection Keys CPU feature found
                        in some Intel CPUs.
 
-       module.async_probe [KNL]
+       <module>.async_probe [KNL]
                        Enable asynchronous probe on this module.
 
        early_ioremap_debug [KNL]
                        1 - Bypass the IOMMU for DMA.
                        unset - Use value of CONFIG_IOMMU_DEFAULT_PASSTHROUGH.
 
-       io7=            [HW] IO7 for Marvel based alpha systems
+       io7=            [HW] IO7 for Marvel-based Alpha systems
                        See comment before marvel_specify_io7 in
                        arch/alpha/kernel/core_marvel.c.
 
        kgdbwait        [KGDB] Stop kernel execution and enter the
                        kernel debugger at the earliest opportunity.
 
-       kmac=           [MIPS] korina ethernet MAC address.
+       kmac=           [MIPS] Korina ethernet MAC address.
                        Configure the RouterBoard 532 series on-chip
                        Ethernet adapter MAC address.
 
                        [KVM,ARM] Allow use of GICv4 for direct injection of
                        LPIs.
 
+       kvm_cma_resv_ratio=n [PPC]
+                       Reserves given percentage from system memory area for
+                       contiguous memory allocation for KVM hash pagetable
+                       allocation.
+                       By default it reserves 5% of total system memory.
+                       Format: <integer>
+                       Default: 5
+
        kvm-intel.ept=  [KVM,Intel] Disable extended page tables
                        (virtualized MMU) support on capable Intel chips.
                        Default is 1 (enabled)
        lapic           [X86-32,APIC] Enable the local APIC even if BIOS
                        disabled it.
 
-       lapic=          [X86,APIC] "notscdeadline" Do not use TSC deadline
+       lapic=          [X86,APIC] Do not use TSC deadline
                        value for LAPIC timer one-shot implementation. Default
                        back to the programmable timer unit in the LAPIC.
+                       Format: notscdeadline
 
        lapic_timer_c2_ok       [X86,APIC] trust the local apic timer
                        in C2 power state.
 
        memblock=debug  [KNL] Enable memblock debug messages.
 
-       load_ramdisk=   [RAM] List of ramdisks to load from floppy
-                       See Documentation/admin-guide/blockdev/ramdisk.rst.
+       load_ramdisk=   [RAM] [Deprecated]
 
        lockd.nlm_grace_period=P  [NFS] Assign grace period.
                        Format: <integer>
                        (machvec) in a generic kernel.
                        Example: machvec=hpzx1
 
-       machtype=       [Loongson] Share the same kernel image file between different
-                        yeeloong laptop.
+       machtype=       [Loongson] Share the same kernel image file between
+                       different yeeloong laptops.
                        Example: machtype=lemote-yeeloong-2f-7inch
 
        max_addr=nn[KMG]        [KNL,BOOT,ia64] All physical memory greater
                        register save and restore. The kernel will only save
                        legacy floating-point registers on task switch.
 
-       nohugeiomap     [KNL,X86,PPC] Disable kernel huge I/O mappings.
+       nohugeiomap     [KNL,X86,PPC,ARM64] Disable kernel huge I/O mappings.
 
        nosmt           [KNL,S390] Disable symmetric multithreading (SMT).
                        Equivalent to smt=1.
                        Param: <number> - step/bucket size as a power of 2 for
                                statistical time based profiling.
 
-       prompt_ramdisk= [RAM] List of RAM disks to prompt for floppy disk
-                       before loading.
-                       See Documentation/admin-guide/blockdev/ramdisk.rst.
+       prompt_ramdisk= [RAM] [Deprecated]
 
        prot_virt=      [S390] enable hosting protected virtual machines
                        isolated from the hypervisor (if hardware supports
        ramdisk_size=   [RAM] Sizes of RAM disks in kilobytes
                        See Documentation/admin-guide/blockdev/ramdisk.rst.
 
+       ramdisk_start=  [RAM] RAM disk image start address
+
        random.trust_cpu={on,off}
                        [KNL] Enable or disable trusting the use of the
                        CPU's random number generator (if available) to
index 5e47786..5fe1ade 100644 (file)
@@ -1434,7 +1434,7 @@ on the feature, restricting the viewing angles.
 
 
 DYTC Lapmode sensor
-------------------
+-------------------
 
 sysfs: dytc_lapmode
 
diff --git a/Documentation/admin-guide/perf/arm-cmn.rst b/Documentation/admin-guide/perf/arm-cmn.rst
new file mode 100644 (file)
index 0000000..0e48093
--- /dev/null
@@ -0,0 +1,65 @@
+=============================
+Arm Coherent Mesh Network PMU
+=============================
+
+CMN-600 is a configurable mesh interconnect consisting of a rectangular
+grid of crosspoints (XPs), with each crosspoint supporting up to two
+device ports to which various AMBA CHI agents are attached.
+
+CMN implements a distributed PMU design as part of its debug and trace
+functionality. This consists of a local monitor (DTM) at every XP, which
+counts up to 4 event signals from the connected device nodes and/or the
+XP itself. Overflow from these local counters is accumulated in up to 8
+global counters implemented by the main controller (DTC), which provides
+overall PMU control and interrupts for global counter overflow.
+
+PMU events
+----------
+
+The PMU driver registers a single PMU device for the whole interconnect,
+see /sys/bus/event_source/devices/arm_cmn. Multi-chip systems may link
+more than one CMN together via external CCIX links - in this situation,
+each mesh counts its own events entirely independently, and additional
+PMU devices will be named arm_cmn_{1..n}.
+
+Most events are specified in a format based directly on the TRM
+definitions - "type" selects the respective node type, and "eventid" the
+event number. Some events require an additional occupancy ID, which is
+specified by "occupid".
+
+* Since RN-D nodes do not have any distinct events from RN-I nodes, they
+  are treated as the same type (0xa), and the common event templates are
+  named "rnid_*".
+
+* The cycle counter is treated as a synthetic event belonging to the DTC
+  node ("type" == 0x3, "eventid" is ignored).
+
+* XP events also encode the port and channel in the "eventid" field, to
+  match the underlying pmu_event0_id encoding for the pmu_event_sel
+  register. The event templates are named with prefixes to cover all
+  permutations.
+
+By default each event provides an aggregate count over all nodes of the
+given type. To target a specific node, "bynodeid" must be set to 1 and
+"nodeid" to the appropriate value derived from the CMN configuration
+(as defined in the "Node ID Mapping" section of the TRM).
+
+Watchpoints
+-----------
+
+The PMU can also count watchpoint events to monitor specific flit
+traffic. Watchpoints are treated as a synthetic event type, and like PMU
+events can be global or targeted with a particular XP's "nodeid" value.
+Since the watchpoint direction is otherwise implicit in the underlying
+register selection, separate events are provided for flit uploads and
+downloads.
+
+The flit match value and mask are passed in config1 and config2 ("val"
+and "mask" respectively). "wp_dev_sel", "wp_chn_sel", "wp_grp" and
+"wp_exclusive" are specified per the TRM definitions for dtm_wp_config0.
+Where a watchpoint needs to match fields from both match groups on the
+REQ or SNP channel, it can be specified as two events - one for each
+group - with the same nonzero "combine" value. The count for such a
+pair of combined events will be attributed to the primary match.
+Watchpoint events with a "combine" value of 0 are considered independent
+and will count individually.
index 47c99f4..5a8f252 100644 (file)
@@ -12,6 +12,7 @@ Performance monitor support
    qcom_l2_pmu
    qcom_l3_pmu
    arm-ccn
+   arm-cmn
    xgene-pmu
    arm_dsu_pmu
    thunderx2-pmu
index a96a423..6ebe163 100644 (file)
@@ -690,7 +690,7 @@ which of the two parameters is added to the kernel command line.  In the
 instruction of the CPUs (which, as a rule, suspends the execution of the program
 and causes the hardware to attempt to enter the shallowest available idle state)
 for this purpose, and if ``idle=poll`` is used, idle CPUs will execute a
-more or less ``lightweight'' sequence of instructions in a tight loop.  [Note
+more or less "lightweight" sequence of instructions in a tight loop.  [Note
 that using ``idle=poll`` is somewhat drastic in many cases, as preventing idle
 CPUs from saving almost any energy at all may not be the only effect of it.
 For example, on Intel hardware it effectively prevents CPUs from using
index 7adef96..5072e70 100644 (file)
@@ -123,7 +123,9 @@ Energy-Performance Bias (EPB) knob (otherwise), which means that the processor's
 internal P-state selection logic is expected to focus entirely on performance.
 
 This will override the EPP/EPB setting coming from the ``sysfs`` interface
-(see `Energy vs Performance Hints`_ below).
+(see `Energy vs Performance Hints`_ below).  Moreover, any attempts to change
+the EPP/EPB to a value different from 0 ("performance") via ``sysfs`` in this
+configuration will be rejected.
 
 Also, in this configuration the range of P-states available to the processor's
 internal P-state selection logic is always restricted to the upper boundary
@@ -564,8 +566,8 @@ Energy-Performance Preference (EPP) knob (if supported) or its
 Energy-Performance Bias (EPB) knob. It is also possible to write a positive
 integer value between 0 to 255, if the EPP feature is present. If the EPP
 feature is not present, writing integer value to this attribute is not
-supported. In this case, user can use
- "/sys/devices/system/cpu/cpu*/power/energy_perf_bias" interface.
+supported. In this case, user can use the
+"/sys/devices/system/cpu/cpu*/power/energy_perf_bias" interface.
 
 [Note that tasks may by migrated from one CPU to another by the scheduler's
 load-balancing algorithm and if different energy vs performance hints are
index b6c2f9a..9eb1e07 100644 (file)
@@ -12,7 +12,8 @@ Intro
 This small document describes the "Video Mode Selection" feature which
 allows the use of various special video modes supported by the video BIOS. Due
 to usage of the BIOS, the selection is limited to boot time (before the
-kernel decompression starts) and works only on 80X86 machines.
+kernel decompression starts) and works only on 80X86 machines that are
+booted through BIOS firmware (as opposed to through UEFI, kexec, etc.).
 
 .. note::
 
@@ -23,7 +24,7 @@ kernel decompression starts) and works only on 80X86 machines.
 
 The video mode to be used is selected by a kernel parameter which can be
 specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..."
-option of LILO (or some other boot loader you use) or by the "vidmode" utility
+option of LILO (or some other boot loader you use) or by the "xrandr" utility
 (present in standard Linux utility packages). You can use the following values
 of this parameter::
 
@@ -41,7 +42,7 @@ of this parameter::
       better to use absolute mode numbers instead.
 
    0x.... - Hexadecimal video mode ID (also displayed on the menu, see below
-      for exact meaning of the ID). Warning: rdev and LILO don't support
+      for exact meaning of the ID). Warning: LILO doesn't support
       hexadecimal numbers -- you have to convert it to decimal manually.
 
 Menu
index 599bcde..ac87eaf 100644 (file)
@@ -1,67 +1,34 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
 ================================
 Documentation for /proc/sys/abi/
 ================================
 
-kernel version 2.6.0.test2
+.. See scripts/check-sysctl-docs to keep this up to date:
+.. scripts/check-sysctl-docs -vtable="abi" \
+..         Documentation/admin-guide/sysctl/abi.rst \
+..         $(git grep -l register_sysctl_)
 
-Copyright (c) 2003,  Fabian Frederick <ffrederick@users.sourceforge.net>
+Copyright (c) 2020, Stephen Kitt
 
-For general info: index.rst.
+For general info, see :doc:`index`.
 
 ------------------------------------------------------------------------------
 
-This path is binary emulation relevant aka personality types aka abi.
-When a process is executed, it's linked to an exec_domain whose
-personality is defined using values available from /proc/sys/abi.
-You can find further details about abi in include/linux/personality.h.
-
-Here are the files featuring in 2.6 kernel:
-
-- defhandler_coff
-- defhandler_elf
-- defhandler_lcall7
-- defhandler_libcso
-- fake_utsname
-- trace
-
-defhandler_coff
----------------
-
-defined value:
-       PER_SCOSVR3::
-
-               0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE
-
-defhandler_elf
---------------
-
-defined value:
-       PER_LINUX::
-
-               0
-
-defhandler_lcall7
------------------
-
-defined value :
-       PER_SVR4::
-
-               0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
-
-defhandler_libsco
------------------
-
-defined value:
-       PER_SVR4::
+The files in ``/proc/sys/abi`` can be used to see and modify
+ABI-related settings.
 
-               0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
+Currently, these files might (depending on your configuration)
+show up in ``/proc/sys/kernel``:
 
-fake_utsname
-------------
+.. contents:: :local:
 
-Unused
+vsyscall32 (x86)
+================
 
-trace
------
+Determines whether the kernels maps a vDSO page into 32-bit processes;
+can be set to 1 to enable, or 0 to disable. Defaults to enabled if
+``CONFIG_COMPAT_VDSO`` is set, disabled otherwide.
 
-Unused
+This controls the same setting as the ``vdso32`` kernel boot
+parameter.
index abf8047..f718a2e 100644 (file)
@@ -130,7 +130,7 @@ More detailed explanation for tainting
  5)  ``B`` If a page-release function has found a bad page reference or some
      unexpected page flags. This indicates a hardware problem or a kernel bug;
      there should be other information in the log indicating why this tainting
-     occured.
+     occurred.
 
  6)  ``U`` if a user or user application specifically requested that the
      Tainted flag be set, ``' '`` otherwise.
index b037428..62b533d 100644 (file)
@@ -108,7 +108,7 @@ SunXi family
 
         * Datasheet
 
-          http://dl.linux-sunxi.org/H3/Allwinner_H3_Datasheet_V1.0.pdf
+          https://linux-sunxi.org/images/4/4b/Allwinner_H3_Datasheet_V1.2.pdf
 
       - Allwinner R40 (sun8i)
 
index f868330..f732f95 100644 (file)
@@ -23,7 +23,7 @@ makes it possible for the kernel to support additional features:
 For actually enabling [U]EFI support, enable:
 
 - CONFIG_EFI=y
-- CONFIG_EFI_VARS=y or m
+- CONFIG_EFIVAR_FS=y or m
 
 The implementation depends on receiving information about the UEFI environment
 in a Flattened Device Tree (FDT) - so is only available with CONFIG_OF.
index 452ec8b..01f2de2 100644 (file)
@@ -1,3 +1,5 @@
+.. _amu_index:
+
 =======================================================
 Activity Monitors Unit (AMU) extension in AArch64 Linux
 =======================================================
index f28853f..328e0c4 100644 (file)
@@ -175,6 +175,8 @@ infrastructure:
      +------------------------------+---------+---------+
      | Name                         |  bits   | visible |
      +------------------------------+---------+---------+
+     | MTE                          | [11-8]  |    y    |
+     +------------------------------+---------+---------+
      | SSBS                         | [7-4]   |    y    |
      +------------------------------+---------+---------+
      | BT                           | [3-0]   |    y    |
index 84a9fd2..bbd9cf5 100644 (file)
@@ -240,6 +240,10 @@ HWCAP2_BTI
 
     Functionality implied by ID_AA64PFR0_EL1.BT == 0b0001.
 
+HWCAP2_MTE
+
+    Functionality implied by ID_AA64PFR1_EL1.MTE == 0b0010, as described
+    by Documentation/arm64/memory-tagging-extension.rst.
 
 4. Unused AT_HWCAP bits
 -----------------------
index d9665d8..937634c 100644 (file)
@@ -1,3 +1,5 @@
+.. _arm64_index:
+
 ==================
 ARM64 Architecture
 ==================
@@ -14,6 +16,7 @@ ARM64 Architecture
     hugetlbpage
     legacy_instructions
     memory
+    memory-tagging-extension
     perf
     pointer-authentication
     silicon-errata
diff --git a/Documentation/arm64/memory-tagging-extension.rst b/Documentation/arm64/memory-tagging-extension.rst
new file mode 100644 (file)
index 0000000..034d37c
--- /dev/null
@@ -0,0 +1,305 @@
+===============================================
+Memory Tagging Extension (MTE) in AArch64 Linux
+===============================================
+
+Authors: Vincenzo Frascino <vincenzo.frascino@arm.com>
+         Catalin Marinas <catalin.marinas@arm.com>
+
+Date: 2020-02-25
+
+This document describes the provision of the Memory Tagging Extension
+functionality in AArch64 Linux.
+
+Introduction
+============
+
+ARMv8.5 based processors introduce the Memory Tagging Extension (MTE)
+feature. MTE is built on top of the ARMv8.0 virtual address tagging TBI
+(Top Byte Ignore) feature and allows software to access a 4-bit
+allocation tag for each 16-byte granule in the physical address space.
+Such memory range must be mapped with the Normal-Tagged memory
+attribute. A logical tag is derived from bits 59-56 of the virtual
+address used for the memory access. A CPU with MTE enabled will compare
+the logical tag against the allocation tag and potentially raise an
+exception on mismatch, subject to system registers configuration.
+
+Userspace Support
+=================
+
+When ``CONFIG_ARM64_MTE`` is selected and Memory Tagging Extension is
+supported by the hardware, the kernel advertises the feature to
+userspace via ``HWCAP2_MTE``.
+
+PROT_MTE
+--------
+
+To access the allocation tags, a user process must enable the Tagged
+memory attribute on an address range using a new ``prot`` flag for
+``mmap()`` and ``mprotect()``:
+
+``PROT_MTE`` - Pages allow access to the MTE allocation tags.
+
+The allocation tag is set to 0 when such pages are first mapped in the
+user address space and preserved on copy-on-write. ``MAP_SHARED`` is
+supported and the allocation tags can be shared between processes.
+
+**Note**: ``PROT_MTE`` is only supported on ``MAP_ANONYMOUS`` and
+RAM-based file mappings (``tmpfs``, ``memfd``). Passing it to other
+types of mapping will result in ``-EINVAL`` returned by these system
+calls.
+
+**Note**: The ``PROT_MTE`` flag (and corresponding memory type) cannot
+be cleared by ``mprotect()``.
+
+**Note**: ``madvise()`` memory ranges with ``MADV_DONTNEED`` and
+``MADV_FREE`` may have the allocation tags cleared (set to 0) at any
+point after the system call.
+
+Tag Check Faults
+----------------
+
+When ``PROT_MTE`` is enabled on an address range and a mismatch between
+the logical and allocation tags occurs on access, there are three
+configurable behaviours:
+
+- *Ignore* - This is the default mode. The CPU (and kernel) ignores the
+  tag check fault.
+
+- *Synchronous* - The kernel raises a ``SIGSEGV`` synchronously, with
+  ``.si_code = SEGV_MTESERR`` and ``.si_addr = <fault-address>``. The
+  memory access is not performed. If ``SIGSEGV`` is ignored or blocked
+  by the offending thread, the containing process is terminated with a
+  ``coredump``.
+
+- *Asynchronous* - The kernel raises a ``SIGSEGV``, in the offending
+  thread, asynchronously following one or multiple tag check faults,
+  with ``.si_code = SEGV_MTEAERR`` and ``.si_addr = 0`` (the faulting
+  address is unknown).
+
+The user can select the above modes, per thread, using the
+``prctl(PR_SET_TAGGED_ADDR_CTRL, flags, 0, 0, 0)`` system call where
+``flags`` contain one of the following values in the ``PR_MTE_TCF_MASK``
+bit-field:
+
+- ``PR_MTE_TCF_NONE``  - *Ignore* tag check faults
+- ``PR_MTE_TCF_SYNC``  - *Synchronous* tag check fault mode
+- ``PR_MTE_TCF_ASYNC`` - *Asynchronous* tag check fault mode
+
+The current tag check fault mode can be read using the
+``prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)`` system call.
+
+Tag checking can also be disabled for a user thread by setting the
+``PSTATE.TCO`` bit with ``MSR TCO, #1``.
+
+**Note**: Signal handlers are always invoked with ``PSTATE.TCO = 0``,
+irrespective of the interrupted context. ``PSTATE.TCO`` is restored on
+``sigreturn()``.
+
+**Note**: There are no *match-all* logical tags available for user
+applications.
+
+**Note**: Kernel accesses to the user address space (e.g. ``read()``
+system call) are not checked if the user thread tag checking mode is
+``PR_MTE_TCF_NONE`` or ``PR_MTE_TCF_ASYNC``. If the tag checking mode is
+``PR_MTE_TCF_SYNC``, the kernel makes a best effort to check its user
+address accesses, however it cannot always guarantee it.
+
+Excluding Tags in the ``IRG``, ``ADDG`` and ``SUBG`` instructions
+-----------------------------------------------------------------
+
+The architecture allows excluding certain tags to be randomly generated
+via the ``GCR_EL1.Exclude`` register bit-field. By default, Linux
+excludes all tags other than 0. A user thread can enable specific tags
+in the randomly generated set using the ``prctl(PR_SET_TAGGED_ADDR_CTRL,
+flags, 0, 0, 0)`` system call where ``flags`` contains the tags bitmap
+in the ``PR_MTE_TAG_MASK`` bit-field.
+
+**Note**: The hardware uses an exclude mask but the ``prctl()``
+interface provides an include mask. An include mask of ``0`` (exclusion
+mask ``0xffff``) results in the CPU always generating tag ``0``.
+
+Initial process state
+---------------------
+
+On ``execve()``, the new process has the following configuration:
+
+- ``PR_TAGGED_ADDR_ENABLE`` set to 0 (disabled)
+- Tag checking mode set to ``PR_MTE_TCF_NONE``
+- ``PR_MTE_TAG_MASK`` set to 0 (all tags excluded)
+- ``PSTATE.TCO`` set to 0
+- ``PROT_MTE`` not set on any of the initial memory maps
+
+On ``fork()``, the new process inherits the parent's configuration and
+memory map attributes with the exception of the ``madvise()`` ranges
+with ``MADV_WIPEONFORK`` which will have the data and tags cleared (set
+to 0).
+
+The ``ptrace()`` interface
+--------------------------
+
+``PTRACE_PEEKMTETAGS`` and ``PTRACE_POKEMTETAGS`` allow a tracer to read
+the tags from or set the tags to a tracee's address space. The
+``ptrace()`` system call is invoked as ``ptrace(request, pid, addr,
+data)`` where:
+
+- ``request`` - one of ``PTRACE_PEEKMTETAGS`` or ``PTRACE_POKEMTETAGS``.
+- ``pid`` - the tracee's PID.
+- ``addr`` - address in the tracee's address space.
+- ``data`` - pointer to a ``struct iovec`` where ``iov_base`` points to
+  a buffer of ``iov_len`` length in the tracer's address space.
+
+The tags in the tracer's ``iov_base`` buffer are represented as one
+4-bit tag per byte and correspond to a 16-byte MTE tag granule in the
+tracee's address space.
+
+**Note**: If ``addr`` is not aligned to a 16-byte granule, the kernel
+will use the corresponding aligned address.
+
+``ptrace()`` return value:
+
+- 0 - tags were copied, the tracer's ``iov_len`` was updated to the
+  number of tags transferred. This may be smaller than the requested
+  ``iov_len`` if the requested address range in the tracee's or the
+  tracer's space cannot be accessed or does not have valid tags.
+- ``-EPERM`` - the specified process cannot be traced.
+- ``-EIO`` - the tracee's address range cannot be accessed (e.g. invalid
+  address) and no tags copied. ``iov_len`` not updated.
+- ``-EFAULT`` - fault on accessing the tracer's memory (``struct iovec``
+  or ``iov_base`` buffer) and no tags copied. ``iov_len`` not updated.
+- ``-EOPNOTSUPP`` - the tracee's address does not have valid tags (never
+  mapped with the ``PROT_MTE`` flag). ``iov_len`` not updated.
+
+**Note**: There are no transient errors for the requests above, so user
+programs should not retry in case of a non-zero system call return.
+
+``PTRACE_GETREGSET`` and ``PTRACE_SETREGSET`` with ``addr ==
+``NT_ARM_TAGGED_ADDR_CTRL`` allow ``ptrace()`` access to the tagged
+address ABI control and MTE configuration of a process as per the
+``prctl()`` options described in
+Documentation/arm64/tagged-address-abi.rst and above. The corresponding
+``regset`` is 1 element of 8 bytes (``sizeof(long))``).
+
+Example of correct usage
+========================
+
+*MTE Example code*
+
+.. code-block:: c
+
+    /*
+     * To be compiled with -march=armv8.5-a+memtag
+     */
+    #include <errno.h>
+    #include <stdint.h>
+    #include <stdio.h>
+    #include <stdlib.h>
+    #include <unistd.h>
+    #include <sys/auxv.h>
+    #include <sys/mman.h>
+    #include <sys/prctl.h>
+
+    /*
+     * From arch/arm64/include/uapi/asm/hwcap.h
+     */
+    #define HWCAP2_MTE              (1 << 18)
+
+    /*
+     * From arch/arm64/include/uapi/asm/mman.h
+     */
+    #define PROT_MTE                 0x20
+
+    /*
+     * From include/uapi/linux/prctl.h
+     */
+    #define PR_SET_TAGGED_ADDR_CTRL 55
+    #define PR_GET_TAGGED_ADDR_CTRL 56
+    # define PR_TAGGED_ADDR_ENABLE  (1UL << 0)
+    # define PR_MTE_TCF_SHIFT       1
+    # define PR_MTE_TCF_NONE        (0UL << PR_MTE_TCF_SHIFT)
+    # define PR_MTE_TCF_SYNC        (1UL << PR_MTE_TCF_SHIFT)
+    # define PR_MTE_TCF_ASYNC       (2UL << PR_MTE_TCF_SHIFT)
+    # define PR_MTE_TCF_MASK        (3UL << PR_MTE_TCF_SHIFT)
+    # define PR_MTE_TAG_SHIFT       3
+    # define PR_MTE_TAG_MASK        (0xffffUL << PR_MTE_TAG_SHIFT)
+
+    /*
+     * Insert a random logical tag into the given pointer.
+     */
+    #define insert_random_tag(ptr) ({                       \
+            uint64_t __val;                                 \
+            asm("irg %0, %1" : "=r" (__val) : "r" (ptr));   \
+            __val;                                          \
+    })
+
+    /*
+     * Set the allocation tag on the destination address.
+     */
+    #define set_tag(tagged_addr) do {                                      \
+            asm volatile("stg %0, [%0]" : : "r" (tagged_addr) : "memory"); \
+    } while (0)
+
+    int main()
+    {
+            unsigned char *a;
+            unsigned long page_sz = sysconf(_SC_PAGESIZE);
+            unsigned long hwcap2 = getauxval(AT_HWCAP2);
+
+            /* check if MTE is present */
+            if (!(hwcap2 & HWCAP2_MTE))
+                    return EXIT_FAILURE;
+
+            /*
+             * Enable the tagged address ABI, synchronous MTE tag check faults and
+             * allow all non-zero tags in the randomly generated set.
+             */
+            if (prctl(PR_SET_TAGGED_ADDR_CTRL,
+                      PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | (0xfffe << PR_MTE_TAG_SHIFT),
+                      0, 0, 0)) {
+                    perror("prctl() failed");
+                    return EXIT_FAILURE;
+            }
+
+            a = mmap(0, page_sz, PROT_READ | PROT_WRITE,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+            if (a == MAP_FAILED) {
+                    perror("mmap() failed");
+                    return EXIT_FAILURE;
+            }
+
+            /*
+             * Enable MTE on the above anonymous mmap. The flag could be passed
+             * directly to mmap() and skip this step.
+             */
+            if (mprotect(a, page_sz, PROT_READ | PROT_WRITE | PROT_MTE)) {
+                    perror("mprotect() failed");
+                    return EXIT_FAILURE;
+            }
+
+            /* access with the default tag (0) */
+            a[0] = 1;
+            a[1] = 2;
+
+            printf("a[0] = %hhu a[1] = %hhu\n", a[0], a[1]);
+
+            /* set the logical and allocation tags */
+            a = (unsigned char *)insert_random_tag(a);
+            set_tag(a);
+
+            printf("%p\n", a);
+
+            /* non-zero tag access */
+            a[0] = 3;
+            printf("a[0] = %hhu a[1] = %hhu\n", a[0], a[1]);
+
+            /*
+             * If MTE is enabled correctly the next instruction will generate an
+             * exception.
+             */
+            printf("Expecting SIGSEGV...\n");
+            a[16] = 0xdd;
+
+            /* this should not be printed in the PR_MTE_TCF_SYNC mode */
+            printf("...haven't got one\n");
+
+            return EXIT_FAILURE;
+    }
index 75f943f..6a615cd 100644 (file)
@@ -182,9 +182,6 @@ in the order of reservations, but only after all previous records where
 already committed. It is thus possible for slow producers to temporarily hold
 off submitted records, that were reserved later.
 
-Reservation/commit/consumer protocol is verified by litmus tests in
-Documentation/litmus_tests/bpf-rb/_.
-
 One interesting implementation bit, that significantly simplifies (and thus
 speeds up as well) implementation of both producers and consumers is how data
 area is mapped twice contiguously back-to-back in the virtual memory. This
@@ -200,7 +197,7 @@ a self-pacing notifications of new data being availability.
 being available after commit only if consumer has already caught up right up to
 the record being committed. If not, consumer still has to catch up and thus
 will see new data anyways without needing an extra poll notification.
-Benchmarks (see tools/testing/selftests/bpf/benchs/bench_ringbuf.c_) show that
+Benchmarks (see tools/testing/selftests/bpf/benchs/bench_ringbufs.c) show that
 this allows to achieve a very high throughput without having to resort to
 tricks like "notify only every Nth sample", which are necessary with perf
 buffer. For extreme cases, when BPF program wants more manual control of
index c503188..0a102d5 100644 (file)
@@ -36,10 +36,23 @@ needs_sphinx = '1.3'
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain',
+extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include',
               'kfigure', 'sphinx.ext.ifconfig', 'automarkup',
               'maintainers_include', 'sphinx.ext.autosectionlabel' ]
 
+#
+# cdomain is badly broken in Sphinx 3+.  Leaving it out generates *most*
+# of the docs correctly, but not all.  Scream bloody murder but allow
+# the process to proceed; hopefully somebody will fix this properly soon.
+#
+if major >= 3:
+    sys.stderr.write('''WARNING: The kernel documentation build process
+       does not work correctly with Sphinx v3.0 and above.  Expect errors
+       in the generated output.
+       ''')
+else:
+    extensions.append('cdomain')
+
 # Ensure that autosectionlabel will produce unique names
 autosectionlabel_prefix_document = True
 autosectionlabel_maxdepth = 2
index 298c9c8..a2c96be 100644 (file)
@@ -30,7 +30,7 @@ which didn't support these methods.
 Command Line Switches
 =====================
 ``maxcpus=n``
-  Restrict boot time CPUs to *n*. Say if you have fourV CPUs, using
+  Restrict boot time CPUs to *n*. Say if you have four CPUs, using
   ``maxcpus=2`` will only boot two. You can choose to bring the
   other CPUs later online.
 
index 52019e9..b45dabb 100644 (file)
@@ -296,15 +296,16 @@ follows:
 
     struct sockaddr_alg sa = {
         .salg_family = AF_ALG,
-        .salg_type = "rng", /* this selects the symmetric cipher */
-        .salg_name = "drbg_nopr_sha256" /* this is the cipher name */
+        .salg_type = "rng", /* this selects the random number generator */
+        .salg_name = "drbg_nopr_sha256" /* this is the RNG name */
     };
 
 
 Depending on the RNG type, the RNG must be seeded. The seed is provided
 using the setsockopt interface to set the key. For example, the
 ansi_cprng requires a seed. The DRBGs do not require a seed, but may be
-seeded.
+seeded. The seed is also known as a *Personalization String* in NIST SP 800-90A
+standard.
 
 Using the read()/recvmsg() system calls, random numbers can be obtained.
 The kernel generates at most 128 bytes in one call. If user space
@@ -314,6 +315,16 @@ WARNING: The user space caller may invoke the initially mentioned accept
 system call multiple times. In this case, the returned file descriptors
 have the same state.
 
+Following CAVP testing interfaces are enabled when kernel is built with
+CRYPTO_USER_API_RNG_CAVP option:
+
+-  the concatenation of *Entropy* and *Nonce* can be provided to the RNG via
+   ALG_SET_DRBG_ENTROPY setsockopt interface. Setting the entropy requires
+   CAP_SYS_ADMIN permission.
+
+-  *Additional Data* can be provided using the send()/sendmsg() system calls,
+   but only after the entropy has been set.
+
 Zero-Copy Interface
 -------------------
 
@@ -377,6 +388,9 @@ mentioned optname:
    provided ciphertext is assumed to contain an authentication tag of
    the given size (see section about AEAD memory layout below).
 
+-  ALG_SET_DRBG_ENTROPY -- Setting the entropy of the random number generator.
+   This option is applicable to RNG cipher type only.
+
 User space API example
 ----------------------
 
index 17e4f20..6834f5e 100644 (file)
@@ -23,7 +23,7 @@ properties:
   compatible:
     items:
       - const: raspberrypi,bcm2835-firmware
-      - const: simple-bus
+      - const: simple-mfd
 
   mboxes:
     $ref: '/schemas/types.yaml#/definitions/phandle'
@@ -57,7 +57,7 @@ required:
 examples:
   - |
     firmware {
-        compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
+        compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
         mboxes = <&mailbox>;
 
         firmware_clocks: clocks {
index 85ef69f..1465c9e 100644 (file)
@@ -67,7 +67,7 @@ examples:
 
     main_crypto: crypto@4e00000 {
         compatible = "ti,j721-sa2ul";
-        reg = <0x0 0x4e00000 0x0 0x1200>;
+        reg = <0x4e00000 0x1200>;
         power-domains = <&k3_pds 264 TI_SCI_PD_EXCLUSIVE>;
         dmas = <&main_udmap 0xc000>, <&main_udmap 0x4000>,
                <&main_udmap 0x4001>;
index 52a939c..7b9d468 100644 (file)
@@ -145,10 +145,10 @@ examples:
 
     display@fd4a0000 {
         compatible = "xlnx,zynqmp-dpsub-1.7";
-        reg = <0x0 0xfd4a0000 0x0 0x1000>,
-              <0x0 0xfd4aa000 0x0 0x1000>,
-              <0x0 0xfd4ab000 0x0 0x1000>,
-              <0x0 0xfd4ac000 0x0 0x1000>;
+        reg = <0xfd4a0000 0x1000>,
+              <0xfd4aa000 0x1000>,
+              <0xfd4ab000 0x1000>,
+              <0xfd4ac000 0x1000>;
         reg-names = "dp", "blend", "av_buf", "aud";
         interrupts = <0 119 4>;
         interrupt-parent = <&gic>;
index 5de510f..2a595b1 100644 (file)
@@ -57,7 +57,7 @@ examples:
 
     dma: dma-controller@fd4c0000 {
       compatible = "xlnx,zynqmp-dpdma";
-      reg = <0x0 0xfd4c0000 0x0 0x1000>;
+      reg = <0xfd4c0000 0x1000>;
       interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
       interrupt-parent = <&gic>;
       clocks = <&dpdma_clk>;
diff --git a/Documentation/devicetree/bindings/edac/amazon,al-mc-edac.yaml b/Documentation/devicetree/bindings/edac/amazon,al-mc-edac.yaml
new file mode 100644 (file)
index 0000000..a25387d
--- /dev/null
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/edac/amazon,al-mc-edac.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amazon's Annapurna Labs Memory Controller EDAC
+
+maintainers:
+  - Talel Shenhar <talel@amazon.com>
+  - Talel Shenhar <talelshenhar@gmail.com>
+
+description: |
+  EDAC node is defined to describe on-chip error detection and correction for
+  Amazon's Annapurna Labs Memory Controller.
+
+properties:
+
+  compatible:
+    const: amazon,al-mc-edac
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 2
+
+  "#size-cells":
+    const: 2
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+    items:
+      - description: uncorrectable error interrupt
+      - description: correctable error interrupt
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 2
+    items:
+      - const: ue
+      - const: ce
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+        edac@f0080000 {
+          #address-cells = <2>;
+          #size-cells = <2>;
+          compatible = "amazon,al-mc-edac";
+          reg = <0x0 0xf0080000 0x0 0x00010000>;
+          interrupt-parent = <&amazon_al_system_fabric>;
+          interrupt-names = "ue";
+          interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
+        };
+    };
index d4d8391..be329ea 100644 (file)
@@ -20,8 +20,9 @@ Required properties:
 - gpio-controller : Marks the device node as a GPIO controller
 - interrupts : Interrupt specifier, see interrupt-controller/interrupts.txt
 - interrupt-controller : Mark the GPIO controller as an interrupt-controller
-- ngpios : number of GPIO lines, see gpio.txt
-  (should be multiple of 8, up to 80 pins)
+- ngpios : number of *hardware* GPIO lines, see gpio.txt. This will expose
+  2 software GPIOs per hardware GPIO: one for hardware input, one for hardware
+  output. Up to 80 pins, must be a multiple of 8.
 - clocks : A phandle to the APB clock for SGPM clock division
 - bus-frequency : SGPM CLK frequency
 
diff --git a/Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml b/Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml
new file mode 100644 (file)
index 0000000..5da333c
--- /dev/null
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/actions,owl-sirq.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Actions Semi Owl SoCs SIRQ interrupt controller
+
+maintainers:
+  - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+  - Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+
+description: |
+  This interrupt controller is found in the Actions Semi Owl SoCs (S500, S700
+  and S900) and provides support for handling up to 3 external interrupt lines.
+
+properties:
+  compatible:
+    enum:
+      - actions,s500-sirq
+      - actions,s700-sirq
+      - actions,s900-sirq
+
+  reg:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+    description:
+      The first cell is the input IRQ number, between 0 and 2, while the second
+      cell is the trigger type as defined in interrupt.txt in this directory.
+
+  'interrupts':
+    description: |
+      Contains the GIC SPI IRQs mapped to the external interrupt lines.
+      They shall be specified sequentially from output 0 to 2.
+    minItems: 3
+    maxItems: 3
+
+required:
+  - compatible
+  - reg
+  - interrupt-controller
+  - '#interrupt-cells'
+  - 'interrupts'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    sirq: interrupt-controller@b01b0200 {
+      compatible = "actions,s500-sirq";
+      reg = <0xb01b0200 0x4>;
+      interrupt-controller;
+      #interrupt-cells = <2>;
+      interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>, /* SIRQ0 */
+                   <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>, /* SIRQ1 */
+                   <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; /* SIRQ2 */
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/interrupt-controller/mstar,mst-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/mstar,mst-intc.yaml
new file mode 100644 (file)
index 0000000..bbf0f26
--- /dev/null
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/mstar,mst-intc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MStar Interrupt Controller
+
+maintainers:
+  - Mark-PK Tsai <mark-pk.tsai@mediatek.com>
+
+description: |+
+  MStar, SigmaStar and Mediatek TV SoCs contain multiple legacy
+  interrupt controllers that routes interrupts to the GIC.
+
+  The HW block exposes a number of interrupt controllers, each
+  can support up to 64 interrupts.
+
+properties:
+  compatible:
+    const: mstar,mst-intc
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 3
+    description: |
+      Use the same format as specified by GIC in arm,gic.yaml.
+
+  reg:
+    maxItems: 1
+
+  mstar,irqs-map-range:
+    description: |
+      The range <start, end> of parent interrupt controller's interrupt
+      lines that are hardwired to mstar interrupt controller.
+    $ref: /schemas/types.yaml#/definitions/uint32-matrix
+    items:
+      minItems: 2
+      maxItems: 2
+
+  mstar,intc-no-eoi:
+    description:
+      Mark this controller has no End Of Interrupt(EOI) implementation.
+    type: boolean
+
+required:
+  - compatible
+  - reg
+  - mstar,irqs-map-range
+
+additionalProperties: false
+
+examples:
+  - |
+    mst_intc0: interrupt-controller@1f2032d0 {
+      compatible = "mstar,mst-intc";
+      interrupt-controller;
+      #interrupt-cells = <3>;
+      interrupt-parent = <&gic>;
+      reg = <0x1f2032d0 0x30>;
+      mstar,irqs-map-range = <0 63>;
+    };
+...
index 086ff08..2db59df 100644 (file)
@@ -2,7 +2,8 @@ Synopsys DesignWare APB interrupt controller (dw_apb_ictl)
 
 Synopsys DesignWare provides interrupt controller IP for APB known as
 dw_apb_ictl. The IP is used as secondary interrupt controller in some SoCs with
-APB bus, e.g. Marvell Armada 1500.
+APB bus, e.g. Marvell Armada 1500. It can also be used as primary interrupt
+controller in some SoCs, e.g. Hisilicon SD5203.
 
 Required properties:
 - compatible: shall be "snps,dw-apb-ictl"
@@ -10,6 +11,8 @@ Required properties:
   region starting with ENABLE_LOW register
 - interrupt-controller: identifies the node as an interrupt controller
 - #interrupt-cells: number of cells to encode an interrupt-specifier, shall be 1
+
+Additional required property when it's used as secondary interrupt controller:
 - interrupts: interrupt reference to primary interrupt controller
 
 The interrupt sources map to the corresponding bits in the interrupt
@@ -21,6 +24,7 @@ registers, i.e.
 - (optional) fast interrupts start at 64.
 
 Example:
+       /* dw_apb_ictl is used as secondary interrupt controller */
        aic: interrupt-controller@3000 {
                compatible = "snps,dw-apb-ictl";
                reg = <0x3000 0xc00>;
@@ -29,3 +33,11 @@ Example:
                interrupt-parent = <&gic>;
                interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
        };
+
+       /* dw_apb_ictl is used as primary interrupt controller */
+       vic: interrupt-controller@10130000 {
+               compatible = "snps,dw-apb-ictl";
+               reg = <0x10130000 0x1000>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+       };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.yaml
new file mode 100644 (file)
index 0000000..bbf79d1
--- /dev/null
@@ -0,0 +1,158 @@
+# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/ti,pruss-intc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI PRU-ICSS Local Interrupt Controller
+
+maintainers:
+  - Suman Anna <s-anna@ti.com>
+
+description: |
+  Each PRU-ICSS has a single interrupt controller instance that is common
+  to all the PRU cores. Most interrupt controllers can route 64 input events
+  which are then mapped to 10 possible output interrupts through two levels
+  of mapping. The input events can be triggered by either the PRUs and/or
+  various other PRUSS internal and external peripherals. The first 2 output
+  interrupts (0, 1) are fed exclusively to the internal PRU cores, with the
+  remaining 8 (2 through 9) connected to external interrupt controllers
+  including the MPU and/or other PRUSS instances, DSPs or devices.
+
+  The property "ti,irqs-reserved" is used for denoting the connection
+  differences on the output interrupts 2 through 9. If this property is not
+  defined, it implies that all the PRUSS INTC output interrupts 2 through 9
+  (host_intr0 through host_intr7) are connected exclusively to the Arm interrupt
+  controller.
+
+  The K3 family of SoCs can handle 160 input events that can be mapped to 20
+  different possible output interrupts. The additional output interrupts (10
+  through 19) are connected to new sub-modules within the ICSSG instances.
+
+  This interrupt-controller node should be defined as a child node of the
+  corresponding PRUSS node. The node should be named "interrupt-controller".
+
+properties:
+  compatible:
+    enum:
+      - ti,pruss-intc
+      - ti,icssg-intc
+    description: |
+      Use "ti,pruss-intc" for OMAP-L13x/AM18x/DA850 SoCs,
+                              AM335x family of SoCs,
+                              AM437x family of SoCs,
+                              AM57xx family of SoCs
+                              66AK2G family of SoCs
+      Use "ti,icssg-intc" for K3 AM65x & J721E family of SoCs
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 8
+    description: |
+      All the interrupts generated towards the main host processor in the SoC.
+      A shared interrupt can be skipped if the desired destination and usage is
+      by a different processor/device.
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 8
+    items:
+      pattern: host_intr[0-7]
+    description: |
+      Should use one of the above names for each valid host event interrupt
+      connected to Arm interrupt controller, the name should match the
+      corresponding host event interrupt number.
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 3
+    description: |
+      Client users shall use the PRU System event number (the interrupt source
+      that the client is interested in) [cell 1], PRU channel [cell 2] and PRU
+      host_event (target) [cell 3] as the value of the interrupts property in
+      their node.  The system events can be mapped to some output host
+      interrupts through 2 levels of many-to-one mapping i.e. events to channel
+      mapping and channels to host interrupts so through this property entire
+      mapping is provided.
+
+  ti,irqs-reserved:
+    $ref: /schemas/types.yaml#definitions/uint8
+    description: |
+      Bitmask of host interrupts between 0 and 7 (corresponding to PRUSS INTC
+      output interrupts 2 through 9) that are not connected to the Arm interrupt
+      controller or are shared and used by other devices or processors in the
+      SoC. Define this property when any of 8 interrupts should not be handled
+      by Arm interrupt controller.
+        Eg: - AM437x and 66AK2G SoCs do not have "host_intr5" interrupt
+              connected to MPU
+            - AM65x and J721E SoCs have "host_intr5", "host_intr6" and
+              "host_intr7" interrupts connected to MPU, and other ICSSG
+              instances.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - interrupt-names
+ - interrupt-controller
+ - "#interrupt-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    /* AM33xx PRU-ICSS */
+    pruss: pruss@0 {
+        compatible = "ti,am3356-pruss";
+        reg = <0x0 0x80000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges;
+
+        pruss_intc: interrupt-controller@20000 {
+            compatible = "ti,pruss-intc";
+            reg = <0x20000 0x2000>;
+            interrupts = <20 21 22 23 24 25 26 27>;
+            interrupt-names = "host_intr0", "host_intr1",
+                              "host_intr2", "host_intr3",
+                              "host_intr4", "host_intr5",
+                              "host_intr6", "host_intr7";
+            interrupt-controller;
+            #interrupt-cells = <3>;
+        };
+    };
+
+  - |
+
+    /* AM4376 PRU-ICSS */
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    pruss@0 {
+        compatible = "ti,am4376-pruss";
+        reg = <0x0 0x40000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges;
+
+        interrupt-controller@20000 {
+            compatible = "ti,pruss-intc";
+            reg = <0x20000 0x2000>;
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+            interrupt-names = "host_intr0", "host_intr1",
+                              "host_intr2", "host_intr3",
+                              "host_intr4",
+                              "host_intr6", "host_intr7";
+            ti,irqs-reserved = /bits/ 8 <0x20>; /* BIT(5) */
+        };
+    };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
deleted file mode 100644 (file)
index 7841cb0..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-Texas Instruments K3 Interrupt Aggregator
-=========================================
-
-The Interrupt Aggregator (INTA) provides a centralized machine
-which handles the termination of system events to that they can
-be coherently processed by the host(s) in the system. A maximum
-of 64 events can be mapped to a single interrupt.
-
-
-                              Interrupt Aggregator
-                     +-----------------------------------------+
-                     |      Intmap            VINT             |
-                     | +--------------+  +------------+        |
-            m ------>| | vint  | bit  |  | 0 |.....|63| vint0  |
-               .     | +--------------+  +------------+        |       +------+
-               .     |         .               .               |       | HOST |
-Globalevents  ------>|         .               .               |------>| IRQ  |
-               .     |         .               .               |       | CTRL |
-               .     |         .               .               |       +------+
-            n ------>| +--------------+  +------------+        |
-                     | | vint  | bit  |  | 0 |.....|63| vintx  |
-                     | +--------------+  +------------+        |
-                     |                                         |
-                     +-----------------------------------------+
-
-Configuration of these Intmap registers that maps global events to vint is done
-by a system controller (like the Device Memory and Security Controller on K3
-AM654 SoC). Driver should request the system controller to get the range
-of global events and vints assigned to the requesting host. Management
-of these requested resources should be handled by driver and requests
-system controller to map specific global event to vint, bit pair.
-
-Communication between the host processor running an OS and the system
-controller happens through a protocol called TI System Control Interface
-(TISCI protocol). For more details refer:
-Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
-
-TISCI Interrupt Aggregator Node:
--------------------------------
-- compatible:          Must be "ti,sci-inta".
-- reg:                 Should contain registers location and length.
-- interrupt-controller:        Identifies the node as an interrupt controller
-- msi-controller:      Identifies the node as an MSI controller.
-- interrupt-parent:    phandle of irq parent.
-- ti,sci:              Phandle to TI-SCI compatible System controller node.
-- ti,sci-dev-id:       TISCI device ID of the Interrupt Aggregator.
-- ti,sci-rm-range-vint:        Array of TISCI subtype ids representing vints(inta
-                       outputs) range within this INTA, assigned to the
-                       requesting host context.
-- ti,sci-rm-range-global-event:        Array of TISCI subtype ids representing the
-                       global events range reaching this IA and are assigned
-                       to the requesting host context.
-
-Example:
---------
-main_udmass_inta: interrupt-controller@33d00000 {
-       compatible = "ti,sci-inta";
-       reg = <0x0 0x33d00000 0x0 0x100000>;
-       interrupt-controller;
-       msi-controller;
-       interrupt-parent = <&main_navss_intr>;
-       ti,sci = <&dmsc>;
-       ti,sci-dev-id = <179>;
-       ti,sci-rm-range-vint = <0x0>;
-       ti,sci-rm-range-global-event = <0x1>;
-};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.yaml b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.yaml
new file mode 100644 (file)
index 0000000..c7cd056
--- /dev/null
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/ti,sci-inta.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments K3 Interrupt Aggregator
+
+maintainers:
+  - Lokesh Vutla <lokeshvutla@ti.com>
+
+allOf:
+  - $ref: /schemas/arm/keystone/ti,k3-sci-common.yaml#
+
+description: |
+  The Interrupt Aggregator (INTA) provides a centralized machine
+  which handles the termination of system events to that they can
+  be coherently processed by the host(s) in the system. A maximum
+  of 64 events can be mapped to a single interrupt.
+
+                                Interrupt Aggregator
+                       +-----------------------------------------+
+                       |      Intmap            VINT             |
+                       | +--------------+  +------------+        |
+              m ------>| | vint  | bit  |  | 0 |.....|63| vint0  |
+                 .     | +--------------+  +------------+        |      +------+
+                 .     |         .               .               |      | HOST |
+  Globalevents  ------>|         .               .               |----->| IRQ  |
+                 .     |         .               .               |      | CTRL |
+                 .     |         .               .               |      +------+
+              n ------>| +--------------+  +------------+        |
+                       | | vint  | bit  |  | 0 |.....|63| vintx  |
+                       | +--------------+  +------------+        |
+                       |                                         |
+                       +-----------------------------------------+
+
+  Configuration of these Intmap registers that maps global events to vint is
+  done by a system controller (like the Device Memory and Security Controller
+  on AM654 SoC). Driver should request the system controller to get the range
+  of global events and vints assigned to the requesting host. Management
+  of these requested resources should be handled by driver and requests
+  system controller to map specific global event to vint, bit pair.
+
+  Communication between the host processor running an OS and the system
+  controller happens through a protocol called TI System Control Interface
+  (TISCI protocol).
+
+properties:
+  compatible:
+    const: ti,sci-inta
+
+  reg:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  msi-controller: true
+
+  ti,interrupt-ranges:
+    $ref: /schemas/types.yaml#/definitions/uint32-matrix
+    description: |
+      Interrupt ranges that converts the INTA output hw irq numbers
+      to parents's input interrupt numbers.
+    items:
+      items:
+        - description: |
+            "output_irq" specifies the base for inta output irq
+        - description: |
+            "parent's input irq" specifies the base for parent irq
+        - description: |
+            "limit" specifies the limit for translation
+
+required:
+  - compatible
+  - reg
+  - interrupt-controller
+  - msi-controller
+  - ti,sci
+  - ti,sci-dev-id
+  - ti,interrupt-ranges
+
+examples:
+  - |
+    bus {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        main_udmass_inta: msi-controller@33d00000 {
+            compatible = "ti,sci-inta";
+            reg = <0x0 0x33d00000 0x0 0x100000>;
+            interrupt-controller;
+            msi-controller;
+            interrupt-parent = <&main_navss_intr>;
+            ti,sci = <&dmsc>;
+            ti,sci-dev-id = <179>;
+            ti,interrupt-ranges = <0 0 256>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
deleted file mode 100644 (file)
index 178fca0..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-Texas Instruments K3 Interrupt Router
-=====================================
-
-The Interrupt Router (INTR) module provides a mechanism to mux M
-interrupt inputs to N interrupt outputs, where all M inputs are selectable
-to be driven per N output. An Interrupt Router can either handle edge triggered
-or level triggered interrupts and that is fixed in hardware.
-
-                                 Interrupt Router
-                             +----------------------+
-                             |  Inputs     Outputs  |
-        +-------+            | +------+    +-----+  |
-        | GPIO  |----------->| | irq0 |    |  0  |  |       Host IRQ
-        +-------+            | +------+    +-----+  |      controller
-                             |    .           .     |      +-------+
-        +-------+            |    .           .     |----->|  IRQ  |
-        | INTA  |----------->|    .           .     |      +-------+
-        +-------+            |    .        +-----+  |
-                             | +------+    |  N  |  |
-                             | | irqM |    +-----+  |
-                             | +------+             |
-                             |                      |
-                             +----------------------+
-
-There is one register per output (MUXCNTL_N) that controls the selection.
-Configuration of these MUXCNTL_N registers is done by a system controller
-(like the Device Memory and Security Controller on K3 AM654 SoC). System
-controller will keep track of the used and unused registers within the Router.
-Driver should request the system controller to get the range of GIC IRQs
-assigned to the requesting hosts. It is the drivers responsibility to keep
-track of Host IRQs.
-
-Communication between the host processor running an OS and the system
-controller happens through a protocol called TI System Control Interface
-(TISCI protocol). For more details refer:
-Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
-
-TISCI Interrupt Router Node:
-----------------------------
-Required Properties:
-- compatible:          Must be "ti,sci-intr".
-- ti,intr-trigger-type:        Should be one of the following:
-                       1: If intr supports edge triggered interrupts.
-                       4: If intr supports level triggered interrupts.
-- interrupt-controller:        Identifies the node as an interrupt controller
-- #interrupt-cells:    Specifies the number of cells needed to encode an
-                       interrupt source. The value should be 2.
-                       First cell should contain the TISCI device ID of source
-                       Second cell should contain the interrupt source offset
-                       within the device.
-- ti,sci:              Phandle to TI-SCI compatible System controller node.
-- ti,sci-dst-id:       TISCI device ID of the destination IRQ controller.
-- ti,sci-rm-range-girq:        Array of TISCI subtype ids representing the host irqs
-                       assigned to this interrupt router. Each subtype id
-                       corresponds to a range of host irqs.
-
-For more details on TISCI IRQ resource management refer:
-https://downloads.ti.com/tisci/esd/latest/2_tisci_msgs/rm/rm_irq.html
-
-Example:
---------
-The following example demonstrates both interrupt router node and the consumer
-node(main gpio) on the AM654 SoC:
-
-main_intr: interrupt-controller0 {
-       compatible = "ti,sci-intr";
-       ti,intr-trigger-type = <1>;
-       interrupt-controller;
-       interrupt-parent = <&gic500>;
-       #interrupt-cells = <2>;
-       ti,sci = <&dmsc>;
-       ti,sci-dst-id = <56>;
-       ti,sci-rm-range-girq = <0x1>;
-};
-
-main_gpio0: gpio@600000 {
-       ...
-       interrupt-parent = <&main_intr>;
-       interrupts = <57 256>, <57 257>, <57 258>,
-                    <57 259>, <57 260>, <57 261>;
-       ...
-};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.yaml b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.yaml
new file mode 100644 (file)
index 0000000..cff6a95
--- /dev/null
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/ti,sci-intr.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments K3 Interrupt Router
+
+maintainers:
+  - Lokesh Vutla <lokeshvutla@ti.com>
+
+allOf:
+  - $ref: /schemas/arm/keystone/ti,k3-sci-common.yaml#
+
+description: |
+  The Interrupt Router (INTR) module provides a mechanism to mux M
+  interrupt inputs to N interrupt outputs, where all M inputs are selectable
+  to be driven per N output. An Interrupt Router can either handle edge
+  triggered or level triggered interrupts and that is fixed in hardware.
+
+                                   Interrupt Router
+                               +----------------------+
+                               |  Inputs     Outputs  |
+          +-------+            | +------+    +-----+  |
+          | GPIO  |----------->| | irq0 |    |  0  |  |       Host IRQ
+          +-------+            | +------+    +-----+  |      controller
+                               |    .           .     |      +-------+
+          +-------+            |    .           .     |----->|  IRQ  |
+          | INTA  |----------->|    .           .     |      +-------+
+          +-------+            |    .        +-----+  |
+                               | +------+    |  N  |  |
+                               | | irqM |    +-----+  |
+                               | +------+             |
+                               |                      |
+                               +----------------------+
+
+  There is one register per output (MUXCNTL_N) that controls the selection.
+  Configuration of these MUXCNTL_N registers is done by a system controller
+  (like the Device Memory and Security Controller on K3 AM654 SoC). System
+  controller will keep track of the used and unused registers within the Router.
+  Driver should request the system controller to get the range of GIC IRQs
+  assigned to the requesting hosts. It is the drivers responsibility to keep
+  track of Host IRQs.
+
+  Communication between the host processor running an OS and the system
+  controller happens through a protocol called TI System Control Interface
+  (TISCI protocol).
+
+properties:
+  compatible:
+    const: ti,sci-intr
+
+  ti,intr-trigger-type:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [1, 4]
+    description: |
+      Should be one of the following.
+        1 = If intr supports edge triggered interrupts.
+        4 = If intr supports level triggered interrupts.
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 1
+    description: |
+      The 1st cell should contain interrupt router input hw number.
+
+  ti,interrupt-ranges:
+    $ref: /schemas/types.yaml#/definitions/uint32-matrix
+    description: |
+      Interrupt ranges that converts the INTR output hw irq numbers
+      to parents's input interrupt numbers.
+    items:
+      items:
+        - description: |
+            "output_irq" specifies the base for intr output irq
+        - description: |
+            "parent's input irq" specifies the base for parent irq
+        - description: |
+            "limit" specifies the limit for translation
+
+required:
+  - compatible
+  - ti,intr-trigger-type
+  - interrupt-controller
+  - '#interrupt-cells'
+  - ti,sci
+  - ti,sci-dev-id
+  - ti,interrupt-ranges
+
+examples:
+  - |
+    main_gpio_intr: interrupt-controller0 {
+        compatible = "ti,sci-intr";
+        ti,intr-trigger-type = <1>;
+        interrupt-controller;
+        interrupt-parent = <&gic500>;
+        #interrupt-cells = <1>;
+        ti,sci = <&dmsc>;
+        ti,sci-dev-id = <131>;
+        ti,interrupt-ranges = <0 360 32>;
+    };
index 24ad144..fe7fa25 100644 (file)
@@ -30,7 +30,7 @@ properties:
     const: 0
 
 patternProperties:
-  "^multi-led[0-9a-f]$":
+  "^multi-led@[0-9a-b]$":
     type: object
     allOf:
       - $ref: leds-class-multicolor.yaml#
diff --git a/Documentation/devicetree/bindings/media/i2c/imx274.txt b/Documentation/devicetree/bindings/media/i2c/imx274.txt
deleted file mode 100644 (file)
index 0727079..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-* Sony 1/2.5-Inch 8.51Mp CMOS Digital Image Sensor
-
-The Sony imx274 is a 1/2.5-inch CMOS active pixel digital image sensor with
-an active array size of 3864H x 2202V. It is programmable through I2C
-interface. The I2C address is fixed to 0x1a as per sensor data sheet.
-Image data is sent through MIPI CSI-2, which is configured as 4 lanes
-at 1440 Mbps.
-
-
-Required Properties:
-- compatible: value should be "sony,imx274" for imx274 sensor
-- reg: I2C bus address of the device
-
-Optional Properties:
-- reset-gpios: Sensor reset GPIO
-- clocks: Reference to the input clock.
-- clock-names: Should be "inck".
-- VANA-supply: Sensor 2.8v analog supply.
-- VDIG-supply: Sensor 1.8v digital core supply.
-- VDDL-supply: Sensor digital IO 1.2v supply.
-
-The imx274 device node should contain one 'port' child node with
-an 'endpoint' subnode. For further reading on port node refer to
-Documentation/devicetree/bindings/media/video-interfaces.txt.
-
-Example:
-       sensor@1a {
-               compatible = "sony,imx274";
-               reg = <0x1a>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               reset-gpios = <&gpio_sensor 0 0>;
-               port {
-                       sensor_out: endpoint {
-                               remote-endpoint = <&csiss_in>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml
new file mode 100644 (file)
index 0000000..f697e1a
--- /dev/null
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/sony,imx274.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony 1/2.5-Inch 8.51MP CMOS Digital Image Sensor
+
+maintainers:
+  - Leon Luo <leonl@leopardimaging.com>
+
+description: |
+  The Sony IMX274 is a 1/2.5-inch CMOS active pixel digital image sensor with an
+  active array size of 3864H x 2202V. It is programmable through I2C interface.
+  Image data is sent through MIPI CSI-2, which is configured as 4 lanes at 1440
+  Mbps.
+
+properties:
+  compatible:
+    const: sony,imx274
+
+  reg:
+    const: 0x1a
+
+  reset-gpios:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: inck
+
+  vana-supply:
+    description: Sensor 2.8 V analog supply.
+    maxItems: 1
+
+  vdig-supply:
+    description: Sensor 1.8 V digital core supply.
+    maxItems: 1
+
+  vddl-supply:
+    description: Sensor digital IO 1.2 V supply.
+    maxItems: 1
+
+  port:
+    type: object
+    description: Output video port. See ../video-interfaces.txt.
+
+required:
+  - compatible
+  - reg
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        imx274: camera-sensor@1a {
+            compatible = "sony,imx274";
+            reg = <0x1a>;
+            reset-gpios = <&gpio_sensor 0 0>;
+
+            port {
+                sensor_out: endpoint {
+                    remote-endpoint = <&csiss_in>;
+                };
+            };
+        };
+    };
+
+...
index 5887c91..58fe9d0 100644 (file)
@@ -30,9 +30,13 @@ allOf:
     then:
       properties:
         clock-output-names:
-          items:
-            - const: clk_out_sd0
-            - const: clk_in_sd0
+          oneOf:
+            - items:
+              - const: clk_out_sd0
+              - const: clk_in_sd0
+            - items:
+              - const: clk_out_sd1
+              - const: clk_in_sd1
 
 properties:
   compatible:
index 0c9cf6a..26a8f32 100644 (file)
@@ -50,6 +50,8 @@ Optional properties:
                     error caused by stop clock(fifo full)
                     Valid range = [0:0x7]. if not present, default value is 0.
                     applied to compatible "mediatek,mt2701-mmc".
+- resets: Phandle and reset specifier pair to softreset line of MSDC IP.
+- reset-names: Should be "hrst".
 
 Examples:
 mmc0: mmc@11230000 {
index 2cf3aff..96c0b14 100644 (file)
@@ -15,8 +15,15 @@ Required properties:
   - "nvidia,tegra210-sdhci": for Tegra210
   - "nvidia,tegra186-sdhci": for Tegra186
   - "nvidia,tegra194-sdhci": for Tegra194
-- clocks : Must contain one entry, for the module clock.
-  See ../clocks/clock-bindings.txt for details.
+- clocks: For Tegra210, Tegra186 and Tegra194 must contain two entries.
+         One for the module clock and one for the timeout clock.
+         For all other Tegra devices, must contain a single entry for
+         the module clock. See ../clocks/clock-bindings.txt for details.
+- clock-names: For Tegra210, Tegra186 and Tegra194 must contain the
+              strings 'sdhci' and 'tmclk' to represent the module and
+              the timeout clocks, respectively.
+              For all other Tegra devices must contain the string 'sdhci'
+              to represent the module clock.
 - resets : Must contain an entry for each entry in reset-names.
   See ../reset/reset.txt for details.
 - reset-names : Must include the following entries:
@@ -99,7 +106,7 @@ Optional properties for Tegra210, Tegra186 and Tegra194:
 
 Example:
 sdhci@700b0000 {
-       compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
+       compatible = "nvidia,tegra124-sdhci";
        reg = <0x0 0x700b0000 0x0 0x200>;
        interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
        clocks = <&tegra_car TEGRA210_CLK_SDMMC1>;
@@ -115,3 +122,22 @@ sdhci@700b0000 {
        nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>;
        status = "disabled";
 };
+
+sdhci@700b0000 {
+       compatible = "nvidia,tegra210-sdhci";
+       reg = <0x0 0x700b0000 0x0 0x200>;
+       interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&tegra_car TEGRA210_CLK_SDMMC1>,
+                <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
+       clock-names = "sdhci", "tmclk";
+       resets = <&tegra_car 14>;
+       reset-names = "sdhci";
+       pinctrl-names = "sdmmc-3v3", "sdmmc-1v8";
+       pinctrl-0 = <&sdmmc1_3v3>;
+       pinctrl-1 = <&sdmmc1_1v8>;
+       nvidia,pad-autocal-pull-up-offset-3v3 = <0x00>;
+       nvidia,pad-autocal-pull-down-offset-3v3 = <0x7d>;
+       nvidia,pad-autocal-pull-up-offset-1v8 = <0x7b>;
+       nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>;
+       status = "disabled";
+};
index bf7328a..dab208b 100644 (file)
@@ -1,4 +1,4 @@
 Distributed Switch Architecture Device Tree Bindings
 ----------------------------------------------------
 
-See Documentation/devicetree/bindings/net/dsa/dsa.yaml for the documenation.
+See Documentation/devicetree/bindings/net/dsa/dsa.yaml for the documentation.
index 032b76f..9119f1c 100644 (file)
@@ -21,6 +21,7 @@ Required properties:
       - "renesas,etheravb-r8a774a1" for the R8A774A1 SoC.
       - "renesas,etheravb-r8a774b1" for the R8A774B1 SoC.
       - "renesas,etheravb-r8a774c0" for the R8A774C0 SoC.
+      - "renesas,etheravb-r8a774e1" for the R8A774E1 SoC.
       - "renesas,etheravb-r8a7795" for the R8A7795 SoC.
       - "renesas,etheravb-r8a7796" for the R8A77960 SoC.
       - "renesas,etheravb-r8a77961" for the R8A77961 SoC.
diff --git a/Documentation/devicetree/bindings/perf/arm,cmn.yaml b/Documentation/devicetree/bindings/perf/arm,cmn.yaml
new file mode 100644 (file)
index 0000000..e4fcc0d
--- /dev/null
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2020 Arm Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/perf/arm,cmn.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Arm CMN (Coherent Mesh Network) Performance Monitors
+
+maintainers:
+  - Robin Murphy <robin.murphy@arm.com>
+
+properties:
+  compatible:
+    const: arm,cmn-600
+
+  reg:
+    items:
+      - description: Physical address of the base (PERIPHBASE) and
+          size (up to 64MB) of the configuration address space.
+
+  interrupts:
+    minItems: 1
+    maxItems: 4
+    items:
+      - description: Overflow interrupt for DTC0
+      - description: Overflow interrupt for DTC1
+      - description: Overflow interrupt for DTC2
+      - description: Overflow interrupt for DTC3
+    description: One interrupt for each DTC domain implemented must
+      be specified, in order. DTC0 is always present.
+
+  arm,root-node:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Offset from PERIPHBASE of the configuration
+      discovery node (see TRM definition of ROOTNODEBASE).
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - arm,root-node
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    pmu@50000000 {
+        compatible = "arm,cmn-600";
+        reg = <0x50000000 0x4000000>;
+        /* 4x2 mesh with one DTC, and CFG node at 0,1,1,0 */
+        interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+        arm,root-node = <0x104000>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/rng/ingenic,trng.yaml b/Documentation/devicetree/bindings/rng/ingenic,trng.yaml
new file mode 100644 (file)
index 0000000..808f247
--- /dev/null
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rng/ingenic,trng.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for DTRNG in Ingenic SoCs
+
+maintainers:
+  - 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
+
+description:
+  The True Random Number Generator in Ingenic SoCs.
+
+properties:
+  compatible:
+    enum:
+      - ingenic,x1830-dtrng
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/x1830-cgu.h>
+
+    dtrng: trng@10072000 {
+        compatible = "ingenic,x1830-dtrng";
+        reg = <0x10072000 0xc>;
+
+        clocks = <&cgu X1830_CLK_DTRNG>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/rng/xiphera,xip8001b-trng.yaml b/Documentation/devicetree/bindings/rng/xiphera,xip8001b-trng.yaml
new file mode 100644 (file)
index 0000000..1e17e55
--- /dev/null
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rng/xiphera,xip8001b-trng.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Xiphera XIP8001B-trng bindings
+
+maintainers:
+  - Atte Tommiska <atte.tommiska@xiphera.com>
+
+description: |
+  Xiphera FPGA-based true random number generator intellectual property core.
+
+properties:
+  compatible:
+    const: xiphera,xip8001b-trng
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    rng@43c00000 {
+        compatible = "xiphera,xip8001b-trng";
+        reg = <0x43c00000 0x10000>;
+    };
index f5e518d..62d4ed2 100644 (file)
@@ -23,8 +23,8 @@ Required properties:
 
 - compatible:
     Must be one of :
-    "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-qspi" : MSPI+BSPI on BRCMSTB SoCs
-    "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
+    "brcm,spi-brcmstb-qspi", "brcm,spi-bcm-qspi" : MSPI+BSPI on BRCMSTB SoCs
+    "brcm,spi-brcmstb-mspi", "brcm,spi-bcm-qspi" : Second Instance of MSPI
                                                   BRCMSTB  SoCs
     "brcm,spi-bcm7425-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
                                                                            BRCMSTB  SoCs
@@ -36,8 +36,8 @@ Required properties:
                                                                            BRCMSTB  SoCs
     "brcm,spi-bcm7278-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
                                                                            BRCMSTB  SoCs
-    "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi"     : MSPI+BSPI on Cygnus, NSP
-    "brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi"     : NS2 SoCs
+    "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi"     : MSPI+BSPI on Cygnus, NSP
+    "brcm,spi-ns2-qspi", "brcm,spi-bcm-qspi"     : NS2 SoCs
 
 - reg:
     Define the bases and ranges of the associated I/O address spaces.
@@ -86,7 +86,7 @@ BRCMSTB SoC Example:
     spi@f03e3400 {
                #address-cells = <0x1>;
                #size-cells = <0x0>;
-               compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-brcmstb-qspi";
+               compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-bcm-qspi";
                reg = <0xf03e0920 0x4 0xf03e3400 0x188 0xf03e3200 0x50>;
                reg-names = "cs_reg", "mspi", "bspi";
                interrupts = <0x6 0x5 0x4 0x3 0x2 0x1 0x0>;
@@ -149,7 +149,7 @@ BRCMSTB SoC Example:
                #address-cells = <1>;
                #size-cells = <0>;
                clocks = <&upg_fixed>;
-               compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-brcmstb-mspi";
+               compatible = "brcm,spi-brcmstb-mspi", "brcm,spi-bcm-qspi";
                reg = <0xf0416000 0x180>;
                reg-names = "mspi";
                interrupts = <0x14>;
@@ -160,7 +160,7 @@ BRCMSTB SoC Example:
 iProc SoC Example:
 
     qspi: spi@18027200 {
-       compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi";
+       compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi";
        reg = <0x18027200 0x184>,
              <0x18027000 0x124>,
              <0x1811c408 0x004>,
@@ -191,7 +191,7 @@ iProc SoC Example:
  NS2 SoC Example:
 
               qspi: spi@66470200 {
-                      compatible = "brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi";
+                      compatible = "brcm,spi-ns2-qspi", "brcm,spi-bcm-qspi";
                       reg = <0x66470200 0x184>,
                             <0x66470000 0x124>,
                             <0x67017408 0x004>,
index 7e4dc56..428db3a 100644 (file)
@@ -39,6 +39,7 @@ properties:
       - items:
           - enum:
               - renesas,r8a73a4-cmt0      # 32-bit CMT0 on R-Mobile APE6
+              - renesas,r8a7742-cmt0      # 32-bit CMT0 on RZ/G1H
               - renesas,r8a7743-cmt0      # 32-bit CMT0 on RZ/G1M
               - renesas,r8a7744-cmt0      # 32-bit CMT0 on RZ/G1N
               - renesas,r8a7745-cmt0      # 32-bit CMT0 on RZ/G1E
@@ -53,6 +54,7 @@ properties:
       - items:
           - enum:
               - renesas,r8a73a4-cmt1      # 48-bit CMT1 on R-Mobile APE6
+              - renesas,r8a7742-cmt1      # 48-bit CMT1 on RZ/G1H
               - renesas,r8a7743-cmt1      # 48-bit CMT1 on RZ/G1M
               - renesas,r8a7744-cmt1      # 48-bit CMT1 on RZ/G1N
               - renesas,r8a7745-cmt1      # 48-bit CMT1 on RZ/G1E
@@ -69,6 +71,7 @@ properties:
               - renesas,r8a774a1-cmt0     # 32-bit CMT0 on RZ/G2M
               - renesas,r8a774b1-cmt0     # 32-bit CMT0 on RZ/G2N
               - renesas,r8a774c0-cmt0     # 32-bit CMT0 on RZ/G2E
+              - renesas,r8a774e1-cmt0     # 32-bit CMT0 on RZ/G2H
               - renesas,r8a7795-cmt0      # 32-bit CMT0 on R-Car H3
               - renesas,r8a7796-cmt0      # 32-bit CMT0 on R-Car M3-W
               - renesas,r8a77965-cmt0     # 32-bit CMT0 on R-Car M3-N
@@ -83,6 +86,7 @@ properties:
               - renesas,r8a774a1-cmt1     # 48-bit CMT on RZ/G2M
               - renesas,r8a774b1-cmt1     # 48-bit CMT on RZ/G2N
               - renesas,r8a774c0-cmt1     # 48-bit CMT on RZ/G2E
+              - renesas,r8a774e1-cmt1     # 48-bit CMT on RZ/G2H
               - renesas,r8a7795-cmt1      # 48-bit CMT on R-Car H3
               - renesas,r8a7796-cmt1      # 48-bit CMT on R-Car M3-W
               - renesas,r8a77965-cmt1     # 48-bit CMT on R-Car M3-N
index 4ace803..25c4239 100644 (file)
@@ -326,6 +326,8 @@ properties:
           - silabs,si7020
             # Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply
           - skyworks,sky81452
+            # Socionext SynQuacer TPM MMIO module
+          - socionext,synquacer-tpm-mmio
             # i2c serial eeprom  (24cxx)
           - st,24c256
             # Ambient Light Sensor with SMBUS/Two Wire Serial Interface
index 63996ab..7d58834 100644 (file)
@@ -1174,6 +1174,8 @@ patternProperties:
     description: Shenzhen Xingbangda Display Technology Co., Ltd
   "^xinpeng,.*":
     description: Shenzhen Xinpeng Technology Co., Ltd
+  "^xiphera,.*":
+    description: Xiphera Ltd.
   "^xlnx,.*":
     description: Xilinx
   "^xnano,.*":
index fff6604..4fd86c2 100644 (file)
@@ -387,22 +387,23 @@ Domain`_ references.
 Cross-referencing from reStructuredText
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-To cross-reference the functions and types defined in the kernel-doc comments
-from reStructuredText documents, please use the `Sphinx C Domain`_
-references. For example::
-
-  See function :c:func:`foo` and struct/union/enum/typedef :c:type:`bar`.
-
-While the type reference works with just the type name, without the
-struct/union/enum/typedef part in front, you may want to use::
-
-  See :c:type:`struct foo <foo>`.
-  See :c:type:`union bar <bar>`.
-  See :c:type:`enum baz <baz>`.
-  See :c:type:`typedef meh <meh>`.
-
-This will produce prettier links, and is in line with how kernel-doc does the
-cross-references.
+No additional syntax is needed to cross-reference the functions and types
+defined in the kernel-doc comments from reStructuredText documents.
+Just end function names with ``()`` and write ``struct``, ``union``, ``enum``
+or ``typedef`` before types.
+For example::
+
+  See foo().
+  See struct foo.
+  See union bar.
+  See enum baz.
+  See typedef meh.
+
+However, if you want custom text in the cross-reference link, that can be done
+through the following syntax::
+
+  See :c:func:`my custom link text for function foo <foo>`.
+  See :c:type:`my custom link text for struct bar <bar>`.
 
 For further details, please refer to the `Sphinx C Domain`_ documentation.
 
index f71ddd5..896478b 100644 (file)
@@ -337,6 +337,23 @@ Rendered as:
 
         - column 3
 
+Cross-referencing
+-----------------
+
+Cross-referencing from one documentation page to another can be done by passing
+the path to the file starting from the Documentation folder.
+For example, to cross-reference to this page (the .rst extension is optional)::
+
+    See Documentation/doc-guide/sphinx.rst.
+
+If you want to use a relative path, you need to use Sphinx's ``doc`` directive.
+For example, referencing this page from the same directory would be done as::
+
+    See :doc:`sphinx`.
+
+For information on cross-referencing to kernel-doc functions or types, see
+Documentation/doc-guide/kernel-doc.rst.
+
 .. _sphinx_kfigure:
 
 Figures & Images
index 100bfd2..4144b66 100644 (file)
@@ -85,7 +85,7 @@ consider though:
 - Memory mapping the contents of the DMA buffer is also supported. See the
   discussion below on `CPU Access to DMA Buffer Objects`_ for the full details.
 
-- The DMA buffer FD is also pollable, see `Fence Poll Support`_ below for
+- The DMA buffer FD is also pollable, see `Implicit Fence Poll Support`_ below for
   details.
 
 Basic Operation and Device DMA Access
@@ -179,7 +179,7 @@ DMA Fence uABI/Sync File
    :internal:
 
 Indefinite DMA Fences
-~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~
 
 At various times &dma_fence with an indefinite time until dma_fence_wait()
 finishes have been proposed. Examples include:
index 71c5a40..ccd677b 100644 (file)
@@ -6,9 +6,9 @@ API to implement a new FPGA bridge
 
 * struct :c:type:`fpga_bridge` — The FPGA Bridge structure
 * struct :c:type:`fpga_bridge_ops` — Low level Bridge driver ops
-* :c:func:`devm_fpga_bridge_create()` — Allocate and init a bridge struct
-* :c:func:`fpga_bridge_register()` — Register a bridge
-* :c:func:`fpga_bridge_unregister()` — Unregister a bridge
+* devm_fpga_bridge_create() — Allocate and init a bridge struct
+* fpga_bridge_register() — Register a bridge
+* fpga_bridge_unregister() — Unregister a bridge
 
 .. kernel-doc:: include/linux/fpga/fpga-bridge.h
    :functions: fpga_bridge
index 576f194..af5382a 100644 (file)
@@ -104,9 +104,9 @@ API for implementing a new FPGA Manager driver
 * ``fpga_mgr_states`` —  Values for :c:member:`fpga_manager->state`.
 * struct :c:type:`fpga_manager` —  the FPGA manager struct
 * struct :c:type:`fpga_manager_ops` —  Low level FPGA manager driver ops
-* :c:func:`devm_fpga_mgr_create` —  Allocate and init a manager struct
-* :c:func:`fpga_mgr_register` —  Register an FPGA manager
-* :c:func:`fpga_mgr_unregister` —  Unregister an FPGA manager
+* devm_fpga_mgr_create() —  Allocate and init a manager struct
+* fpga_mgr_register() —  Register an FPGA manager
+* fpga_mgr_unregister() —  Unregister an FPGA manager
 
 .. kernel-doc:: include/linux/fpga/fpga-mgr.h
    :functions: fpga_mgr_states
index b5484df..f487ad6 100644 (file)
@@ -6,9 +6,9 @@ Overview
 
 The in-kernel API for FPGA programming is a combination of APIs from
 FPGA manager, bridge, and regions.  The actual function used to
-trigger FPGA programming is :c:func:`fpga_region_program_fpga()`.
+trigger FPGA programming is fpga_region_program_fpga().
 
-:c:func:`fpga_region_program_fpga()` uses functionality supplied by
+fpga_region_program_fpga() uses functionality supplied by
 the FPGA manager and bridges.  It will:
 
  * lock the region's mutex
@@ -20,8 +20,8 @@ the FPGA manager and bridges.  It will:
  * release the locks
 
 The struct fpga_image_info specifies what FPGA image to program.  It is
-allocated/freed by :c:func:`fpga_image_info_alloc()` and freed with
-:c:func:`fpga_image_info_free()`
+allocated/freed by fpga_image_info_alloc() and freed with
+fpga_image_info_free()
 
 How to program an FPGA using a region
 -------------------------------------
@@ -84,10 +84,10 @@ will generate that list.  Here's some sample code of what to do next::
 API for programming an FPGA
 ---------------------------
 
-* :c:func:`fpga_region_program_fpga` —  Program an FPGA
-* :c:type:`fpga_image_info` —  Specifies what FPGA image to program
-* :c:func:`fpga_image_info_alloc()` —  Allocate an FPGA image info struct
-* :c:func:`fpga_image_info_free()` —  Free an FPGA image info struct
+* fpga_region_program_fpga() —  Program an FPGA
+* fpga_image_info() —  Specifies what FPGA image to program
+* fpga_image_info_alloc() —  Allocate an FPGA image info struct
+* fpga_image_info_free() —  Free an FPGA image info struct
 
 .. kernel-doc:: drivers/fpga/fpga-region.c
    :functions: fpga_region_program_fpga
index 0529b2d..31118a8 100644 (file)
@@ -46,18 +46,18 @@ API to add a new FPGA region
 ----------------------------
 
 * struct :c:type:`fpga_region` — The FPGA region struct
-* :c:func:`devm_fpga_region_create` — Allocate and init a region struct
-* :c:func:`fpga_region_register` —  Register an FPGA region
-* :c:func:`fpga_region_unregister` —  Unregister an FPGA region
+* devm_fpga_region_create() — Allocate and init a region struct
+* fpga_region_register() —  Register an FPGA region
+* fpga_region_unregister() —  Unregister an FPGA region
 
 The FPGA region's probe function will need to get a reference to the FPGA
 Manager it will be using to do the programming.  This usually would happen
 during the region's probe function.
 
-* :c:func:`fpga_mgr_get` — Get a reference to an FPGA manager, raise ref count
-* :c:func:`of_fpga_mgr_get` —  Get a reference to an FPGA manager, raise ref count,
+* fpga_mgr_get() — Get a reference to an FPGA manager, raise ref count
+* of_fpga_mgr_get() —  Get a reference to an FPGA manager, raise ref count,
   given a device node.
-* :c:func:`fpga_mgr_put` — Put an FPGA manager
+* fpga_mgr_put() — Put an FPGA manager
 
 The FPGA region will need to specify which bridges to control while programming
 the FPGA.  The region driver can build a list of bridges during probe time
@@ -66,11 +66,11 @@ the list of bridges to program just before programming
 (:c:member:`fpga_region->get_bridges`).  The FPGA bridge framework supplies the
 following APIs to handle building or tearing down that list.
 
-* :c:func:`fpga_bridge_get_to_list` — Get a ref of an FPGA bridge, add it to a
+* fpga_bridge_get_to_list() — Get a ref of an FPGA bridge, add it to a
   list
-* :c:func:`of_fpga_bridge_get_to_list` — Get a ref of an FPGA bridge, add it to a
+* of_fpga_bridge_get_to_list() — Get a ref of an FPGA bridge, add it to a
   list, given a device node
-* :c:func:`fpga_bridges_put` — Given a list of bridges, put them
+* fpga_bridges_put() — Given a list of bridges, put them
 
 .. kernel-doc:: include/linux/fpga/fpga-region.h
    :functions: fpga_region
index 9809f59..072a745 100644 (file)
@@ -342,12 +342,12 @@ Cascaded GPIO irqchips usually fall in one of three categories:
   forced to a thread. The "fake?" raw lock can be used to work around this
   problem::
 
-       raw_spinlock_t wa_lock;
-       static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
-               unsigned long wa_lock_flags;
-               raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
-               generic_handle_irq(irq_find_mapping(bank->chip.irq.domain, bit));
-               raw_spin_unlock_irqrestore(&bank->wa_lock, wa_lock_flags);
+    raw_spinlock_t wa_lock;
+    static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
+        unsigned long wa_lock_flags;
+        raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
+        generic_handle_irq(irq_find_mapping(bank->chip.irq.domain, bit));
+        raw_spin_unlock_irqrestore(&bank->wa_lock, wa_lock_flags);
 
 - GENERIC CHAINED GPIO IRQCHIPS: these are the same as "CHAINED GPIO irqchips",
   but chained IRQ handlers are not used. Instead GPIO IRQs dispatching is
index b0bc0c0..51b21e0 100644 (file)
@@ -11,10 +11,10 @@ Industrial I/O Devices
 ----------------------
 
 * struct :c:type:`iio_dev` - industrial I/O device
-* :c:func:`iio_device_alloc()` - allocate an :c:type:`iio_dev` from a driver
-* :c:func:`iio_device_free()` - free an :c:type:`iio_dev` from a driver
-* :c:func:`iio_device_register()` - register a device with the IIO subsystem
-* :c:func:`iio_device_unregister()` - unregister a device from the IIO
+* iio_device_alloc() - allocate an :c:type:`iio_dev` from a driver
+* iio_device_free() - free an :c:type:`iio_dev` from a driver
+* iio_device_register() - register a device with the IIO subsystem
+* iio_device_unregister() - unregister a device from the IIO
   subsystem
 
 An IIO device usually corresponds to a single hardware sensor and it
@@ -34,17 +34,17 @@ A typical IIO driver will register itself as an :doc:`I2C <../i2c>` or
 
 At probe:
 
-1. Call :c:func:`iio_device_alloc()`, which allocates memory for an IIO device.
+1. Call iio_device_alloc(), which allocates memory for an IIO device.
 2. Initialize IIO device fields with driver specific information (e.g.
    device name, device channels).
-3. Call :c:func:`iio_device_register()`, this registers the device with the
+3. Call iio_device_register(), this registers the device with the
    IIO core. After this call the device is ready to accept requests from user
    space applications.
 
 At remove, we free the resources allocated in probe in reverse order:
 
-1. :c:func:`iio_device_unregister()`, unregister the device from the IIO core.
-2. :c:func:`iio_device_free()`, free the memory allocated for the IIO device.
+1. iio_device_unregister(), unregister the device from the IIO core.
+2. iio_device_free(), free the memory allocated for the IIO device.
 
 IIO device sysfs interface
 ==========================
index a4f8f98..5863bd0 100644 (file)
@@ -10,3 +10,4 @@ Non-Volatile Memory Device (NVDIMM)
    nvdimm
    btt
    security
+   firmware-activate
index 8858cea..b432a2d 100644 (file)
@@ -518,10 +518,10 @@ typically called during a dailink .shutdown() callback, which clears
 the stream pointer for all DAIS connected to a stream and releases the
 memory allocated for the stream.
 
-  Not Supported
+Not Supported
 =============
 
 1. A single port with multiple channels supported cannot be used between two
-streams or across stream. For example a port with 4 channels cannot be used
-to handle 2 independent stereo streams even though it's possible in theory
-in SoundWire.
+   streams or across stream. For example a port with 4 channels cannot be used
+   to handle 2 independent stereo streams even though it's possible in theory
+   in SoundWire.
index cdb2e82..1d44278 100644 (file)
@@ -3,7 +3,7 @@ NVMe Fault Injection
 Linux's fault injection framework provides a systematic way to support
 error injection via debugfs in the /sys/kernel/debug directory. When
 enabled, the default NVME_SC_INVALID_OPCODE with no retry will be
-injected into the nvme_end_request. Users can change the default status
+injected into the nvme_try_complete_req. Users can change the default status
 code and no retry flag via the debugfs. The list of Generic Command
 Status can be found in include/linux/nvme.h
 
index e57a3d1..328f698 100644 (file)
@@ -87,15 +87,8 @@ C. Boot options
        Note, not all drivers can handle font with widths not divisible by 8,
        such as vga16fb.
 
-2. fbcon=scrollback:<value>[k]
 
-       The scrollback buffer is memory that is used to preserve display
-       contents that has already scrolled past your view.  This is accessed
-       by using the Shift-PageUp key combination.  The value 'value' is any
-       integer. It defaults to 32KB.  The 'k' suffix is optional, and will
-       multiply the 'value' by 1024.
-
-3. fbcon=map:<0123>
+2. fbcon=map:<0123>
 
        This is an interesting option. It tells which driver gets mapped to
        which console. The value '0123' is a sequence that gets repeated until
@@ -116,7 +109,7 @@ C. Boot options
        Later on, when you want to map the console the to the framebuffer
        device, you can use the con2fbmap utility.
 
-4. fbcon=vc:<n1>-<n2>
+3. fbcon=vc:<n1>-<n2>
 
        This option tells fbcon to take over only a range of consoles as
        specified by the values 'n1' and 'n2'. The rest of the consoles
@@ -127,7 +120,7 @@ C. Boot options
        is typically located on the same video card.  Thus, the consoles that
        are controlled by the VGA console will be garbled.
 
-5. fbcon=rotate:<n>
+4. fbcon=rotate:<n>
 
        This option changes the orientation angle of the console display. The
        value 'n' accepts the following:
@@ -152,21 +145,21 @@ C. Boot options
        Actually, the underlying fb driver is totally ignorant of console
        rotation.
 
-6. fbcon=margin:<color>
+5. fbcon=margin:<color>
 
        This option specifies the color of the margins. The margins are the
        leftover area at the right and the bottom of the screen that are not
        used by text. By default, this area will be black. The 'color' value
        is an integer number that depends on the framebuffer driver being used.
 
-7. fbcon=nodefer
+6. fbcon=nodefer
 
        If the kernel is compiled with deferred fbcon takeover support, normally
        the framebuffer contents, left in place by the firmware/bootloader, will
        be preserved until there actually is some text is output to the console.
        This option causes fbcon to bind immediately to the fbdev device.
 
-8. fbcon=logo-pos:<location>
+7. fbcon=logo-pos:<location>
 
        The only possible 'location' is 'center' (without quotes), and when
        given, the bootup logo is moved from the default top-left corner
@@ -174,7 +167,7 @@ C. Boot options
        displayed due to multiple CPUs, the collected line of logos is moved
        as a whole.
 
-9. fbcon=logo-count:<n>
+8. fbcon=logo-count:<n>
 
        The value 'n' overrides the number of bootup logos. 0 disables the
        logo, and -1 gives the default which is the number of online CPUs.
index f1859d9..6158c49 100644 (file)
@@ -317,8 +317,6 @@ Currently there are following known bugs:
  - interlaced text mode is not supported; it looks like hardware limitation,
    but I'm not sure.
  - Gxx0 SGRAM/SDRAM is not autodetected.
- - If you are using more than one framebuffer device, you must boot kernel
-   with 'video=scrollback:0'.
  - maybe more...
 
 And following misfeatures:
index 8e8c1b9..42466ff 100644 (file)
@@ -185,9 +185,6 @@ Bugs
   contact me.
 - The 24/32 is not likely to work anytime soon, knowing that the
   hardware does ... unusual things in 24/32 bpp.
-- When used with another video board, current limitations of the linux
-  console subsystem can cause some troubles, specifically, you should
-  disable software scrollback, as it can oops badly ...
 
 Todo
 ====
index 6821c87..f890a4f 100644 (file)
@@ -135,8 +135,6 @@ ypan          enable display panning using the VESA protected mode
 
                 * scrolling (fullscreen) is fast, because there is
                  no need to copy around data.
-               * You'll get scrollback (the Shift-PgUp thing),
-                 the video memory can be used as scrollback buffer
 
           kontra:
 
index 53da483..1c49723 100644 (file)
@@ -22,7 +22,7 @@
     |       nios2: | TODO |
     |    openrisc: | TODO |
     |      parisc: | TODO |
-    |     powerpc: |  ok  |
+    |     powerpc: | TODO |
     |       riscv: |  ok  |
     |        s390: |  ok  |
     |          sh: | TODO |
index 7f1a40d..5776cbd 100644 (file)
@@ -110,13 +110,15 @@ The Amiga protection flags RWEDRWEDHSPARWED are handled as follows:
 
   - R maps to r for user, group and others. On directories, R implies x.
 
-  - If both W and D are allowed, w will be set.
+  - W maps to w.
 
   - E maps to x.
 
-  - H and P are always retained and ignored under Linux.
+  - D is ignored.
 
-  - A is always reset when a file is written to.
+  - H, S and P are always retained and ignored under Linux.
+
+  - A is cleared when a file is written to.
 
 User id and group id will be used unless set[gu]id are given as mount
 options. Since most of the Amiga file systems are single user systems
@@ -128,11 +130,13 @@ Linux -> Amiga:
 
 The Linux rwxrwxrwx file mode is handled as follows:
 
-  - r permission will set R for user, group and others.
+  - r permission will allow R for user, group and others.
+
+  - w permission will allow W for user, group and others.
 
-  - w permission will set W and D for user, group and others.
+  - x permission of the user will allow E for plain files.
 
-  - x permission of the user will set E for plain files.
+  - D will be allowed for user, group and others.
 
   - All other flags (suid, sgid, ...) are ignored and will
     not be retained.
index 4c536e6..98f59a8 100644 (file)
@@ -34,8 +34,6 @@ algorithms work.
    quota
    seq_file
    sharedsubtree
-   sysfs-pci
-   sysfs-tagging
 
    automount-support
 
index 29c169c..d7f53d6 100644 (file)
@@ -1,7 +1,7 @@
 .. SPDX-License-Identifier: GPL-2.0
 
 ====================
-fILESYSTEM Mount API
+Filesystem Mount API
 ====================
 
 .. CONTENTS
@@ -479,7 +479,7 @@ returned.
         int vfs_parse_fs_param(struct fs_context *fc,
                               struct fs_parameter *param);
 
-     Supply a single mount parameter to the filesystem context.  This include
+     Supply a single mount parameter to the filesystem context.  This includes
      the specification of the source/device which is specified as the "source"
      parameter (which may be specified multiple times if the filesystem
      supports that).
@@ -592,8 +592,7 @@ The following helpers all wrap sget_fc():
            one.
 
 
-=====================
-PARAMETER DESCRIPTION
+Parameter Description
 =====================
 
 Parameters are described using structures defined in linux/fs_parser.h.
index 7f7ee06..5685648 100644 (file)
@@ -129,7 +129,9 @@ also a special value which can be returned by the start() function
 called SEQ_START_TOKEN; it can be used if you wish to instruct your
 show() function (described below) to print a header at the top of the
 output. SEQ_START_TOKEN should only be used if the offset is zero,
-however.
+however.  SEQ_START_TOKEN has no special meaning to the core seq_file
+code.  It is provided as a convenience for a start() funciton to
+communicate with the next() and show() functions.
 
 The next function to implement is called, amazingly, next(); its job is to
 move the iterator forward to the next position in the sequence.  The
@@ -145,6 +147,22 @@ complete. Here's the example version::
                return spos;
        }
 
+The next() function should set ``*pos`` to a value that start() can use
+to find the new location in the sequence.  When the iterator is being
+stored in the private data area, rather than being reinitialized on each
+start(), it might seem sufficient to simply set ``*pos`` to any non-zero
+value (zero always tells start() to restart the sequence).  This is not
+sufficient due to historical problems.
+
+Historically, many next() functions have *not* updated ``*pos`` at
+end-of-file.  If the value is then used by start() to initialise the
+iterator, this can result in corner cases where the last entry in the
+sequence is reported twice in the file.  In order to discourage this bug
+from being resurrected, the core seq_file code now produces a warning if
+a next() function does not change the value of ``*pos``.  Consequently a
+next() function *must* change the value of ``*pos``, and of course must
+set it to a non-zero value.
+
 The stop() function closes a session; its job, of course, is to clean
 up. If dynamic memory is allocated for the iterator, stop() is the
 place to free it; if a lock was taken by start(), stop() must release
index ab0f779..5a3209a 100644 (file)
@@ -172,14 +172,13 @@ calls the associated methods.
 
 To illustrate::
 
-    #define to_dev(obj) container_of(obj, struct device, kobj)
     #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
 
     static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
                                char *buf)
     {
            struct device_attribute *dev_attr = to_dev_attr(attr);
-           struct device *dev = to_dev(kobj);
+           struct device *dev = kobj_to_dev(kobj);
            ssize_t ret = -EIO;
 
            if (dev_attr->show)
index 1f39c8c..5210aed 100644 (file)
@@ -1,11 +1,13 @@
 .. SPDX-License-Identifier: GPL-2.0
 
-:orphan:
-
 .. UBIFS Authentication
 .. sigma star gmbh
 .. 2018
 
+============================
+UBIFS Authentication Support
+============================
+
 Introduction
 ============
 
index ad3b5af..f72b5f1 100644 (file)
@@ -26,3 +26,4 @@ ACPI Support
    lpit
    video_extension
    extcon-intel-int3496
+   intel-pmc-mux
index 6d5253e..0cd6147 100644 (file)
@@ -68,7 +68,7 @@ See below for all known bank addresses, numbers of sensors in that bank,
 number of bytes data per sensor and contents/meaning of those bytes.
 
 Although both this document and the kernel driver have kept the sensor
-terminoligy for the addressing within a bank this is not 100% correct, in
+terminology for the addressing within a bank this is not 100% correct, in
 bank 0x24 for example the addressing within the bank selects a PWM output not
 a sensor.
 
@@ -155,7 +155,7 @@ After wider testing of the Linux kernel driver some variants of the uGuru have
 turned up which do not hold 0x08 at DATA within 250 reads after writing the
 bank address. With these versions this happens quite frequent, using larger
 timeouts doesn't help, they just go offline for a second or 2, doing some
-internal callibration or whatever. Your code should be prepared to handle
+internal calibration or whatever. Your code should be prepared to handle
 this and in case of no response in this specific case just goto sleep for a
 while and then retry.
 
@@ -331,6 +331,6 @@ the voltage / clock programming out, I tried reading and only reading banks
 0-0x30 with the reading code used for the sensor banks (0x20-0x28) and this
 resulted in a _permanent_ reprogramming of the voltages, luckily I had the
 sensors part configured so that it would shutdown my system on any out of spec
-voltages which proprably safed my computer (after a reboot I managed to
+voltages which probably safed my computer (after a reboot I managed to
 immediately enter the bios and reload the defaults). This probably means that
 the read/write cycle for the non sensor part is different from the sensor part.
index d8243c8..cfda60b 100644 (file)
@@ -17,7 +17,7 @@ Supported chips:
     Note:
        The uGuru is a microcontroller with onboard firmware which programs
        it to behave as a hwmon IC. There are many different revisions of the
-       firmware and thus effectivly many different revisions of the uGuru.
+       firmware and thus effectively many different revisions of the uGuru.
        Below is an incomplete list with which revisions are used for which
        Motherboards:
 
@@ -33,7 +33,7 @@ Supported chips:
        sensortype (Volt or Temp) for bank1 sensors, for revision 1 uGuru's
        this does not always work. For these uGuru's the autodetection can
        be overridden with the bank1_types module param. For all 3 known
-       revison 1 motherboards the correct use of this param is:
+       revision 1 motherboards the correct use of this param is:
        bank1_types=1,1,0,0,0,0,0,2,0,0,0,0,2,0,0,1
        You may also need to specify the fan_sensors option for these boards
        fan_sensors=5
index 514f11f..88046d8 100644 (file)
@@ -13,7 +13,7 @@ Supported chips:
     Note:
        The uGuru is a microcontroller with onboard firmware which programs
        it to behave as a hwmon IC. There are many different revisions of the
-       firmware and thus effectivly many different revisions of the uGuru.
+       firmware and thus effectively many different revisions of the uGuru.
        Below is an incomplete list with which revisions are used for which
        Motherboards:
 
@@ -24,7 +24,7 @@ Supported chips:
        - uGuru 3.0.0.0 ~ 3.0.x.x (AW8, AL8, AT8, NI8 SLI, AT8 32X, AN8 32X,
          AW9D-MAX)
 
-       The abituguru3 driver is only for revison 3.0.x.x motherboards,
+       The abituguru3 driver is only for revision 3.0.x.x motherboards,
        this driver will not work on older motherboards. For older
        motherboards use the abituguru (without the 3 !) driver.
 
index 750d3a9..77a1ae9 100644 (file)
@@ -158,6 +158,7 @@ Hardware Monitoring Kernel Drivers
    smsc47b397
    smsc47m192
    smsc47m1
+   sparx5-temp
    tc654
    tc74
    thmc50
index 0436e10..4bdfe28 100644 (file)
@@ -15,4 +15,3 @@ IA-64 Architecture
    irq-redir
    mca
    serial
-   xen
diff --git a/Documentation/ia64/xen.rst b/Documentation/ia64/xen.rst
deleted file mode 100644 (file)
index 831339c..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-********************************************************
-Recipe for getting/building/running Xen/ia64 with pv_ops
-********************************************************
-This recipe describes how to get xen-ia64 source and build it,
-and run domU with pv_ops.
-
-Requirements
-============
-
-  - python
-  - mercurial
-    it (aka "hg") is an open-source source code
-    management software. See the below.
-    http://www.selenic.com/mercurial/wiki/
-  - git
-  - bridge-utils
-
-Getting and Building Xen and Dom0
-=================================
-
-  My environment is:
-
-    - Machine  : Tiger4
-    - Domain0 OS  : RHEL5
-    - DomainU OS  : RHEL5
-
- 1. Download source::
-
-       # hg clone http://xenbits.xensource.com/ext/ia64/xen-unstable.hg
-       # cd xen-unstable.hg
-       # hg clone http://xenbits.xensource.com/ext/ia64/linux-2.6.18-xen.hg
-
- 2. # make world
-
- 3. # make install-tools
-
- 4. copy kernels and xen::
-
-       # cp xen/xen.gz /boot/efi/efi/redhat/
-       # cp build-linux-2.6.18-xen_ia64/vmlinux.gz \
-       /boot/efi/efi/redhat/vmlinuz-2.6.18.8-xen
-
- 5. make initrd for Dom0/DomU::
-
-       # make -C linux-2.6.18-xen.hg ARCH=ia64 modules_install \
-          O=$(pwd)/build-linux-2.6.18-xen_ia64
-       # mkinitrd -f /boot/efi/efi/redhat/initrd-2.6.18.8-xen.img \
-         2.6.18.8-xen --builtin mptspi --builtin mptbase \
-         --builtin mptscsih --builtin uhci-hcd --builtin ohci-hcd \
-         --builtin ehci-hcd
-
-Making a disk image for guest OS
-================================
-
- 1. make file::
-
-      # dd if=/dev/zero of=/root/rhel5.img bs=1M seek=4096 count=0
-      # mke2fs -F -j /root/rhel5.img
-      # mount -o loop /root/rhel5.img /mnt
-      # cp -ax /{dev,var,etc,usr,bin,sbin,lib} /mnt
-      # mkdir /mnt/{root,proc,sys,home,tmp}
-
-      Note: You may miss some device files. If so, please create them
-      with mknod. Or you can use tar instead of cp.
-
- 2. modify DomU's fstab::
-
-      # vi /mnt/etc/fstab
-         /dev/xvda1  /            ext3    defaults        1 1
-         none        /dev/pts     devpts  gid=5,mode=620  0 0
-         none        /dev/shm     tmpfs   defaults        0 0
-         none        /proc        proc    defaults        0 0
-         none        /sys         sysfs   defaults        0 0
-
- 3. modify inittab
-
-    set runlevel to 3 to avoid X trying to start::
-
-      # vi /mnt/etc/inittab
-         id:3:initdefault:
-
-    Start a getty on the hvc0 console::
-
-       X0:2345:respawn:/sbin/mingetty hvc0
-
-    tty1-6 mingetty can be commented out
-
- 4. add hvc0 into /etc/securetty::
-
-      # vi /mnt/etc/securetty (add hvc0)
-
- 5. umount::
-
-      # umount /mnt
-
-FYI, virt-manager can also make a disk image for guest OS.
-It's GUI tools and easy to make it.
-
-Boot Xen & Domain0
-==================
-
- 1. replace elilo
-    elilo of RHEL5 can boot Xen and Dom0.
-    If you use old elilo (e.g RHEL4), please download from the below
-    http://elilo.sourceforge.net/cgi-bin/blosxom
-    and copy into /boot/efi/efi/redhat/::
-
-      # cp elilo-3.6-ia64.efi /boot/efi/efi/redhat/elilo.efi
-
- 2. modify elilo.conf (like the below)::
-
-      # vi /boot/efi/efi/redhat/elilo.conf
-      prompt
-      timeout=20
-      default=xen
-      relocatable
-
-      image=vmlinuz-2.6.18.8-xen
-             label=xen
-             vmm=xen.gz
-             initrd=initrd-2.6.18.8-xen.img
-             read-only
-             append=" -- rhgb root=/dev/sda2"
-
-The append options before "--" are for xen hypervisor,
-the options after "--" are for dom0.
-
-FYI, your machine may need console options like
-"com1=19200,8n1 console=vga,com1". For example,
-append="com1=19200,8n1 console=vga,com1 -- rhgb console=tty0 \
-console=ttyS0 root=/dev/sda2"
-
-Getting and Building domU with pv_ops
-=====================================
-
- 1. get pv_ops tree::
-
-      # git clone http://people.valinux.co.jp/~yamahata/xen-ia64/linux-2.6-xen-ia64.git/
-
- 2. git branch (if necessary)::
-
-      # cd linux-2.6-xen-ia64/
-      # git checkout -b your_branch origin/xen-ia64-domu-minimal-2008may19
-
-   Note:
-     The current branch is xen-ia64-domu-minimal-2008may19.
-     But you would find the new branch. You can see with
-     "git branch -r" to get the branch lists.
-
-       http://people.valinux.co.jp/~yamahata/xen-ia64/for_eagl/linux-2.6-ia64-pv-ops.git/
-
-     is also available.
-
-     The tree is based on
-
-      git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6 test)
-
- 3. copy .config for pv_ops of domU::
-
-      # cp arch/ia64/configs/xen_domu_wip_defconfig .config
-
- 4. make kernel with pv_ops::
-
-      # make oldconfig
-      # make
-
- 5. install the kernel and initrd::
-
-      # cp vmlinux.gz /boot/efi/efi/redhat/vmlinuz-2.6-pv_ops-xenU
-      # make modules_install
-      # mkinitrd -f /boot/efi/efi/redhat/initrd-2.6-pv_ops-xenU.img \
-        2.6.26-rc3xen-ia64-08941-g1b12161 --builtin mptspi \
-        --builtin mptbase --builtin mptscsih --builtin uhci-hcd \
-        --builtin ohci-hcd --builtin ehci-hcd
-
-Boot DomainU with pv_ops
-========================
-
- 1. make config of DomU::
-
-     # vi /etc/xen/rhel5
-       kernel = "/boot/efi/efi/redhat/vmlinuz-2.6-pv_ops-xenU"
-       ramdisk = "/boot/efi/efi/redhat/initrd-2.6-pv_ops-xenU.img"
-       vcpus = 1
-       memory = 512
-       name = "rhel5"
-       disk = [ 'file:/root/rhel5.img,xvda1,w' ]
-       root = "/dev/xvda1 ro"
-       extra= "rhgb console=hvc0"
-
- 2. After boot xen and dom0, start xend::
-
-       # /etc/init.d/xend start
-
-   ( In the debugging case, `# XEND_DEBUG=1 xend trace_start` )
-
- 3. start domU::
-
-       # xm create -c rhel5
-
-Reference
-=========
-- Wiki of Xen/IA64 upstream merge
-  http://wiki.xensource.com/xenwiki/XenIA64/UpstreamMerge
-
-Written by Akio Takebe <takebe_akio@jp.fujitsu.com> on 28 May 2008
index 6e38cbb..3a5d76f 100644 (file)
@@ -53,7 +53,7 @@ kernel module following the interface in include/linux/iio/sw_trigger.h::
         */
   }
 
-  static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt)
+  static int iio_trig_sample_remove(struct iio_sw_trigger *swt)
   {
        /*
         * This undoes the actions in iio_trig_sample_probe
index 2aac50b..cf3ca23 100644 (file)
@@ -1,3 +1,5 @@
+.. _kbuild_llvm:
+
 ==============================
 Building Linux with Clang/LLVM
 ==============================
@@ -23,8 +25,8 @@ supports C and the GNU C extensions required by the kernel, and is pronounced
 Clang
 -----
 
-The compiler used can be swapped out via `CC=` command line argument to `make`.
-`CC=` should be set when selecting a config and during a build.
+The compiler used can be swapped out via ``CC=`` command line argument to ``make``.
+``CC=`` should be set when selecting a config and during a build. ::
 
        make CC=clang defconfig
 
@@ -34,33 +36,33 @@ Cross Compiling
 ---------------
 
 A single Clang compiler binary will typically contain all supported backends,
-which can help simplify cross compiling.
+which can help simplify cross compiling. ::
 
        ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make CC=clang
 
-`CROSS_COMPILE` is not used to prefix the Clang compiler binary, instead
-`CROSS_COMPILE` is used to set a command line flag: `--target <triple>`. For
-example:
+``CROSS_COMPILE`` is not used to prefix the Clang compiler binary, instead
+``CROSS_COMPILE`` is used to set a command line flag: ``--target=<triple>``. For
+example: ::
 
-       clang --target aarch64-linux-gnu foo.c
+       clang --target=aarch64-linux-gnu foo.c
 
 LLVM Utilities
 --------------
 
-LLVM has substitutes for GNU binutils utilities. Kbuild supports `LLVM=1`
-to enable them.
+LLVM has substitutes for GNU binutils utilities. Kbuild supports ``LLVM=1``
+to enable them. ::
 
        make LLVM=1
 
-They can be enabled individually. The full list of the parameters:
+They can be enabled individually. The full list of the parameters: ::
 
-       make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \\
-         OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump OBJSIZE=llvm-size \\
-         READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar \\
+       make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \
+         OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump OBJSIZE=llvm-size \
+         READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar \
          HOSTLD=ld.lld
 
 Currently, the integrated assembler is disabled by default. You can pass
-`LLVM_IAS=1` to enable it.
+``LLVM_IAS=1`` to enable it.
 
 Getting Help
 ------------
@@ -73,6 +75,8 @@ Getting Help
 - `Wiki <https://github.com/ClangBuiltLinux/linux/wiki>`_
 - `Beginner Bugs <https://github.com/ClangBuiltLinux/linux/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22>`_
 
+.. _getting_llvm:
+
 Getting LLVM
 -------------
 
index b81b891..58d513a 100644 (file)
@@ -16,7 +16,7 @@ This document describes the Linux kernel Makefiles.
           --- 3.5 Library file goals - lib-y
           --- 3.6 Descending down in directories
           --- 3.7 Compilation flags
-          --- 3.8 Command line dependency
+          --- 3.8 <deleted>
           --- 3.9 Dependency tracking
           --- 3.10 Special Rules
           --- 3.11 $(CC) support functions
@@ -39,8 +39,8 @@ This document describes the Linux kernel Makefiles.
 
        === 7 Architecture Makefiles
           --- 7.1 Set variables to tweak the build to the architecture
-          --- 7.2 Add prerequisites to archheaders:
-          --- 7.3 Add prerequisites to archprepare:
+          --- 7.2 Add prerequisites to archheaders
+          --- 7.3 Add prerequisites to archprepare
           --- 7.4 List directories to visit when descending
           --- 7.5 Architecture-specific boot images
           --- 7.6 Building non-kbuild targets
@@ -129,7 +129,7 @@ The preferred name for the kbuild files are 'Makefile' but 'Kbuild' can
 be used and if both a 'Makefile' and a 'Kbuild' file exists, then the 'Kbuild'
 file will be used.
 
-Section 3.1 "Goal definitions" is a quick intro, further chapters provide
+Section 3.1 "Goal definitions" is a quick intro; further chapters provide
 more details, with real examples.
 
 3.1 Goal definitions
@@ -965,7 +965,7 @@ When kbuild executes, the following steps are followed (roughly):
                KBUILD_LDFLAGS         := -m elf_s390
 
        Note: ldflags-y can be used to further customise
-       the flags used. See chapter 3.7.
+       the flags used. See section 3.7.
 
     LDFLAGS_vmlinux
        Options for $(LD) when linking vmlinux
@@ -1121,7 +1121,7 @@ When kbuild executes, the following steps are followed (roughly):
 
        In this example, the file target maketools will be processed
        before descending down in the subdirectories.
-       See also chapter XXX-TODO that describe how kbuild supports
+       See also chapter XXX-TODO that describes how kbuild supports
        generating offset header files.
 
 
@@ -1261,7 +1261,7 @@ When kbuild executes, the following steps are followed (roughly):
        always be built.
        Assignments to $(targets) are without $(obj)/ prefix.
        if_changed may be used in conjunction with custom commands as
-       defined in 6.8 "Custom kbuild commands".
+       defined in 7.8 "Custom kbuild commands".
 
        Note: It is a typical mistake to forget the FORCE prerequisite.
        Another common pitfall is that whitespace is sometimes
@@ -1411,7 +1411,7 @@ When kbuild executes, the following steps are followed (roughly):
        that may be shared between individual architectures.
        The recommended approach how to use a generic header file is
        to list the file in the Kbuild file.
-       See "7.2 generic-y" for further info on syntax etc.
+       See "8.2 generic-y" for further info on syntax etc.
 
 7.11 Post-link pass
 -------------------
@@ -1601,4 +1601,4 @@ is the right choice.
 
 - Describe how kbuild supports shipped files with _shipped.
 - Generating offset header files.
-- Add more variables to section 7?
+- Add more variables to chapters 7 or 9?
index 23fcbc4..cec03bd 100644 (file)
@@ -392,3 +392,261 @@ Run the command and save the output, then compare against the output from
 a later run of this command to identify the leakers.  This same output
 can also help you find situations where runtime lock initialization has
 been omitted.
+
+Recursive read locks:
+---------------------
+The whole of the rest document tries to prove a certain type of cycle is equivalent
+to deadlock possibility.
+
+There are three types of lockers: writers (i.e. exclusive lockers, like
+spin_lock() or write_lock()), non-recursive readers (i.e. shared lockers, like
+down_read()) and recursive readers (recursive shared lockers, like rcu_read_lock()).
+And we use the following notations of those lockers in the rest of the document:
+
+       W or E: stands for writers (exclusive lockers).
+       r:      stands for non-recursive readers.
+       R:      stands for recursive readers.
+       S:      stands for all readers (non-recursive + recursive), as both are shared lockers.
+       N:      stands for writers and non-recursive readers, as both are not recursive.
+
+Obviously, N is "r or W" and S is "r or R".
+
+Recursive readers, as their name indicates, are the lockers allowed to acquire
+even inside the critical section of another reader of the same lock instance,
+in other words, allowing nested read-side critical sections of one lock instance.
+
+While non-recursive readers will cause a self deadlock if trying to acquire inside
+the critical section of another reader of the same lock instance.
+
+The difference between recursive readers and non-recursive readers is because:
+recursive readers get blocked only by a write lock *holder*, while non-recursive
+readers could get blocked by a write lock *waiter*. Considering the follow example:
+
+       TASK A:                 TASK B:
+
+       read_lock(X);
+                               write_lock(X);
+       read_lock_2(X);
+
+Task A gets the reader (no matter whether recursive or non-recursive) on X via
+read_lock() first. And when task B tries to acquire writer on X, it will block
+and become a waiter for writer on X. Now if read_lock_2() is recursive readers,
+task A will make progress, because writer waiters don't block recursive readers,
+and there is no deadlock. However, if read_lock_2() is non-recursive readers,
+it will get blocked by writer waiter B, and cause a self deadlock.
+
+Block conditions on readers/writers of the same lock instance:
+--------------------------------------------------------------
+There are simply four block conditions:
+
+1.     Writers block other writers.
+2.     Readers block writers.
+3.     Writers block both recursive readers and non-recursive readers.
+4.     And readers (recursive or not) don't block other recursive readers but
+       may block non-recursive readers (because of the potential co-existing
+       writer waiters)
+
+Block condition matrix, Y means the row blocks the column, and N means otherwise.
+
+           | E | r | R |
+       +---+---+---+---+
+         E | Y | Y | Y |
+       +---+---+---+---+
+         r | Y | Y | N |
+       +---+---+---+---+
+         R | Y | Y | N |
+
+       (W: writers, r: non-recursive readers, R: recursive readers)
+
+
+acquired recursively. Unlike non-recursive read locks, recursive read locks
+only get blocked by current write lock *holders* other than write lock
+*waiters*, for example:
+
+       TASK A:                 TASK B:
+
+       read_lock(X);
+
+                               write_lock(X);
+
+       read_lock(X);
+
+is not a deadlock for recursive read locks, as while the task B is waiting for
+the lock X, the second read_lock() doesn't need to wait because it's a recursive
+read lock. However if the read_lock() is non-recursive read lock, then the above
+case is a deadlock, because even if the write_lock() in TASK B cannot get the
+lock, but it can block the second read_lock() in TASK A.
+
+Note that a lock can be a write lock (exclusive lock), a non-recursive read
+lock (non-recursive shared lock) or a recursive read lock (recursive shared
+lock), depending on the lock operations used to acquire it (more specifically,
+the value of the 'read' parameter for lock_acquire()). In other words, a single
+lock instance has three types of acquisition depending on the acquisition
+functions: exclusive, non-recursive read, and recursive read.
+
+To be concise, we call that write locks and non-recursive read locks as
+"non-recursive" locks and recursive read locks as "recursive" locks.
+
+Recursive locks don't block each other, while non-recursive locks do (this is
+even true for two non-recursive read locks). A non-recursive lock can block the
+corresponding recursive lock, and vice versa.
+
+A deadlock case with recursive locks involved is as follow:
+
+       TASK A:                 TASK B:
+
+       read_lock(X);
+                               read_lock(Y);
+       write_lock(Y);
+                               write_lock(X);
+
+Task A is waiting for task B to read_unlock() Y and task B is waiting for task
+A to read_unlock() X.
+
+Dependency types and strong dependency paths:
+---------------------------------------------
+Lock dependencies record the orders of the acquisitions of a pair of locks, and
+because there are 3 types for lockers, there are, in theory, 9 types of lock
+dependencies, but we can show that 4 types of lock dependencies are enough for
+deadlock detection.
+
+For each lock dependency:
+
+       L1 -> L2
+
+, which means lockdep has seen L1 held before L2 held in the same context at runtime.
+And in deadlock detection, we care whether we could get blocked on L2 with L1 held,
+IOW, whether there is a locker L3 that L1 blocks L3 and L2 gets blocked by L3. So
+we only care about 1) what L1 blocks and 2) what blocks L2. As a result, we can combine
+recursive readers and non-recursive readers for L1 (as they block the same types) and
+we can combine writers and non-recursive readers for L2 (as they get blocked by the
+same types).
+
+With the above combination for simplification, there are 4 types of dependency edges
+in the lockdep graph:
+
+1) -(ER)->: exclusive writer to recursive reader dependency, "X -(ER)-> Y" means
+           X -> Y and X is a writer and Y is a recursive reader.
+
+2) -(EN)->: exclusive writer to non-recursive locker dependency, "X -(EN)-> Y" means
+           X -> Y and X is a writer and Y is either a writer or non-recursive reader.
+
+3) -(SR)->: shared reader to recursive reader dependency, "X -(SR)-> Y" means
+           X -> Y and X is a reader (recursive or not) and Y is a recursive reader.
+
+4) -(SN)->: shared reader to non-recursive locker dependency, "X -(SN)-> Y" means
+           X -> Y and X is a reader (recursive or not) and Y is either a writer or
+           non-recursive reader.
+
+Note that given two locks, they may have multiple dependencies between them, for example:
+
+       TASK A:
+
+       read_lock(X);
+       write_lock(Y);
+       ...
+
+       TASK B:
+
+       write_lock(X);
+       write_lock(Y);
+
+, we have both X -(SN)-> Y and X -(EN)-> Y in the dependency graph.
+
+We use -(xN)-> to represent edges that are either -(EN)-> or -(SN)->, the
+similar for -(Ex)->, -(xR)-> and -(Sx)->
+
+A "path" is a series of conjunct dependency edges in the graph. And we define a
+"strong" path, which indicates the strong dependency throughout each dependency
+in the path, as the path that doesn't have two conjunct edges (dependencies) as
+-(xR)-> and -(Sx)->. In other words, a "strong" path is a path from a lock
+walking to another through the lock dependencies, and if X -> Y -> Z is in the
+path (where X, Y, Z are locks), and the walk from X to Y is through a -(SR)-> or
+-(ER)-> dependency, the walk from Y to Z must not be through a -(SN)-> or
+-(SR)-> dependency.
+
+We will see why the path is called "strong" in next section.
+
+Recursive Read Deadlock Detection:
+----------------------------------
+
+We now prove two things:
+
+Lemma 1:
+
+If there is a closed strong path (i.e. a strong circle), then there is a
+combination of locking sequences that causes deadlock. I.e. a strong circle is
+sufficient for deadlock detection.
+
+Lemma 2:
+
+If there is no closed strong path (i.e. strong circle), then there is no
+combination of locking sequences that could cause deadlock. I.e.  strong
+circles are necessary for deadlock detection.
+
+With these two Lemmas, we can easily say a closed strong path is both sufficient
+and necessary for deadlocks, therefore a closed strong path is equivalent to
+deadlock possibility. As a closed strong path stands for a dependency chain that
+could cause deadlocks, so we call it "strong", considering there are dependency
+circles that won't cause deadlocks.
+
+Proof for sufficiency (Lemma 1):
+
+Let's say we have a strong circle:
+
+       L1 -> L2 ... -> Ln -> L1
+
+, which means we have dependencies:
+
+       L1 -> L2
+       L2 -> L3
+       ...
+       Ln-1 -> Ln
+       Ln -> L1
+
+We now can construct a combination of locking sequences that cause deadlock:
+
+Firstly let's make one CPU/task get the L1 in L1 -> L2, and then another get
+the L2 in L2 -> L3, and so on. After this, all of the Lx in Lx -> Lx+1 are
+held by different CPU/tasks.
+
+And then because we have L1 -> L2, so the holder of L1 is going to acquire L2
+in L1 -> L2, however since L2 is already held by another CPU/task, plus L1 ->
+L2 and L2 -> L3 are not -(xR)-> and -(Sx)-> (the definition of strong), which
+means either L2 in L1 -> L2 is a non-recursive locker (blocked by anyone) or
+the L2 in L2 -> L3, is writer (blocking anyone), therefore the holder of L1
+cannot get L2, it has to wait L2's holder to release.
+
+Moreover, we can have a similar conclusion for L2's holder: it has to wait L3's
+holder to release, and so on. We now can prove that Lx's holder has to wait for
+Lx+1's holder to release, and note that Ln+1 is L1, so we have a circular
+waiting scenario and nobody can get progress, therefore a deadlock.
+
+Proof for necessary (Lemma 2):
+
+Lemma 2 is equivalent to: If there is a deadlock scenario, then there must be a
+strong circle in the dependency graph.
+
+According to Wikipedia[1], if there is a deadlock, then there must be a circular
+waiting scenario, means there are N CPU/tasks, where CPU/task P1 is waiting for
+a lock held by P2, and P2 is waiting for a lock held by P3, ... and Pn is waiting
+for a lock held by P1. Let's name the lock Px is waiting as Lx, so since P1 is waiting
+for L1 and holding Ln, so we will have Ln -> L1 in the dependency graph. Similarly,
+we have L1 -> L2, L2 -> L3, ..., Ln-1 -> Ln in the dependency graph, which means we
+have a circle:
+
+       Ln -> L1 -> L2 -> ... -> Ln
+
+, and now let's prove the circle is strong:
+
+For a lock Lx, Px contributes the dependency Lx-1 -> Lx and Px+1 contributes
+the dependency Lx -> Lx+1, and since Px is waiting for Px+1 to release Lx,
+so it's impossible that Lx on Px+1 is a reader and Lx on Px is a recursive
+reader, because readers (no matter recursive or not) don't block recursive
+readers, therefore Lx-1 -> Lx and Lx -> Lx+1 cannot be a -(xR)-> -(Sx)-> pair,
+and this is true for any lock in the circle, therefore, the circle is strong.
+
+References:
+-----------
+[1]: https://en.wikipedia.org/wiki/Deadlock
+[2]: Shibu, K. (2009). Intro To Embedded Systems (1st ed.). Tata McGraw-Hill
index 4cefed8..ddada4a 100644 (file)
@@ -164,14 +164,14 @@ by disabling preemption or interrupts.
 On non-PREEMPT_RT kernels local_lock operations map to the preemption and
 interrupt disabling and enabling primitives:
 
- =========================== ======================
- local_lock(&llock)          preempt_disable()
- local_unlock(&llock)        preempt_enable()
- local_lock_irq(&llock)      local_irq_disable()
- local_unlock_irq(&llock)    local_irq_enable()
- local_lock_save(&llock)     local_irq_save()
- local_lock_restore(&llock)  local_irq_save()
- =========================== ======================
+ ===============================  ======================
+ local_lock(&llock)               preempt_disable()
+ local_unlock(&llock)             preempt_enable()
+ local_lock_irq(&llock)           local_irq_disable()
+ local_unlock_irq(&llock)         local_irq_enable()
+ local_lock_irqsave(&llock)       local_irq_save()
+ local_unlock_irqrestore(&llock)  local_irq_restore()
+ ===============================  ======================
 
 The named scope of local_lock has two advantages over the regular
 primitives:
@@ -353,14 +353,14 @@ protection scope. So the following substitution is wrong::
   {
     local_irq_save(flags);    -> local_lock_irqsave(&local_lock_1, flags);
     func3();
-    local_irq_restore(flags); -> local_lock_irqrestore(&local_lock_1, flags);
+    local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock_1, flags);
   }
 
   func2()
   {
     local_irq_save(flags);    -> local_lock_irqsave(&local_lock_2, flags);
     func3();
-    local_irq_restore(flags); -> local_lock_irqrestore(&local_lock_2, flags);
+    local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock_2, flags);
   }
 
   func3()
@@ -379,14 +379,14 @@ PREEMPT_RT-specific semantics of spinlock_t. The correct substitution is::
   {
     local_irq_save(flags);    -> local_lock_irqsave(&local_lock, flags);
     func3();
-    local_irq_restore(flags); -> local_lock_irqrestore(&local_lock, flags);
+    local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock, flags);
   }
 
   func2()
   {
     local_irq_save(flags);    -> local_lock_irqsave(&local_lock, flags);
     func3();
-    local_irq_restore(flags); -> local_lock_irqrestore(&local_lock, flags);
+    local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock, flags);
   }
 
   func3()
index 62c5ad9..a334b58 100644 (file)
@@ -139,6 +139,24 @@ with the associated LOCKTYPE lock acquired.
 
 Read path: same as in :ref:`seqcount_t`.
 
+
+.. _seqcount_latch_t:
+
+Latch sequence counters (``seqcount_latch_t``)
+----------------------------------------------
+
+Latch sequence counters are a multiversion concurrency control mechanism
+where the embedded seqcount_t counter even/odd value is used to switch
+between two copies of protected data. This allows the sequence counter
+read path to safely interrupt its own write side critical section.
+
+Use seqcount_latch_t when the write side sections cannot be protected
+from interruption by readers. This is typically the case when the read
+side can be invoked from NMI handlers.
+
+Check `raw_write_seqcount_latch()` for more information.
+
+
 .. _seqlock_t:
 
 Sequential locks (``seqlock_t``)
index d904e74..f0a6043 100644 (file)
@@ -13,4 +13,5 @@ additions to this manual.
    rebasing-and-merging
    pull-requests
    maintainer-entry-profile
+   modifying-patches
 
index 227f427..b7a627d 100644 (file)
@@ -101,3 +101,4 @@ to do something different in the near future.
 
    ../doc-guide/maintainer-profile
    ../nvdimm/maintainer-entry-profile
+   ../riscv/patch-acceptance
diff --git a/Documentation/maintainer/modifying-patches.rst b/Documentation/maintainer/modifying-patches.rst
new file mode 100644 (file)
index 0000000..58385d2
--- /dev/null
@@ -0,0 +1,50 @@
+.. _modifyingpatches:
+
+Modifying Patches
+=================
+
+If you are a subsystem or branch maintainer, sometimes you need to slightly
+modify patches you receive in order to merge them, because the code is not
+exactly the same in your tree and the submitters'. If you stick strictly to
+rule (c) of the developers certificate of origin, you should ask the submitter
+to rediff, but this is a totally counter-productive waste of time and energy.
+Rule (b) allows you to adjust the code, but then it is very impolite to change
+one submitters code and make him endorse your bugs. To solve this problem, it
+is recommended that you add a line between the last Signed-off-by header and
+yours, indicating the nature of your changes. While there is nothing mandatory
+about this, it seems like prepending the description with your mail and/or
+name, all enclosed in square brackets, is noticeable enough to make it obvious
+that you are responsible for last-minute changes. Example::
+
+       Signed-off-by: Random J Developer <random@developer.example.org>
+       [lucky@maintainer.example.org: struct foo moved from foo.c to foo.h]
+       Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>
+
+This practice is particularly helpful if you maintain a stable branch and
+want at the same time to credit the author, track changes, merge the fix,
+and protect the submitter from complaints. Note that under no circumstances
+can you change the author's identity (the From header), as it is the one
+which appears in the changelog.
+
+Special note to back-porters: It seems to be a common and useful practice
+to insert an indication of the origin of a patch at the top of the commit
+message (just after the subject line) to facilitate tracking. For instance,
+here's what we see in a 3.x-stable release::
+
+  Date:   Tue Oct 7 07:26:38 2014 -0400
+
+    libata: Un-break ATA blacklist
+
+    commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream.
+
+And here's what might appear in an older kernel once a patch is backported::
+
+    Date:   Tue May 13 22:12:27 2008 +0200
+
+        wireless, airo: waitbusy() won't delay
+
+        [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a]
+
+Whatever the format, this information provides a valuable help to people
+tracking your trees, and to people trying to troubleshoot bugs in your
+tree.
index 9618633..17c8e0c 100644 (file)
@@ -546,8 +546,8 @@ There are certain things that the Linux kernel memory barriers do not guarantee:
        [*] For information on bus mastering DMA and coherency please read:
 
            Documentation/driver-api/pci/pci.rst
-           Documentation/DMA-API-HOWTO.txt
-           Documentation/DMA-API.txt
+           Documentation/core-api/dma-api-howto.rst
+           Documentation/core-api/dma-api.rst
 
 
 DATA DEPENDENCY BARRIERS (HISTORICAL)
@@ -1932,8 +1932,8 @@ There are some more advanced barrier functions:
      here.
 
      See the subsection "Kernel I/O barrier effects" for more information on
-     relaxed I/O accessors and the Documentation/DMA-API.txt file for more
-     information on consistent memory.
+     relaxed I/O accessors and the Documentation/core-api/dma-api.rst file for
+     more information on consistent memory.
 
  (*) pmem_wmb();
 
index af029b3..11bd5e6 100644 (file)
@@ -180,7 +180,7 @@ The configuration can only be set up via VLAN tagging and bridge setup.
 
   # bring up the slave interfaces
   ip link set lan1 up
-  ip link set lan1 up
+  ip link set lan2 up
   ip link set lan3 up
 
   # create bridge
index d53bcb3..b5a7988 100644 (file)
@@ -206,6 +206,7 @@ Userspace to kernel:
   ``ETHTOOL_MSG_TSINFO_GET``           get timestamping info
   ``ETHTOOL_MSG_CABLE_TEST_ACT``        action start cable test
   ``ETHTOOL_MSG_CABLE_TEST_TDR_ACT``    action start raw TDR cable test
+  ``ETHTOOL_MSG_TUNNEL_INFO_GET``       get tunnel offload info
   ===================================== ================================
 
 Kernel to userspace:
@@ -239,6 +240,7 @@ Kernel to userspace:
   ``ETHTOOL_MSG_TSINFO_GET_REPLY``     timestamping info
   ``ETHTOOL_MSG_CABLE_TEST_NTF``        Cable test results
   ``ETHTOOL_MSG_CABLE_TEST_TDR_NTF``    Cable test TDR results
+  ``ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY`` tunnel offload info
   ===================================== =================================
 
 ``GET`` requests are sent by userspace applications to retrieve device
@@ -1363,4 +1365,5 @@ are netlink only.
   ``ETHTOOL_SFECPARAM``               n/a
   n/a                                 ''ETHTOOL_MSG_CABLE_TEST_ACT''
   n/a                                 ''ETHTOOL_MSG_CABLE_TEST_TDR_ACT''
+  n/a                                 ``ETHTOOL_MSG_TUNNEL_INFO_GET``
   =================================== =====================================
index c29496f..611e4b1 100644 (file)
@@ -95,6 +95,7 @@ Contents:
    seg6-sysctl
    strparser
    switchdev
+   sysfs-tagging
    tc-actions-env-rules
    tcp-thin
    team
index 46caaad..379817c 100644 (file)
@@ -49,16 +49,18 @@ Register preservation rules
 Register preservation rules match the ELF ABI calling sequence with the
 following differences:
 
-=========== ============= ========================================
 --- For the sc instruction, differences with the ELF ABI ---
+=========== ============= ========================================
 r0          Volatile      (System call number.)
 r3          Volatile      (Parameter 1, and return value.)
 r4-r8       Volatile      (Parameters 2-6.)
 cr0         Volatile      (cr0.SO is the return error condition.)
 cr1, cr5-7  Nonvolatile
 lr          Nonvolatile
+=========== ============= ========================================
 
 --- For the scv 0 instruction, differences with the ELF ABI ---
+=========== ============= ========================================
 r0          Volatile      (System call number.)
 r3          Volatile      (Parameter 1, and return value.)
 r4-r8       Volatile      (Parameters 2-6.)
index 4ae1e0f..e05fb1b 100644 (file)
@@ -405,7 +405,7 @@ be found at:
        http://vger.kernel.org/vger-lists.html
 
 There are lists hosted elsewhere, though; a number of them are at
-lists.redhat.com.
+redhat.com/mailman/listinfo.
 
 The core mailing list for kernel development is, of course, linux-kernel.
 This list is an intimidating place to be; volume can reach 500 messages per
index ee74176..dac1771 100644 (file)
@@ -30,6 +30,7 @@ you probably needn't concern yourself with pcmciautils.
         Program        Minimal version       Command to check the version
 ====================== ===============  ========================================
 GNU C                  4.9              gcc --version
+Clang/LLVM (optional)  10.0.1           clang --version
 GNU make               3.81             make --version
 binutils               2.23             ld -v
 flex                   2.5.35           flex --version
@@ -68,6 +69,15 @@ GCC
 The gcc version requirements may vary depending on the type of CPU in your
 computer.
 
+Clang/LLVM (optional)
+---------------------
+
+The latest formal release of clang and LLVM utils (according to
+`releases.llvm.org <https://releases.llvm.org>`_) are supported for building
+kernels. Older releases aren't guaranteed to work, and we may drop workarounds
+from the kernel that were used to support older versions. Please see additional
+docs on :ref:`Building Linux with Clang/LLVM <kbuild_llvm>`.
+
 Make
 ----
 
@@ -331,6 +341,11 @@ gcc
 
 - <ftp://ftp.gnu.org/gnu/gcc/>
 
+Clang/LLVM
+----------
+
+- :ref:`Getting LLVM <getting_llvm>`.
+
 Make
 ----
 
index 4a9aa4f..ff71d80 100644 (file)
@@ -51,24 +51,6 @@ to make sure their systems do not continue running in the face of
 "unreachable" conditions. (For example, see commits like `this one
 <https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_.)
 
-uninitialized_var()
--------------------
-For any compiler warnings about uninitialized variables, just add
-an initializer. Using the uninitialized_var() macro (or similar
-warning-silencing tricks) is dangerous as it papers over `real bugs
-<https://lore.kernel.org/lkml/20200603174714.192027-1-glider@google.com/>`_
-(or can in the future), and suppresses unrelated compiler warnings
-(e.g. "unused variable"). If the compiler thinks it is uninitialized,
-either simply initialize the variable or make compiler changes. Keep in
-mind that in most cases, if an initialization is obviously redundant,
-the compiler's dead-store elimination pass will make sure there are no
-needless variable writes.
-
-As Linus has said, this macro
-`must <https://lore.kernel.org/lkml/CA+55aFw+Vbj0i=1TGqCR5vQkCzWJ0QxK6CernOU6eedsudAixw@mail.gmail.com/>`_
-`be <https://lore.kernel.org/lkml/CA+55aFwgbgqhbp1fkxvRKEpzyR5J8n1vKT1VZdz9knmPuXhOeg@mail.gmail.com/>`_
-`removed <https://lore.kernel.org/lkml/CA+55aFz2500WfbKXAx8s67wrm9=yVJu65TpLgN_ybYNv0VEOKA@mail.gmail.com/>`_.
-
 open-coded arithmetic in allocator arguments
 --------------------------------------------
 Dynamic size calculations (especially multiplication) should not be
@@ -142,7 +124,7 @@ only NUL-terminated strings. The safe replacement is strscpy().
 (Users of strscpy() still needing NUL-padding should instead
 use strscpy_pad().)
 
-If a caller is using non-NUL-terminated strings, strncpy()() can
+If a caller is using non-NUL-terminated strings, strncpy() can
 still be used, but destinations should be marked with the `__nonstring
 <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
 attribute to avoid future compiler warnings.
@@ -322,7 +304,8 @@ to allocate for a structure containing an array of this kind as a member::
 In the example above, we had to remember to calculate ``count - 1`` when using
 the struct_size() helper, otherwise we would have --unintentionally-- allocated
 memory for one too many ``items`` objects. The cleanest and least error-prone way
-to implement this is through the use of a `flexible array member`::
+to implement this is through the use of a `flexible array member`, together with
+struct_size() and flex_array_size() helpers::
 
         struct something {
                 size_t count;
@@ -334,5 +317,4 @@ to implement this is through the use of a `flexible array member`::
         instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
         instance->count = count;
 
-        size = sizeof(instance->items[0]) * instance->count;
-        memcpy(instance->items, source, size);
+        memcpy(instance->items, source, flex_array_size(instance, items, instance->count));
index c9e4ce2..16586f6 100644 (file)
@@ -25,6 +25,11 @@ attachments, but then the attachments should have content-type
 it makes quoting portions of the patch more difficult in the patch
 review process.
 
+It's also strongly recommended that you use plain text in your email body,
+for patches and other emails alike. https://useplaintext.email may be useful
+for information on how to configure your preferred email client, as well as
+listing recommended email clients should you not already have a preference.
+
 Email clients that are used for Linux kernel patches should send the
 patch text untouched.  For example, they should not modify or delete tabs
 or spaces, even at the beginning or end of lines.
index e5f5f06..ec474a7 100644 (file)
@@ -6,14 +6,15 @@ Programming Language
 The kernel is written in the C programming language [c-language]_.
 More precisely, the kernel is typically compiled with ``gcc`` [gcc]_
 under ``-std=gnu89`` [gcc-c-dialect-options]_: the GNU dialect of ISO C90
-(including some C99 features).
+(including some C99 features). ``clang`` [clang]_ is also supported, see
+docs on :ref:`Building Linux with Clang/LLVM <kbuild_llvm>`.
 
 This dialect contains many extensions to the language [gnu-extensions]_,
 and many of them are used within the kernel as a matter of course.
 
-There is some support for compiling the kernel with ``clang`` [clang]_
-and ``icc`` [icc]_ for several of the architectures, although at the time
-of writing it is not completed, requiring third-party patches.
+There is some support for compiling the kernel with ``icc`` [icc]_ for several
+of the architectures, although at the time of writing it is not completed,
+requiring third-party patches.
 
 Attributes
 ----------
index 3f8e9d5..b681e86 100644 (file)
@@ -24,6 +24,10 @@ and elsewhere regarding submitting Linux kernel patches.
 
   c) Builds successfully when using ``O=builddir``
 
+  d) Any Documentation/ changes build successfully without new warnings/errors.
+     Use ``make htmldocs`` or ``make pdfdocs`` to check the build and
+     fix any issues.
+
 3) Builds on multiple CPU architectures by using local cross-compile tools
    or some other build farm.
 
index 74b35bf..3861887 100644 (file)
@@ -60,10 +60,11 @@ What Criteria Determine Acceptance
 
 Licensing:
                The code must be released to us under the
-               GNU General Public License. We don't insist on any kind
-               of exclusive GPL licensing, and if you wish the driver
-               to be useful to other communities such as BSD you may well
-               wish to release under multiple licenses.
+               GNU General Public License. If you wish the driver to be
+               useful to other communities such as BSD you may release
+               under multiple licenses. If you choose to release under
+               licenses other than the GPL, you should include your
+               rationale for your license choices in your cover letter.
                See accepted licenses at include/linux/module.h
 
 Copyright:
index 5219bf3..58586ff 100644 (file)
@@ -10,22 +10,18 @@ can greatly increase the chances of your change being accepted.
 
 This document contains a large number of suggestions in a relatively terse
 format.  For detailed information on how the kernel development process
-works, see :ref:`Documentation/process <development_process_main>`.
-Also, read :ref:`Documentation/process/submit-checklist.rst <submitchecklist>`
-for a list of items to check before
-submitting code.  If you are submitting a driver, also read
-:ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`;
-for device tree binding patches, read
-Documentation/devicetree/bindings/submitting-patches.rst.
-
-Many of these steps describe the default behavior of the ``git`` version
-control system; if you use ``git`` to prepare your patches, you'll find much
-of the mechanical work done for you, though you'll still need to prepare
-and document a sensible set of patches.  In general, use of ``git`` will make
-your life as a kernel developer easier.
-
-0) Obtain a current source tree
--------------------------------
+works, see :doc:`development-process`. Also, read :doc:`submit-checklist`
+for a list of items to check before submitting code.  If you are submitting
+a driver, also read :doc:`submitting-drivers`; for device tree binding patches,
+read :doc:`submitting-patches`.
+
+This documentation assumes that you're using ``git`` to prepare your patches.
+If you're unfamiliar with ``git``, you would be well-advised to learn how to
+use it, it will make your life as a kernel developer and in general much
+easier.
+
+Obtain a current source tree
+----------------------------
 
 If you do not have a repository with the current kernel source handy, use
 ``git`` to obtain one.  You'll want to start with the mainline repository,
@@ -39,68 +35,10 @@ patches prepared against those trees.  See the **T:** entry for the subsystem
 in the MAINTAINERS file to find that tree, or simply ask the maintainer if
 the tree is not listed there.
 
-It is still possible to download kernel releases via tarballs (as described
-in the next section), but that is the hard way to do kernel development.
-
-1) ``diff -up``
----------------
-
-If you must generate your patches by hand, use ``diff -up`` or ``diff -uprN``
-to create patches.  Git generates patches in this form by default; if
-you're using ``git``, you can skip this section entirely.
-
-All changes to the Linux kernel occur in the form of patches, as
-generated by :manpage:`diff(1)`.  When creating your patch, make sure to
-create it in "unified diff" format, as supplied by the ``-u`` argument
-to :manpage:`diff(1)`.
-Also, please use the ``-p`` argument which shows which C function each
-change is in - that makes the resultant ``diff`` a lot easier to read.
-Patches should be based in the root kernel source directory,
-not in any lower subdirectory.
-
-To create a patch for a single file, it is often sufficient to do::
-
-       SRCTREE=linux
-       MYFILE=drivers/net/mydriver.c
-
-       cd $SRCTREE
-       cp $MYFILE $MYFILE.orig
-       vi $MYFILE      # make your change
-       cd ..
-       diff -up $SRCTREE/$MYFILE{.orig,} > /tmp/patch
-
-To create a patch for multiple files, you should unpack a "vanilla",
-or unmodified kernel source tree, and generate a ``diff`` against your
-own source tree.  For example::
-
-       MYSRC=/devel/linux
-
-       tar xvfz linux-3.19.tar.gz
-       mv linux-3.19 linux-3.19-vanilla
-       diff -uprN -X linux-3.19-vanilla/Documentation/dontdiff \
-               linux-3.19-vanilla $MYSRC > /tmp/patch
-
-``dontdiff`` is a list of files which are generated by the kernel during
-the build process, and should be ignored in any :manpage:`diff(1)`-generated
-patch.
-
-Make sure your patch does not include any extra files which do not
-belong in a patch submission.  Make sure to review your patch -after-
-generating it with :manpage:`diff(1)`, to ensure accuracy.
-
-If your changes produce a lot of deltas, you need to split them into
-individual patches which modify things in logical stages; see
-:ref:`split_changes`.  This will facilitate review by other kernel developers,
-very important if you want your patch accepted.
-
-If you're using ``git``, ``git rebase -i`` can help you with this process.  If
-you're not using ``git``, ``quilt`` <https://savannah.nongnu.org/projects/quilt>
-is another popular alternative.
-
 .. _describe_changes:
 
-2) Describe your changes
-------------------------
+Describe your changes
+---------------------
 
 Describe your problem.  Whether your patch is a one-line bug fix or
 5000 lines of a new feature, there must be an underlying problem that
@@ -203,8 +141,8 @@ An example call::
 
 .. _split_changes:
 
-3) Separate your changes
-------------------------
+Separate your changes
+---------------------
 
 Separate each **logical change** into a separate patch.
 
@@ -236,8 +174,8 @@ then only post say 15 or so at a time and wait for review and integration.
 
 
 
-4) Style-check your changes
----------------------------
+Style-check your changes
+------------------------
 
 Check your patch for basic style violations, details of which can be
 found in
@@ -267,8 +205,8 @@ You should be able to justify all violations that remain in your
 patch.
 
 
-5) Select the recipients for your patch
----------------------------------------
+Select the recipients for your patch
+------------------------------------
 
 You should always copy the appropriate subsystem maintainer(s) on any patch
 to code that they maintain; look through the MAINTAINERS file and the
@@ -299,7 +237,8 @@ sending him e-mail.
 If you have a patch that fixes an exploitable security bug, send that patch
 to security@kernel.org.  For severe bugs, a short embargo may be considered
 to allow distributors to get the patch out to users; in such cases,
-obviously, the patch should not be sent to any public lists.
+obviously, the patch should not be sent to any public lists. See also
+:doc:`/admin-guide/security-bugs`.
 
 Patches that fix a severe bug in a released kernel should be directed
 toward the stable maintainers by putting a line like this::
@@ -342,15 +281,20 @@ Trivial patches must qualify for one of the following rules:
 
 
 
-6) No MIME, no links, no compression, no attachments.  Just plain text
-----------------------------------------------------------------------
+No MIME, no links, no compression, no attachments.  Just plain text
+-------------------------------------------------------------------
 
 Linus and other kernel developers need to be able to read and comment
 on the changes you are submitting.  It is important for a kernel
 developer to be able to "quote" your changes, using standard e-mail
 tools, so that they may comment on specific portions of your code.
 
-For this reason, all patches should be submitted by e-mail "inline".
+For this reason, all patches should be submitted by e-mail "inline". The
+easiest way to do this is with ``git send-email``, which is strongly
+recommended.  An interactive tutorial for ``git send-email`` is available at
+https://git-send-email.io.
+
+If you choose not to use ``git send-email``:
 
 .. warning::
 
@@ -366,27 +310,17 @@ decreasing the likelihood of your MIME-attached change being accepted.
 Exception:  If your mailer is mangling patches then someone may ask
 you to re-send them using MIME.
 
-See :ref:`Documentation/process/email-clients.rst <email_clients>`
-for hints about configuring your e-mail client so that it sends your patches
-untouched.
-
-7) E-mail size
---------------
+See :doc:`/process/email-clients` for hints about configuring your e-mail
+client so that it sends your patches untouched.
 
-Large changes are not appropriate for mailing lists, and some
-maintainers.  If your patch, uncompressed, exceeds 300 kB in size,
-it is preferred that you store your patch on an Internet-accessible
-server, and provide instead a URL (link) pointing to your patch.  But note
-that if your patch exceeds 300 kB, it almost certainly needs to be broken up
-anyway.
-
-8) Respond to review comments
------------------------------
+Respond to review comments
+--------------------------
 
 Your patch will almost certainly get comments from reviewers on ways in
-which the patch can be improved.  You must respond to those comments;
-ignoring reviewers is a good way to get ignored in return.  Review comments
-or questions that do not lead to a code change should almost certainly
+which the patch can be improved, in the form of a reply to your email. You must
+respond to those comments; ignoring reviewers is a good way to get ignored in
+return. You can simply reply to their emails to answer their comments. Review
+comments or questions that do not lead to a code change should almost certainly
 bring about a comment or changelog entry so that the next reviewer better
 understands what is going on.
 
@@ -395,9 +329,12 @@ for their time.  Code review is a tiring and time-consuming process, and
 reviewers sometimes get grumpy.  Even in that case, though, respond
 politely and address the problems they have pointed out.
 
+See :doc:`email-clients` for recommendations on email
+clients and mailing list etiquette.
 
-9) Don't get discouraged - or impatient
----------------------------------------
+
+Don't get discouraged - or impatient
+------------------------------------
 
 After you have submitted your change, be patient and wait.  Reviewers are
 busy people and may not get to your patch right away.
@@ -410,18 +347,19 @@ one week before resubmitting or pinging reviewers - possibly longer during
 busy times like merge windows.
 
 
-10) Include PATCH in the subject
---------------------------------
+Include PATCH in the subject
+-----------------------------
 
 Due to high e-mail traffic to Linus, and to linux-kernel, it is common
 convention to prefix your subject line with [PATCH].  This lets Linus
 and other kernel developers more easily distinguish patches from other
 e-mail discussions.
 
+``git send-email`` will do this for you automatically.
 
 
-11) Sign your work - the Developer's Certificate of Origin
-----------------------------------------------------------
+Sign your work - the Developer's Certificate of Origin
+------------------------------------------------------
 
 To improve tracking of who did what, especially with patches that can
 percolate to their final resting place in the kernel through several
@@ -465,60 +403,15 @@ then you just add a line saying::
        Signed-off-by: Random J Developer <random@developer.example.org>
 
 using your real name (sorry, no pseudonyms or anonymous contributions.)
+This will be done for you automatically if you use ``git commit -s``.
 
 Some people also put extra tags at the end.  They'll just be ignored for
 now, but you can do this to mark internal company procedures or just
 point out some special detail about the sign-off.
 
-If you are a subsystem or branch maintainer, sometimes you need to slightly
-modify patches you receive in order to merge them, because the code is not
-exactly the same in your tree and the submitters'. If you stick strictly to
-rule (c), you should ask the submitter to rediff, but this is a totally
-counter-productive waste of time and energy. Rule (b) allows you to adjust
-the code, but then it is very impolite to change one submitter's code and
-make him endorse your bugs. To solve this problem, it is recommended that
-you add a line between the last Signed-off-by header and yours, indicating
-the nature of your changes. While there is nothing mandatory about this, it
-seems like prepending the description with your mail and/or name, all
-enclosed in square brackets, is noticeable enough to make it obvious that
-you are responsible for last-minute changes. Example::
 
-       Signed-off-by: Random J Developer <random@developer.example.org>
-       [lucky@maintainer.example.org: struct foo moved from foo.c to foo.h]
-       Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>
-
-This practice is particularly helpful if you maintain a stable branch and
-want at the same time to credit the author, track changes, merge the fix,
-and protect the submitter from complaints. Note that under no circumstances
-can you change the author's identity (the From header), as it is the one
-which appears in the changelog.
-
-Special note to back-porters: It seems to be a common and useful practice
-to insert an indication of the origin of a patch at the top of the commit
-message (just after the subject line) to facilitate tracking. For instance,
-here's what we see in a 3.x-stable release::
-
-  Date:   Tue Oct 7 07:26:38 2014 -0400
-
-    libata: Un-break ATA blacklist
-
-    commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream.
-
-And here's what might appear in an older kernel once a patch is backported::
-
-    Date:   Tue May 13 22:12:27 2008 +0200
-
-        wireless, airo: waitbusy() won't delay
-
-        [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a]
-
-Whatever the format, this information provides a valuable help to people
-tracking your trees, and to people trying to troubleshoot bugs in your
-tree.
-
-
-12) When to use Acked-by:, Cc:, and Co-developed-by:
--------------------------------------------------------
+When to use Acked-by:, Cc:, and Co-developed-by:
+------------------------------------------------
 
 The Signed-off-by: tag indicates that the signer was involved in the
 development of the patch, or that he/she was in the patch's delivery path.
@@ -586,8 +479,8 @@ Example of a patch submitted by a Co-developed-by: author::
        Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>
 
 
-13) Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes:
---------------------------------------------------------------------------
+Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes:
+----------------------------------------------------------------------
 
 The Reported-by tag gives credit to people who find bugs and report them and it
 hopefully inspires them to help us again in the future.  Please note that if
@@ -650,8 +543,8 @@ for more details.
 
 .. _the_canonical_patch_format:
 
-14) The canonical patch format
-------------------------------
+The canonical patch format
+--------------------------
 
 This section describes how the patch itself should be formatted.  Note
 that, if you have your patches stored in a ``git`` repository, proper patch
@@ -773,8 +666,8 @@ references.
 
 .. _explicit_in_reply_to:
 
-15) Explicit In-Reply-To headers
---------------------------------
+Explicit In-Reply-To headers
+----------------------------
 
 It can be helpful to manually add In-Reply-To: headers to a patch
 (e.g., when using ``git send-email``) to associate the patch with
@@ -787,8 +680,8 @@ helpful, you can use the https://lkml.kernel.org/ redirector (e.g., in
 the cover email text) to link to an earlier version of the patch series.
 
 
-16) Providing base tree information
------------------------------------
+Providing base tree information
+-------------------------------
 
 When other developers receive your patches and start the review process,
 it is often useful for them to know where in the tree history they
@@ -838,61 +731,6 @@ either below the ``---`` line or at the very bottom of all other
 content, right before your email signature.
 
 
-17) Sending ``git pull`` requests
----------------------------------
-
-If you have a series of patches, it may be most convenient to have the
-maintainer pull them directly into the subsystem repository with a
-``git pull`` operation.  Note, however, that pulling patches from a developer
-requires a higher degree of trust than taking patches from a mailing list.
-As a result, many subsystem maintainers are reluctant to take pull
-requests, especially from new, unknown developers.  If in doubt you can use
-the pull request as the cover letter for a normal posting of the patch
-series, giving the maintainer the option of using either.
-
-A pull request should have [GIT PULL] in the subject line.  The
-request itself should include the repository name and the branch of
-interest on a single line; it should look something like::
-
-  Please pull from
-
-      git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus
-
-  to get these changes:
-
-A pull request should also include an overall message saying what will be
-included in the request, a ``git shortlog`` listing of the patches
-themselves, and a ``diffstat`` showing the overall effect of the patch series.
-The easiest way to get all this information together is, of course, to let
-``git`` do it for you with the ``git request-pull`` command.
-
-Some maintainers (including Linus) want to see pull requests from signed
-commits; that increases their confidence that the request actually came
-from you.  Linus, in particular, will not pull from public hosting sites
-like GitHub in the absence of a signed tag.
-
-The first step toward creating such tags is to make a GNUPG key and get it
-signed by one or more core kernel developers.  This step can be hard for
-new developers, but there is no way around it.  Attending conferences can
-be a good way to find developers who can sign your key.
-
-Once you have prepared a patch series in ``git`` that you wish to have somebody
-pull, create a signed tag with ``git tag -s``.  This will create a new tag
-identifying the last commit in the series and containing a signature
-created with your private key.  You will also have the opportunity to add a
-changelog-style message to the tag; this is an ideal place to describe the
-effects of the pull request as a whole.
-
-If the tree the maintainer will be pulling from is not the repository you
-are working from, don't forget to push the signed tag explicitly to the
-public tree.
-
-When generating your pull request, use the signed tag as the target.  A
-command like this will do the trick::
-
-  git request-pull master git://my.public.tree/linux.git my-signed-tag
-
-
 References
 ----------
 
index 00bf0d0..9b7cbe4 100644 (file)
@@ -365,7 +365,7 @@ giving it a high uclamp.min value.
 .. note::
 
   Wakeup CPU selection in CFS can be eclipsed by Energy Aware Scheduling
-  (EAS), which is described in Documentation/scheduling/sched-energy.rst.
+  (EAS), which is described in Documentation/scheduler/sched-energy.rst.
 
 5.1.3 Load balancing
 ~~~~~~~~~~~~~~~~~~~~
index 78f8507..001e09c 100644 (file)
@@ -331,7 +331,7 @@ asymmetric CPU topologies for now. This requirement is checked at run-time by
 looking for the presence of the SD_ASYM_CPUCAPACITY flag when the scheduling
 domains are built.
 
-See Documentation/sched/sched-capacity.rst for requirements to be met for this
+See Documentation/scheduler/sched-capacity.rst for requirements to be met for this
 flag to be set in the sched_domain hierarchy.
 
 Please note that EAS is not fundamentally incompatible with SMP, but no
index d938720..357328d 100644 (file)
@@ -323,7 +323,6 @@ credentials (the value is simply returned in each case)::
        uid_t current_fsuid(void)       Current's file access UID
        gid_t current_fsgid(void)       Current's file access GID
        kernel_cap_t current_cap(void)  Current's effective capabilities
-       void *current_security(void)    Current's LSM security pointer
        struct user_struct *current_user(void)  Current's user account
 
 There are also convenience wrappers for retrieving specific associated pairs of
index 9483a74..1da879a 100644 (file)
@@ -39,10 +39,9 @@ With the IBM TSS 2 stack::
 
 Or with the Intel TSS 2 stack::
 
-  #> tpm2_createprimary --hierarchy o -G rsa2048 -o key.ctxt
+  #> tpm2_createprimary --hierarchy o -G rsa2048 -c key.ctxt
   [...]
-  handle: 0x800000FF
-  #> tpm2_evictcontrol -c key.ctxt -p 0x81000001
+  #> tpm2_evictcontrol -c key.ctxt 0x81000001
   persistentHandle: 0x81000001
 
 Usage::
index 998f76e..f3f4640 100644 (file)
@@ -332,7 +332,7 @@ WO 9901953 (A1)
 
 
 US Patents (https://www.uspto.gov/)
-----------------------------------
+-----------------------------------
 
 US 5925841
        Digital Sampling Instrument employing cache memory (Jul. 20, 1999)
index eccb0f0..2ce41d3 100644 (file)
@@ -337,7 +337,7 @@ WO 9901953 (A1)
 
 
 US Patents (https://www.uspto.gov/)
-----------------------------------
+-----------------------------------
 
 US 5925841
        Digital Sampling Instrument employing cache memory (Jul. 20, 1999)
index 2b0fff5..7c7ecf5 100644 (file)
@@ -143,7 +143,7 @@ timestamp shows when the information is put together by the driver
 before returning from the ``STATUS`` and ``STATUS_EXT`` ioctl. in most cases
 this driver_timestamp will be identical to the regular system tstamp.
 
-Examples of typestamping with HDaudio:
+Examples of timestamping with HDAudio:
 
 1. DMA timestamp, no compensation for DMA+analog delay
 ::
index b182363..a1b0f55 100644 (file)
@@ -13,6 +13,7 @@ if sphinx.version_info[0] < 2 or \
 else:
     from sphinx.errors import NoUri
 import re
+from itertools import chain
 
 #
 # Regex nastiness.  Of course.
@@ -21,7 +22,13 @@ import re
 # :c:func: block (i.e. ":c:func:`mmap()`s" flakes out), so the last
 # bit tries to restrict matches to things that won't create trouble.
 #
-RE_function = re.compile(r'([\w_][\w\d_]+\(\))')
+RE_function = re.compile(r'(([\w_][\w\d_]+)\(\))')
+RE_type = re.compile(r'(struct|union|enum|typedef)\s+([\w_][\w\d_]+)')
+#
+# Detects a reference to a documentation page of the form Documentation/... with
+# an optional extension
+#
+RE_doc = re.compile(r'Documentation(/[\w\-_/]+)(\.\w+)*')
 
 #
 # Many places in the docs refer to common system calls.  It is
@@ -34,56 +41,110 @@ Skipfuncs = [ 'open', 'close', 'read', 'write', 'fcntl', 'mmap',
               'select', 'poll', 'fork', 'execve', 'clone', 'ioctl',
               'socket' ]
 
-#
-# Find all occurrences of function() and try to replace them with
-# appropriate cross references.
-#
-def markup_funcs(docname, app, node):
-    cdom = app.env.domains['c']
+def markup_refs(docname, app, node):
     t = node.astext()
     done = 0
     repl = [ ]
-    for m in RE_function.finditer(t):
+    #
+    # Associate each regex with the function that will markup its matches
+    #
+    markup_func = {RE_type: markup_c_ref,
+                   RE_function: markup_c_ref,
+                   RE_doc: markup_doc_ref}
+    match_iterators = [regex.finditer(t) for regex in markup_func]
+    #
+    # Sort all references by the starting position in text
+    #
+    sorted_matches = sorted(chain(*match_iterators), key=lambda m: m.start())
+    for m in sorted_matches:
         #
-        # Include any text prior to function() as a normal text node.
+        # Include any text prior to match as a normal text node.
         #
         if m.start() > done:
             repl.append(nodes.Text(t[done:m.start()]))
+
         #
-        # Go through the dance of getting an xref out of the C domain
-        #
-        target = m.group(1)[:-2]
-        target_text = nodes.Text(target + '()')
-        xref = None
-        if target not in Skipfuncs:
-            lit_text = nodes.literal(classes=['xref', 'c', 'c-func'])
-            lit_text += target_text
-            pxref = addnodes.pending_xref('', refdomain = 'c',
-                                          reftype = 'function',
-                                          reftarget = target, modname = None,
-                                          classname = None)
-            #
-            # XXX The Latex builder will throw NoUri exceptions here,
-            # work around that by ignoring them.
-            #
-            try:
-                xref = cdom.resolve_xref(app.env, docname, app.builder,
-                                         'function', target, pxref, lit_text)
-            except NoUri:
-                xref = None
-        #
-        # Toss the xref into the list if we got it; otherwise just put
-        # the function text.
+        # Call the function associated with the regex that matched this text and
+        # append its return to the text
         #
-        if xref:
-            repl.append(xref)
-        else:
-            repl.append(target_text)
+        repl.append(markup_func[m.re](docname, app, m))
+
         done = m.end()
     if done < len(t):
         repl.append(nodes.Text(t[done:]))
     return repl
 
+#
+# Try to replace a C reference (function() or struct/union/enum/typedef
+# type_name) with an appropriate cross reference.
+#
+def markup_c_ref(docname, app, match):
+    class_str = {RE_function: 'c-func', RE_type: 'c-type'}
+    reftype_str = {RE_function: 'function', RE_type: 'type'}
+
+    cdom = app.env.domains['c']
+    #
+    # Go through the dance of getting an xref out of the C domain
+    #
+    target = match.group(2)
+    target_text = nodes.Text(match.group(0))
+    xref = None
+    if not (match.re == RE_function and target in Skipfuncs):
+        lit_text = nodes.literal(classes=['xref', 'c', class_str[match.re]])
+        lit_text += target_text
+        pxref = addnodes.pending_xref('', refdomain = 'c',
+                                      reftype = reftype_str[match.re],
+                                      reftarget = target, modname = None,
+                                      classname = None)
+        #
+        # XXX The Latex builder will throw NoUri exceptions here,
+        # work around that by ignoring them.
+        #
+        try:
+            xref = cdom.resolve_xref(app.env, docname, app.builder,
+                                     reftype_str[match.re], target, pxref,
+                                     lit_text)
+        except NoUri:
+            xref = None
+    #
+    # Return the xref if we got it; otherwise just return the plain text.
+    #
+    if xref:
+        return xref
+    else:
+        return target_text
+
+#
+# Try to replace a documentation reference of the form Documentation/... with a
+# cross reference to that page
+#
+def markup_doc_ref(docname, app, match):
+    stddom = app.env.domains['std']
+    #
+    # Go through the dance of getting an xref out of the std domain
+    #
+    target = match.group(1)
+    xref = None
+    pxref = addnodes.pending_xref('', refdomain = 'std', reftype = 'doc',
+                                  reftarget = target, modname = None,
+                                  classname = None, refexplicit = False)
+    #
+    # XXX The Latex builder will throw NoUri exceptions here,
+    # work around that by ignoring them.
+    #
+    try:
+        xref = stddom.resolve_xref(app.env, docname, app.builder, 'doc',
+                                   target, pxref, None)
+    except NoUri:
+        xref = None
+    #
+    # Return the xref if we got it; otherwise just return the plain text.
+    #
+    if xref:
+        return xref
+    else:
+        return nodes.Text(match.group(0))
+
 def auto_markup(app, doctree, name):
     #
     # This loop could eventually be improved on.  Someday maybe we
@@ -97,7 +158,7 @@ def auto_markup(app, doctree, name):
     for para in doctree.traverse(nodes.paragraph):
         for node in para.traverse(nodes.Text):
             if not isinstance(node.parent, nodes.literal):
-                node.parent.replace(node, markup_funcs(name, app, node))
+                node.parent.replace(node, markup_refs(name, app, node))
 
 def setup(app):
     app.connect('doctree-resolved', auto_markup)
index c170916..10850a9 100644 (file)
@@ -40,7 +40,7 @@ Synopsis of kprobe_events
  MEMADDR       : Address where the probe is inserted.
  MAXACTIVE     : Maximum number of instances of the specified function that
                  can be probed simultaneously, or 0 for the default value
-                 as defined in Documentation/staging/kprobes.rst section 1.3.1.
+                 as defined in Documentation/trace/kprobes.rst section 1.3.1.
 
  FETCHARGS     : Arguments. Each probe can have up to 128 args.
   %REG         : Fetch register REG
index 9c8d22a..c5d77fc 100644 (file)
@@ -1,28 +1,4 @@
-.. This file is dual-licensed: you can use it either under the terms
-.. of the GPL 2.0 or the GFDL 1.2 license, at your option. Note that this
-.. dual licensing only applies to this file, and not this project as a
-.. whole.
-..
-.. a) This file is free software; you can redistribute it and/or
-..    modify it under the terms of the GNU General Public License as
-..    published by the Free Software Foundation version 2 of
-..    the License.
-..
-..    This file is distributed in the hope that it will be useful,
-..    but WITHOUT ANY WARRANTY; without even the implied warranty of
-..    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-..    GNU General Public License for more details.
-..
-.. Or, alternatively,
-..
-.. b) Permission is granted to copy, distribute and/or modify this
-..    document under the terms of the GNU Free Documentation License,
-..    Version 1.2 version published by the Free Software
-..    Foundation, with no Invariant Sections, no Front-Cover Texts
-..    and no Back-Cover Texts. A copy of the license is included at
-..    Documentation/userspace-api/media/fdl-appendix.rst.
-..
-.. TODO: replace it to GPL-2.0 OR GFDL-1.2 WITH no-invariant-sections
+.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.2-no-invariants-only
 
 ===========================
 Lockless Ring Buffer Design
index e108eaf..a642ff3 100644 (file)
@@ -130,7 +130,7 @@ chi usa solo stringe terminate. La versione sicura da usare è
 strscpy(). (chi usa strscpy() e necessita di estendere la
 terminazione con NUL deve aggiungere una chiamata a memset())
 
-Se il chiamate no usa stringhe terminate con NUL, allore strncpy()()
+Se il chiamate no usa stringhe terminate con NUL, allore strncpy()
 può continuare ad essere usata, ma i buffer di destinazione devono essere
 marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
 per evitare avvisi durante la compilazione.
index 71d4823..240d29b 100644 (file)
@@ -284,9 +284,10 @@ Andrew Morton의 글이 있다.
 여러 메이저 넘버를 갖는 다양한 안정된 커널 트리들
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-3 자리 숫자로 이루어진 버젼의 커널들은 -stable 커널들이다. 그것들은 해당 메이저
-메인라인 릴리즈에서 발견된 큰 회귀들이나 보안 문제들 중 비교적 작고 중요한
-수정들을 포함하며, 앞의 두 버전 넘버는 같은 기반 버전을 의미한다.
+세개의 버젼 넘버로 이루어진 버젼의 커널들은 -stable 커널들이다. 그것들은 해당
+메이저 메인라인 릴리즈에서 발견된 큰 회귀들이나 보안 문제들 중 비교적 작고
+중요한 수정들을 포함한다.  주요 stable 시리즈 릴리즈는 세번째 버젼 넘버를
+증가시키며 앞의 두 버젼 넘버는 그대로 유지한다.
 
 이것은 가장 최근의 안정적인 커널을 원하는 사용자에게 추천되는 브랜치이며,
 개발/실험적 버젼을 테스트하는 것을 돕고자 하는 사용자들과는 별로 관련이 없다.
@@ -316,7 +317,7 @@ Andrew Morton의 글이 있다.
 제안된 패치는 서브시스템 트리에 커밋되기 전에 메일링 리스트를 통해
 리뷰된다(아래의 관련 섹션을 참고하기 바란다). 일부 커널 서브시스템의 경우, 이
 리뷰 프로세스는 patchwork라는 도구를 통해 추적된다. patchwork은 등록된 패치와
\8c¨ì¹\98ì\97\90 ë\8c\80í\95\9c ì½\94ë©\98í\8a¸, í\8c¨ì¹\98ì\9d\98 ë²\84ì \84을 볼 수 있는 웹 인터페이스를 제공하고,
\8c¨ì¹\98ì\97\90 ë\8c\80í\95\9c ì½\94ë©\98í\8a¸, í\8c¨ì¹\98ì\9d\98 ë²\84ì ¼을 볼 수 있는 웹 인터페이스를 제공하고,
 메인테이너는 패치를 리뷰 중, 리뷰 통과, 또는 반려됨으로 표시할 수 있다.
 대부분의 이러한 patchwork 사이트는 https://patchwork.kernel.org/ 에 나열되어
 있다.
index 9dcc7c9..64d932f 100644 (file)
@@ -91,7 +91,6 @@ Documentation/memory-barriers.txt
 
      - 컴파일러 배리어.
      - CPU 메모리 배리어.
-     - MMIO 쓰기 배리어.
 
  (*) 암묵적 커널 메모리 배리어.
 
@@ -103,7 +102,6 @@ Documentation/memory-barriers.txt
  (*) CPU 간 ACQUIRING 배리어의 효과.
 
      - Acquire vs 메모리 액세스.
-     - Acquire vs I/O 액세스.
 
  (*) 메모리 배리어가 필요한 곳
 
@@ -515,14 +513,13 @@ CPU 에게 기대할 수 있는 최소한의 보장사항 몇가지가 있습니
      완료되기 전에 행해진 것처럼 보일 수 있습니다.
 
      ACQUIRE 와 RELEASE 오퍼레이션의 사용은 일반적으로 다른 메모리 배리어의
-     필요성을 없앱니다 (하지만 "MMIO 쓰기 배리어" 서브섹션에서 설명되는 예외를
-     알아두세요).  또한, RELEASE+ACQUIRE 조합은 범용 메모리 배리어처럼 동작할
-     것을 보장하지 -않습니다-.  하지만, 어떤 변수에 대한 RELEASE 오퍼레이션을
-     앞서는 메모리 액세스들의 수행 결과는 이 RELEASE 오퍼레이션을 뒤이어 같은
-     변수에 대해 수행된 ACQUIRE 오퍼레이션을 뒤따르는 메모리 액세스에는 보여질
-     것이 보장됩니다.  다르게 말하자면, 주어진 변수의 크리티컬 섹션에서는, 해당
-     변수에 대한 앞의 크리티컬 섹션에서의 모든 액세스들이 완료되었을 것을
-     보장합니다.
+     필요성을 없앱니다.  또한, RELEASE+ACQUIRE 조합은 범용 메모리 배리어처럼
+     동작할 것을 보장하지 -않습니다-.  하지만, 어떤 변수에 대한 RELEASE
+     오퍼레이션을 앞서는 메모리 액세스들의 수행 결과는 이 RELEASE 오퍼레이션을
+     뒤이어 같은 변수에 대해 수행된 ACQUIRE 오퍼레이션을 뒤따르는 메모리
+     액세스에는 보여질 것이 보장됩니다.  다르게 말하자면, 주어진 변수의
+     크리티컬 섹션에서는, 해당 변수에 대한 앞의 크리티컬 섹션에서의 모든
+     액세스들이 완료되었을 것을 보장합니다.
 
      즉, ACQUIRE 는 최소한의 "취득" 동작처럼, 그리고 RELEASE 는 최소한의 "공개"
      처럼 동작한다는 의미입니다.
@@ -1501,8 +1498,6 @@ u 로의 스토어를 cpu1() 의 v 로부터의 로드 뒤에 일어난 것으
 
   (*) CPU 메모리 배리어.
 
-  (*) MMIO 쓰기 배리어.
-
 
 컴파일러 배리어
 ---------------
@@ -1909,6 +1904,19 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
      "커널 I/O 배리어의 효과" 섹션을, consistent memory 에 대한 자세한 내용을
      위해선 Documentation/core-api/dma-api.rst 문서를 참고하세요.
 
+ (*) pmem_wmb();
+
+     이것은 persistent memory 를 위한 것으로, persistent 저장소에 가해진 변경
+     사항이 플랫폼 연속성 도메인에 도달했을 것을 보장하기 위한 것입니다.
+
+     예를 들어, 임시적이지 않은 pmem 영역으로의 쓰기 후, 우리는 쓰기가 플랫폼
+     연속성 도메인에 도달했을 것을 보장하기 위해 pmem_wmb() 를 사용합니다.
+     이는 쓰기가 뒤따르는 instruction 들이 유발하는 어떠한 데이터 액세스나
+     데이터 전송의 시작 전에 persistent 저장소를 업데이트 했을 것을 보장합니다.
+     이는 wmb() 에 의해 이뤄지는 순서 규칙을 포함합니다.
+
+     Persistent memory 에서의 로드를 위해선 현재의 읽기 메모리 배리어로도 읽기
+     순서를 보장하는데 충분합니다.
 
 =========================
 암묵적 커널 메모리 배리어
diff --git a/Documentation/translations/zh_CN/arm64/amu.rst b/Documentation/translations/zh_CN/arm64/amu.rst
new file mode 100644 (file)
index 0000000..bd875f2
--- /dev/null
@@ -0,0 +1,100 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/arm64/amu.rst <amu_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+
+=================================
+AArch64 Linux 中扩展的活动监控单元
+=================================
+
+作者: Ionela Voinescu <ionela.voinescu@arm.com>
+
+日期: 2019-09-10
+
+本文档简要描述了 AArch64 Linux 支持的活动监控单元的规范。
+
+
+架构总述
+--------
+
+活动监控是 ARMv8.4 CPU 架构引入的一个可选扩展特性。
+
+活动监控单元(在每个 CPU 中实现)为系统管理提供了性能计数器。既可以通
+过系统寄存器的方式访问计数器,同时也支持外部内存映射的方式访问计数器。
+
+AMUv1 架构实现了一个由4个固定的64位事件计数器组成的计数器组。
+
+  - CPU 周期计数器:同 CPU 的频率增长
+  - 常量计数器:同固定的系统时钟频率增长
+  - 淘汰指令计数器: 同每次架构指令执行增长
+  - 内存停顿周期计数器:计算由在时钟域内的最后一级缓存中未命中而引起
+    的指令调度停顿周期数
+
+当处于 WFI 或者 WFE 状态时,计数器不会增长。
+
+AMU 架构提供了一个高达16位的事件计数器空间,未来新的 AMU 版本中可能
+用它来实现新增的事件计数器。
+
+另外,AMUv1 实现了一个多达16个64位辅助事件计数器的计数器组。
+
+冷复位时所有的计数器会清零。
+
+
+基本支持
+--------
+
+内核可以安全地运行在支持 AMU 和不支持 AMU 的 CPU 组合中。
+因此,当配置 CONFIG_ARM64_AMU_EXTN 后我们无条件使能后续
+(secondary or hotplugged) CPU 检测和使用这个特性。
+
+当在 CPU 上检测到该特性时,我们会标记为特性可用但是不能保证计数器的功能,
+仅表明有扩展属性。
+
+固件(代码运行在高异常级别,例如 arm-tf )需支持以下功能:
+
+ - 提供低异常级别(EL2 和 EL1)访问 AMU 寄存器的能力。
+ - 使能计数器。如果未使能,它的值应为 0。
+ - 在从电源关闭状态启动 CPU 前或后保存或者恢复计数器。
+
+当使用使能了该特性的内核启动但固件损坏时,访问计数器寄存器可能会遭遇
+panic 或者死锁。即使未发现这些症状,计数器寄存器返回的数据结果并不一
+定能反映真实情况。通常,计数器会返回 0,表明他们未被使能。
+
+如果固件没有提供适当的支持最好关闭 CONFIG_ARM64_AMU_EXTN。
+值得注意的是,出于安全原因,不要绕过 AMUSERRENR_EL0 设置而捕获从
+EL0(用户空间) 访问 EL1(内核空间)。 因此,固件应该确保访问 AMU寄存器
+不会困在 EL2或EL3。
+
+AMUv1 的固定计数器可以通过如下系统寄存器访问:
+
+ - SYS_AMEVCNTR0_CORE_EL0
+ - SYS_AMEVCNTR0_CONST_EL0
+ - SYS_AMEVCNTR0_INST_RET_EL0
+ - SYS_AMEVCNTR0_MEM_STALL_EL0
+
+特定辅助计数器可以通过 SYS_AMEVCNTR1_EL0(n) 访问,其中n介于0到15。
+
+详细信息定义在目录:arch/arm64/include/asm/sysreg.h。
+
+
+用户空间访问
+------------
+
+由于以下原因,当前禁止从用户空间访问 AMU 的寄存器:
+
+  - 安全因数:可能会暴露处于安全模式执行的代码信息。
+  - 意愿:AMU 是用于系统管理的。
+
+同样,该功能对用户空间不可见。
+
+
+虚拟化
+------
+
+由于以下原因,当前禁止从 KVM 客户端的用户空间(EL0)和内核空间(EL1)
+访问 AMU 的寄存器:
+
+  - 安全因数:可能会暴露给其他客户端或主机端执行的代码信息。
+
+任何试图访问 AMU 寄存器的行为都会触发一个注册在客户端的未定义异常。
diff --git a/Documentation/translations/zh_CN/arm64/index.rst b/Documentation/translations/zh_CN/arm64/index.rst
new file mode 100644 (file)
index 0000000..646ed1f
--- /dev/null
@@ -0,0 +1,16 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/arm64/index.rst <arm64_index>`
+:Translator: Bailu Lin <bailu.lin@vivo.com>
+
+.. _cn_arm64_index:
+
+
+==========
+ARM64 架构
+==========
+
+.. toctree::
+    :maxdepth: 2
+
+    amu
index 9481e3e..046cc1d 100644 (file)
@@ -154,14 +154,13 @@ sysfs 会为这个类型调用适当的方法。当一个文件被读写时,
 
 示例:
 
-#define to_dev(obj) container_of(obj, struct device, kobj)
 #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
 
 static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
                              char *buf)
 {
         struct device_attribute *dev_attr = to_dev_attr(attr);
-        struct device *dev = to_dev(kobj);
+        struct device *dev = kobj_to_dev(kobj);
         ssize_t ret = -EIO;
 
         if (dev_attr->show)
index 85643e4..be6f111 100644 (file)
@@ -19,6 +19,7 @@
    admin-guide/index
    process/index
    filesystems/index
+   arm64/index
 
 目录和表格
 ----------
index 57e752a..2044ed1 100644 (file)
@@ -701,23 +701,6 @@ Memory Consistency Flags
     :stub-columns: 0
     :widths:       3 1 4
 
-    * .. _`V4L2-FLAG-MEMORY-NON-CONSISTENT`:
-
-      - ``V4L2_FLAG_MEMORY_NON_CONSISTENT``
-      - 0x00000001
-      - A buffer is allocated either in consistent (it will be automatically
-       coherent between the CPU and the bus) or non-consistent memory. The
-       latter can provide performance gains, for instance the CPU cache
-       sync/flush operations can be avoided if the buffer is accessed by the
-       corresponding device only and the CPU does not read/write to/from that
-       buffer. However, this requires extra care from the driver -- it must
-       guarantee memory consistency by issuing a cache flush/sync when
-       consistency is needed. If this flag is set V4L2 will attempt to
-       allocate the buffer in non-consistent memory. The flag takes effect
-       only if the buffer is used for :ref:`memory mapping <mmap>` I/O and the
-       queue reports the :ref:`V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS
-       <V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS>` capability.
-
 .. c:type:: v4l2_memory
 
 enum v4l2_memory
index f2a7028..12cf6b4 100644 (file)
@@ -120,13 +120,9 @@ than the number requested.
        If you want to just query the capabilities without making any
        other changes, then set ``count`` to 0, ``memory`` to
        ``V4L2_MEMORY_MMAP`` and ``format.type`` to the buffer type.
-    * - __u32
-      - ``flags``
-      - Specifies additional buffer management attributes.
-       See :ref:`memory-flags`.
 
     * - __u32
-      - ``reserved``\ [6]
+      - ``reserved``\ [7]
       - A place holder for future extensions. Drivers and applications
        must set the array to zero.
 
index 75d894d..0e3e2fd 100644 (file)
@@ -112,17 +112,10 @@ aborting or finishing any DMA in progress, an implicit
        ``V4L2_MEMORY_MMAP`` and ``type`` set to the buffer type. This will
        free any previously allocated buffers, so this is typically something
        that will be done at the start of the application.
-    * - union {
-      - (anonymous)
-    * - __u32
-      - ``flags``
-      - Specifies additional buffer management attributes.
-       See :ref:`memory-flags`.
     * - __u32
       - ``reserved``\ [1]
-      - Kept for backwards compatibility. Use ``flags`` instead.
-    * - }
-      -
+      - A place holder for future extensions. Drivers and applications
+       must set the array to zero.
 
 .. tabularcolumns:: |p{6.1cm}|p{2.2cm}|p{8.7cm}|
 
@@ -169,7 +162,6 @@ aborting or finishing any DMA in progress, an implicit
       - This capability is set by the driver to indicate that the queue supports
         cache and memory management hints. However, it's only valid when the
         queue is used for :ref:`memory mapping <mmap>` streaming I/O. See
-        :ref:`V4L2_FLAG_MEMORY_NON_CONSISTENT <V4L2-FLAG-MEMORY-NON-CONSISTENT>`,
         :ref:`V4L2_BUF_FLAG_NO_CACHE_INVALIDATE <V4L2-BUF-FLAG-NO-CACHE-INVALIDATE>` and
         :ref:`V4L2_BUF_FLAG_NO_CACHE_CLEAN <V4L2-BUF-FLAG-NO-CACHE-CLEAN>`.
 
index de1ab81..d204902 100644 (file)
@@ -8,7 +8,7 @@ Linux Virtualization Support
    :maxdepth: 2
 
    kvm/index
-   uml/user_mode_linux
+   uml/user_mode_linux_howto_v2
    paravirt_ops
    guest-halt-polling
 
index 2d44388..09a8f2a 100644 (file)
@@ -53,11 +53,11 @@ key management interface to perform common hypervisor activities such as
 encrypting bootstrap code, snapshot, migrating and debugging the guest. For more
 information, see the SEV Key Management spec [api-spec]_
 
-The main ioctl to access SEV is KVM_MEM_ENCRYPT_OP.  If the argument
-to KVM_MEM_ENCRYPT_OP is NULL, the ioctl returns 0 if SEV is enabled
+The main ioctl to access SEV is KVM_MEMORY_ENCRYPT_OP.  If the argument
+to KVM_MEMORY_ENCRYPT_OP is NULL, the ioctl returns 0 if SEV is enabled
 and ``ENOTTY` if it is disabled (on some older versions of Linux,
 the ioctl runs normally even with a NULL argument, and therefore will
-likely return ``EFAULT``).  If non-NULL, the argument to KVM_MEM_ENCRYPT_OP
+likely return ``EFAULT``).  If non-NULL, the argument to KVM_MEMORY_ENCRYPT_OP
 must be a struct kvm_sev_cmd::
 
        struct kvm_sev_cmd {
index eb3a131..1f26d83 100644 (file)
@@ -4211,7 +4211,7 @@ H_GET_CPU_CHARACTERISTICS hypercall.
 
 :Capability: basic
 :Architectures: x86
-:Type: system
+:Type: vm
 :Parameters: an opaque platform specific structure (in/out)
 :Returns: 0 on success; -1 on error
 
@@ -4343,7 +4343,7 @@ Errors:
   #define KVM_STATE_NESTED_VMX_SMM_GUEST_MODE  0x00000001
   #define KVM_STATE_NESTED_VMX_SMM_VMXON       0x00000002
 
-#define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE 0x00000001
+  #define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE 0x00000001
 
   struct kvm_vmx_nested_state_hdr {
        __u64 vmxon_pa;
@@ -6130,7 +6130,7 @@ HvCallSendSyntheticClusterIpi, HvCallSendSyntheticClusterIpiEx.
 8.21 KVM_CAP_HYPERV_DIRECT_TLBFLUSH
 -----------------------------------
 
-:Architecture: x86
+:Architectures: x86
 
 This capability indicates that KVM running on top of Hyper-V hypervisor
 enables Direct TLB flush for its guests meaning that TLB flush
@@ -6143,19 +6143,53 @@ in CPUID and only exposes Hyper-V identification. In this case, guest
 thinks it's running on Hyper-V and only use Hyper-V hypercalls.
 
 8.22 KVM_CAP_S390_VCPU_RESETS
+-----------------------------
 
-Architectures: s390
+:Architectures: s390
 
 This capability indicates that the KVM_S390_NORMAL_RESET and
 KVM_S390_CLEAR_RESET ioctls are available.
 
 8.23 KVM_CAP_S390_PROTECTED
+---------------------------
 
-Architecture: s390
-
+:Architectures: s390
 
 This capability indicates that the Ultravisor has been initialized and
 KVM can therefore start protected VMs.
 This capability governs the KVM_S390_PV_COMMAND ioctl and the
 KVM_MP_STATE_LOAD MP_STATE. KVM_SET_MP_STATE can fail for protected
 guests when the state change is invalid.
+
+8.24 KVM_CAP_STEAL_TIME
+-----------------------
+
+:Architectures: arm64, x86
+
+This capability indicates that KVM supports steal time accounting.
+When steal time accounting is supported it may be enabled with
+architecture-specific interfaces.  This capability and the architecture-
+specific interfaces must be consistent, i.e. if one says the feature
+is supported, than the other should as well and vice versa.  For arm64
+see Documentation/virt/kvm/devices/vcpu.rst "KVM_ARM_VCPU_PVTIME_CTRL".
+For x86 see Documentation/virt/kvm/msr.rst "MSR_KVM_STEAL_TIME".
+
+8.25 KVM_CAP_S390_DIAG318
+-------------------------
+
+:Architectures: s390
+
+This capability enables a guest to set information about its control program
+(i.e. guest kernel type and version). The information is helpful during
+system/firmware service events, providing additional data about the guest
+environments running on the machine.
+
+The information is associated with the DIAGNOSE 0x318 instruction, which sets
+an 8-byte value consisting of a one-byte Control Program Name Code (CPNC) and
+a 7-byte Control Program Version Code (CPVC). The CPNC determines what
+environment the control program is running in (e.g. Linux, z/VM...), and the
+CPVC is used for information specific to OS (e.g. Linux version, Linux
+distribution...)
+
+If this capability is available, then the CPNC and CPVC can be synchronized
+between KVM and userspace via the sync regs mechanism (KVM_SYNC_DIAG318).
index d9eba93..83cadd8 100644 (file)
@@ -54,9 +54,9 @@ these functions (see arch/arm{,64}/include/asm/virt.h):
     x3 = x1's value when entering the next payload (arm64)
     x4 = x2's value when entering the next payload (arm64)
 
-  Mask all exceptions, disable the MMU, move the arguments into place
-  (arm64 only), and jump to the restart address while at HYP/EL2. This
-  hypercall is not expected to return to its caller.
+  Mask all exceptions, disable the MMU, clear I+D bits, move the arguments
+  into place (arm64 only), and jump to the restart address while at HYP/EL2.
+  This hypercall is not expected to return to its caller.
 
 Any other value of r0/x0 triggers a hypervisor-specific handling,
 which is not documented here.
index a7dff91..9150e9d 100644 (file)
@@ -78,7 +78,7 @@ KVM_FEATURE_PV_SEND_IPI           11          guest checks this feature bit
                                               before enabling paravirtualized
                                               sebd IPIs
 
-KVM_FEATURE_PV_POLL_CONTROL       12          host-side polling on HLT can
+KVM_FEATURE_POLL_CONTROL          12          host-side polling on HLT can
                                               be disabled by writing
                                               to msr 0x4b564d05.
 
diff --git a/Documentation/virt/uml/user_mode_linux.rst b/Documentation/virt/uml/user_mode_linux.rst
deleted file mode 100644 (file)
index de0f0b2..0000000
+++ /dev/null
@@ -1,4403 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-=====================
-User Mode Linux HOWTO
-=====================
-
-:Author:  User Mode Linux Core Team
-:Last-updated: Sat Jan 25 16:07:55 CET 2020
-
-This document describes the use and abuse of Jeff Dike's User Mode
-Linux: a port of the Linux kernel as a normal Intel Linux process.
-
-
-.. Table of Contents
-
-  1. Introduction
-
-     1.1 How is User Mode Linux Different?
-     1.2 Why Would I Want User Mode Linux?
-
-  2. Compiling the kernel and modules
-
-     2.1 Compiling the kernel
-     2.2 Compiling and installing kernel modules
-     2.3 Compiling and installing uml_utilities
-
-  3. Running UML and logging in
-
-     3.1 Running UML
-     3.2 Logging in
-     3.3 Examples
-
-  4. UML on 2G/2G hosts
-
-     4.1 Introduction
-     4.2 The problem
-     4.3 The solution
-
-  5. Setting up serial lines and consoles
-
-     5.1 Specifying the device
-     5.2 Specifying the channel
-     5.3 Examples
-
-  6. Setting up the network
-
-     6.1 General setup
-     6.2 Userspace daemons
-     6.3 Specifying ethernet addresses
-     6.4 UML interface setup
-     6.5 Multicast
-     6.6 TUN/TAP with the uml_net helper
-     6.7 TUN/TAP with a preconfigured tap device
-     6.8 Ethertap
-     6.9 The switch daemon
-     6.10 Slip
-     6.11 Slirp
-     6.12 pcap
-     6.13 Setting up the host yourself
-
-  7. Sharing Filesystems between Virtual Machines
-
-     7.1 A warning
-     7.2 Using layered block devices
-     7.3 Note!
-     7.4 Another warning
-     7.5 uml_moo : Merging a COW file with its backing file
-
-  8. Creating filesystems
-
-     8.1 Create the filesystem file
-     8.2 Assign the file to a UML device
-     8.3 Creating and mounting the filesystem
-
-  9. Host file access
-
-     9.1 Using hostfs
-     9.2 hostfs as the root filesystem
-     9.3 Building hostfs
-
-  10. The Management Console
-     10.1 version
-     10.2 halt and reboot
-     10.3 config
-     10.4 remove
-     10.5 sysrq
-     10.6 help
-     10.7 cad
-     10.8 stop
-     10.9 go
-
-  11. Kernel debugging
-
-     11.1 Starting the kernel under gdb
-     11.2 Examining sleeping processes
-     11.3 Running ddd on UML
-     11.4 Debugging modules
-     11.5 Attaching gdb to the kernel
-     11.6 Using alternate debuggers
-
-  12. Kernel debugging examples
-
-     12.1 The case of the hung fsck
-     12.2 Episode 2: The case of the hung fsck
-
-  13. What to do when UML doesn't work
-
-     13.1 Strange compilation errors when you build from source
-     13.2 (obsolete)
-     13.3 A variety of panics and hangs with /tmp on a reiserfs  filesystem
-     13.4 The compile fails with errors about conflicting types for 'open', 'dup', and 'waitpid'
-     13.5 UML doesn't work when /tmp is an NFS filesystem
-     13.6 UML hangs on boot when compiled with gprof support
-     13.7 syslogd dies with a SIGTERM on startup
-     13.8 TUN/TAP networking doesn't work on a 2.4 host
-     13.9 You can network to the host but not to other machines on the net
-     13.10 I have no root and I want to scream
-     13.11 UML build conflict between ptrace.h and ucontext.h
-     13.12 The UML BogoMips is exactly half the host's BogoMips
-     13.13 When you run UML, it immediately segfaults
-     13.14 xterms appear, then immediately disappear
-     13.15 Any other panic, hang, or strange behavior
-
-  14. Diagnosing Problems
-
-     14.1 Case 1 : Normal kernel panics
-     14.2 Case 2 : Tracing thread panics
-     14.3 Case 3 : Tracing thread panics caused by other threads
-     14.4 Case 4 : Hangs
-
-  15. Thanks
-
-     15.1 Code and Documentation
-     15.2 Flushing out bugs
-     15.3 Buglets and clean-ups
-     15.4 Case Studies
-     15.5 Other contributions
-
-
-1.  Introduction
-================
-
-  Welcome to User Mode Linux.  It's going to be fun.
-
-
-
-1.1.  How is User Mode Linux Different?
----------------------------------------
-
-  Normally, the Linux Kernel talks straight to your hardware (video
-  card, keyboard, hard drives, etc), and any programs which run ask the
-  kernel to operate the hardware, like so::
-
-
-
-         +-----------+-----------+----+
-         | Process 1 | Process 2 | ...|
-         +-----------+-----------+----+
-         |       Linux Kernel         |
-         +----------------------------+
-         |         Hardware           |
-         +----------------------------+
-
-
-
-
-  The User Mode Linux Kernel is different; instead of talking to the
-  hardware, it talks to a `real` Linux kernel (called the `host kernel`
-  from now on), like any other program.  Programs can then run inside
-  User-Mode Linux as if they were running under a normal kernel, like
-  so::
-
-
-
-                     +----------------+
-                     | Process 2 | ...|
-         +-----------+----------------+
-         | Process 1 | User-Mode Linux|
-         +----------------------------+
-         |       Linux Kernel         |
-         +----------------------------+
-         |         Hardware           |
-         +----------------------------+
-
-
-
-
-
-1.2.  Why Would I Want User Mode Linux?
----------------------------------------
-
-
-  1. If User Mode Linux crashes, your host kernel is still fine.
-
-  2. You can run a usermode kernel as a non-root user.
-
-  3. You can debug the User Mode Linux like any normal process.
-
-  4. You can run gprof (profiling) and gcov (coverage testing).
-
-  5. You can play with your kernel without breaking things.
-
-  6. You can use it as a sandbox for testing new apps.
-
-  7. You can try new development kernels safely.
-
-  8. You can run different distributions simultaneously.
-
-  9. It's extremely fun.
-
-
-
-.. _Compiling_the_kernel_and_modules:
-
-2.  Compiling the kernel and modules
-====================================
-
-
-
-
-2.1.  Compiling the kernel
---------------------------
-
-
-  Compiling the user mode kernel is just like compiling any other
-  kernel.
-
-
-  1. Download the latest kernel from your favourite kernel mirror,
-     such as:
-
-     https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.14.tar.xz
-
-  2. Make a directory and unpack the kernel into it::
-
-       host%
-       mkdir ~/uml
-
-       host%
-       cd ~/uml
-
-       host%
-       tar xvf linux-5.4.14.tar.xz
-
-
-  3. Run your favorite config; ``make xconfig ARCH=um`` is the most
-     convenient.  ``make config ARCH=um`` and ``make menuconfig ARCH=um``
-     will work as well.  The defaults will give you a useful kernel.  If
-     you want to change something, go ahead, it probably won't hurt
-     anything.
-
-
-     Note:  If the host is configured with a 2G/2G address space split
-     rather than the usual 3G/1G split, then the packaged UML binaries
-     will not run.  They will immediately segfault.  See
-     :ref:`UML_on_2G/2G_hosts`  for the scoop on running UML on your system.
-
-
-
-  4. Finish with ``make linux ARCH=um``: the result is a file called
-     ``linux`` in the top directory of your source tree.
-
-
-2.2.  Compiling and installing kernel modules
----------------------------------------------
-
-  UML modules are built in the same way as the native kernel (with the
-  exception of the 'ARCH=um' that you always need for UML)::
-
-
-       host% make modules ARCH=um
-
-
-
-
-  Any modules that you want to load into this kernel need to be built in
-  the user-mode pool.  Modules from the native kernel won't work.
-
-  You can install them by using ftp or something to copy them into the
-  virtual machine and dropping them into ``/lib/modules/$(uname -r)``.
-
-  You can also get the kernel build process to install them as follows:
-
-  1. with the kernel not booted, mount the root filesystem in the top
-     level of the kernel pool::
-
-
-       host% mount root_fs mnt -o loop
-
-
-
-
-
-
-  2. run::
-
-
-       host%
-       make modules_install INSTALL_MOD_PATH=`pwd`/mnt ARCH=um
-
-
-
-
-
-
-  3. unmount the filesystem::
-
-
-       host% umount mnt
-
-
-
-
-
-
-  4. boot the kernel on it
-
-
-  When the system is booted, you can use insmod as usual to get the
-  modules into the kernel.  A number of things have been loaded into UML
-  as modules, especially filesystems and network protocols and filters,
-  so most symbols which need to be exported probably already are.
-  However, if you do find symbols that need exporting, let  us
-  know at http://user-mode-linux.sourceforge.net/, and
-  they'll be "taken care of".
-
-
-
-2.3.  Compiling and installing uml_utilities
---------------------------------------------
-
-  Many features of the UML kernel require a user-space helper program,
-  so a uml_utilities package is distributed separately from the kernel
-  patch which provides these helpers. Included within this is:
-
-  -  port-helper - Used by consoles which connect to xterms or ports
-
-  -  tunctl - Configuration tool to create and delete tap devices
-
-  -  uml_net - Setuid binary for automatic tap device configuration
-
-  -  uml_switch - User-space virtual switch required for daemon
-     transport
-
-     The uml_utilities tree is compiled with::
-
-
-       host#
-       make && make install
-
-
-
-
-  Note that UML kernel patches may require a specific version of the
-  uml_utilities distribution. If you don't keep up with the mailing
-  lists, ensure that you have the latest release of uml_utilities if you
-  are experiencing problems with your UML kernel, particularly when
-  dealing with consoles or command-line switches to the helper programs
-
-
-
-
-
-
-
-
-3.  Running UML and logging in
-==============================
-
-
-
-3.1.  Running UML
------------------
-
-  It runs on 2.2.15 or later, and all kernel versions since 2.4.
-
-
-  Booting UML is straightforward.  Simply run 'linux': it will try to
-  mount the file ``root_fs`` in the current directory.  You do not need to
-  run it as root.  If your root filesystem is not named ``root_fs``, then
-  you need to put a ``ubd0=root_fs_whatever`` switch on the linux command
-  line.
-
-
-  You will need a filesystem to boot UML from.  There are a number
-  available for download from http://user-mode-linux.sourceforge.net.
-  There are also  several tools at
-  http://user-mode-linux.sourceforge.net/  which can be
-  used to generate UML-compatible filesystem images from media.
-  The kernel will boot up and present you with a login prompt.
-
-
-Note:
-  If the host is configured with a 2G/2G address space split
-  rather than the usual 3G/1G split, then the packaged UML binaries will
-  not run.  They will immediately segfault.  See :ref:`UML_on_2G/2G_hosts`
-  for the scoop on running UML on your system.
-
-
-
-3.2.  Logging in
-----------------
-
-
-
-  The prepackaged filesystems have a root account with password 'root'
-  and a user account with password 'user'.  The login banner will
-  generally tell you how to log in.  So, you log in and you will find
-  yourself inside a little virtual machine. Our filesystems have a
-  variety of commands and utilities installed (and it is fairly easy to
-  add more), so you will have a lot of tools with which to poke around
-  the system.
-
-  There are a couple of other ways to log in:
-
-  -  On a virtual console
-
-
-
-     Each virtual console that is configured (i.e. the device exists in
-     /dev and /etc/inittab runs a getty on it) will come up in its own
-     xterm.  If you get tired of the xterms, read
-     :ref:`setting_up_serial_lines_and_consoles` to see how to attach
-     the consoles to something else, like host ptys.
-
-
-
-  -  Over the serial line
-
-
-     In the boot output, find a line that looks like::
-
-
-
-       serial line 0 assigned pty /dev/ptyp1
-
-
-
-
-  Attach your favorite terminal program to the corresponding tty.  I.e.
-  for minicom, the command would be::
-
-
-       host% minicom -o -p /dev/ttyp1
-
-
-
-
-
-
-  -  Over the net
-
-
-     If the network is running, then you can telnet to the virtual
-     machine and log in to it.  See :ref:`Setting_up_the_network`  to learn
-     about setting up a virtual network.
-
-  When you're done using it, run halt, and the kernel will bring itself
-  down and the process will exit.
-
-
-3.3.  Examples
---------------
-
-  Here are some examples of UML in action:
-
-  -  A login session http://user-mode-linux.sourceforge.net/old/login.html
-
-  -  A virtual network http://user-mode-linux.sourceforge.net/old/net.html
-
-
-
-
-
-.. _UML_on_2G/2G_hosts:
-
-4.  UML on 2G/2G hosts
-======================
-
-
-
-
-4.1.  Introduction
-------------------
-
-
-  Most Linux machines are configured so that the kernel occupies the
-  upper 1G (0xc0000000 - 0xffffffff) of the 4G address space and
-  processes use the lower 3G (0x00000000 - 0xbfffffff).  However, some
-  machine are configured with a 2G/2G split, with the kernel occupying
-  the upper 2G (0x80000000 - 0xffffffff) and processes using the lower
-  2G (0x00000000 - 0x7fffffff).
-
-
-
-
-4.2.  The problem
------------------
-
-
-  The prebuilt UML binaries on this site will not run on 2G/2G hosts
-  because UML occupies the upper .5G of the 3G process address space
-  (0xa0000000 - 0xbfffffff).  Obviously, on 2G/2G hosts, this is right
-  in the middle of the kernel address space, so UML won't even load - it
-  will immediately segfault.
-
-
-
-
-4.3.  The solution
-------------------
-
-
-  The fix for this is to rebuild UML from source after enabling
-  CONFIG_HOST_2G_2G (under 'General Setup').  This will cause UML to
-  load itself in the top .5G of that smaller process address space,
-  where it will run fine.  See :ref:`Compiling_the_kernel_and_modules`  if
-  you need help building UML from source.
-
-
-
-
-
-
-
-.. _setting_up_serial_lines_and_consoles:
-
-
-5.  Setting up serial lines and consoles
-========================================
-
-
-  It is possible to attach UML serial lines and consoles to many types
-  of host I/O channels by specifying them on the command line.
-
-
-  You can attach them to host ptys, ttys, file descriptors, and ports.
-  This allows you to do things like:
-
-  -  have a UML console appear on an unused host console,
-
-  -  hook two virtual machines together by having one attach to a pty
-     and having the other attach to the corresponding tty
-
-  -  make a virtual machine accessible from the net by attaching a
-     console to a port on the host.
-
-
-  The general format of the command line option is ``device=channel``.
-
-
-
-5.1.  Specifying the device
----------------------------
-
-  Devices are specified with "con" or "ssl" (console or serial line,
-  respectively), optionally with a device number if you are talking
-  about a specific device.
-
-
-  Using just "con" or "ssl" describes all of the consoles or serial
-  lines.  If you want to talk about console #3 or serial line #10, they
-  would be "con3" and "ssl10", respectively.
-
-
-  A specific device name will override a less general "con=" or "ssl=".
-  So, for example, you can assign a pty to each of the serial lines
-  except for the first two like this::
-
-
-        ssl=pty ssl0=tty:/dev/tty0 ssl1=tty:/dev/tty1
-
-
-
-
-  The specificity of the device name is all that matters; order on the
-  command line is irrelevant.
-
-
-
-5.2.  Specifying the channel
-----------------------------
-
-  There are a number of different types of channels to attach a UML
-  device to, each with a different way of specifying exactly what to
-  attach to.
-
-  -  pseudo-terminals - device=pty pts terminals - device=pts
-
-
-     This will cause UML to allocate a free host pseudo-terminal for the
-     device.  The terminal that it got will be announced in the boot
-     log.  You access it by attaching a terminal program to the
-     corresponding tty:
-
-  -  screen /dev/pts/n
-
-  -  screen /dev/ttyxx
-
-  -  minicom -o -p /dev/ttyxx - minicom seems not able to handle pts
-     devices
-
-  -  kermit - start it up, 'open' the device, then 'connect'
-
-
-
-
-
-  -  terminals - device=tty:tty device file
-
-
-     This will make UML attach the device to the specified tty (i.e::
-
-
-        con1=tty:/dev/tty3
-
-
-
-
-  will attach UML's console 1 to the host's /dev/tty3).  If the tty that
-  you specify is the slave end of a tty/pty pair, something else must
-  have already opened the corresponding pty in order for this to work.
-
-
-
-
-
-  -  xterms - device=xterm
-
-
-     UML will run an xterm and the device will be attached to it.
-
-
-
-
-
-  -  Port - device=port:port number
-
-
-     This will attach the UML devices to the specified host port.
-     Attaching console 1 to the host's port 9000 would be done like
-     this::
-
-
-        con1=port:9000
-
-
-
-
-  Attaching all the serial lines to that port would be done similarly::
-
-
-        ssl=port:9000
-
-
-
-
-  You access these devices by telnetting to that port.  Each active
-  telnet session gets a different device.  If there are more telnets to a
-  port than UML devices attached to it, then the extra telnet sessions
-  will block until an existing telnet detaches, or until another device
-  becomes active (i.e. by being activated in /etc/inittab).
-
-  This channel has the advantage that you can both attach multiple UML
-  devices to it and know how to access them without reading the UML boot
-  log.  It is also unique in allowing access to a UML from remote
-  machines without requiring that the UML be networked.  This could be
-  useful in allowing public access to UMLs because they would be
-  accessible from the net, but wouldn't need any kind of network
-  filtering or access control because they would have no network access.
-
-
-  If you attach the main console to a portal, then the UML boot will
-  appear to hang.  In reality, it's waiting for a telnet to connect, at
-  which point the boot will proceed.
-
-
-
-
-
-  -  already-existing file descriptors - device=file descriptor
-
-
-     If you set up a file descriptor on the UML command line, you can
-     attach a UML device to it.  This is most commonly used to put the
-     main console back on stdin and stdout after assigning all the other
-     consoles to something else::
-
-
-        con0=fd:0,fd:1 con=pts
-
-
-
-
-
-
-
-
-  -  Nothing - device=null
-
-
-     This allows the device to be opened, in contrast to 'none', but
-     reads will block, and writes will succeed and the data will be
-     thrown out.
-
-
-
-
-
-  -  None - device=none
-
-
-     This causes the device to disappear.
-
-
-
-  You can also specify different input and output channels for a device
-  by putting a comma between them::
-
-
-        ssl3=tty:/dev/tty2,xterm
-
-
-
-
-  will cause serial line 3 to accept input on the host's /dev/tty2 and
-  display output on an xterm.  That's a silly example - the most common
-  use of this syntax is to reattach the main console to stdin and stdout
-  as shown above.
-
-
-  If you decide to move the main console away from stdin/stdout, the
-  initial boot output will appear in the terminal that you're running
-  UML in.  However, once the console driver has been officially
-  initialized, then the boot output will start appearing wherever you
-  specified that console 0 should be.  That device will receive all
-  subsequent output.
-
-
-
-5.3.  Examples
---------------
-
-  There are a number of interesting things you can do with this
-  capability.
-
-
-  First, this is how you get rid of those bleeding console xterms by
-  attaching them to host ptys::
-
-
-        con=pty con0=fd:0,fd:1
-
-
-
-
-  This will make a UML console take over an unused host virtual console,
-  so that when you switch to it, you will see the UML login prompt
-  rather than the host login prompt::
-
-
-        con1=tty:/dev/tty6
-
-
-
-
-  You can attach two virtual machines together with what amounts to a
-  serial line as follows:
-
-  Run one UML with a serial line attached to a pty::
-
-
-        ssl1=pty
-
-
-
-
-  Look at the boot log to see what pty it got (this example will assume
-  that it got /dev/ptyp1).
-
-  Boot the other UML with a serial line attached to the corresponding
-  tty::
-
-
-        ssl1=tty:/dev/ttyp1
-
-
-
-
-  Log in, make sure that it has no getty on that serial line, attach a
-  terminal program like minicom to it, and you should see the login
-  prompt of the other virtual machine.
-
-
-.. _setting_up_the_network:
-
-6.  Setting up the network
-==========================
-
-
-
-  This page describes how to set up the various transports and to
-  provide a UML instance with network access to the host, other machines
-  on the local net, and the rest of the net.
-
-
-  As of 2.4.5, UML networking has been completely redone to make it much
-  easier to set up, fix bugs, and add new features.
-
-
-  There is a new helper, uml_net, which does the host setup that
-  requires root privileges.
-
-
-  There are currently five transport types available for a UML virtual
-  machine to exchange packets with other hosts:
-
-  -  ethertap
-
-  -  TUN/TAP
-
-  -  Multicast
-
-  -  a switch daemon
-
-  -  slip
-
-  -  slirp
-
-  -  pcap
-
-     The TUN/TAP, ethertap, slip, and slirp transports allow a UML
-     instance to exchange packets with the host.  They may be directed
-     to the host or the host may just act as a router to provide access
-     to other physical or virtual machines.
-
-
-  The pcap transport is a synthetic read-only interface, using the
-  libpcap binary to collect packets from interfaces on the host and
-  filter them.  This is useful for building preconfigured traffic
-  monitors or sniffers.
-
-
-  The daemon and multicast transports provide a completely virtual
-  network to other virtual machines.  This network is completely
-  disconnected from the physical network unless one of the virtual
-  machines on it is acting as a gateway.
-
-
-  With so many host transports, which one should you use?  Here's when
-  you should use each one:
-
-  -  ethertap - if you want access to the host networking and it is
-     running 2.2
-
-  -  TUN/TAP - if you want access to the host networking and it is
-     running 2.4.  Also, the TUN/TAP transport is able to use a
-     preconfigured device, allowing it to avoid using the setuid uml_net
-     helper, which is a security advantage.
-
-  -  Multicast - if you want a purely virtual network and you don't want
-     to set up anything but the UML
-
-  -  a switch daemon - if you want a purely virtual network and you
-     don't mind running the daemon in order to get somewhat better
-     performance
-
-  -  slip - there is no particular reason to run the slip backend unless
-     ethertap and TUN/TAP are just not available for some reason
-
-  -  slirp - if you don't have root access on the host to setup
-     networking, or if you don't want to allocate an IP to your UML
-
-  -  pcap - not much use for actual network connectivity, but great for
-     monitoring traffic on the host
-
-     Ethertap is available on 2.4 and works fine.  TUN/TAP is preferred
-     to it because it has better performance and ethertap is officially
-     considered obsolete in 2.4.  Also, the root helper only needs to
-     run occasionally for TUN/TAP, rather than handling every packet, as
-     it does with ethertap.  This is a slight security advantage since
-     it provides fewer opportunities for a nasty UML user to somehow
-     exploit the helper's root privileges.
-
-
-6.1.  General setup
--------------------
-
-  First, you must have the virtual network enabled in your UML.  If are
-  running a prebuilt kernel from this site, everything is already
-  enabled.  If you build the kernel yourself, under the "Network device
-  support" menu, enable "Network device support", and then the three
-  transports.
-
-
-  The next step is to provide a network device to the virtual machine.
-  This is done by describing it on the kernel command line.
-
-  The general format is::
-
-
-       eth <n> = <transport> , <transport args>
-
-
-
-
-  For example, a virtual ethernet device may be attached to a host
-  ethertap device as follows::
-
-
-       eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254
-
-
-
-
-  This sets up eth0 inside the virtual machine to attach itself to the
-  host /dev/tap0, assigns it an ethernet address, and assigns the host
-  tap0 interface an IP address.
-
-
-
-  Note that the IP address you assign to the host end of the tap device
-  must be different than the IP you assign to the eth device inside UML.
-  If you are short on IPs and don't want to consume two per UML, then
-  you can reuse the host's eth IP address for the host ends of the tap
-  devices.  Internally, the UMLs must still get unique IPs for their eth
-  devices.  You can also give the UMLs non-routable IPs (192.168.x.x or
-  10.x.x.x) and have the host masquerade them.  This will let outgoing
-  connections work, but incoming connections won't without more work,
-  such as port forwarding from the host.
-  Also note that when you configure the host side of an interface, it is
-  only acting as a gateway.  It will respond to pings sent to it
-  locally, but is not useful to do that since it's a host interface.
-  You are not talking to the UML when you ping that interface and get a
-  response.
-
-
-  You can also add devices to a UML and remove them at runtime.  See the
-  :ref:`The_Management_Console`  page for details.
-
-
-  The sections below describe this in more detail.
-
-
-  Once you've decided how you're going to set up the devices, you boot
-  UML, log in, configure the UML side of the devices, and set up routes
-  to the outside world.  At that point, you will be able to talk to any
-  other machines, physical or virtual, on the net.
-
-
-  If ifconfig inside UML fails and the network refuses to come up, run
-  tell you what went wrong.
-
-
-
-6.2.  Userspace daemons
------------------------
-
-  You will likely need the setuid helper, or the switch daemon, or both.
-  They are both installed with the RPM and deb, so if you've installed
-  either, you can skip the rest of this section.
-
-
-  If not, then you need to check them out of CVS, build them, and
-  install them.  The helper is uml_net, in CVS /tools/uml_net, and the
-  daemon is uml_switch, in CVS /tools/uml_router.  They are both built
-  with a plain 'make'.  Both need to be installed in a directory that's
-  in your path - /usr/bin is recommend.  On top of that, uml_net needs
-  to be setuid root.
-
-
-
-6.3.  Specifying ethernet addresses
------------------------------------
-
-  Below, you will see that the TUN/TAP, ethertap, and daemon interfaces
-  allow you to specify hardware addresses for the virtual ethernet
-  devices.  This is generally not necessary.  If you don't have a
-  specific reason to do it, you probably shouldn't.  If one is not
-  specified on the command line, the driver will assign one based on the
-  device IP address.  It will provide the address fe:fd:nn:nn:nn:nn
-  where nn.nn.nn.nn is the device IP address.  This is nearly always
-  sufficient to guarantee a unique hardware address for the device.  A
-  couple of exceptions are:
-
-  -  Another set of virtual ethernet devices are on the same network and
-     they are assigned hardware addresses using a different scheme which
-     may conflict with the UML IP address-based scheme
-
-  -  You aren't going to use the device for IP networking, so you don't
-     assign the device an IP address
-
-     If you let the driver provide the hardware address, you should make
-     sure that the device IP address is known before the interface is
-     brought up.  So, inside UML, this will guarantee that::
-
-
-
-         UML#
-         ifconfig eth0 192.168.0.250 up
-
-
-
-
-  If you decide to assign the hardware address yourself, make sure that
-  the first byte of the address is even.  Addresses with an odd first
-  byte are broadcast addresses, which you don't want assigned to a
-  device.
-
-
-
-6.4.  UML interface setup
--------------------------
-
-  Once the network devices have been described on the command line, you
-  should boot UML and log in.
-
-
-  The first thing to do is bring the interface up::
-
-
-       UML# ifconfig ethn ip-address up
-
-
-
-
-  You should be able to ping the host at this point.
-
-
-  To reach the rest of the world, you should set a default route to the
-  host::
-
-
-       UML# route add default gw host ip
-
-
-
-
-  Again, with host ip of 192.168.0.4::
-
-
-       UML# route add default gw 192.168.0.4
-
-
-
-
-  This page used to recommend setting a network route to your local net.
-  This is wrong, because it will cause UML to try to figure out hardware
-  addresses of the local machines by arping on the interface to the
-  host.  Since that interface is basically a single strand of ethernet
-  with two nodes on it (UML and the host) and arp requests don't cross
-  networks, they will fail to elicit any responses.  So, what you want
-  is for UML to just blindly throw all packets at the host and let it
-  figure out what to do with them, which is what leaving out the network
-  route and adding the default route does.
-
-
-  Note: If you can't communicate with other hosts on your physical
-  ethernet, it's probably because of a network route that's
-  automatically set up.  If you run 'route -n' and see a route that
-  looks like this::
-
-
-
-
-    Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
-    192.168.0.0     0.0.0.0         255.255.255.0   U     0      0      0   eth0
-
-
-
-
-  with a mask that's not 255.255.255.255, then replace it with a route
-  to your host::
-
-
-       UML#
-       route del -net 192.168.0.0 dev eth0 netmask 255.255.255.0
-
-
-       UML#
-       route add -host 192.168.0.4 dev eth0
-
-
-
-
-  This, plus the default route to the host, will allow UML to exchange
-  packets with any machine on your ethernet.
-
-
-
-6.5.  Multicast
----------------
-
-  The simplest way to set up a virtual network between multiple UMLs is
-  to use the mcast transport.  This was written by Harald Welte and is
-  present in UML version 2.4.5-5um and later.  Your system must have
-  multicast enabled in the kernel and there must be a multicast-capable
-  network device on the host.  Normally, this is eth0, but if there is
-  no ethernet card on the host, then you will likely get strange error
-  messages when you bring the device up inside UML.
-
-
-  To use it, run two UMLs with::
-
-
-        eth0=mcast
-
-
-
-
-  on their command lines.  Log in, configure the ethernet device in each
-  machine with different IP addresses::
-
-
-       UML1# ifconfig eth0 192.168.0.254
-
-
-       UML2# ifconfig eth0 192.168.0.253
-
-
-
-
-  and they should be able to talk to each other.
-
-  The full set of command line options for this transport are::
-
-
-
-       ethn=mcast,ethernet address,multicast
-       address,multicast port,ttl
-
-
-
-  There is also a related point-to-point only "ucast" transport.
-  This is useful when your network does not support multicast, and
-  all network connections are simple point to point links.
-
-  The full set of command line options for this transport are::
-
-
-       ethn=ucast,ethernet address,remote address,listen port,remote port
-
-
-
-
-6.6.  TUN/TAP with the uml_net helper
--------------------------------------
-
-  TUN/TAP is the preferred mechanism on 2.4 to exchange packets with the
-  host.  The TUN/TAP backend has been in UML since 2.4.9-3um.
-
-
-  The easiest way to get up and running is to let the setuid uml_net
-  helper do the host setup for you.  This involves insmod-ing the tun.o
-  module if necessary, configuring the device, and setting up IP
-  forwarding, routing, and proxy arp.  If you are new to UML networking,
-  do this first.  If you're concerned about the security implications of
-  the setuid helper, use it to get up and running, then read the next
-  section to see how to have UML use a preconfigured tap device, which
-  avoids the use of uml_net.
-
-
-  If you specify an IP address for the host side of the device, the
-  uml_net helper will do all necessary setup on the host - the only
-  requirement is that TUN/TAP be available, either built in to the host
-  kernel or as the tun.o module.
-
-  The format of the command line switch to attach a device to a TUN/TAP
-  device is::
-
-
-       eth <n> =tuntap,,, <IP address>
-
-
-
-
-  For example, this argument will attach the UML's eth0 to the next
-  available tap device and assign an ethernet address to it based on its
-  IP address::
-
-
-       eth0=tuntap,,,192.168.0.254
-
-
-
-
-
-
-  Note that the IP address that must be used for the eth device inside
-  UML is fixed by the routing and proxy arp that is set up on the
-  TUN/TAP device on the host.  You can use a different one, but it won't
-  work because reply packets won't reach the UML.  This is a feature.
-  It prevents a nasty UML user from doing things like setting the UML IP
-  to the same as the network's nameserver or mail server.
-
-
-  There are a couple potential problems with running the TUN/TAP
-  transport on a 2.4 host kernel
-
-  -  TUN/TAP seems not to work on 2.4.3 and earlier.  Upgrade the host
-     kernel or use the ethertap transport.
-
-  -  With an upgraded kernel, TUN/TAP may fail with::
-
-
-       File descriptor in bad state
-
-
-
-
-  This is due to a header mismatch between the upgraded kernel and the
-  kernel that was originally installed on the machine.  The fix is to
-  make sure that /usr/src/linux points to the headers for the running
-  kernel.
-
-  These were pointed out by Tim Robinson <timro at trkr dot net> in the past.
-
-
-
-6.7.  TUN/TAP with a preconfigured tap device
----------------------------------------------
-
-  If you prefer not to have UML use uml_net (which is somewhat
-  insecure), with UML 2.4.17-11, you can set up a TUN/TAP device
-  beforehand.  The setup needs to be done as root, but once that's done,
-  there is no need for root assistance.  Setting up the device is done
-  as follows:
-
-  -  Create the device with tunctl (available from the UML utilities
-     tarball)::
-
-
-
-
-       host#  tunctl -u uid
-
-
-
-
-  where uid is the user id or username that UML will be run as.  This
-  will tell you what device was created.
-
-  -  Configure the device IP (change IP addresses and device name to
-     suit)::
-
-
-
-
-       host#  ifconfig tap0 192.168.0.254 up
-
-
-
-
-
-  -  Set up routing and arping if desired - this is my recipe, there are
-     other ways of doing the same thing::
-
-
-       host#
-       bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
-
-       host#
-       route add -host 192.168.0.253 dev tap0
-
-       host#
-       bash -c 'echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp'
-
-       host#
-       arp -Ds 192.168.0.253 eth0 pub
-
-
-
-
-  Note that this must be done every time the host boots - this configu-
-  ration is not stored across host reboots.  So, it's probably a good
-  idea to stick it in an rc file.  An even better idea would be a little
-  utility which reads the information from a config file and sets up
-  devices at boot time.
-
-  -  Rather than using up two IPs and ARPing for one of them, you can
-     also provide direct access to your LAN by the UML by using a
-     bridge::
-
-
-       host#
-       brctl addbr br0
-
-
-       host#
-       ifconfig eth0 0.0.0.0 promisc up
-
-
-       host#
-       ifconfig tap0 0.0.0.0 promisc up
-
-
-       host#
-       ifconfig br0 192.168.0.1 netmask 255.255.255.0 up
-
-
-       host#
-       brctl stp br0 off
-
-
-       host#
-       brctl setfd br0 1
-
-
-       host#
-       brctl sethello br0 1
-
-
-       host#
-       brctl addif br0 eth0
-
-
-       host#
-       brctl addif br0 tap0
-
-
-
-
-  Note that 'br0' should be setup using ifconfig with the existing IP
-  address of eth0, as eth0 no longer has its own IP.
-
-  -
-
-
-     Also, the /dev/net/tun device must be writable by the user running
-     UML in order for the UML to use the device that's been configured
-     for it.  The simplest thing to do is::
-
-
-       host#  chmod 666 /dev/net/tun
-
-
-
-
-  Making it world-writable looks bad, but it seems not to be
-  exploitable as a security hole.  However, it does allow anyone to cre-
-  ate useless tap devices (useless because they can't configure them),
-  which is a DOS attack.  A somewhat more secure alternative would to be
-  to create a group containing all the users who have preconfigured tap
-  devices and chgrp /dev/net/tun to that group with mode 664 or 660.
-
-
-  -  Once the device is set up, run UML with 'eth0=tuntap,device name'
-     (i.e. 'eth0=tuntap,tap0') on the command line (or do it with the
-     mconsole config command).
-
-  -  Bring the eth device up in UML and you're in business.
-
-     If you don't want that tap device any more, you can make it non-
-     persistent with::
-
-
-       host#  tunctl -d tap device
-
-
-
-
-  Finally, tunctl has a -b (for brief mode) switch which causes it to
-  output only the name of the tap device it created.  This makes it
-  suitable for capture by a script::
-
-
-       host#  TAP=`tunctl -u 1000 -b`
-
-
-
-
-
-
-6.8.  Ethertap
---------------
-
-  Ethertap is the general mechanism on 2.2 for userspace processes to
-  exchange packets with the kernel.
-
-
-
-  To use this transport, you need to describe the virtual network device
-  on the UML command line.  The general format for this is::
-
-
-       eth <n> =ethertap, <device> , <ethernet address> , <tap IP address>
-
-
-
-
-  So, the previous example::
-
-
-       eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254
-
-
-
-
-  attaches the UML eth0 device to the host /dev/tap0, assigns it the
-  ethernet address fe:fd:0:0:0:1, and assigns the IP address
-  192.168.0.254 to the tap device.
-
-
-
-  The tap device is mandatory, but the others are optional.  If the
-  ethernet address is omitted, one will be assigned to it.
-
-
-  The presence of the tap IP address will cause the helper to run and do
-  whatever host setup is needed to allow the virtual machine to
-  communicate with the outside world.  If you're not sure you know what
-  you're doing, this is the way to go.
-
-
-  If it is absent, then you must configure the tap device and whatever
-  arping and routing you will need on the host.  However, even in this
-  case, the uml_net helper still needs to be in your path and it must be
-  setuid root if you're not running UML as root.  This is because the
-  tap device doesn't support SIGIO, which UML needs in order to use
-  something as a source of input.  So, the helper is used as a
-  convenient asynchronous IO thread.
-
-  If you're using the uml_net helper, you can ignore the following host
-  setup - uml_net will do it for you.  You just need to make sure you
-  have ethertap available, either built in to the host kernel or
-  available as a module.
-
-
-  If you want to set things up yourself, you need to make sure that the
-  appropriate /dev entry exists.  If it doesn't, become root and create
-  it as follows::
-
-
-       mknod /dev/tap <minor>  c 36  <minor>  + 16
-
-
-
-
-  For example, this is how to create /dev/tap0::
-
-
-       mknod /dev/tap0 c 36 0 + 16
-
-
-
-
-  You also need to make sure that the host kernel has ethertap support.
-  If ethertap is enabled as a module, you apparently need to insmod
-  ethertap once for each ethertap device you want to enable.  So,::
-
-
-       host#
-       insmod ethertap
-
-
-
-
-  will give you the tap0 interface.  To get the tap1 interface, you need
-  to run::
-
-
-       host#
-       insmod ethertap unit=1 -o ethertap1
-
-
-
-
-
-
-
-6.9.  The switch daemon
------------------------
-
-  Note: This is the daemon formerly known as uml_router, but which was
-  renamed so the network weenies of the world would stop growling at me.
-
-
-  The switch daemon, uml_switch, provides a mechanism for creating a
-  totally virtual network.  By default, it provides no connection to the
-  host network (but see -tap, below).
-
-
-  The first thing you need to do is run the daemon.  Running it with no
-  arguments will make it listen on a default pair of unix domain
-  sockets.
-
-
-  If you want it to listen on a different pair of sockets, use::
-
-
-        -unix control socket data socket
-
-
-
-
-
-  If you want it to act as a hub rather than a switch, use::
-
-
-        -hub
-
-
-
-
-
-  If you want the switch to be connected to host networking (allowing
-  the umls to get access to the outside world through the host), use::
-
-
-        -tap tap0
-
-
-
-
-
-  Note that the tap device must be preconfigured (see "TUN/TAP with a
-  preconfigured tap device", above).  If you're using a different tap
-  device than tap0, specify that instead of tap0.
-
-
-  uml_switch can be backgrounded as follows::
-
-
-       host%
-       uml_switch [ options ] < /dev/null > /dev/null
-
-
-
-
-  The reason it doesn't background by default is that it listens to
-  stdin for EOF.  When it sees that, it exits.
-
-
-  The general format of the kernel command line switch is::
-
-
-
-       ethn=daemon,ethernet address,socket
-       type,control socket,data socket
-
-
-
-
-  You can leave off everything except the 'daemon'.  You only need to
-  specify the ethernet address if the one that will be assigned to it
-  isn't acceptable for some reason.  The rest of the arguments describe
-  how to communicate with the daemon.  You should only specify them if
-  you told the daemon to use different sockets than the default.  So, if
-  you ran the daemon with no arguments, running the UML on the same
-  machine with::
-
-       eth0=daemon
-
-
-
-
-  will cause the eth0 driver to attach itself to the daemon correctly.
-
-
-
-6.10.  Slip
------------
-
-  Slip is another, less general, mechanism for a process to communicate
-  with the host networking.  In contrast to the ethertap interface,
-  which exchanges ethernet frames with the host and can be used to
-  transport any higher-level protocol, it can only be used to transport
-  IP.
-
-
-  The general format of the command line switch is::
-
-
-
-       ethn=slip,slip IP
-
-
-
-
-  The slip IP argument is the IP address that will be assigned to the
-  host end of the slip device.  If it is specified, the helper will run
-  and will set up the host so that the virtual machine can reach it and
-  the rest of the network.
-
-
-  There are some oddities with this interface that you should be aware
-  of.  You should only specify one slip device on a given virtual
-  machine, and its name inside UML will be 'umn', not 'eth0' or whatever
-  you specified on the command line.  These problems will be fixed at
-  some point.
-
-
-
-6.11.  Slirp
-------------
-
-  slirp uses an external program, usually /usr/bin/slirp, to provide IP
-  only networking connectivity through the host. This is similar to IP
-  masquerading with a firewall, although the translation is performed in
-  user-space, rather than by the kernel.  As slirp does not set up any
-  interfaces on the host, or changes routing, slirp does not require
-  root access or setuid binaries on the host.
-
-
-  The general format of the command line switch for slirp is::
-
-
-
-       ethn=slirp,ethernet address,slirp path
-
-
-
-
-  The ethernet address is optional, as UML will set up the interface
-  with an ethernet address based upon the initial IP address of the
-  interface.  The slirp path is generally /usr/bin/slirp, although it
-  will depend on distribution.
-
-
-  The slirp program can have a number of options passed to the command
-  line and we can't add them to the UML command line, as they will be
-  parsed incorrectly.  Instead, a wrapper shell script can be written or
-  the options inserted into the  /.slirprc file.  More information on
-  all of the slirp options can be found in its man pages.
-
-
-  The eth0 interface on UML should be set up with the IP 10.2.0.15,
-  although you can use anything as long as it is not used by a network
-  you will be connecting to. The default route on UML should be set to
-  use::
-
-
-       UML#
-       route add default dev eth0
-
-
-
-
-  slirp provides a number of useful IP addresses which can be used by
-  UML, such as 10.0.2.3 which is an alias for the DNS server specified
-  in /etc/resolv.conf on the host or the IP given in the 'dns' option
-  for slirp.
-
-
-  Even with a baudrate setting higher than 115200, the slirp connection
-  is limited to 115200. If you need it to go faster, the slirp binary
-  needs to be compiled with FULL_BOLT defined in config.h.
-
-
-
-6.12.  pcap
------------
-
-  The pcap transport is attached to a UML ethernet device on the command
-  line or with uml_mconsole with the following syntax::
-
-
-
-       ethn=pcap,host interface,filter
-       expression,option1,option2
-
-
-
-
-  The expression and options are optional.
-
-
-  The interface is whatever network device on the host you want to
-  sniff.  The expression is a pcap filter expression, which is also what
-  tcpdump uses, so if you know how to specify tcpdump filters, you will
-  use the same expressions here.  The options are up to two of
-  'promisc', control whether pcap puts the host interface into
-  promiscuous mode. 'optimize' and 'nooptimize' control whether the pcap
-  expression optimizer is used.
-
-
-  Example::
-
-
-
-       eth0=pcap,eth0,tcp
-
-       eth1=pcap,eth0,!tcp
-
-
-
-  will cause the UML eth0 to emit all tcp packets on the host eth0 and
-  the UML eth1 to emit all non-tcp packets on the host eth0.
-
-
-
-6.13.  Setting up the host yourself
------------------------------------
-
-  If you don't specify an address for the host side of the ethertap or
-  slip device, UML won't do any setup on the host.  So this is what is
-  needed to get things working (the examples use a host-side IP of
-  192.168.0.251 and a UML-side IP of 192.168.0.250 - adjust to suit your
-  own network):
-
-  -  The device needs to be configured with its IP address.  Tap devices
-     are also configured with an mtu of 1484.  Slip devices are
-     configured with a point-to-point address pointing at the UML ip
-     address::
-
-
-       host#  ifconfig tap0 arp mtu 1484 192.168.0.251 up
-
-
-       host#
-       ifconfig sl0 192.168.0.251 pointopoint 192.168.0.250 up
-
-
-
-
-
-  -  If a tap device is being set up, a route is set to the UML IP::
-
-
-       UML# route add -host 192.168.0.250 gw 192.168.0.251
-
-
-
-
-
-  -  To allow other hosts on your network to see the virtual machine,
-     proxy arp is set up for it::
-
-
-       host#  arp -Ds 192.168.0.250 eth0 pub
-
-
-
-
-
-  -  Finally, the host is set up to route packets::
-
-
-       host#  echo 1 > /proc/sys/net/ipv4/ip_forward
-
-
-
-
-
-
-
-
-
-
-7.  Sharing Filesystems between Virtual Machines
-================================================
-
-
-
-
-7.1.  A warning
----------------
-
-  Don't attempt to share filesystems simply by booting two UMLs from the
-  same file.  That's the same thing as booting two physical machines
-  from a shared disk.  It will result in filesystem corruption.
-
-
-
-7.2.  Using layered block devices
----------------------------------
-
-  The way to share a filesystem between two virtual machines is to use
-  the copy-on-write (COW) layering capability of the ubd block driver.
-  As of 2.4.6-2um, the driver supports layering a read-write private
-  device over a read-only shared device.  A machine's writes are stored
-  in the private device, while reads come from either device - the
-  private one if the requested block is valid in it, the shared one if
-  not.  Using this scheme, the majority of data which is unchanged is
-  shared between an arbitrary number of virtual machines, each of which
-  has a much smaller file containing the changes that it has made.  With
-  a large number of UMLs booting from a large root filesystem, this
-  leads to a huge disk space saving.  It will also help performance,
-  since the host will be able to cache the shared data using a much
-  smaller amount of memory, so UML disk requests will be served from the
-  host's memory rather than its disks.
-
-
-
-
-  To add a copy-on-write layer to an existing block device file, simply
-  add the name of the COW file to the appropriate ubd switch::
-
-
-        ubd0=root_fs_cow,root_fs_debian_22
-
-
-
-
-  where 'root_fs_cow' is the private COW file and 'root_fs_debian_22' is
-  the existing shared filesystem.  The COW file need not exist.  If it
-  doesn't, the driver will create and initialize it.  Once the COW file
-  has been initialized, it can be used on its own on the command line::
-
-
-        ubd0=root_fs_cow
-
-
-
-
-  The name of the backing file is stored in the COW file header, so it
-  would be redundant to continue specifying it on the command line.
-
-
-
-7.3.  Note!
------------
-
-  When checking the size of the COW file in order to see the gobs of
-  space that you're saving, make sure you use 'ls -ls' to see the actual
-  disk consumption rather than the length of the file.  The COW file is
-  sparse, so the length will be very different from the disk usage.
-  Here is a 'ls -l' of a COW file and backing file from one boot and
-  shutdown::
-
-       host% ls -l cow.debian debian2.2
-       -rw-r--r--    1 jdike    jdike    492504064 Aug  6 21:16 cow.debian
-       -rwxrw-rw-    1 jdike    jdike    537919488 Aug  6 20:42 debian2.2
-
-
-
-
-  Doesn't look like much saved space, does it?  Well, here's 'ls -ls'::
-
-
-       host% ls -ls cow.debian debian2.2
-          880 -rw-r--r--    1 jdike    jdike    492504064 Aug  6 21:16 cow.debian
-       525832 -rwxrw-rw-    1 jdike    jdike    537919488 Aug  6 20:42 debian2.2
-
-
-
-
-  Now, you can see that the COW file has less than a meg of disk, rather
-  than 492 meg.
-
-
-
-7.4.  Another warning
----------------------
-
-  Once a filesystem is being used as a readonly backing file for a COW
-  file, do not boot directly from it or modify it in any way.  Doing so
-  will invalidate any COW files that are using it.  The mtime and size
-  of the backing file are stored in the COW file header at its creation,
-  and they must continue to match.  If they don't, the driver will
-  refuse to use the COW file.
-
-
-
-
-  If you attempt to evade this restriction by changing either the
-  backing file or the COW header by hand, you will get a corrupted
-  filesystem.
-
-
-
-
-  Among other things, this means that upgrading the distribution in a
-  backing file and expecting that all of the COW files using it will see
-  the upgrade will not work.
-
-
-
-
-7.5.  uml_moo : Merging a COW file with its backing file
---------------------------------------------------------
-
-  Depending on how you use UML and COW devices, it may be advisable to
-  merge the changes in the COW file into the backing file every once in
-  a while.
-
-
-
-
-  The utility that does this is uml_moo.  Its usage is::
-
-
-       host% uml_moo COW file new backing file
-
-
-
-
-  There's no need to specify the backing file since that information is
-  already in the COW file header.  If you're paranoid, boot the new
-  merged file, and if you're happy with it, move it over the old backing
-  file.
-
-
-
-
-  uml_moo creates a new backing file by default as a safety measure.  It
-  also has a destructive merge option which will merge the COW file
-  directly into its current backing file.  This is really only usable
-  when the backing file only has one COW file associated with it.  If
-  there are multiple COWs associated with a backing file, a -d merge of
-  one of them will invalidate all of the others.  However, it is
-  convenient if you're short of disk space, and it should also be
-  noticeably faster than a non-destructive merge.
-
-
-
-
-  uml_moo is installed with the UML deb and RPM.  If you didn't install
-  UML from one of those packages, you can also get it from the UML
-  utilities http://user-mode-linux.sourceforge.net/utilities tar file
-  in tools/moo.
-
-
-
-
-
-
-
-
-8.  Creating filesystems
-========================
-
-
-  You may want to create and mount new UML filesystems, either because
-  your root filesystem isn't large enough or because you want to use a
-  filesystem other than ext2.
-
-
-  This was written on the occasion of reiserfs being included in the
-  2.4.1 kernel pool, and therefore the 2.4.1 UML, so the examples will
-  talk about reiserfs.  This information is generic, and the examples
-  should be easy to translate to the filesystem of your choice.
-
-
-8.1.  Create the filesystem file
-================================
-
-  dd is your friend.  All you need to do is tell dd to create an empty
-  file of the appropriate size.  I usually make it sparse to save time
-  and to avoid allocating disk space until it's actually used.  For
-  example, the following command will create a sparse 100 meg file full
-  of zeroes::
-
-
-       host%
-       dd if=/dev/zero of=new_filesystem seek=100 count=1 bs=1M
-
-
-
-
-
-
-  8.2.  Assign the file to a UML device
-
-  Add an argument like the following to the UML command line::
-
-       ubd4=new_filesystem
-
-
-
-
-  making sure that you use an unassigned ubd device number.
-
-
-
-  8.3.  Creating and mounting the filesystem
-
-  Make sure that the filesystem is available, either by being built into
-  the kernel, or available as a module, then boot up UML and log in.  If
-  the root filesystem doesn't have the filesystem utilities (mkfs, fsck,
-  etc), then get them into UML by way of the net or hostfs.
-
-
-  Make the new filesystem on the device assigned to the new file::
-
-
-       host#  mkreiserfs /dev/ubd/4
-
-
-       <----------- MKREISERFSv2 ----------->
-
-       ReiserFS version 3.6.25
-       Block size 4096 bytes
-       Block count 25856
-       Used blocks 8212
-               Journal - 8192 blocks (18-8209), journal header is in block 8210
-               Bitmaps: 17
-               Root block 8211
-       Hash function "r5"
-       ATTENTION: ALL DATA WILL BE LOST ON '/dev/ubd/4'! (y/n)y
-       journal size 8192 (from 18)
-       Initializing journal - 0%....20%....40%....60%....80%....100%
-       Syncing..done.
-
-
-
-
-  Now, mount it::
-
-
-       UML#
-       mount /dev/ubd/4 /mnt
-
-
-
-
-  and you're in business.
-
-
-
-
-
-
-
-
-
-9.  Host file access
-====================
-
-
-  If you want to access files on the host machine from inside UML, you
-  can treat it as a separate machine and either nfs mount directories
-  from the host or copy files into the virtual machine with scp or rcp.
-  However, since UML is running on the host, it can access those
-  files just like any other process and make them available inside the
-  virtual machine without needing to use the network.
-
-
-  This is now possible with the hostfs virtual filesystem.  With it, you
-  can mount a host directory into the UML filesystem and access the
-  files contained in it just as you would on the host.
-
-
-9.1.  Using hostfs
-------------------
-
-  To begin with, make sure that hostfs is available inside the virtual
-  machine with::
-
-
-       UML# cat /proc/filesystems
-
-
-
-  .  hostfs should be listed.  If it's not, either rebuild the kernel
-  with hostfs configured into it or make sure that hostfs is built as a
-  module and available inside the virtual machine, and insmod it.
-
-
-  Now all you need to do is run mount::
-
-
-       UML# mount none /mnt/host -t hostfs
-
-
-
-
-  will mount the host's / on the virtual machine's /mnt/host.
-
-
-  If you don't want to mount the host root directory, then you can
-  specify a subdirectory to mount with the -o switch to mount::
-
-
-       UML# mount none /mnt/home -t hostfs -o /home
-
-
-
-
-  will mount the hosts's /home on the virtual machine's /mnt/home.
-
-
-
-9.2.  hostfs as the root filesystem
------------------------------------
-
-  It's possible to boot from a directory hierarchy on the host using
-  hostfs rather than using the standard filesystem in a file.
-
-  To start, you need that hierarchy.  The easiest way is to loop mount
-  an existing root_fs file::
-
-
-       host#  mount root_fs uml_root_dir -o loop
-
-
-
-
-  You need to change the filesystem type of / in etc/fstab to be
-  'hostfs', so that line looks like this::
-
-    /dev/ubd/0       /        hostfs      defaults          1   1
-
-
-
-
-  Then you need to chown to yourself all the files in that directory
-  that are owned by root.  This worked for me::
-
-
-       host#  find . -uid 0 -exec chown jdike {} \;
-
-
-
-
-  Next, make sure that your UML kernel has hostfs compiled in, not as a
-  module.  Then run UML with the boot device pointing at that directory::
-
-
-        ubd0=/path/to/uml/root/directory
-
-
-
-
-  UML should then boot as it does normally.
-
-
-9.3.  Building hostfs
----------------------
-
-  If you need to build hostfs because it's not in your kernel, you have
-  two choices:
-
-
-
-  -  Compiling hostfs into the kernel:
-
-
-     Reconfigure the kernel and set the 'Host filesystem' option under
-
-
-  -  Compiling hostfs as a module:
-
-
-     Reconfigure the kernel and set the 'Host filesystem' option under
-     be in arch/um/fs/hostfs/hostfs.o.  Install that in
-     ``/lib/modules/$(uname -r)/fs`` in the virtual machine, boot it up, and::
-
-
-       UML# insmod hostfs
-
-
-.. _The_Management_Console:
-
-10.  The Management Console
-===========================
-
-
-
-  The UML management console is a low-level interface to the kernel,
-  somewhat like the i386 SysRq interface.  Since there is a full-blown
-  operating system under UML, there is much greater flexibility possible
-  than with the SysRq mechanism.
-
-
-  There are a number of things you can do with the mconsole interface:
-
-  -  get the kernel version
-
-  -  add and remove devices
-
-  -  halt or reboot the machine
-
-  -  Send SysRq commands
-
-  -  Pause and resume the UML
-
-
-  You need the mconsole client (uml_mconsole) which is present in CVS
-  (/tools/mconsole) in 2.4.5-9um and later, and will be in the RPM in
-  2.4.6.
-
-
-  You also need CONFIG_MCONSOLE (under 'General Setup') enabled in UML.
-  When you boot UML, you'll see a line like::
-
-
-       mconsole initialized on /home/jdike/.uml/umlNJ32yL/mconsole
-
-
-
-
-  If you specify a unique machine id one the UML command line, i.e.::
-
-
-        umid=debian
-
-
-
-
-  you'll see this::
-
-
-       mconsole initialized on /home/jdike/.uml/debian/mconsole
-
-
-
-
-  That file is the socket that uml_mconsole will use to communicate with
-  UML.  Run it with either the umid or the full path as its argument::
-
-
-       host% uml_mconsole debian
-
-
-
-
-  or::
-
-
-       host% uml_mconsole /home/jdike/.uml/debian/mconsole
-
-
-
-
-  You'll get a prompt, at which you can run one of these commands:
-
-  -  version
-
-  -  halt
-
-  -  reboot
-
-  -  config
-
-  -  remove
-
-  -  sysrq
-
-  -  help
-
-  -  cad
-
-  -  stop
-
-  -  go
-
-
-10.1.  version
---------------
-
-  This takes no arguments.  It prints the UML version::
-
-
-       (mconsole)  version
-       OK Linux usermode 2.4.5-9um #1 Wed Jun 20 22:47:08 EDT 2001 i686
-
-
-
-
-  There are a couple actual uses for this.  It's a simple no-op which
-  can be used to check that a UML is running.  It's also a way of
-  sending an interrupt to the UML.  This is sometimes useful on SMP
-  hosts, where there's a bug which causes signals to UML to be lost,
-  often causing it to appear to hang.  Sending such a UML the mconsole
-  version command is a good way to 'wake it up' before networking has
-  been enabled, as it does not do anything to the function of the UML.
-
-
-
-10.2.  halt and reboot
-----------------------
-
-  These take no arguments.  They shut the machine down immediately, with
-  no syncing of disks and no clean shutdown of userspace.  So, they are
-  pretty close to crashing the machine::
-
-
-       (mconsole)  halt
-       OK
-
-
-
-
-
-
-10.3.  config
--------------
-
-  "config" adds a new device to the virtual machine.  Currently the ubd
-  and network drivers support this.  It takes one argument, which is the
-  device to add, with the same syntax as the kernel command line::
-
-
-
-
-       (mconsole)
-       config ubd3=/home/jdike/incoming/roots/root_fs_debian22
-
-       OK
-       (mconsole)  config eth1=mcast
-       OK
-
-
-
-
-
-
-10.4.  remove
--------------
-
-  "remove" deletes a device from the system.  Its argument is just the
-  name of the device to be removed. The device must be idle in whatever
-  sense the driver considers necessary.  In the case of the ubd driver,
-  the removed block device must not be mounted, swapped on, or otherwise
-  open, and in the case of the network driver, the device must be down::
-
-
-       (mconsole)  remove ubd3
-       OK
-       (mconsole)  remove eth1
-       OK
-
-
-
-
-
-
-10.5.  sysrq
-------------
-
-  This takes one argument, which is a single letter.  It calls the
-  generic kernel's SysRq driver, which does whatever is called for by
-  that argument.  See the SysRq documentation in
-  Documentation/admin-guide/sysrq.rst in your favorite kernel tree to
-  see what letters are valid and what they do.
-
-
-
-10.6.  help
------------
-
-  "help" returns a string listing the valid commands and what each one
-  does.
-
-
-
-10.7.  cad
-----------
-
-  This invokes the Ctl-Alt-Del action on init.  What exactly this ends
-  up doing is up to /etc/inittab.  Normally, it reboots the machine.
-  With UML, this is usually not desired, so if a halt would be better,
-  then find the section of inittab that looks like this::
-
-
-       # What to do when CTRL-ALT-DEL is pressed.
-       ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now
-
-
-
-
-  and change the command to halt.
-
-
-
-10.8.  stop
------------
-
-  This puts the UML in a loop reading mconsole requests until a 'go'
-  mconsole command is received. This is very useful for making backups
-  of UML filesystems, as the UML can be stopped, then synced via 'sysrq
-  s', so that everything is written to the filesystem. You can then copy
-  the filesystem and then send the UML 'go' via mconsole.
-
-
-  Note that a UML running with more than one CPU will have problems
-  after you send the 'stop' command, as only one CPU will be held in a
-  mconsole loop and all others will continue as normal.  This is a bug,
-  and will be fixed.
-
-
-
-10.9.  go
----------
-
-  This resumes a UML after being paused by a 'stop' command. Note that
-  when the UML has resumed, TCP connections may have timed out and if
-  the UML is paused for a long period of time, crond might go a little
-  crazy, running all the jobs it didn't do earlier.
-
-
-
-
-
-
-.. _Kernel_debugging:
-
-11.  Kernel debugging
-=====================
-
-
-  Note: The interface that makes debugging, as described here, possible
-  is present in 2.4.0-test6 kernels and later.
-
-
-  Since the user-mode kernel runs as a normal Linux process, it is
-  possible to debug it with gdb almost like any other process.  It is
-  slightly different because the kernel's threads are already being
-  ptraced for system call interception, so gdb can't ptrace them.
-  However, a mechanism has been added to work around that problem.
-
-
-  In order to debug the kernel, you need build it from source.  See
-  :ref:`Compiling_the_kernel_and_modules`  for information on doing that.
-  Make sure that you enable CONFIG_DEBUGSYM and CONFIG_PT_PROXY during
-  the config.  These will compile the kernel with ``-g``, and enable the
-  ptrace proxy so that gdb works with UML, respectively.
-
-
-
-
-11.1.  Starting the kernel under gdb
-------------------------------------
-
-  You can have the kernel running under the control of gdb from the
-  beginning by putting 'debug' on the command line.  You will get an
-  xterm with gdb running inside it.  The kernel will send some commands
-  to gdb which will leave it stopped at the beginning of start_kernel.
-  At this point, you can get things going with 'next', 'step', or
-  'cont'.
-
-
-  There is a transcript of a debugging session  here <debug-
-  session.html> , with breakpoints being set in the scheduler and in an
-  interrupt handler.
-
-
-11.2.  Examining sleeping processes
------------------------------------
-
-
-  Not every bug is evident in the currently running process.  Sometimes,
-  processes hang in the kernel when they shouldn't because they've
-  deadlocked on a semaphore or something similar.  In this case, when
-  you ^C gdb and get a backtrace, you will see the idle thread, which
-  isn't very relevant.
-
-
-  What you want is the stack of whatever process is sleeping when it
-  shouldn't be.  You need to figure out which process that is, which is
-  generally fairly easy.  Then you need to get its host process id,
-  which you can do either by looking at ps on the host or at
-  task.thread.extern_pid in gdb.
-
-
-  Now what you do is this:
-
-  -  detach from the current thread::
-
-
-       (UML gdb)  det
-
-
-
-
-
-  -  attach to the thread you are interested in::
-
-
-       (UML gdb)  att <host pid>
-
-
-
-
-
-  -  look at its stack and anything else of interest::
-
-
-       (UML gdb)  bt
-
-
-
-
-  Note that you can't do anything at this point that requires that a
-  process execute, e.g. calling a function
-
-  -  when you're done looking at that process, reattach to the current
-     thread and continue it::
-
-
-       (UML gdb)
-       att 1
-
-
-       (UML gdb)
-       c
-
-
-
-
-  Here, specifying any pid which is not the process id of a UML thread
-  will cause gdb to reattach to the current thread.  I commonly use 1,
-  but any other invalid pid would work.
-
-
-
-11.3.  Running ddd on UML
--------------------------
-
-  ddd works on UML, but requires a special kludge.  The process goes
-  like this:
-
-  -  Start ddd::
-
-
-       host% ddd linux
-
-
-
-
-
-  -  With ps, get the pid of the gdb that ddd started.  You can ask the
-     gdb to tell you, but for some reason that confuses things and
-     causes a hang.
-
-  -  run UML with 'debug=parent gdb-pid=<pid>' added to the command line
-     - it will just sit there after you hit return
-
-  -  type 'att 1' to the ddd gdb and you will see something like::
-
-
-       0xa013dc51 in __kill ()
-
-
-       (gdb)
-
-
-
-
-
-  -  At this point, type 'c', UML will boot up, and you can use ddd just
-     as you do on any other process.
-
-
-
-11.4.  Debugging modules
-------------------------
-
-
-  gdb has support for debugging code which is dynamically loaded into
-  the process.  This support is what is needed to debug kernel modules
-  under UML.
-
-
-  Using that support is somewhat complicated.  You have to tell gdb what
-  object file you just loaded into UML and where in memory it is.  Then,
-  it can read the symbol table, and figure out where all the symbols are
-  from the load address that you provided.  It gets more interesting
-  when you load the module again (i.e. after an rmmod).  You have to
-  tell gdb to forget about all its symbols, including the main UML ones
-  for some reason, then load then all back in again.
-
-
-  There's an easy way and a hard way to do this.  The easy way is to use
-  the umlgdb expect script written by Chandan Kudige.  It basically
-  automates the process for you.
-
-
-  First, you must tell it where your modules are.  There is a list in
-  the script that looks like this::
-
-       set MODULE_PATHS {
-       "fat" "/usr/src/uml/linux-2.4.18/fs/fat/fat.o"
-       "isofs" "/usr/src/uml/linux-2.4.18/fs/isofs/isofs.o"
-       "minix" "/usr/src/uml/linux-2.4.18/fs/minix/minix.o"
-       }
-
-
-
-
-  You change that to list the names and paths of the modules that you
-  are going to debug.  Then you run it from the toplevel directory of
-  your UML pool and it basically tells you what to do::
-
-
-                   ******** GDB pid is 21903 ********
-       Start UML as: ./linux <kernel switches> debug gdb-pid=21903
-
-
-
-       GNU gdb 5.0rh-5 Red Hat Linux 7.1
-       Copyright 2001 Free Software Foundation, Inc.
-       GDB is free software, covered by the GNU General Public License, and you are
-       welcome to change it and/or distribute copies of it under certain conditions.
-       Type "show copying" to see the conditions.
-       There is absolutely no warranty for GDB.  Type "show warranty" for details.
-       This GDB was configured as "i386-redhat-linux"...
-       (gdb) b sys_init_module
-       Breakpoint 1 at 0xa0011923: file module.c, line 349.
-       (gdb) att 1
-
-
-
-
-  After you run UML and it sits there doing nothing, you hit return at
-  the 'att 1' and continue it::
-
-
-       Attaching to program: /home/jdike/linux/2.4/um/./linux, process 1
-       0xa00f4221 in __kill ()
-       (UML gdb)  c
-       Continuing.
-
-
-
-
-  At this point, you debug normally.  When you insmod something, the
-  expect magic will kick in and you'll see something like::
-
-
-     *** Module hostfs loaded ***
-    Breakpoint 1, sys_init_module (name_user=0x805abb0 "hostfs",
-        mod_user=0x8070e00) at module.c:349
-    349             char *name, *n_name, *name_tmp = NULL;
-    (UML gdb)  finish
-    Run till exit from #0  sys_init_module (name_user=0x805abb0 "hostfs",
-        mod_user=0x8070e00) at module.c:349
-    0xa00e2e23 in execute_syscall (r=0xa8140284) at syscall_kern.c:411
-    411             else res = EXECUTE_SYSCALL(syscall, regs);
-    Value returned is $1 = 0
-    (UML gdb)
-    p/x (int)module_list + module_list->size_of_struct
-
-    $2 = 0xa9021054
-    (UML gdb)  symbol-file ./linux
-    Load new symbol table from "./linux"? (y or n) y
-    Reading symbols from ./linux...
-    done.
-    (UML gdb)
-    add-symbol-file /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o 0xa9021054
-
-    add symbol table from file "/home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o" at
-            .text_addr = 0xa9021054
-     (y or n) y
-
-    Reading symbols from /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o...
-    done.
-    (UML gdb)  p *module_list
-    $1 = {size_of_struct = 84, next = 0xa0178720, name = 0xa9022de0 "hostfs",
-      size = 9016, uc = {usecount = {counter = 0}, pad = 0}, flags = 1,
-      nsyms = 57, ndeps = 0, syms = 0xa9023170, deps = 0x0, refs = 0x0,
-      init = 0xa90221f0 <init_hostfs>, cleanup = 0xa902222c <exit_hostfs>,
-      ex_table_start = 0x0, ex_table_end = 0x0, persist_start = 0x0,
-      persist_end = 0x0, can_unload = 0, runsize = 0, kallsyms_start = 0x0,
-      kallsyms_end = 0x0,
-      archdata_start = 0x1b855 <Address 0x1b855 out of bounds>,
-      archdata_end = 0xe5890000 <Address 0xe5890000 out of bounds>,
-      kernel_data = 0xf689c35d <Address 0xf689c35d out of bounds>}
-    >> Finished loading symbols for hostfs ...
-
-
-
-
-  That's the easy way.  It's highly recommended.  The hard way is
-  described below in case you're interested in what's going on.
-
-
-  Boot the kernel under the debugger and load the module with insmod or
-  modprobe.  With gdb, do::
-
-
-       (UML gdb)  p module_list
-
-
-
-
-  This is a list of modules that have been loaded into the kernel, with
-  the most recently loaded module first.  Normally, the module you want
-  is at module_list.  If it's not, walk down the next links, looking at
-  the name fields until find the module you want to debug.  Take the
-  address of that structure, and add module.size_of_struct (which in
-  2.4.10 kernels is 96 (0x60)) to it.  Gdb can make this hard addition
-  for you :-)::
-
-
-
-       (UML gdb)
-       printf "%#x\n", (int)module_list module_list->size_of_struct
-
-
-
-
-  The offset from the module start occasionally changes (before 2.4.0,
-  it was module.size_of_struct + 4), so it's a good idea to check the
-  init and cleanup addresses once in a while, as describe below.  Now
-  do::
-
-
-       (UML gdb)
-       add-symbol-file /path/to/module/on/host that_address
-
-
-
-
-  Tell gdb you really want to do it, and you're in business.
-
-
-  If there's any doubt that you got the offset right, like breakpoints
-  appear not to work, or they're appearing in the wrong place, you can
-  check it by looking at the module structure.  The init and cleanup
-  fields should look like::
-
-
-       init = 0x588066b0 <init_hostfs>, cleanup = 0x588066c0 <exit_hostfs>
-
-
-
-
-  with no offsets on the symbol names.  If the names are right, but they
-  are offset, then the offset tells you how much you need to add to the
-  address you gave to add-symbol-file.
-
-
-  When you want to load in a new version of the module, you need to get
-  gdb to forget about the old one.  The only way I've found to do that
-  is to tell gdb to forget about all symbols that it knows about::
-
-
-       (UML gdb)  symbol-file
-
-
-
-
-  Then reload the symbols from the kernel binary::
-
-
-       (UML gdb)  symbol-file /path/to/kernel
-
-
-
-
-  and repeat the process above.  You'll also need to re-enable break-
-  points.  They were disabled when you dumped all the symbols because
-  gdb couldn't figure out where they should go.
-
-
-
-11.5.  Attaching gdb to the kernel
-----------------------------------
-
-  If you don't have the kernel running under gdb, you can attach gdb to
-  it later by sending the tracing thread a SIGUSR1.  The first line of
-  the console output identifies its pid::
-
-       tracing thread pid = 20093
-
-
-
-
-  When you send it the signal::
-
-
-       host% kill -USR1 20093
-
-
-
-
-  you will get an xterm with gdb running in it.
-
-
-  If you have the mconsole compiled into UML, then the mconsole client
-  can be used to start gdb::
-
-
-       (mconsole)  (mconsole) config gdb=xterm
-
-
-
-
-  will fire up an xterm with gdb running in it.
-
-
-
-11.6.  Using alternate debuggers
---------------------------------
-
-  UML has support for attaching to an already running debugger rather
-  than starting gdb itself.  This is present in CVS as of 17 Apr 2001.
-  I sent it to Alan for inclusion in the ac tree, and it will be in my
-  2.4.4 release.
-
-
-  This is useful when gdb is a subprocess of some UI, such as emacs or
-  ddd.  It can also be used to run debuggers other than gdb on UML.
-  Below is an example of using strace as an alternate debugger.
-
-
-  To do this, you need to get the pid of the debugger and pass it in
-  with the
-
-
-  If you are using gdb under some UI, then tell it to 'att 1', and
-  you'll find yourself attached to UML.
-
-
-  If you are using something other than gdb as your debugger, then
-  you'll need to get it to do the equivalent of 'att 1' if it doesn't do
-  it automatically.
-
-
-  An example of an alternate debugger is strace.  You can strace the
-  actual kernel as follows:
-
-  -  Run the following in a shell::
-
-
-       host%
-       sh -c 'echo pid=$$; echo -n hit return; read x; exec strace -p 1 -o strace.out'
-
-
-
-  -  Run UML with 'debug' and 'gdb-pid=<pid>' with the pid printed out
-     by the previous command
-
-  -  Hit return in the shell, and UML will start running, and strace
-     output will start accumulating in the output file.
-
-     Note that this is different from running::
-
-
-       host% strace ./linux
-
-
-
-
-  That will strace only the main UML thread, the tracing thread, which
-  doesn't do any of the actual kernel work.  It just oversees the vir-
-  tual machine.  In contrast, using strace as described above will show
-  you the low-level activity of the virtual machine.
-
-
-
-
-
-12.  Kernel debugging examples
-==============================
-
-12.1.  The case of the hung fsck
---------------------------------
-
-  When booting up the kernel, fsck failed, and dropped me into a shell
-  to fix things up.  I ran fsck -y, which hung::
-
-
-    Setting hostname uml                    [ OK ]
-    Checking root filesystem
-    /dev/fhd0 was not cleanly unmounted, check forced.
-    Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780.
-
-    /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.
-           (i.e., without -a or -p options)
-    [ FAILED ]
-
-    *** An error occurred during the file system check.
-    *** Dropping you to a shell; the system will reboot
-    *** when you leave the shell.
-    Give root password for maintenance
-    (or type Control-D for normal startup):
-
-    [root@uml /root]# fsck -y /dev/fhd0
-    fsck -y /dev/fhd0
-    Parallelizing fsck version 1.14 (9-Jan-1999)
-    e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09
-    /dev/fhd0 contains a file system with errors, check forced.
-    Pass 1: Checking inodes, blocks, and sizes
-    Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780.  Ignore error? yes
-
-    Inode 19780, i_blocks is 1548, should be 540.  Fix? yes
-
-    Pass 2: Checking directory structure
-    Error reading block 49405 (Attempt to read block from filesystem resulted in short read).  Ignore error? yes
-
-    Directory inode 11858, block 0, offset 0: directory corrupted
-    Salvage? yes
-
-    Missing '.' in directory inode 11858.
-    Fix? yes
-
-    Missing '..' in directory inode 11858.
-    Fix? yes
-
-
-  The standard drill in this sort of situation is to fire up gdb on the
-  signal thread, which, in this case, was pid 1935.  In another window,
-  I run gdb and attach pid 1935::
-
-
-       ~/linux/2.3.26/um 1016: gdb linux
-       GNU gdb 4.17.0.11 with Linux support
-       Copyright 1998 Free Software Foundation, Inc.
-       GDB is free software, covered by the GNU General Public License, and you are
-       welcome to change it and/or distribute copies of it under certain conditions.
-       Type "show copying" to see the conditions.
-       There is absolutely no warranty for GDB.  Type "show warranty" for details.
-       This GDB was configured as "i386-redhat-linux"...
-
-       (gdb) att 1935
-       Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1935
-       0x100756d9 in __wait4 ()
-
-
-  Let's see what's currently running::
-
-
-
-       (gdb) p current_task.pid
-       $1 = 0
-
-
-
-
-
-  It's the idle thread, which means that fsck went to sleep for some
-  reason and never woke up.
-
-
-  Let's guess that the last process in the process list is fsck::
-
-
-
-       (gdb) p current_task.prev_task.comm
-       $13 = "fsck.ext2\000\000\000\000\000\000"
-
-
-
-
-
-  It is, so let's see what it thinks it's up to::
-
-
-
-       (gdb) p current_task.prev_task.thread
-       $14 = {extern_pid = 1980, tracing = 0, want_tracing = 0, forking = 0,
-         kernel_stack_page = 0, signal_stack = 1342627840, syscall = {id = 4, args = {
-             3, 134973440, 1024, 0, 1024}, have_result = 0, result = 50590720},
-         request = {op = 2, u = {exec = {ip = 1350467584, sp = 2952789424}, fork = {
-               regs = {1350467584, 2952789424, 0 <repeats 15 times>}, sigstack = 0,
-               pid = 0}, switch_to = 0x507e8000, thread = {proc = 0x507e8000,
-               arg = 0xaffffdb0, flags = 0, new_pid = 0}, input_request = {
-               op = 1350467584, fd = -1342177872, proc = 0, pid = 0}}}}
-
-
-
-  The interesting things here are the fact that its .thread.syscall.id
-  is __NR_write (see the big switch in arch/um/kernel/syscall_kern.c or
-  the defines in include/asm-um/arch/unistd.h), and that it never
-  returned.  Also, its .request.op is OP_SWITCH (see
-  arch/um/include/user_util.h).  These mean that it went into a write,
-  and, for some reason, called schedule().
-
-
-  The fact that it never returned from write means that its stack should
-  be fairly interesting.  Its pid is 1980 (.thread.extern_pid).  That
-  process is being ptraced by the signal thread, so it must be detached
-  before gdb can attach it::
-
-
-
-    (gdb) call detach(1980)
-
-    Program received signal SIGSEGV, Segmentation fault.
-    <function called from gdb>
-    The program being debugged stopped while in a function called from GDB.
-    When the function (detach) is done executing, GDB will silently
-    stop (instead of continuing to evaluate the expression containing
-    the function call).
-    (gdb) call detach(1980)
-    $15 = 0
-
-
-  The first detach segfaults for some reason, and the second one
-  succeeds.
-
-
-  Now I detach from the signal thread, attach to the fsck thread, and
-  look at its stack::
-
-
-       (gdb) det
-       Detaching from program: /home/dike/linux/2.3.26/um/linux Pid 1935
-       (gdb) att 1980
-       Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1980
-       0x10070451 in __kill ()
-       (gdb) bt
-       #0  0x10070451 in __kill ()
-       #1  0x10068ccd in usr1_pid (pid=1980) at process.c:30
-       #2  0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000)
-           at process_kern.c:156
-       #3  0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000)
-           at process_kern.c:161
-       #4  0x10001d12 in schedule () at core.c:777
-       #5  0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71
-       #6  0x1006aa10 in __down_failed () at semaphore.c:157
-       #7  0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174
-       #8  0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182
-       #9  <signal handler called>
-       #10 0x10155404 in errno ()
-       #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50
-       #12 0x1006c5d8 in segv_handler (sc=0x5006eaf8) at trap_user.c:174
-       #13 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182
-       #14 <signal handler called>
-       #15 0xc0fd in ?? ()
-       #16 0x10016647 in sys_write (fd=3,
-           buf=0x80b8800 <Address 0x80b8800 out of bounds>, count=1024)
-           at read_write.c:159
-       #17 0x1006d5b3 in execute_syscall (syscall=4, args=0x5006ef08)
-           at syscall_kern.c:254
-       #18 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35
-       #19 <signal handler called>
-       #20 0x400dc8b0 in ?? ()
-
-
-
-
-
-  The interesting things here are:
-
-  -  There are two segfaults on this stack (frames 9 and 14)
-
-  -  The first faulting address (frame 11) is 0x50000800::
-
-       (gdb) p (void *)1342179328
-       $16 = (void *) 0x50000800
-
-
-
-
-
-  The initial faulting address is interesting because it is on the idle
-  thread's stack.  I had been seeing the idle thread segfault for no
-  apparent reason, and the cause looked like stack corruption.  In hopes
-  of catching the culprit in the act, I had turned off all protections
-  to that stack while the idle thread wasn't running.  This apparently
-  tripped that trap.
-
-
-  However, the more immediate problem is that second segfault and I'm
-  going to concentrate on that.  First, I want to see where the fault
-  happened, so I have to go look at the sigcontent struct in frame 8::
-
-
-
-       (gdb) up
-       #1  0x10068ccd in usr1_pid (pid=1980) at process.c:30
-       30        kill(pid, SIGUSR1);
-       (gdb)
-       #2  0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000)
-           at process_kern.c:156
-       156       usr1_pid(getpid());
-       (gdb)
-       #3  0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000)
-           at process_kern.c:161
-       161       _switch_to(prev, next);
-       (gdb)
-       #4  0x10001d12 in schedule () at core.c:777
-       777             switch_to(prev, next, prev);
-       (gdb)
-       #5  0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71
-       71                      schedule();
-       (gdb)
-       #6  0x1006aa10 in __down_failed () at semaphore.c:157
-       157     }
-       (gdb)
-       #7  0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174
-       174       segv(sc->cr2, sc->err & 2);
-       (gdb)
-       #8  0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182
-       182       segv_handler(sc);
-       (gdb) p *sc
-       Cannot access memory at address 0x0.
-
-
-
-
-  That's not very useful, so I'll try a more manual method::
-
-
-       (gdb) p *((struct sigcontext *) (&sig + 1))
-       $19 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43,
-         __dsh = 0, edi = 1342179328, esi = 1350378548, ebp = 1342630440,
-         esp = 1342630420, ebx = 1348150624, edx = 1280, ecx = 0, eax = 0,
-         trapno = 14, err = 4, eip = 268480945, cs = 35, __csh = 0, eflags = 66118,
-         esp_at_signal = 1342630420, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0,
-         cr2 = 1280}
-
-
-
-  The ip is in handle_mm_fault::
-
-
-       (gdb) p (void *)268480945
-       $20 = (void *) 0x1000b1b1
-       (gdb) i sym $20
-       handle_mm_fault + 57 in section .text
-
-
-
-
-
-  Specifically, it's in pte_alloc::
-
-
-       (gdb) i line *$20
-       Line 124 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
-          starts at address 0x1000b1b1 <handle_mm_fault+57>
-          and ends at 0x1000b1b7 <handle_mm_fault+63>.
-
-
-
-
-
-  To find where in handle_mm_fault this is, I'll jump forward in the
-  code until I see an address in that procedure::
-
-
-
-       (gdb) i line *0x1000b1c0
-       Line 126 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
-          starts at address 0x1000b1b7 <handle_mm_fault+63>
-          and ends at 0x1000b1c3 <handle_mm_fault+75>.
-       (gdb) i line *0x1000b1d0
-       Line 131 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
-          starts at address 0x1000b1d0 <handle_mm_fault+88>
-          and ends at 0x1000b1da <handle_mm_fault+98>.
-       (gdb) i line *0x1000b1e0
-       Line 61 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
-          starts at address 0x1000b1da <handle_mm_fault+98>
-          and ends at 0x1000b1e1 <handle_mm_fault+105>.
-       (gdb) i line *0x1000b1f0
-       Line 134 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
-          starts at address 0x1000b1f0 <handle_mm_fault+120>
-          and ends at 0x1000b200 <handle_mm_fault+136>.
-       (gdb) i line *0x1000b200
-       Line 135 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
-          starts at address 0x1000b200 <handle_mm_fault+136>
-          and ends at 0x1000b208 <handle_mm_fault+144>.
-       (gdb) i line *0x1000b210
-       Line 139 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h"
-          starts at address 0x1000b210 <handle_mm_fault+152>
-          and ends at 0x1000b219 <handle_mm_fault+161>.
-       (gdb) i line *0x1000b220
-       Line 1168 of "memory.c" starts at address 0x1000b21e <handle_mm_fault+166>
-          and ends at 0x1000b222 <handle_mm_fault+170>.
-
-
-
-
-
-  Something is apparently wrong with the page tables or vma_structs, so
-  lets go back to frame 11 and have a look at them::
-
-
-
-    #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50
-    50        handle_mm_fault(current, vma, address, is_write);
-    (gdb) call pgd_offset_proc(vma->vm_mm, address)
-    $22 = (pgd_t *) 0x80a548c
-
-
-
-
-
-  That's pretty bogus.  Page tables aren't supposed to be in process
-  text or data areas.  Let's see what's in the vma::
-
-
-       (gdb) p *vma
-       $23 = {vm_mm = 0x507d2434, vm_start = 0, vm_end = 134512640,
-         vm_next = 0x80a4f8c, vm_page_prot = {pgprot = 0}, vm_flags = 31200,
-         vm_avl_height = 2058, vm_avl_left = 0x80a8c94, vm_avl_right = 0x80d1000,
-         vm_next_share = 0xaffffdb0, vm_pprev_share = 0xaffffe63,
-         vm_ops = 0xaffffe7a, vm_pgoff = 2952789626, vm_file = 0xafffffec,
-         vm_private_data = 0x62}
-       (gdb) p *vma.vm_mm
-       $24 = {mmap = 0x507d2434, mmap_avl = 0x0, mmap_cache = 0x8048000,
-         pgd = 0x80a4f8c, mm_users = {counter = 0}, mm_count = {counter = 134904288},
-         map_count = 134909076, mmap_sem = {count = {counter = 135073792},
-           sleepers = -1342177872, wait = {lock = <optimized out or zero length>,
-             task_list = {next = 0xaffffe63, prev = 0xaffffe7a},
-             __magic = -1342177670, __creator = -1342177300}, __magic = 98},
-         page_table_lock = {}, context = 138, start_code = 0, end_code = 0,
-         start_data = 0, end_data = 0, start_brk = 0, brk = 0, start_stack = 0,
-         arg_start = 0, arg_end = 0, env_start = 0, env_end = 0, rss = 1350381536,
-         total_vm = 0, locked_vm = 0, def_flags = 0, cpu_vm_mask = 0, swap_cnt = 0,
-         swap_address = 0, segments = 0x0}
-
-
-
-  This also pretty bogus.  With all of the 0x80xxxxx and 0xaffffxxx
-  addresses, this is looking like a stack was plonked down on top of
-  these structures.  Maybe it's a stack overflow from the next page::
-
-
-       (gdb) p vma
-       $25 = (struct vm_area_struct *) 0x507d2434
-
-
-
-  That's towards the lower quarter of the page, so that would have to
-  have been pretty heavy stack overflow::
-
-
-    (gdb) x/100x $25
-    0x507d2434:     0x507d2434      0x00000000      0x08048000      0x080a4f8c
-    0x507d2444:     0x00000000      0x080a79e0      0x080a8c94      0x080d1000
-    0x507d2454:     0xaffffdb0      0xaffffe63      0xaffffe7a      0xaffffe7a
-    0x507d2464:     0xafffffec      0x00000062      0x0000008a      0x00000000
-    0x507d2474:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2484:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2494:     0x00000000      0x00000000      0x507d2fe0      0x00000000
-    0x507d24a4:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d24b4:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d24c4:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d24d4:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d24e4:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d24f4:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2504:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2514:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2524:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2534:     0x00000000      0x00000000      0x507d25dc      0x00000000
-    0x507d2544:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2554:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2564:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2574:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2584:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d2594:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d25a4:     0x00000000      0x00000000      0x00000000      0x00000000
-    0x507d25b4:     0x00000000      0x00000000      0x00000000      0x00000000
-
-
-
-  It's not stack overflow.  The only "stack-like" piece of this data is
-  the vma_struct itself.
-
-
-  At this point, I don't see any avenues to pursue, so I just have to
-  admit that I have no idea what's going on.  What I will do, though, is
-  stick a trap on the segfault handler which will stop if it sees any
-  writes to the idle thread's stack.  That was the thing that happened
-  first, and it may be that if I can catch it immediately, what's going
-  on will be somewhat clearer.
-
-
-12.2.  Episode 2: The case of the hung fsck
--------------------------------------------
-
-  After setting a trap in the SEGV handler for accesses to the signal
-  thread's stack, I reran the kernel.
-
-
-  fsck hung again, this time by hitting the trap::
-
-
-
-    Setting hostname uml                            [ OK ]
-    Checking root filesystem
-    /dev/fhd0 contains a file system with errors, check forced.
-    Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780.
-
-    /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.
-           (i.e., without -a or -p options)
-    [ FAILED ]
-
-    *** An error occurred during the file system check.
-    *** Dropping you to a shell; the system will reboot
-    *** when you leave the shell.
-    Give root password for maintenance
-    (or type Control-D for normal startup):
-
-    [root@uml /root]# fsck -y /dev/fhd0
-    fsck -y /dev/fhd0
-    Parallelizing fsck version 1.14 (9-Jan-1999)
-    e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09
-    /dev/fhd0 contains a file system with errors, check forced.
-    Pass 1: Checking inodes, blocks, and sizes
-    Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780.  Ignore error? yes
-
-    Pass 2: Checking directory structure
-    Error reading block 49405 (Attempt to read block from filesystem resulted in short read).  Ignore error? yes
-
-    Directory inode 11858, block 0, offset 0: directory corrupted
-    Salvage? yes
-
-    Missing '.' in directory inode 11858.
-    Fix? yes
-
-    Missing '..' in directory inode 11858.
-    Fix? yes
-
-    Untested (4127) [100fe44c]: trap_kern.c line 31
-
-
-
-
-
-  I need to get the signal thread to detach from pid 4127 so that I can
-  attach to it with gdb.  This is done by sending it a SIGUSR1, which is
-  caught by the signal thread, which detaches the process::
-
-
-       kill -USR1 4127
-
-
-
-
-
-  Now I can run gdb on it::
-
-
-    ~/linux/2.3.26/um 1034: gdb linux
-    GNU gdb 4.17.0.11 with Linux support
-    Copyright 1998 Free Software Foundation, Inc.
-    GDB is free software, covered by the GNU General Public License, and you are
-    welcome to change it and/or distribute copies of it under certain conditions.
-    Type "show copying" to see the conditions.
-    There is absolutely no warranty for GDB.  Type "show warranty" for details.
-    This GDB was configured as "i386-redhat-linux"...
-    (gdb) att 4127
-    Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 4127
-    0x10075891 in __libc_nanosleep ()
-
-
-
-
-
-  The backtrace shows that it was in a write and that the fault address
-  (address in frame 3) is 0x50000800, which is right in the middle of
-  the signal thread's stack page::
-
-
-       (gdb) bt
-       #0  0x10075891 in __libc_nanosleep ()
-       #1  0x1007584d in __sleep (seconds=1000000)
-           at ../sysdeps/unix/sysv/linux/sleep.c:78
-       #2  0x1006ce9a in stop () at user_util.c:191
-       #3  0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31
-       #4  0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174
-       #5  0x1006c63c in kern_segv_handler (sig=11) at trap_user.c:182
-       #6  <signal handler called>
-       #7  0xc0fd in ?? ()
-       #8  0x10016647 in sys_write (fd=3, buf=0x80b8800 "R.", count=1024)
-           at read_write.c:159
-       #9  0x1006d603 in execute_syscall (syscall=4, args=0x5006ef08)
-           at syscall_kern.c:254
-       #10 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35
-       #11 <signal handler called>
-       #12 0x400dc8b0 in ?? ()
-       #13 <signal handler called>
-       #14 0x400dc8b0 in ?? ()
-       #15 0x80545fd in ?? ()
-       #16 0x804daae in ?? ()
-       #17 0x8054334 in ?? ()
-       #18 0x804d23e in ?? ()
-       #19 0x8049632 in ?? ()
-       #20 0x80491d2 in ?? ()
-       #21 0x80596b5 in ?? ()
-       (gdb) p (void *)1342179328
-       $3 = (void *) 0x50000800
-
-
-
-  Going up the stack to the segv_handler frame and looking at where in
-  the code the access happened shows that it happened near line 110 of
-  block_dev.c::
-
-
-
-    (gdb) up
-    #1  0x1007584d in __sleep (seconds=1000000)
-       at ../sysdeps/unix/sysv/linux/sleep.c:78
-    ../sysdeps/unix/sysv/linux/sleep.c:78: No such file or directory.
-    (gdb)
-    #2  0x1006ce9a in stop () at user_util.c:191
-    191       while(1) sleep(1000000);
-    (gdb)
-    #3  0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31
-    31          KERN_UNTESTED();
-    (gdb)
-    #4  0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174
-    174       segv(sc->cr2, sc->err & 2);
-    (gdb) p *sc
-    $1 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43,
-       __dsh = 0, edi = 1342179328, esi = 134973440, ebp = 1342631484,
-       esp = 1342630864, ebx = 256, edx = 0, ecx = 256, eax = 1024, trapno = 14,
-       err = 6, eip = 268550834, cs = 35, __csh = 0, eflags = 66070,
-       esp_at_signal = 1342630864, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0,
-       cr2 = 1342179328}
-    (gdb) p (void *)268550834
-    $2 = (void *) 0x1001c2b2
-    (gdb) i sym $2
-    block_write + 1090 in section .text
-    (gdb) i line *$2
-    Line 209 of "/home/dike/linux/2.3.26/um/include/asm/arch/string.h"
-       starts at address 0x1001c2a1 <block_write+1073>
-       and ends at 0x1001c2bf <block_write+1103>.
-    (gdb) i line *0x1001c2c0
-    Line 110 of "block_dev.c" starts at address 0x1001c2bf <block_write+1103>
-       and ends at 0x1001c2e3 <block_write+1139>.
-
-
-
-  Looking at the source shows that the fault happened during a call to
-  copy_from_user to copy the data into the kernel::
-
-
-       107             count -= chars;
-       108             copy_from_user(p,buf,chars);
-       109             p += chars;
-       110             buf += chars;
-
-
-
-  p is the pointer which must contain 0x50000800, since buf contains
-  0x80b8800 (frame 8 above).  It is defined as::
-
-
-                       p = offset + bh->b_data;
-
-
-
-
-
-  I need to figure out what bh is, and it just so happens that bh is
-  passed as an argument to mark_buffer_uptodate and mark_buffer_dirty a
-  few lines later, so I do a little disassembly::
-
-
-    (gdb) disas 0x1001c2bf 0x1001c2e0
-    Dump of assembler code from 0x1001c2bf to 0x1001c2d0:
-    0x1001c2bf <block_write+1103>:  addl   %eax,0xc(%ebp)
-    0x1001c2c2 <block_write+1106>:  movl   0xfffffdd4(%ebp),%edx
-    0x1001c2c8 <block_write+1112>:  btsl   $0x0,0x18(%edx)
-    0x1001c2cd <block_write+1117>:  btsl   $0x1,0x18(%edx)
-    0x1001c2d2 <block_write+1122>:  sbbl   %ecx,%ecx
-    0x1001c2d4 <block_write+1124>:  testl  %ecx,%ecx
-    0x1001c2d6 <block_write+1126>:  jne    0x1001c2e3 <block_write+1139>
-    0x1001c2d8 <block_write+1128>:  pushl  $0x0
-    0x1001c2da <block_write+1130>:  pushl  %edx
-    0x1001c2db <block_write+1131>:  call   0x1001819c <__mark_buffer_dirty>
-    End of assembler dump.
-
-
-
-
-
-  At that point, bh is in %edx (address 0x1001c2da), which is calculated
-  at 0x1001c2c2 as %ebp + 0xfffffdd4, so I figure exactly what that is,
-  taking %ebp from the sigcontext_struct above::
-
-
-       (gdb) p (void *)1342631484
-       $5 = (void *) 0x5006ee3c
-       (gdb) p 0x5006ee3c+0xfffffdd4
-       $6 = 1342630928
-       (gdb) p (void *)$6
-       $7 = (void *) 0x5006ec10
-       (gdb) p *((void **)$7)
-       $8 = (void *) 0x50100200
-
-
-
-
-
-  Now, I look at the structure to see what's in it, and particularly,
-  what its b_data field contains::
-
-
-       (gdb) p *((struct buffer_head *)0x50100200)
-       $13 = {b_next = 0x50289380, b_blocknr = 49405, b_size = 1024, b_list = 0,
-         b_dev = 15872, b_count = {counter = 1}, b_rdev = 15872, b_state = 24,
-         b_flushtime = 0, b_next_free = 0x501001a0, b_prev_free = 0x50100260,
-         b_this_page = 0x501001a0, b_reqnext = 0x0, b_pprev = 0x507fcf58,
-         b_data = 0x50000800 "", b_page = 0x50004000,
-         b_end_io = 0x10017f60 <end_buffer_io_sync>, b_dev_id = 0x0,
-         b_rsector = 98810, b_wait = {lock = <optimized out or zero length>,
-           task_list = {next = 0x50100248, prev = 0x50100248}, __magic = 1343226448,
-           __creator = 0}, b_kiobuf = 0x0}
-
-
-
-
-
-  The b_data field is indeed 0x50000800, so the question becomes how
-  that happened.  The rest of the structure looks fine, so this probably
-  is not a case of data corruption.  It happened on purpose somehow.
-
-
-  The b_page field is a pointer to the page_struct representing the
-  0x50000000 page.  Looking at it shows the kernel's idea of the state
-  of that page::
-
-
-
-    (gdb) p *$13.b_page
-    $17 = {list = {next = 0x50004a5c, prev = 0x100c5174}, mapping = 0x0,
-       index = 0, next_hash = 0x0, count = {counter = 1}, flags = 132, lru = {
-       next = 0x50008460, prev = 0x50019350}, wait = {
-       lock = <optimized out or zero length>, task_list = {next = 0x50004024,
-           prev = 0x50004024}, __magic = 1342193708, __creator = 0},
-       pprev_hash = 0x0, buffers = 0x501002c0, virtual = 1342177280,
-       zone = 0x100c5160}
-
-
-
-
-
-  Some sanity-checking: the virtual field shows the "virtual" address of
-  this page, which in this kernel is the same as its "physical" address,
-  and the page_struct itself should be mem_map[0], since it represents
-  the first page of memory::
-
-
-
-       (gdb) p (void *)1342177280
-       $18 = (void *) 0x50000000
-       (gdb) p mem_map
-       $19 = (mem_map_t *) 0x50004000
-
-
-
-
-
-  These check out fine.
-
-
-  Now to check out the page_struct itself.  In particular, the flags
-  field shows whether the page is considered free or not::
-
-
-       (gdb) p (void *)132
-       $21 = (void *) 0x84
-
-
-
-
-
-  The "reserved" bit is the high bit, which is definitely not set, so
-  the kernel considers the signal stack page to be free and available to
-  be used.
-
-
-  At this point, I jump to conclusions and start looking at my early
-  boot code, because that's where that page is supposed to be reserved.
-
-
-  In my setup_arch procedure, I have the following code which looks just
-  fine::
-
-
-
-       bootmap_size = init_bootmem(start_pfn, end_pfn - start_pfn);
-       free_bootmem(__pa(low_physmem) + bootmap_size, high_physmem - low_physmem);
-
-
-
-
-
-  Two stack pages have already been allocated, and low_physmem points to
-  the third page, which is the beginning of free memory.
-  The init_bootmem call declares the entire memory to the boot memory
-  manager, which marks it all reserved.  The free_bootmem call frees up
-  all of it, except for the first two pages.  This looks correct to me.
-
-
-  So, I decide to see init_bootmem run and make sure that it is marking
-  those first two pages as reserved.  I never get that far.
-
-
-  Stepping into init_bootmem, and looking at bootmem_map before looking
-  at what it contains shows the following::
-
-
-
-       (gdb) p bootmem_map
-       $3 = (void *) 0x50000000
-
-
-
-
-
-  Aha!  The light dawns.  That first page is doing double duty as a
-  stack and as the boot memory map.  The last thing that the boot memory
-  manager does is to free the pages used by its memory map, so this page
-  is getting freed even its marked as reserved.
-
-
-  The fix was to initialize the boot memory manager before allocating
-  those two stack pages, and then allocate them through the boot memory
-  manager.  After doing this, and fixing a couple of subsequent buglets,
-  the stack corruption problem disappeared.
-
-
-
-
-
-13.  What to do when UML doesn't work
-=====================================
-
-
-
-
-13.1.  Strange compilation errors when you build from source
-------------------------------------------------------------
-
-  As of test11, it is necessary to have "ARCH=um" in the environment or
-  on the make command line for all steps in building UML, including
-  clean, distclean, or mrproper, config, menuconfig, or xconfig, dep,
-  and linux.  If you forget for any of them, the i386 build seems to
-  contaminate the UML build.  If this happens, start from scratch with::
-
-
-       host%
-       make mrproper ARCH=um
-
-
-
-
-  and repeat the build process with ARCH=um on all the steps.
-
-
-  See :ref:`Compiling_the_kernel_and_modules`  for more details.
-
-
-  Another cause of strange compilation errors is building UML in
-  /usr/src/linux.  If you do this, the first thing you need to do is
-  clean up the mess you made.  The /usr/src/linux/asm link will now
-  point to /usr/src/linux/asm-um.  Make it point back to
-  /usr/src/linux/asm-i386.  Then, move your UML pool someplace else and
-  build it there.  Also see below, where a more specific set of symptoms
-  is described.
-
-
-
-13.3.  A variety of panics and hangs with /tmp on a reiserfs filesystem
------------------------------------------------------------------------
-
-  I saw this on reiserfs 3.5.21 and it seems to be fixed in 3.5.27.
-  Panics preceded by::
-
-
-       Detaching pid nnnn
-
-
-
-  are diagnostic of this problem.  This is a reiserfs bug which causes a
-  thread to occasionally read stale data from a mmapped page shared with
-  another thread.  The fix is to upgrade the filesystem or to have /tmp
-  be an ext2 filesystem.
-
-
-
-  13.4.  The compile fails with errors about conflicting types for
-  'open', 'dup', and 'waitpid'
-
-  This happens when you build in /usr/src/linux.  The UML build makes
-  the include/asm link point to include/asm-um.  /usr/include/asm points
-  to /usr/src/linux/include/asm, so when that link gets moved, files
-  which need to include the asm-i386 versions of headers get the
-  incompatible asm-um versions.  The fix is to move the include/asm link
-  back to include/asm-i386 and to do UML builds someplace else.
-
-
-
-13.5.  UML doesn't work when /tmp is an NFS filesystem
-------------------------------------------------------
-
-  This seems to be a similar situation with the ReiserFS problem above.
-  Some versions of NFS seems not to handle mmap correctly, which UML
-  depends on.  The workaround is have /tmp be a non-NFS directory.
-
-
-13.6.  UML hangs on boot when compiled with gprof support
----------------------------------------------------------
-
-  If you build UML with gprof support and, early in the boot, it does
-  this::
-
-
-       kernel BUG at page_alloc.c:100!
-
-
-
-
-  you have a buggy gcc.  You can work around the problem by removing
-  UM_FASTCALL from CFLAGS in arch/um/Makefile-i386.  This will open up
-  another bug, but that one is fairly hard to reproduce.
-
-
-
-13.7.  syslogd dies with a SIGTERM on startup
----------------------------------------------
-
-  The exact boot error depends on the distribution that you're booting,
-  but Debian produces this::
-
-
-       /etc/rc2.d/S10sysklogd: line 49:    93 Terminated
-       start-stop-daemon --start --quiet --exec /sbin/syslogd -- $SYSLOGD
-
-
-
-
-  This is a syslogd bug.  There's a race between a parent process
-  installing a signal handler and its child sending the signal.
-
-
-
-13.8.  TUN/TAP networking doesn't work on a 2.4 host
-----------------------------------------------------
-
-  There are a couple of problems which were reported by
-  Tim Robinson <timro at trkr dot net>
-
-  -  It doesn't work on hosts running 2.4.7 (or thereabouts) or earlier.
-     The fix is to upgrade to something more recent and then read the
-     next item.
-
-  -  If you see::
-
-
-       File descriptor in bad state
-
-
-
-  when you bring up the device inside UML, you have a header mismatch
-  between the original kernel and the upgraded one.  Make /usr/src/linux
-  point at the new headers.  This will only be a problem if you build
-  uml_net yourself.
-
-
-
-13.9.  You can network to the host but not to other machines on the net
-=======================================================================
-
-  If you can connect to the host, and the host can connect to UML, but
-  you cannot connect to any other machines, then you may need to enable
-  IP Masquerading on the host.  Usually this is only experienced when
-  using private IP addresses (192.168.x.x or 10.x.x.x) for host/UML
-  networking, rather than the public address space that your host is
-  connected to.  UML does not enable IP Masquerading, so you will need
-  to create a static rule to enable it::
-
-
-       host%
-       iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
-
-
-
-
-  Replace eth0 with the interface that you use to talk to the rest of
-  the world.
-
-
-  Documentation on IP Masquerading, and SNAT, can be found at
-  http://www.netfilter.org.
-
-
-  If you can reach the local net, but not the outside Internet, then
-  that is usually a routing problem.  The UML needs a default route::
-
-
-       UML#
-       route add default gw gateway IP
-
-
-
-
-  The gateway IP can be any machine on the local net that knows how to
-  reach the outside world.  Usually, this is the host or the local net-
-  work's gateway.
-
-
-  Occasionally, we hear from someone who can reach some machines, but
-  not others on the same net, or who can reach some ports on other
-  machines, but not others.  These are usually caused by strange
-  firewalling somewhere between the UML and the other box.  You track
-  this down by running tcpdump on every interface the packets travel
-  over and see where they disappear.  When you find a machine that takes
-  the packets in, but does not send them onward, that's the culprit.
-
-
-
-13.10.  I have no root and I want to scream
-===========================================
-
-  Thanks to Birgit Wahlich for telling me about this strange one.  It
-  turns out that there's a limit of six environment variables on the
-  kernel command line.  When that limit is reached or exceeded, argument
-  processing stops, which means that the 'root=' argument that UML
-  usually adds is not seen.  So, the filesystem has no idea what the
-  root device is, so it panics.
-
-
-  The fix is to put less stuff on the command line.  Glomming all your
-  setup variables into one is probably the best way to go.
-
-
-
-13.11.  UML build conflict between ptrace.h and ucontext.h
-==========================================================
-
-  On some older systems, /usr/include/asm/ptrace.h and
-  /usr/include/sys/ucontext.h define the same names.  So, when they're
-  included together, the defines from one completely mess up the parsing
-  of the other, producing errors like::
-
-       /usr/include/sys/ucontext.h:47: parse error before
-       `10`
-
-
-
-
-  plus a pile of warnings.
-
-
-  This is a libc botch, which has since been fixed, and I don't see any
-  way around it besides upgrading.
-
-
-
-13.12.  The UML BogoMips is exactly half the host's BogoMips
-------------------------------------------------------------
-
-  On i386 kernels, there are two ways of running the loop that is used
-  to calculate the BogoMips rating, using the TSC if it's there or using
-  a one-instruction loop.  The TSC produces twice the BogoMips as the
-  loop.  UML uses the loop, since it has nothing resembling a TSC, and
-  will get almost exactly the same BogoMips as a host using the loop.
-  However, on a host with a TSC, its BogoMips will be double the loop
-  BogoMips, and therefore double the UML BogoMips.
-
-
-
-13.13.  When you run UML, it immediately segfaults
---------------------------------------------------
-
-  If the host is configured with the 2G/2G address space split, that's
-  why.  See ref:`UML_on_2G/2G_hosts`  for the details on getting UML to
-  run on your host.
-
-
-
-13.14.  xterms appear, then immediately disappear
--------------------------------------------------
-
-  If you're running an up to date kernel with an old release of
-  uml_utilities, the port-helper program will not work properly, so
-  xterms will exit straight after they appear. The solution is to
-  upgrade to the latest release of uml_utilities.  Usually this problem
-  occurs when you have installed a packaged release of UML then compiled
-  your own development kernel without upgrading the uml_utilities from
-  the source distribution.
-
-
-
-13.15.  Any other panic, hang, or strange behavior
---------------------------------------------------
-
-  If you're seeing truly strange behavior, such as hangs or panics that
-  happen in random places, or you try running the debugger to see what's
-  happening and it acts strangely, then it could be a problem in the
-  host kernel.  If you're not running a stock Linus or -ac kernel, then
-  try that.  An early version of the preemption patch and a 2.4.10 SuSE
-  kernel have caused very strange problems in UML.
-
-
-  Otherwise, let me know about it.  Send a message to one of the UML
-  mailing lists - either the developer list - user-mode-linux-devel at
-  lists dot sourceforge dot net (subscription info) or the user list -
-  user-mode-linux-user at lists dot sourceforge do net (subscription
-  info), whichever you prefer.  Don't assume that everyone knows about
-  it and that a fix is imminent.
-
-
-  If you want to be super-helpful, read :ref:`Diagnosing_Problems` and
-  follow the instructions contained therein.
-
-.. _Diagnosing_Problems:
-
-14.  Diagnosing Problems
-========================
-
-
-  If you get UML to crash, hang, or otherwise misbehave, you should
-  report this on one of the project mailing lists, either the developer
-  list - user-mode-linux-devel at lists dot sourceforge dot net
-  (subscription info) or the user list - user-mode-linux-user at lists
-  dot sourceforge dot net (subscription info).  When you do, it is
-  likely that I will want more information.  So, it would be helpful to
-  read the stuff below, do whatever is applicable in your case, and
-  report the results to the list.
-
-
-  For any diagnosis, you're going to need to build a debugging kernel.
-  The binaries from this site aren't debuggable.  If you haven't done
-  this before, read about :ref:`Compiling_the_kernel_and_modules`  and
-  :ref:`Kernel_debugging` UML first.
-
-
-14.1.  Case 1 : Normal kernel panics
-------------------------------------
-
-  The most common case is for a normal thread to panic.  To debug this,
-  you will need to run it under the debugger (add 'debug' to the command
-  line).  An xterm will start up with gdb running inside it.  Continue
-  it when it stops in start_kernel and make it crash.  Now ``^C gdb`` and
-
-
-  If the panic was a "Kernel mode fault", then there will be a segv
-  frame on the stack and I'm going to want some more information.  The
-  stack might look something like this::
-
-
-       (UML gdb)  backtrace
-       #0  0x1009bf76 in __sigprocmask (how=1, set=0x5f347940, oset=0x0)
-           at ../sysdeps/unix/sysv/linux/sigprocmask.c:49
-       #1  0x10091411 in change_sig (signal=10, on=1) at process.c:218
-       #2  0x10094785 in timer_handler (sig=26) at time_kern.c:32
-       #3  0x1009bf38 in __restore ()
-           at ../sysdeps/unix/sysv/linux/i386/sigaction.c:125
-       #4  0x1009534c in segv (address=8, ip=268849158, is_write=2, is_user=0)
-           at trap_kern.c:66
-       #5  0x10095c04 in segv_handler (sig=11) at trap_user.c:285
-       #6  0x1009bf38 in __restore ()
-
-
-
-
-  I'm going to want to see the symbol and line information for the value
-  of ip in the segv frame.  In this case, you would do the following::
-
-
-       (UML gdb)  i sym 268849158
-
-
-
-
-  and::
-
-
-       (UML gdb)  i line *268849158
-
-
-
-
-  The reason for this is the __restore frame right above the segv_han-
-  dler frame is hiding the frame that actually segfaulted.  So, I have
-  to get that information from the faulting ip.
-
-
-14.2.  Case 2 : Tracing thread panics
--------------------------------------
-
-  The less common and more painful case is when the tracing thread
-  panics.  In this case, the kernel debugger will be useless because it
-  needs a healthy tracing thread in order to work.  The first thing to
-  do is get a backtrace from the tracing thread.  This is done by
-  figuring out what its pid is, firing up gdb, and attaching it to that
-  pid.  You can figure out the tracing thread pid by looking at the
-  first line of the console output, which will look like this::
-
-
-       tracing thread pid = 15851
-
-
-
-
-  or by running ps on the host and finding the line that looks like
-  this::
-
-
-       jdike 15851 4.5 0.4 132568 1104 pts/0 S 21:34 0:05 ./linux [(tracing thread)]
-
-
-
-
-  If the panic was 'segfault in signals', then follow the instructions
-  above for collecting information about the location of the seg fault.
-
-
-  If the tracing thread flaked out all by itself, then send that
-  backtrace in and wait for our crack debugging team to fix the problem.
-
-
-  14.3.  Case 3 : Tracing thread panics caused by other threads
-
-  However, there are cases where the misbehavior of another thread
-  caused the problem.  The most common panic of this type is::
-
-
-       wait_for_stop failed to wait for  <pid>  to stop with  <signal number>
-
-
-
-
-  In this case, you'll need to get a backtrace from the process men-
-  tioned in the panic, which is complicated by the fact that the kernel
-  debugger is defunct and without some fancy footwork, another gdb can't
-  attach to it.  So, this is how the fancy footwork goes:
-
-  In a shell::
-
-
-       host% kill -STOP pid
-
-
-
-
-  Run gdb on the tracing thread as described in case 2 and do::
-
-
-       (host gdb)  call detach(pid)
-
-
-  If you get a segfault, do it again.  It always works the second time.
-
-  Detach from the tracing thread and attach to that other thread::
-
-
-       (host gdb)  detach
-
-
-
-
-
-
-       (host gdb)  attach pid
-
-
-
-
-  If gdb hangs when attaching to that process, go back to a shell and
-  do::
-
-
-       host%
-       kill -CONT pid
-
-
-
-
-  And then get the backtrace::
-
-
-       (host gdb)  backtrace
-
-
-
-
-
-14.4.  Case 4 : Hangs
----------------------
-
-  Hangs seem to be fairly rare, but they sometimes happen.  When a hang
-  happens, we need a backtrace from the offending process.  Run the
-  kernel debugger as described in case 1 and get a backtrace.  If the
-  current process is not the idle thread, then send in the backtrace.
-  You can tell that it's the idle thread if the stack looks like this::
-
-
-       #0  0x100b1401 in __libc_nanosleep ()
-       #1  0x100a2885 in idle_sleep (secs=10) at time.c:122
-       #2  0x100a546f in do_idle () at process_kern.c:445
-       #3  0x100a5508 in cpu_idle () at process_kern.c:471
-       #4  0x100ec18f in start_kernel () at init/main.c:592
-       #5  0x100a3e10 in start_kernel_proc (unused=0x0) at um_arch.c:71
-       #6  0x100a383f in signal_tramp (arg=0x100a3dd8) at trap_user.c:50
-
-
-
-
-  If this is the case, then some other process is at fault, and went to
-  sleep when it shouldn't have.  Run ps on the host and figure out which
-  process should not have gone to sleep and stayed asleep.  Then attach
-  to it with gdb and get a backtrace as described in case 3.
-
-
-
-
-
-
-15.  Thanks
-===========
-
-
-  A number of people have helped this project in various ways, and this
-  page gives recognition where recognition is due.
-
-
-  If you're listed here and you would prefer a real link on your name,
-  or no link at all, instead of the despammed email address pseudo-link,
-  let me know.
-
-
-  If you're not listed here and you think maybe you should be, please
-  let me know that as well.  I try to get everyone, but sometimes my
-  bookkeeping lapses and I forget about contributions.
-
-
-15.1.  Code and Documentation
------------------------------
-
-  Rusty Russell <rusty at linuxcare.com.au>  -
-
-  -  wrote the  HOWTO
-     http://user-mode-linux.sourceforge.net/old/UserModeLinux-HOWTO.html
-
-  -  prodded me into making this project official and putting it on
-     SourceForge
-
-  -  came up with the way cool UML logo
-     http://user-mode-linux.sourceforge.net/uml-small.png
-
-  -  redid the config process
-
-
-  Peter Moulder <reiter at netspace.net.au>  - Fixed my config and build
-  processes, and added some useful code to the block driver
-
-
-  Bill Stearns <wstearns at pobox.com>  -
-
-  -  HOWTO updates
-
-  -  lots of bug reports
-
-  -  lots of testing
-
-  -  dedicated a box (uml.ists.dartmouth.edu) to support UML development
-
-  -  wrote the mkrootfs script, which allows bootable filesystems of
-     RPM-based distributions to be cranked out
-
-  -  cranked out a large number of filesystems with said script
-
-
-  Jim Leu <jleu at mindspring.com>  - Wrote the virtual ethernet driver
-  and associated usermode tools
-
-  Lars Brinkhoff http://lars.nocrew.org/  - Contributed the ptrace
-  proxy from his own  project to allow easier kernel debugging
-
-
-  Andrea Arcangeli <andrea at suse.de>  - Redid some of the early boot
-  code so that it would work on machines with Large File Support
-
-
-  Chris Emerson - Did the first UML port to Linux/ppc
-
-
-  Harald Welte <laforge at gnumonks.org>  - Wrote the multicast
-  transport for the network driver
-
-
-  Jorgen Cederlof - Added special file support to hostfs
-
-
-  Greg Lonnon  <glonnon at ridgerun dot com>  - Changed the ubd driver
-  to allow it to layer a COW file on a shared read-only filesystem and
-  wrote the iomem emulation support
-
-
-  Henrik Nordstrom http://hem.passagen.se/hno/  - Provided a variety
-  of patches, fixes, and clues
-
-
-  Lennert Buytenhek - Contributed various patches, a rewrite of the
-  network driver, the first implementation of the mconsole driver, and
-  did the bulk of the work needed to get SMP working again.
-
-
-  Yon Uriarte - Fixed the TUN/TAP network backend while I slept.
-
-
-  Adam Heath - Made a bunch of nice cleanups to the initialization code,
-  plus various other small patches.
-
-
-  Matt Zimmerman - Matt volunteered to be the UML Debian maintainer and
-  is doing a real nice job of it.  He also noticed and fixed a number of
-  actually and potentially exploitable security holes in uml_net.  Plus
-  the occasional patch.  I like patches.
-
-
-  James McMechan - James seems to have taken over maintenance of the ubd
-  driver and is doing a nice job of it.
-
-
-  Chandan Kudige - wrote the umlgdb script which automates the reloading
-  of module symbols.
-
-
-  Steve Schmidtke - wrote the UML slirp transport and hostaudio drivers,
-  enabling UML processes to access audio devices on the host. He also
-  submitted patches for the slip transport and lots of other things.
-
-
-  David Coulson http://davidcoulson.net  -
-
-  -  Set up the http://usermodelinux.org  site,
-     which is a great way of keeping the UML user community on top of
-     UML goings-on.
-
-  -  Site documentation and updates
-
-  -  Nifty little UML management daemon  UMLd
-
-  -  Lots of testing and bug reports
-
-
-
-
-15.2.  Flushing out bugs
-------------------------
-
-
-
-  -  Yuri Pudgorodsky
-
-  -  Gerald Britton
-
-  -  Ian Wehrman
-
-  -  Gord Lamb
-
-  -  Eugene Koontz
-
-  -  John H. Hartman
-
-  -  Anders Karlsson
-
-  -  Daniel Phillips
-
-  -  John Fremlin
-
-  -  Rainer Burgstaller
-
-  -  James Stevenson
-
-  -  Matt Clay
-
-  -  Cliff Jefferies
-
-  -  Geoff Hoff
-
-  -  Lennert Buytenhek
-
-  -  Al Viro
-
-  -  Frank Klingenhoefer
-
-  -  Livio Baldini Soares
-
-  -  Jon Burgess
-
-  -  Petru Paler
-
-  -  Paul
-
-  -  Chris Reahard
-
-  -  Sverker Nilsson
-
-  -  Gong Su
-
-  -  johan verrept
-
-  -  Bjorn Eriksson
-
-  -  Lorenzo Allegrucci
-
-  -  Muli Ben-Yehuda
-
-  -  David Mansfield
-
-  -  Howard Goff
-
-  -  Mike Anderson
-
-  -  John Byrne
-
-  -  Sapan J. Batia
-
-  -  Iris Huang
-
-  -  Jan Hudec
-
-  -  Voluspa
-
-
-
-
-15.3.  Buglets and clean-ups
-----------------------------
-
-
-
-  -  Dave Zarzycki
-
-  -  Adam Lazur
-
-  -  Boria Feigin
-
-  -  Brian J. Murrell
-
-  -  JS
-
-  -  Roman Zippel
-
-  -  Wil Cooley
-
-  -  Ayelet Shemesh
-
-  -  Will Dyson
-
-  -  Sverker Nilsson
-
-  -  dvorak
-
-  -  v.naga srinivas
-
-  -  Shlomi Fish
-
-  -  Roger Binns
-
-  -  johan verrept
-
-  -  MrChuoi
-
-  -  Peter Cleve
-
-  -  Vincent Guffens
-
-  -  Nathan Scott
-
-  -  Patrick Caulfield
-
-  -  jbearce
-
-  -  Catalin Marinas
-
-  -  Shane Spencer
-
-  -  Zou Min
-
-
-  -  Ryan Boder
-
-  -  Lorenzo Colitti
-
-  -  Gwendal Grignou
-
-  -  Andre' Breiler
-
-  -  Tsutomu Yasuda
-
-
-
-15.4.  Case Studies
--------------------
-
-
-  -  Jon Wright
-
-  -  William McEwan
-
-  -  Michael Richardson
-
-
-
-15.5.  Other contributions
---------------------------
-
-
-  Bill Carr <Bill.Carr at compaq.com>  made the Red Hat mkrootfs script
-  work with RH 6.2.
-
-  Michael Jennings <mikejen at hevanet.com>  sent in some material which
-  is now gracing the top of the  index  page
-  http://user-mode-linux.sourceforge.net/  of this site.
-
-  SGI (and more specifically Ralf Baechle <ralf at
-  uni-koblenz.de> ) gave me an account on oss.sgi.com.
-  The bandwidth there made it possible to
-  produce most of the filesystems available on the project download
-  page.
-
-  Laurent Bonnaud <Laurent.Bonnaud at inpg.fr>  took the old grotty
-  Debian filesystem that I've been distributing and updated it to 2.2.
-  It is now available by itself here.
-
-  Rik van Riel gave me some ftp space on ftp.nl.linux.org so I can make
-  releases even when Sourceforge is broken.
-
-  Rodrigo de Castro looked at my broken pte code and told me what was
-  wrong with it, letting me fix a long-standing (several weeks) and
-  serious set of bugs.
-
-  Chris Reahard built a specialized root filesystem for running a DNS
-  server jailed inside UML.  It's available from the download
-  http://user-mode-linux.sourceforge.net/old/dl-sf.html  page in the Jail
-  Filesystems section.
diff --git a/Documentation/virt/uml/user_mode_linux_howto_v2.rst b/Documentation/virt/uml/user_mode_linux_howto_v2.rst
new file mode 100644 (file)
index 0000000..f70e6f5
--- /dev/null
@@ -0,0 +1,1208 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+#########
+UML HowTo
+#########
+
+.. contents:: :local:
+
+************
+Introduction
+************
+
+Welcome to User Mode Linux
+
+User Mode Linux is the first Open Source virtualization platform (first
+release date 1991) and second virtualization platform for an x86 PC.
+
+How is UML Different from a VM using Virtualization package X?
+==============================================================
+
+We have come to assume that virtualization also means some level of
+hardware emulation. In fact, it does not. As long as a virtualization
+package provides the OS with devices which the OS can recognize and
+has a driver for, the devices do not need to emulate real hardware.
+Most OSes today have built-in support for a number of "fake"
+devices used only under virtualization.
+User Mode Linux takes this concept to the ultimate extreme - there
+is not a single real device in sight. It is 100% artificial or if
+we use the correct term 100% paravirtual. All UML devices are abstract
+concepts which map onto something provided by the host - files, sockets,
+pipes, etc.
+
+The other major difference between UML and various virtualization
+packages is that there is a distinct difference between the way the UML
+kernel and the UML programs operate.
+The UML kernel is just a process running on Linux - same as any other
+program. It can be run by an unprivileged user and it does not require
+anything in terms of special CPU features.
+The UML userspace, however, is a bit different. The Linux kernel on the
+host machine assists UML in intercepting everything the program running
+on a UML instance is trying to do and making the UML kernel handle all
+of its requests.
+This is different from other virtualization packages which do not make any
+difference between the guest kernel and guest programs. This difference
+results in a number of advantages and disadvantages of UML over let's say
+QEMU which we will cover later in this document.
+
+
+Why Would I Want User Mode Linux?
+=================================
+
+
+* If User Mode Linux kernel crashes, your host kernel is still fine. It
+  is not accelerated in any way (vhost, kvm, etc) and it is not trying to
+  access any devices directly.  It is, in fact, a process like any other.
+
+* You can run a usermode kernel as a non-root user (you may need to
+  arrange appropriate permissions for some devices).
+
+* You can run a very small VM with a minimal footprint for a specific
+  task (for example 32M or less).
+
+* You can get extremely high performance for anything which is a "kernel
+  specific task" such as forwarding, firewalling, etc while still being
+  isolated from the host kernel.
+
+* You can play with kernel concepts without breaking things.
+
+* You are not bound by "emulating" hardware, so you can try weird and
+  wonderful concepts which are very difficult to support when emulating
+  real hardware such as time travel and making your system clock
+  dependent on what UML does (very useful for things like tests).
+
+* It's fun.
+
+Why not to run UML
+==================
+
+* The syscall interception technique used by UML makes it inherently
+  slower for any userspace applications. While it can do kernel tasks
+  on par with most other virtualization packages, its userspace is
+  **slow**. The root cause is that UML has a very high cost of creating
+  new processes and threads (something most Unix/Linux applications
+  take for granted).
+
+* UML is strictly uniprocessor at present. If you want to run an
+  application which needs many CPUs to function, it is clearly the
+  wrong choice.
+
+***********************
+Building a UML instance
+***********************
+
+There is no UML installer in any distribution. While you can use off
+the shelf install media to install into a blank VM using a virtualization
+package, there is no UML equivalent. You have to use appropriate tools on
+your host to build a viable filesystem image.
+
+This is extremely easy on Debian - you can do it using debootstrap. It is
+also easy on OpenWRT - the build process can build UML images. All other
+distros - YMMV.
+
+Creating an image
+=================
+
+Create a sparse raw disk image::
+
+   # dd if=/dev/zero of=disk_image_name bs=1 count=1 seek=16G
+
+This will create a 16G disk image. The OS will initially allocate only one
+block and will allocate more as they are written by UML. As of kernel
+version 4.19 UML fully supports TRIM (as usually used by flash drives).
+Using TRIM inside the UML image by specifying discard as a mount option
+or by running ``tune2fs -o discard /dev/ubdXX`` will request UML to
+return any unused blocks to the OS.
+
+Create a filesystem on the disk image and mount it::
+
+   # mkfs.ext4 ./disk_image_name && mount ./disk_image_name /mnt
+
+This example uses ext4, any other filesystem such as ext3, btrfs, xfs,
+jfs, etc will work too.
+
+Create a minimal OS installation on the mounted filesystem::
+
+   # debootstrap buster /mnt http://deb.debian.org/debian
+
+debootstrap does not set up the root password, fstab, hostname or
+anything related to networking. It is up to the user to do that.
+
+Set the root password -t he easiest way to do that is to chroot into the
+mounted image::
+
+   # chroot /mnt
+   # passwd
+   # exit
+
+Edit key system files
+=====================
+
+UML block devices are called ubds. The fstab created by debootstrap
+will be empty and it needs an entry for the root file system::
+
+   /dev/ubd0   ext4    discard,errors=remount-ro  0       1
+
+The image hostname will be set to the same as the host on which you
+are creating it image. It is a good idea to change that to avoid
+"Oh, bummer, I rebooted the wrong machine".
+
+UML supports two classes of network devices - the older uml_net ones
+which are scheduled for obsoletion. These are called ethX. It also
+supports the newer vector IO devices which are significantly faster
+and have support for some standard virtual network encapsulations like
+Ethernet over GRE and Ethernet over L2TPv3. These are called vec0.
+
+Depending on which one is in use, ``/etc/network/interfaces`` will
+need entries like::
+
+   # legacy UML network devices
+   auto eth0
+   iface eth0 inet dhcp
+
+   # vector UML network devices
+   auto vec0
+   iface eth0 inet dhcp
+
+We now have a UML image which is nearly ready to run, all we need is a
+UML kernel and modules for it.
+
+Most distributions have a UML package. Even if you intend to use your own
+kernel, testing the image with a stock one is always a good start. These
+packages come with a set of modules which should be copied to the target
+filesystem. The location is distribution dependent. For Debian these
+reside under /usr/lib/uml/modules. Copy recursively the content of this
+directory to the mounted UML filesystem::
+
+   # cp -rax /usr/lib/uml/modules /mnt/lib/modules
+
+If you have compiled your own kernel, you need to use the usual "install
+modules to a location" procedure by running::
+
+  # make install MODULES_DIR=/mnt/lib/modules
+
+At this point the image is ready to be brought up.
+
+*************************
+Setting Up UML Networking
+*************************
+
+UML networking is designed to emulate an Ethernet connection. This
+connection may be either a point-to-point (similar to a connection
+between machines using a back-to-back cable) or a connection to a
+switch. UML supports a wide variety of means to build these
+connections to all of: local machine, remote machine(s), local and
+remote UML and other VM instances.
+
+
++-----------+--------+------------------------------------+------------+
+| Transport |  Type  |        Capabilities                | Throughput |
++===========+========+====================================+============+
+| tap       | vector | checksum, tso                      | > 8Gbit    |
++-----------+--------+------------------------------------+------------+
+| hybrid    | vector | checksum, tso, multipacket rx      | > 6GBit    |
++-----------+--------+------------------------------------+------------+
+| raw       | vector | checksum, tso, multipacket rx, tx" | > 6GBit    |
++-----------+--------+------------------------------------+------------+
+| EoGRE     | vector | multipacket rx, tx                 | > 3Gbit    |
++-----------+--------+------------------------------------+------------+
+| Eol2tpv3  | vector | multipacket rx, tx                 | > 3Gbit    |
++-----------+--------+------------------------------------+------------+
+| bess      | vector | multipacket rx, tx                 | > 3Gbit    |
++-----------+--------+------------------------------------+------------+
+| fd        | vector | dependent on fd type               | varies     |
++-----------+--------+------------------------------------+------------+
+| tuntap    | legacy | none                               | ~ 500Mbit  |
++-----------+--------+------------------------------------+------------+
+| daemon    | legacy | none                               | ~ 450Mbit  |
++-----------+--------+------------------------------------+------------+
+| socket    | legacy | none                               | ~ 450Mbit  |
++-----------+--------+------------------------------------+------------+
+| pcap      | legacy | rx only                            | ~ 450Mbit  |
++-----------+--------+------------------------------------+------------+
+| ethertap  | legacy | obsolete                           | ~ 500Mbit  |
++-----------+--------+------------------------------------+------------+
+| vde       | legacy | obsolete                           | ~ 500Mbit  |
++-----------+--------+------------------------------------+------------+
+
+* All transports which have tso and checksum offloads can deliver speeds
+  approaching 10G on TCP streams.
+
+* All transports which have multi-packet rx and/or tx can deliver pps
+  rates of up to 1Mps or more.
+
+* All legacy transports are generally limited to ~600-700MBit and 0.05Mps
+
+* GRE and L2TPv3 allow connections to all of: local machine, remote
+  machines, remote network devices and remote UML instances.
+
+* Socket allows connections only between UML instances.
+
+* Daemon and bess require running a local switch. This switch may be
+  connected to the host as well.
+
+
+Network configuration privileges
+================================
+
+The majority of the supported networking modes need ``root`` privileges.
+For example, in the legacy tuntap networking mode, users were required
+to be part of the group associated with the tunnel device.
+
+For newer network drivers like the vector transports, ``root`` privilege
+is required to fire an ioctl to setup the tun interface and/or use
+raw sockets where needed.
+
+This can be achieved by granting the user a particular capability instead
+of running UML as root.  In case of vector transport, a user can add the
+capability ``CAP_NET_ADMIN`` or ``CAP_NET_RAW``, to the uml binary.
+Thenceforth, UML can be run with normal user privilges, along with
+full networking.
+
+For example::
+
+   # sudo setcap cap_net_raw,cap_net_admin+ep linux
+
+Configuring vector transports
+===============================
+
+All vector transports support a similar syntax:
+
+If X is the interface number as in vec0, vec1, vec2, etc, the general
+syntax for options is::
+
+   vecX:transport="Transport Name",option=value,option=value,...,option=value
+
+Common options
+--------------
+
+These options are common for all transports:
+
+* ``depth=int`` - sets the queue depth for vector IO. This is the
+  amount of packets UML will attempt to read or write in a single
+  system call. The default number is 64 and is generally sufficient
+  for most applications that need throughput in the 2-4 Gbit range.
+  Higher speeds may require larger values.
+
+* ``mac=XX:XX:XX:XX:XX`` - sets the interface MAC address value.
+
+* ``gro=[0,1]`` - sets GRO on or off. Enables receive/transmit offloads.
+  The effect of this option depends on the host side support in the transport
+  which is being configured. In most cases it will enable TCP segmentation and
+  RX/TX checksumming offloads. The setting must be identical on the host side
+  and the UML side. The UML kernel will produce warnings if it is not.
+  For example, GRO is enabled by default on local machine interfaces
+  (e.g. veth pairs, bridge, etc), so it should be enabled in UML in the
+  corresponding UML transports (raw, tap, hybrid) in order for networking to
+  operate correctly.
+
+* ``mtu=int`` - sets the interface MTU
+
+* ``headroom=int`` - adjusts the default headroom (32 bytes) reserved
+  if a packet will need to be re-encapsulated into for instance VXLAN.
+
+* ``vec=0`` - disable multipacket io and fall back to packet at a
+  time mode
+
+Shared Options
+--------------
+
+* ``ifname=str`` Transports which bind to a local network interface
+  have a shared option - the name of the interface to bind to.
+
+* ``src, dst, src_port, dst_port`` - all transports which use sockets
+  which have the notion of source and destination and/or source port
+  and destination port use these to specify them.
+
+* ``v6=[0,1]`` to specify if a v6 connection is desired for all
+  transports which operate over IP. Additionally, for transports that
+  have some differences in the way they operate over v4 and v6 (for example
+  EoL2TPv3), sets the correct mode of operation. In the absense of this
+  option, the socket type is determined based on what do the src and dst
+  arguments resolve/parse to.
+
+tap transport
+-------------
+
+Example::
+
+   vecX:transport=tap,ifname=tap0,depth=128,gro=1
+
+This will connect vec0 to tap0 on the host. Tap0 must already exist (for example
+created using tunctl) and UP.
+
+tap0 can be configured as a point-to-point interface and given an ip
+address so that UML can talk to the host. Alternatively, it is possible
+to connect UML to a tap interface which is connected to a bridge.
+
+While tap relies on the vector infrastructure, it is not a true vector
+transport at this point, because Linux does not support multi-packet
+IO on tap file descriptors for normal userspace apps like UML. This
+is a privilege which is offered only to something which can hook up
+to it at kernel level via specialized interfaces like vhost-net. A
+vhost-net like helper for UML is planned at some point in the future.
+
+Privileges required: tap transport requires either:
+
+* tap interface to exist and be created persistent and owned by the
+  UML user using tunctl. Example ``tunctl -u uml-user -t tap0``
+
+* binary to have ``CAP_NET_ADMIN`` privilege
+
+hybrid transport
+----------------
+
+Example::
+
+   vecX:transport=hybrid,ifname=tap0,depth=128,gro=1
+
+This is an experimental/demo transport which couples tap for transmit
+and a raw socket for receive. The raw socket allows multi-packet
+receive resulting in significantly higher packet rates than normal tap
+
+Privileges required: hybrid requires ``CAP_NET_RAW`` capability by
+the UML user as well as the requirements for the tap transport.
+
+raw socket transport
+--------------------
+
+Example::
+
+   vecX:transport=raw,ifname=p-veth0,depth=128,gro=1
+
+
+This transport uses vector IO on raw sockets. While you can bind to any
+interface including a physical one, the most common use it to bind to
+the "peer" side of a veth pair with the other side configured on the
+host.
+
+Example host configuration for Debian:
+
+**/etc/network/interfaces**::
+
+   auto veth0
+   iface veth0 inet static
+       address 192.168.4.1
+       netmask 255.255.255.252
+       broadcast 192.168.4.3
+       pre-up ip link add veth0 type veth peer name p-veth0 && \
+          ifconfig p-veth0 up
+
+UML can now bind to p-veth0 like this::
+
+   vec0:transport=raw,ifname=p-veth0,depth=128,gro=1
+
+
+If the UML guest is configured with 192.168.4.2 and netmask 255.255.255.0
+it can talk to the host on 192.168.4.1
+
+The raw transport also provides some support for offloading some of the
+filtering to the host. The two options to control it are:
+
+* ``bpffile=str`` filename of raw bpf code to be loaded as a socket filter
+
+* ``bpfflash=int`` 0/1 allow loading of bpf from inside User Mode Linux.
+  This option allows the use of the ethtool load firmware command to
+  load bpf code.
+
+In either case the bpf code is loaded into the host kernel. While this is
+presently limited to legacy bpf syntax (not ebpf), it is still a security
+risk. It is not recommended to allow this unless the User Mode Linux
+instance is considered trusted.
+
+Privileges required: raw socket transport requires `CAP_NET_RAW`
+capability.
+
+GRE socket transport
+--------------------
+
+Example::
+
+   vecX:transport=gre,src=$src_host,dst=$dst_host
+
+
+This will configure an Ethernet over ``GRE`` (aka ``GRETAP`` or
+``GREIRB``) tunnel which will connect the UML instance to a ``GRE``
+endpoint at host dst_host. ``GRE`` supports the following additional
+options:
+
+* ``rx_key=int`` - GRE 32 bit integer key for rx packets, if set,
+  ``txkey`` must be set too
+
+* ``tx_key=int`` - GRE 32 bit integer key for tx packets, if set
+  ``rx_key`` must be set too
+
+* ``sequence=[0,1]`` - enable GRE sequence
+
+* ``pin_sequence=[0,1]`` - pretend that the sequence is always reset
+  on each packet (needed to interoperate with some really broken
+  implementations)
+
+* ``v6=[0,1]`` - force IPv4 or IPv6 sockets respectively
+
+* GRE checksum is not presently supported
+
+GRE has a number of caveats:
+
+* You can use only one GRE connection per ip address. There is no way to
+  multiplex connections as each GRE tunnel is terminated directly on
+  the UML instance.
+
+* The key is not really a security feature. While it was intended as such
+  it's "security" is laughable. It is, however, a useful feature to
+  ensure that the tunnel is not misconfigured.
+
+An example configuration for a Linux host with a local address of
+192.168.128.1 to connect to a UML instance at 192.168.129.1
+
+**/etc/network/interfaces**::
+
+   auto gt0
+   iface gt0 inet static
+    address 10.0.0.1
+    netmask 255.255.255.0
+    broadcast 10.0.0.255
+    mtu 1500
+    pre-up ip link add gt0 type gretap local 192.168.128.1 \
+           remote 192.168.129.1 || true
+    down ip link del gt0 || true
+
+Additionally, GRE has been tested versus a variety of network equipment.
+
+Privileges required: GRE requires ``CAP_NET_RAW``
+
+l2tpv3 socket transport
+-----------------------
+
+_Warning_. L2TPv3 has a "bug". It is the "bug" known as "has more
+options than GNU ls". While it has some advantages, there are usually
+easier (and less verbose) ways to connect a UML instance to something.
+For example, most devices which support L2TPv3 also support GRE.
+
+Example::
+
+    vec0:transport=l2tpv3,udp=1,src=$src_host,dst=$dst_host,srcport=$src_port,dstport=$dst_port,depth=128,rx_session=0xffffffff,tx_session=0xffff
+
+This will configure an Ethernet over L2TPv3 fixed tunnel which will
+connect the UML instance to a L2TPv3 endpoint at host $dst_host using
+the L2TPv3 UDP flavour and UDP destination port $dst_port.
+
+L2TPv3 always requires the following additional options:
+
+* ``rx_session=int`` - l2tpv3 32 bit integer session for rx packets
+
+* ``tx_session=int`` - l2tpv3 32 bit integer session for tx packets
+
+As the tunnel is fixed these are not negotiated and they are
+preconfigured on both ends.
+
+Additionally, L2TPv3 supports the following optional parameters
+
+* ``rx_cookie=int`` - l2tpv3 32 bit integer cookie for rx packets - same
+  functionality as GRE key, more to prevent misconfiguration than provide
+  actual security
+
+* ``tx_cookie=int`` - l2tpv3 32 bit integer cookie for tx packets
+
+* ``cookie64=[0,1]`` - use 64 bit cookies instead of 32 bit.
+
+* ``counter=[0,1]`` - enable l2tpv3 counter
+
+* ``pin_counter=[0,1]`` - pretend that the counter is always reset on
+  each packet (needed to interoperate with some really broken
+  implementations)
+
+* ``v6=[0,1]`` - force v6 sockets
+
+* ``udp=[0,1]`` - use raw sockets (0) or UDP (1) version of the protocol
+
+L2TPv3 has a number of caveats:
+
+* you can use only one connection per ip address in raw mode. There is
+  no way to multiplex connections as each L2TPv3 tunnel is terminated
+  directly on the UML instance. UDP mode can use different ports for
+  this purpose.
+
+Here is an example of how to configure a linux host to connect to UML
+via L2TPv3:
+
+**/etc/network/interfaces**::
+
+   auto l2tp1
+   iface l2tp1 inet static
+    address 192.168.126.1
+    netmask 255.255.255.0
+    broadcast 192.168.126.255
+    mtu 1500
+    pre-up ip l2tp add tunnel remote 127.0.0.1 \
+           local 127.0.0.1 encap udp tunnel_id 2 \
+           peer_tunnel_id 2 udp_sport 1706 udp_dport 1707 && \
+           ip l2tp add session name l2tp1 tunnel_id 2 \
+           session_id 0xffffffff peer_session_id 0xffffffff
+    down ip l2tp del session tunnel_id 2 session_id 0xffffffff && \
+           ip l2tp del tunnel tunnel_id 2
+
+
+Privileges required: L2TPv3 requires ``CAP_NET_RAW`` for raw IP mode and
+no special privileges for the UDP mode.
+
+BESS socket transport
+---------------------
+
+BESS is a high performance modular network switch.
+
+https://github.com/NetSys/bess
+
+It has support for a simple sequential packet socket mode which in the
+more recent versions is using vector IO for high performance.
+
+Example::
+
+   vecX:transport=bess,src=$unix_src,dst=$unix_dst
+
+This will configure a BESS transport using the unix_src Unix domain
+socket address as source and unix_dst socket address as destination.
+
+For BESS configuration and how to allocate a BESS Unix domain socket port
+please see the BESS documentation.
+
+https://github.com/NetSys/bess/wiki/Built-In-Modules-and-Ports
+
+BESS transport does not require any special privileges.
+
+Configuring Legacy transports
+=============================
+
+Legacy transports are now considered obsolete. Please use the vector
+versions.
+
+***********
+Running UML
+***********
+
+This section assumes that either the user-mode-linux package from the
+distribution or a custom built kernel has been installed on the host.
+
+These add an executable called linux to the system. This is the UML
+kernel. It can be run just like any other executable.
+It will take most normal linux kernel arguments as command line
+arguments.  Additionally, it will need some UML specific arguments
+in order to do something useful.
+
+Arguments
+=========
+
+Mandatory Arguments:
+--------------------
+
+* ``mem=int[K,M,G]`` - amount of memory. By default bytes. It will
+  also accept K, M or G qualifiers.
+
+* ``ubdX[s,d,c,t]=`` virtual disk specification. This is not really
+  mandatory, but it is likely to be needed in nearly all cases so we can
+  specify a root file system.
+  The simplest possible image specification is the name of the image
+  file for the filesystem (created using one of the methods described
+  in `Creating an image`_)
+
+  * UBD devices support copy on write (COW). The changes are kept in
+    a separate file which can be discarded allowing a rollback to the
+    original pristine image.  If COW is desired, the UBD image is
+    specified as: ``cow_file,master_image``.
+    Example:``ubd0=Filesystem.cow,Filesystem.img``
+
+  * UBD devices can be set to use synchronous IO. Any writes are
+    immediately flushed to disk. This is done by adding ``s`` after
+    the ``ubdX`` specification
+
+  * UBD performs some euristics on devices specified as a single
+    filename to make sure that a COW file has not been specified as
+    the image. To turn them off, use the ``d`` flag after ``ubdX``
+
+  * UBD supports TRIM - asking the Host OS to reclaim any unused
+    blocks in the image. To turn it off, specify the ``t`` flag after
+    ``ubdX``
+
+* ``root=`` root device - most likely ``/dev/ubd0`` (this is a Linux
+  filesystem image)
+
+Important Optional Arguments
+----------------------------
+
+If UML is run as "linux" with no extra arguments, it will try to start an
+xterm for every console configured inside the image (up to 6 in most
+linux distributions). Each console is started inside an
+xterm. This makes it nice and easy to use UML on a host with a GUI. It is,
+however, the wrong approach if UML is to be used as a testing harness or run
+in a text-only environment.
+
+In order to change this behaviour we need to specify an alternative console
+and wire it to one of the supported "line" channels. For this we need to map a
+console to use something different from the default xterm.
+
+Example which will divert console number 1 to stdin/stdout::
+
+   con1=fd:0,fd:1
+
+UML supports a wide variety of serial line channels which are specified using
+the following syntax
+
+   conX=channel_type:options[,channel_type:options]
+
+
+If the channel specification contains two parts separated by comma, the first
+one is input, the second one output.
+
+* The null channel - Discard all input or output. Example ``con=null`` will set
+  all consoles to null by default.
+
+* The fd channel - use file descriptor numbers for input/out. Example:
+  ``con1=fd:0,fd:1.``
+
+* The port channel - listen on tcp port number. Example: ``con1=port:4321``
+
+* The pty and pts channels - use system pty/pts.
+
+* The tty channel - bind to an existing system tty. Example: ``con1=/dev/tty8``
+  will make UML use the host 8th console (usually unused).
+
+* The xterm channel - this is the default - bring up an xterm on this channel
+  and direct IO to it. Note, that in order for xterm to work, the host must
+  have the UML distribution package installed. This usually contains the
+  port-helper and other utilities needed for UML to communicate with the xterm.
+  Alternatively, these need to be complied and installed from source. All
+  options applicable to consoles also apply to UML serial lines which are
+  presented as ttyS inside UML.
+
+Starting UML
+============
+
+We can now run UML.
+::
+   # linux mem=2048M umid=TEST \
+    ubd0=Filesystem.img \
+    vec0:transport=tap,ifname=tap0,depth=128,gro=1 \
+    root=/dev/ubda con=null con0=null,fd:2 con1=fd:0,fd:1
+
+This will run an instance with ``2048M RAM``, try to use the image file
+called ``Filesystem.img`` as root. It will connect to the host using tap0.
+All consoles except ``con1`` will be disabled and console 1 will
+use standard input/output making it appear in the same terminal it was started.
+
+Logging in
+============
+
+If you have not set up a password when generating the image, you will have to
+shut down the UML instance, mount the image, chroot into it and set it - as
+described in the Generating an Image section.  If the password is already set,
+you can just log in.
+
+The UML Management Console
+============================
+
+In addition to managing the image from "the inside" using normal sysadmin tools,
+it is possible to perform a number of low level operations using the UML
+management console. The UML management console is a low-level interface to the
+kernel on a running UML instance, somewhat like the i386 SysRq interface. Since
+there is a full-blown operating system under UML, there is much greater
+flexibility possible than with the SysRq mechanism.
+
+There are a number of things you can do with the mconsole interface:
+
+* get the kernel version
+* add and remove devices
+* halt or reboot the machine
+* Send SysRq commands
+* Pause and resume the UML
+* Inspect processes running inside UML
+* Inspect UML internal /proc state
+
+You need the mconsole client (uml\_mconsole) which is a part of the UML
+tools package available in most Linux distritions.
+
+You also need ``CONFIG_MCONSOLE`` (under 'General Setup') enabled in the UML
+kernel.  When you boot UML, you'll see a line like::
+
+   mconsole initialized on /home/jdike/.uml/umlNJ32yL/mconsole
+
+If you specify a unique machine id one the UML command line, i.e. 
+``umid=debian``, you'll see this::
+
+   mconsole initialized on /home/jdike/.uml/debian/mconsole
+
+
+That file is the socket that uml_mconsole will use to communicate with
+UML.  Run it with either the umid or the full path as its argument::
+
+   # uml_mconsole debian
+
+or
+
+   # uml_mconsole /home/jdike/.uml/debian/mconsole
+
+
+You'll get a prompt, at which you can run one of these commands:
+
+* version
+* help
+* halt
+* reboot
+* config
+* remove
+* sysrq
+* help
+* cad
+* stop
+* go
+* proc
+* stack
+
+version
+-------
+
+This command takes no arguments.  It prints the UML version::
+
+   (mconsole)  version
+   OK Linux OpenWrt 4.14.106 #0 Tue Mar 19 08:19:41 2019 x86_64
+
+
+There are a couple actual uses for this.  It's a simple no-op which
+can be used to check that a UML is running.  It's also a way of
+sending a device interrupt to the UML. UML mconsole is treated internally as
+a UML device.
+
+help
+----
+
+This command takes no arguments. It prints a short help screen with the
+supported mconsole commands.
+
+
+halt and reboot
+---------------
+
+These commands take no arguments.  They shut the machine down immediately, with
+no syncing of disks and no clean shutdown of userspace.  So, they are
+pretty close to crashing the machine::
+
+   (mconsole)  halt
+   OK
+
+config
+------
+
+"config" adds a new device to the virtual machine. This is supported
+by most UML device drivers. It takes one argument, which is the
+device to add, with the same syntax as the kernel command line::
+
+   (mconsole) config ubd3=/home/jdike/incoming/roots/root_fs_debian22
+
+remove
+------
+
+"remove" deletes a device from the system.  Its argument is just the
+name of the device to be removed. The device must be idle in whatever
+sense the driver considers necessary.  In the case of the ubd driver,
+the removed block device must not be mounted, swapped on, or otherwise
+open, and in the case of the network driver, the device must be down::
+
+   (mconsole)  remove ubd3
+
+sysrq
+-----
+
+This command takes one argument, which is a single letter.  It calls the
+generic kernel's SysRq driver, which does whatever is called for by
+that argument.  See the SysRq documentation in
+Documentation/admin-guide/sysrq.rst in your favorite kernel tree to
+see what letters are valid and what they do.
+
+cad
+---
+
+This invokes the ``Ctl-Alt-Del`` action in the running image.  What exactly
+this ends up doing is up to init, systemd, etc.  Normally, it reboots the
+machine.
+
+stop
+----
+
+This puts the UML in a loop reading mconsole requests until a 'go'
+mconsole command is received. This is very useful as a
+debugging/snapshotting tool.
+
+go
+--
+
+This resumes a UML after being paused by a 'stop' command. Note that
+when the UML has resumed, TCP connections may have timed out and if
+the UML is paused for a long period of time, crond might go a little
+crazy, running all the jobs it didn't do earlier.
+
+proc
+----
+
+This takes one argument - the name of a file in /proc which is printed
+to the mconsole standard output
+
+stack
+-----
+
+This takes one argument - the pid number of a process. Its stack is
+printed to a standard output.
+
+*******************
+Advanced UML Topics
+*******************
+
+Sharing Filesystems between Virtual Machines
+============================================
+
+Don't attempt to share filesystems simply by booting two UMLs from the
+same file.  That's the same thing as booting two physical machines
+from a shared disk.  It will result in filesystem corruption.
+
+Using layered block devices
+---------------------------
+
+The way to share a filesystem between two virtual machines is to use
+the copy-on-write (COW) layering capability of the ubd block driver.
+Any changed blocks are stored in the private COW file, while reads come
+from either device - the private one if the requested block is valid in
+it, the shared one if not.  Using this scheme, the majority of data
+which is unchanged is shared between an arbitrary number of virtual
+machines, each of which has a much smaller file containing the changes
+that it has made.  With a large number of UMLs booting from a large root
+filesystem, this leads to a huge disk space saving.
+
+Sharing file system data will also help performance, since the host will
+be able to cache the shared data using a much smaller amount of memory,
+so UML disk requests will be served from the host's memory rather than
+its disks.  There is a major caveat in doing this on multisocket NUMA
+machines.  On such hardware, running many UML instances with a shared
+master image and COW changes may caise issues like NMIs from excess of
+inter-socket traffic.
+
+If you are running UML on high end hardware like this, make sure to
+bind UML to a set of logical cpus residing on the same socket using the
+``taskset`` command or have a look at the "tuning" section.
+
+To add a copy-on-write layer to an existing block device file, simply
+add the name of the COW file to the appropriate ubd switch::
+
+   ubd0=root_fs_cow,root_fs_debian_22
+
+where ``root_fs_cow`` is the private COW file and ``root_fs_debian_22`` is
+the existing shared filesystem.  The COW file need not exist.  If it
+doesn't, the driver will create and initialize it.
+
+Disk Usage
+----------
+
+UML has TRIM support which will release any unused space in its disk
+image files to the underlying OS. It is important to use either ls -ls
+or du to verify the actual file size.
+
+COW validity.
+-------------
+
+Any changes to the master image will invalidate all COW files. If this
+happens, UML will *NOT* automatically delete any of the COW files and
+will refuse to boot. In this case the only solution is to either
+restore the old image (including its last modified timestamp) or remove
+all COW files which will result in their recreation. Any changes in
+the COW files will be lost.
+
+Cows can moo - uml_moo : Merging a COW file with its backing file
+-----------------------------------------------------------------
+
+Depending on how you use UML and COW devices, it may be advisable to
+merge the changes in the COW file into the backing file every once in
+a while.
+
+The utility that does this is uml_moo.  Its usage is::
+
+   uml_moo COW_file new_backing_file
+
+
+There's no need to specify the backing file since that information is
+already in the COW file header.  If you're paranoid, boot the new
+merged file, and if you're happy with it, move it over the old backing
+file.
+
+``uml_moo`` creates a new backing file by default as a safety measure.
+It also has a destructive merge option which will merge the COW file
+directly into its current backing file.  This is really only usable
+when the backing file only has one COW file associated with it.  If
+there are multiple COWs associated with a backing file, a -d merge of
+one of them will invalidate all of the others.  However, it is
+convenient if you're short of disk space, and it should also be
+noticeably faster than a non-destructive merge.
+
+``uml_moo`` is installed with the UML distribution packages and is
+available as a part of UML utilities.
+
+Host file access
+==================
+
+If you want to access files on the host machine from inside UML, you
+can treat it as a separate machine and either nfs mount directories
+from the host or copy files into the virtual machine with scp.
+However, since UML is running on the host, it can access those
+files just like any other process and make them available inside the
+virtual machine without the need to use the network.
+This is possible with the hostfs virtual filesystem.  With it, you
+can mount a host directory into the UML filesystem and access the
+files contained in it just as you would on the host.
+
+*SECURITY WARNING*
+
+Hostfs without any parameters to the UML Image will allow the image
+to mount any part of the host filesystem and write to it. Always
+confine hostfs to a specific "harmless" directory (for example ``/var/tmp``)
+if running UML. This is especially important if UML is being run as root.
+
+Using hostfs
+------------
+
+To begin with, make sure that hostfs is available inside the virtual
+machine with::
+
+   # cat /proc/filesystems
+
+``hostfs`` should be listed.  If it's not, either rebuild the kernel
+with hostfs configured into it or make sure that hostfs is built as a
+module and available inside the virtual machine, and insmod it.
+
+
+Now all you need to do is run mount::
+
+   # mount none /mnt/host -t hostfs
+
+will mount the host's ``/`` on the virtual machine's ``/mnt/host``.
+If you don't want to mount the host root directory, then you can
+specify a subdirectory to mount with the -o switch to mount::
+
+   # mount none /mnt/home -t hostfs -o /home
+
+will mount the hosts's /home on the virtual machine's /mnt/home.
+
+hostfs as the root filesystem
+-----------------------------
+
+It's possible to boot from a directory hierarchy on the host using
+hostfs rather than using the standard filesystem in a file.
+To start, you need that hierarchy.  The easiest way is to loop mount
+an existing root_fs file::
+
+   #  mount root_fs uml_root_dir -o loop
+
+
+You need to change the filesystem type of ``/`` in ``etc/fstab`` to be
+'hostfs', so that line looks like this::
+
+   /dev/ubd/0       /        hostfs      defaults          1   1
+
+Then you need to chown to yourself all the files in that directory
+that are owned by root.  This worked for me::
+
+   #  find . -uid 0 -exec chown jdike {} \;
+
+Next, make sure that your UML kernel has hostfs compiled in, not as a
+module.  Then run UML with the boot device pointing at that directory::
+
+   ubd0=/path/to/uml/root/directory
+
+UML should then boot as it does normally.
+
+Hostfs Caveats
+--------------
+
+Hostfs does not support keeping track of host filesystem changes on the
+host (outside UML). As a result, if a file is changed without UML's
+knowledge, UML will not know about it and its own in-memory cache of
+the file may be corrupt. While it is possible to fix this, it is not
+something which is being worked on at present.
+
+Tuning UML
+============
+
+UML at present is strictly uniprocessor. It will, however spin up a
+number of threads to handle various functions.
+
+The UBD driver, SIGIO and the MMU emulation do that. If the system is
+idle, these threads will be migrated to other processors on a SMP host.
+This, unfortunately, will usually result in LOWER performance because of
+all of the cache/memory synchronization traffic between cores. As a
+result, UML will usually benefit from being pinned on a single CPU
+especially on a large system. This can result in performance differences
+of 5 times or higher on some benchmarks.
+
+Similarly, on large multi-node NUMA systems UML will benefit if all of
+its memory is allocated from the same NUMA node it will run on. The
+OS will *NOT* do that by default. In order to do that, the sysadmin
+needs to create a suitable tmpfs ramdisk bound to a particular node
+and use that as the source for UML RAM allocation by specifying it
+in the TMP or TEMP environment variables. UML will look at the values
+of ``TMPDIR``, ``TMP`` or ``TEMP`` for that. If that fails, it will
+look for shmfs mounted under ``/dev/shm``. If everything else fails use
+``/tmp/`` regardless of the filesystem type used for it::
+
+   mount -t tmpfs -ompol=bind:X none /mnt/tmpfs-nodeX
+   TEMP=/mnt/tmpfs-nodeX taskset -cX linux options options options..
+
+*******************************************
+Contributing to UML and Developing with UML
+*******************************************
+
+UML is an excellent platform to develop new Linux kernel concepts -
+filesystems, devices, virtualization, etc. It provides unrivalled
+opportunities to create and test them without being constrained to
+emulating specific hardware.
+
+Example - want to try how linux will work with 4096 "proper" network
+devices?
+
+Not an issue with UML. At the same time, this is something which
+is difficult with other virtualization packages - they are
+constrained by the number of devices allowed on the hardware bus
+they are trying to emulate (for example 16 on a PCI bus in qemu).
+
+If you have something to contribute such as a patch, a bugfix, a
+new feature, please send it to ``linux-um@lists.infradead.org``
+
+Please follow all standard Linux patch guidelines such as cc-ing
+relevant maintainers and run ``./sripts/checkpatch.pl`` on your patch.
+For more details see ``Documentation/process/submitting-patches.rst``
+
+Note - the list does not accept HTML or attachments, all emails must
+be formatted as plain text.
+
+Developing always goes hand in hand with debugging. First of all,
+you can always run UML under gdb and there will be a whole section
+later on on how to do that. That, however, is not the only way to
+debug a linux kernel. Quite often adding tracing statements and/or
+using UML specific approaches such as ptracing the UML kernel process
+are significantly more informative.
+
+Tracing UML
+=============
+
+When running UML consists of a main kernel thread and a number of
+helper threads. The ones of interest for tracing are NOT the ones
+that are already ptraced by UML as a part of its MMU emulation.
+
+These are usually the first three threads visible in a ps display.
+The one with the lowest PID number and using most CPU is usually the
+kernel thread. The other threads are the disk
+(ubd) device helper thread and the sigio helper thread.
+Running ptrace on this thread usually results in the following picture::
+
+   host$ strace -p 16566
+   --- SIGIO {si_signo=SIGIO, si_code=POLL_IN, si_band=65} ---
+   epoll_wait(4, [{EPOLLIN, {u32=3721159424, u64=3721159424}}], 64, 0) = 1
+   epoll_wait(4, [], 64, 0)                = 0
+   rt_sigreturn({mask=[PIPE]})             = 16967
+   ptrace(PTRACE_GETREGS, 16967, NULL, 0xd5f34f38) = 0
+   ptrace(PTRACE_GETREGSET, 16967, NT_X86_XSTATE, [{iov_base=0xd5f35010, iov_len=832}]) = 0
+   ptrace(PTRACE_GETSIGINFO, 16967, NULL, {si_signo=SIGTRAP, si_code=0x85, si_pid=16967, si_uid=0}) = 0
+   ptrace(PTRACE_SETREGS, 16967, NULL, 0xd5f34f38) = 0
+   ptrace(PTRACE_SETREGSET, 16967, NT_X86_XSTATE, [{iov_base=0xd5f35010, iov_len=2696}]) = 0
+   ptrace(PTRACE_SYSEMU, 16967, NULL, 0)   = 0
+   --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_TRAPPED, si_pid=16967, si_uid=0, si_status=SIGTRAP, si_utime=65, si_stime=89} ---
+   wait4(16967, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGTRAP | 0x80}], WSTOPPED|__WALL, NULL) = 16967
+   ptrace(PTRACE_GETREGS, 16967, NULL, 0xd5f34f38) = 0
+   ptrace(PTRACE_GETREGSET, 16967, NT_X86_XSTATE, [{iov_base=0xd5f35010, iov_len=832}]) = 0
+   ptrace(PTRACE_GETSIGINFO, 16967, NULL, {si_signo=SIGTRAP, si_code=0x85, si_pid=16967, si_uid=0}) = 0
+   timer_settime(0, 0, {it_interval={tv_sec=0, tv_nsec=0}, it_value={tv_sec=0, tv_nsec=2830912}}, NULL) = 0
+   getpid()                                = 16566
+   clock_nanosleep(CLOCK_MONOTONIC, 0, {tv_sec=1, tv_nsec=0}, NULL) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
+   --- SIGALRM {si_signo=SIGALRM, si_code=SI_TIMER, si_timerid=0, si_overrun=0, si_value={int=1631716592, ptr=0x614204f0}} ---
+   rt_sigreturn({mask=[PIPE]})             = -1 EINTR (Interrupted system call)
+
+This is a typical picture from a mostly idle UML instance
+
+* UML interrupt controller uses epoll - this is UML waiting for IO
+  interrupts:
+
+   epoll_wait(4, [{EPOLLIN, {u32=3721159424, u64=3721159424}}], 64, 0) = 1
+
+* The sequence of ptrace calls is part of MMU emulation and runnin the
+  UML userspace
+* ``timer_settime`` is part of the UML high res timer subsystem mapping
+  timer requests from inside UML onto the host high resultion timers.
+* ``clock_nanosleep`` is UML going into idle (similar to the way a PC
+  will execute an ACPI idle).
+
+As you can see UML will generate quite a bit of output even in idle.The output
+can be very informative when observing IO. It shows the actual IO calls, their
+arguments and returns values.
+
+Kernel debugging
+================
+
+You can run UML under gdb now, though it will not necessarily agree to
+be started under it. If you are trying to track a runtime bug, it is
+much better to attach gdb to a running UML instance and let UML run.
+
+Assuming the same PID number as in the previous example, this would be::
+
+   # gdb -p 16566
+
+This will STOP the UML instance, so you must enter `cont` at the GDB
+command line to request it to continue. It may be a good idea to make
+this into a gdb script and pass it to gdb as an argument.
+
+Developing Device Drivers
+=========================
+
+Nearly all UML drivers are monolithic. While it is possible to build a
+UML driver as a kernel module, that limits the possible functionality
+to in-kernel only and non-UML specific.  The reason for this is that
+in order to really leverage UML, one needs to write a piece of
+userspace code which maps driver concepts onto actual userspace host
+calls.
+
+This forms the so called "user" portion of the driver. While it can
+reuse a lot of kernel concepts, it is generally just another piece of
+userspace code. This portion needs some matching "kernel" code which
+resides inside the UML image and which implements the Linux kernel part.
+
+*Note: There are very few limitations in the way "kernel" and "user" interact*.
+
+UML does not have a strictly defined kernel to host API. It does not
+try to emulate a specific architecture or bus. UML's "kernel" and
+"user" can share memory, code and interact as needed to implement
+whatever design the software developer has in mind. The only
+limitations are purely technical. Due to a lot of functions and
+variables having the same names, the developer should be careful
+which includes and libraries they are trying to refer to.
+
+As a result a lot of userspace code consists of simple wrappers.
+F.e. ``os_close_file()`` is just a wrapper around ``close()``
+which ensures that the userspace function close does not clash
+with similarly named function(s) in the kernel part.
+
+Security Considerations
+-----------------------
+
+Drivers or any new functionality should default to not
+accepting arbitrary filename, bpf code or other  parameters
+which can affect the host from inside the UML instance.
+For example, specifying the socket used for IPC communication
+between a driver and the host at the UML command line is OK
+security-wise. Allowing it as a loadable module parameter
+isn't.
+
+If such functionality is desireable for a particular application
+(e.g. loading BPF "firmware" for raw socket network transports),
+it should be off by default and should be explicitly turned on
+as a command line parameter at startup.
+
+Even with this in mind, the level of isolation between UML
+and the host is relatively weak. If the UML userspace is
+allowed to load arbitrary kernel drivers, an attacker can
+use this to break out of UML. Thus, if UML is used in
+a production application, it is recommended that all modules
+are loaded at boot and kernel module loading is disabled
+afterwards.
index 6f9e000..dd9f76a 100644 (file)
@@ -1,4 +1,4 @@
-.. hmm:
+.. _hmm:
 
 =====================================
 Heterogeneous Memory Management (HMM)
@@ -271,10 +271,139 @@ map those pages from the CPU side.
 Migration to and from device memory
 ===================================
 
-Because the CPU cannot access device memory, migration must use the device DMA
-engine to perform copy from and to device memory. For this we need to use
-migrate_vma_setup(), migrate_vma_pages(), and migrate_vma_finalize() helpers.
-
+Because the CPU cannot access device memory directly, the device driver must
+use hardware DMA or device specific load/store instructions to migrate data.
+The migrate_vma_setup(), migrate_vma_pages(), and migrate_vma_finalize()
+functions are designed to make drivers easier to write and to centralize common
+code across drivers.
+
+Before migrating pages to device private memory, special device private
+``struct page`` need to be created. These will be used as special "swap"
+page table entries so that a CPU process will fault if it tries to access
+a page that has been migrated to device private memory.
+
+These can be allocated and freed with::
+
+    struct resource *res;
+    struct dev_pagemap pagemap;
+
+    res = request_free_mem_region(&iomem_resource, /* number of bytes */,
+                                  "name of driver resource");
+    pagemap.type = MEMORY_DEVICE_PRIVATE;
+    pagemap.range.start = res->start;
+    pagemap.range.end = res->end;
+    pagemap.nr_range = 1;
+    pagemap.ops = &device_devmem_ops;
+    memremap_pages(&pagemap, numa_node_id());
+
+    memunmap_pages(&pagemap);
+    release_mem_region(pagemap.range.start, range_len(&pagemap.range));
+
+There are also devm_request_free_mem_region(), devm_memremap_pages(),
+devm_memunmap_pages(), and devm_release_mem_region() when the resources can
+be tied to a ``struct device``.
+
+The overall migration steps are similar to migrating NUMA pages within system
+memory (see :ref:`Page migration <page_migration>`) but the steps are split
+between device driver specific code and shared common code:
+
+1. ``mmap_read_lock()``
+
+   The device driver has to pass a ``struct vm_area_struct`` to
+   migrate_vma_setup() so the mmap_read_lock() or mmap_write_lock() needs to
+   be held for the duration of the migration.
+
+2. ``migrate_vma_setup(struct migrate_vma *args)``
+
+   The device driver initializes the ``struct migrate_vma`` fields and passes
+   the pointer to migrate_vma_setup(). The ``args->flags`` field is used to
+   filter which source pages should be migrated. For example, setting
+   ``MIGRATE_VMA_SELECT_SYSTEM`` will only migrate system memory and
+   ``MIGRATE_VMA_SELECT_DEVICE_PRIVATE`` will only migrate pages residing in
+   device private memory. If the latter flag is set, the ``args->pgmap_owner``
+   field is used to identify device private pages owned by the driver. This
+   avoids trying to migrate device private pages residing in other devices.
+   Currently only anonymous private VMA ranges can be migrated to or from
+   system memory and device private memory.
+
+   One of the first steps migrate_vma_setup() does is to invalidate other
+   device's MMUs with the ``mmu_notifier_invalidate_range_start(()`` and
+   ``mmu_notifier_invalidate_range_end()`` calls around the page table
+   walks to fill in the ``args->src`` array with PFNs to be migrated.
+   The ``invalidate_range_start()`` callback is passed a
+   ``struct mmu_notifier_range`` with the ``event`` field set to
+   ``MMU_NOTIFY_MIGRATE`` and the ``migrate_pgmap_owner`` field set to
+   the ``args->pgmap_owner`` field passed to migrate_vma_setup(). This is
+   allows the device driver to skip the invalidation callback and only
+   invalidate device private MMU mappings that are actually migrating.
+   This is explained more in the next section.
+
+   While walking the page tables, a ``pte_none()`` or ``is_zero_pfn()``
+   entry results in a valid "zero" PFN stored in the ``args->src`` array.
+   This lets the driver allocate device private memory and clear it instead
+   of copying a page of zeros. Valid PTE entries to system memory or
+   device private struct pages will be locked with ``lock_page()``, isolated
+   from the LRU (if system memory since device private pages are not on
+   the LRU), unmapped from the process, and a special migration PTE is
+   inserted in place of the original PTE.
+   migrate_vma_setup() also clears the ``args->dst`` array.
+
+3. The device driver allocates destination pages and copies source pages to
+   destination pages.
+
+   The driver checks each ``src`` entry to see if the ``MIGRATE_PFN_MIGRATE``
+   bit is set and skips entries that are not migrating. The device driver
+   can also choose to skip migrating a page by not filling in the ``dst``
+   array for that page.
+
+   The driver then allocates either a device private struct page or a
+   system memory page, locks the page with ``lock_page()``, and fills in the
+   ``dst`` array entry with::
+
+   dst[i] = migrate_pfn(page_to_pfn(dpage)) | MIGRATE_PFN_LOCKED;
+
+   Now that the driver knows that this page is being migrated, it can
+   invalidate device private MMU mappings and copy device private memory
+   to system memory or another device private page. The core Linux kernel
+   handles CPU page table invalidations so the device driver only has to
+   invalidate its own MMU mappings.
+
+   The driver can use ``migrate_pfn_to_page(src[i])`` to get the
+   ``struct page`` of the source and either copy the source page to the
+   destination or clear the destination device private memory if the pointer
+   is ``NULL`` meaning the source page was not populated in system memory.
+
+4. ``migrate_vma_pages()``
+
+   This step is where the migration is actually "committed".
+
+   If the source page was a ``pte_none()`` or ``is_zero_pfn()`` page, this
+   is where the newly allocated page is inserted into the CPU's page table.
+   This can fail if a CPU thread faults on the same page. However, the page
+   table is locked and only one of the new pages will be inserted.
+   The device driver will see that the ``MIGRATE_PFN_MIGRATE`` bit is cleared
+   if it loses the race.
+
+   If the source page was locked, isolated, etc. the source ``struct page``
+   information is now copied to destination ``struct page`` finalizing the
+   migration on the CPU side.
+
+5. Device driver updates device MMU page tables for pages still migrating,
+   rolling back pages not migrating.
+
+   If the ``src`` entry still has ``MIGRATE_PFN_MIGRATE`` bit set, the device
+   driver can update the device MMU and set the write enable bit if the
+   ``MIGRATE_PFN_WRITE`` bit is set.
+
+6. ``migrate_vma_finalize()``
+
+   This step replaces the special migration page table entry with the new
+   page's page table entry and releases the reference to the source and
+   destination ``struct page``.
+
+7. ``mmap_read_unlock()``
+
+   The lock can now be released.
 
 Memory cgroup (memcg) and rss accounting
 ========================================
index 611140f..eff5fbd 100644 (file)
@@ -29,6 +29,7 @@ descriptions of data structures and algorithms.
    :maxdepth: 1
 
    active_mm
+   arch_pgtable_helpers
    balance
    cleancache
    free_page_reporting
index 68883ac..91a98a6 100644 (file)
@@ -4,25 +4,28 @@
 Page migration
 ==============
 
-Page migration allows the moving of the physical location of pages between
-nodes in a numa system while the process is running. This means that the
+Page migration allows moving the physical location of pages between
+nodes in a NUMA system while the process is running. This means that the
 virtual addresses that the process sees do not change. However, the
 system rearranges the physical location of those pages.
 
-The main intend of page migration is to reduce the latency of memory access
+Also see :ref:`Heterogeneous Memory Management (HMM) <hmm>`
+for migrating pages to or from device private memory.
+
+The main intent of page migration is to reduce the latency of memory accesses
 by moving pages near to the processor where the process accessing that memory
 is running.
 
 Page migration allows a process to manually relocate the node on which its
 pages are located through the MF_MOVE and MF_MOVE_ALL options while setting
-a new memory policy via mbind(). The pages of process can also be relocated
+a new memory policy via mbind(). The pages of process can also be relocated
 from another process using the sys_migrate_pages() function call. The
-migrate_pages function call takes two sets of nodes and moves pages of a
+migrate_pages() function call takes two sets of nodes and moves pages of a
 process that are located on the from nodes to the destination nodes.
 Page migration functions are provided by the numactl package by Andi Kleen
 (a version later than 0.9.3 is required. Get it from
-ftp://oss.sgi.com/www/projects/libnuma/download/). numactl provides libnuma
-which provides an interface similar to other numa functionality for page
+https://github.com/numactl/numactl.git). numactl provides libnuma
+which provides an interface similar to other NUMA functionality for page
 migration.  cat ``/proc/<pid>/numa_maps`` allows an easy review of where the
 pages of a process are located. See also the numa_maps documentation in the
 proc(5) man page.
@@ -30,19 +33,19 @@ proc(5) man page.
 Manual migration is useful if for example the scheduler has relocated
 a process to a processor on a distant node. A batch scheduler or an
 administrator may detect the situation and move the pages of the process
-nearer to the new processor. The kernel itself does only provide
+nearer to the new processor. The kernel itself only provides
 manual page migration support. Automatic page migration may be implemented
 through user space processes that move pages. A special function call
 "move_pages" allows the moving of individual pages within a process.
-A NUMA profiler may f.e. obtain a log showing frequent off node
+For example, A NUMA profiler may obtain a log showing frequent off-node
 accesses and may use the result to move pages to more advantageous
 locations.
 
 Larger installations usually partition the system using cpusets into
 sections of nodes. Paul Jackson has equipped cpusets with the ability to
 move pages when a task is moved to another cpuset (See
-Documentation/admin-guide/cgroup-v1/cpusets.rst).
-Cpusets allows the automation of process locality. If a task is moved to
+:ref:`CPUSETS <cpusets>`).
+Cpusets allow the automation of process locality. If a task is moved to
 a new cpuset then also all its pages are moved with it so that the
 performance of the process does not sink dramatically. Also the pages
 of processes in a cpuset are moved if the allowed memory nodes of a
@@ -67,9 +70,9 @@ In kernel use of migrate_pages()
    Lists of pages to be migrated are generated by scanning over
    pages and moving them into lists. This is done by
    calling isolate_lru_page().
-   Calling isolate_lru_page increases the references to the page
+   Calling isolate_lru_page() increases the references to the page
    so that it cannot vanish while the page migration occurs.
-   It also prevents the swapper or other scans to encounter
+   It also prevents the swapper or other scans from encountering
    the page.
 
 2. We need to have a function of type new_page_t that can be
@@ -91,23 +94,24 @@ is increased so that the page cannot be freed while page migration occurs.
 
 Steps:
 
-1. Lock the page to be migrated
+1. Lock the page to be migrated.
 
 2. Ensure that writeback is complete.
 
 3. Lock the new page that we want to move to. It is locked so that accesses to
-   this (not yet uptodate) page immediately lock while the move is in progress.
+   this (not yet uptodate) page immediately block while the move is in progress.
 
 4. All the page table references to the page are converted to migration
    entries. This decreases the mapcount of a page. If the resulting
    mapcount is not zero then we do not migrate the page. All user space
-   processes that attempt to access the page will now wait on the page lock.
+   processes that attempt to access the page will now wait on the page lock
+   or wait for the migration page table entry to be removed.
 
 5. The i_pages lock is taken. This will cause all processes trying
    to access the page via the mapping to block on the spinlock.
 
-6. The refcount of the page is examined and we back out if references remain
-   otherwise we know that we are the only one referencing this page.
+6. The refcount of the page is examined and we back out if references remain.
+   Otherwise, we know that we are the only one referencing this page.
 
 7. The radix tree is checked and if it does not contain the pointer to this
    page then we back out because someone else modified the radix tree.
@@ -134,124 +138,124 @@ Steps:
 
 15. Queued up writeback on the new page is triggered.
 
-16. If migration entries were page then replace them with real ptes. Doing
-    so will enable access for user space processes not already waiting for
-    the page lock.
+16. If migration entries were inserted into the page table, then replace them
+    with real ptes. Doing so will enable access for user space processes not
+    already waiting for the page lock.
 
-19. The page locks are dropped from the old and new page.
+17. The page locks are dropped from the old and new page.
     Processes waiting on the page lock will redo their page faults
     and will reach the new page.
 
-20. The new page is moved to the LRU and can be scanned by the swapper
-    etc again.
+18. The new page is moved to the LRU and can be scanned by the swapper,
+    etc. again.
 
 Non-LRU page migration
 ======================
 
-Although original migration aimed for reducing the latency of memory access
-for NUMA, compaction who want to create high-order page is also main customer.
+Although migration originally aimed for reducing the latency of memory accesses
+for NUMA, compaction also uses migration to create high-order pages.
 
 Current problem of the implementation is that it is designed to migrate only
-*LRU* pages. However, there are potential non-lru pages which can be migrated
+*LRU* pages. However, there are potential non-LRU pages which can be migrated
 in drivers, for example, zsmalloc, virtio-balloon pages.
 
 For virtio-balloon pages, some parts of migration code path have been hooked
 up and added virtio-balloon specific functions to intercept migration logics.
 It's too specific to a driver so other drivers who want to make their pages
-movable would have to add own specific hooks in migration path.
+movable would have to add their own specific hooks in the migration path.
 
-To overclome the problem, VM supports non-LRU page migration which provides
+To overcome the problem, VM supports non-LRU page migration which provides
 generic functions for non-LRU movable pages without driver specific hooks
-migration path.
+in the migration path.
 
-If a driver want to make own pages movable, it should define three functions
+If a driver wants to make its pages movable, it should define three functions
 which are function pointers of struct address_space_operations.
 
 1. ``bool (*isolate_page) (struct page *page, isolate_mode_t mode);``
 
-   What VM expects on isolate_page function of driver is to return *true*
-   if driver isolates page successfully. On returing true, VM marks the page
+   What VM expects from isolate_page() function of driver is to return *true*
+   if driver isolates the page successfully. On returning true, VM marks the page
    as PG_isolated so concurrent isolation in several CPUs skip the page
    for isolation. If a driver cannot isolate the page, it should return *false*.
 
    Once page is successfully isolated, VM uses page.lru fields so driver
-   shouldn't expect to preserve values in that fields.
+   shouldn't expect to preserve values in those fields.
 
 2. ``int (*migratepage) (struct address_space *mapping,``
 |      ``struct page *newpage, struct page *oldpage, enum migrate_mode);``
 
-   After isolation, VM calls migratepage of driver with isolated page.
-   The function of migratepage is to move content of the old page to new page
+   After isolation, VM calls migratepage() of driver with the isolated page.
+   The function of migratepage() is to move the contents of the old page to the
+   new page
    and set up fields of struct page newpage. Keep in mind that you should
    indicate to the VM the oldpage is no longer movable via __ClearPageMovable()
-   under page_lock if you migrated the oldpage successfully and returns
+   under page_lock if you migrated the oldpage successfully and returned
    MIGRATEPAGE_SUCCESS. If driver cannot migrate the page at the moment, driver
    can return -EAGAIN. On -EAGAIN, VM will retry page migration in a short time
-   because VM interprets -EAGAIN as "temporal migration failure". On returning
-   any error except -EAGAIN, VM will give up the page migration without retrying
-   in this time.
+   because VM interprets -EAGAIN as "temporary migration failure". On returning
+   any error except -EAGAIN, VM will give up the page migration without
+   retrying.
 
-   Driver shouldn't touch page.lru field VM using in the functions.
+   Driver shouldn't touch the page.lru field while in the migratepage() function.
 
 3. ``void (*putback_page)(struct page *);``
 
-   If migration fails on isolated page, VM should return the isolated page
-   to the driver so VM calls driver's putback_page with migration failed page.
-   In this function, driver should put the isolated page back to the own data
+   If migration fails on the isolated page, VM should return the isolated page
+   to the driver so VM calls the driver's putback_page() with the isolated page.
+   In this function, the driver should put the isolated page back into its own data
    structure.
 
-4. non-lru movable page flags
+4. non-LRU movable page flags
 
-   There are two page flags for supporting non-lru movable page.
+   There are two page flags for supporting non-LRU movable page.
 
    * PG_movable
 
-     Driver should use the below function to make page movable under page_lock::
+     Driver should use the function below to make page movable under page_lock::
 
        void __SetPageMovable(struct page *page, struct address_space *mapping)
 
      It needs argument of address_space for registering migration
      family functions which will be called by VM. Exactly speaking,
-     PG_movable is not a real flag of struct page. Rather than, VM
-     reuses page->mapping's lower bits to represent it.
+     PG_movable is not a real flag of struct page. Rather, VM
+     reuses the page->mapping's lower bits to represent it::
 
-::
        #define PAGE_MAPPING_MOVABLE 0x2
        page->mapping = page->mapping | PAGE_MAPPING_MOVABLE;
 
      so driver shouldn't access page->mapping directly. Instead, driver should
-     use page_mapping which mask off the low two bits of page->mapping under
-     page lock so it can get right struct address_space.
-
-     For testing of non-lru movable page, VM supports __PageMovable function.
-     However, it doesn't guarantee to identify non-lru movable page because
-     page->mapping field is unified with other variables in struct page.
-     As well, if driver releases the page after isolation by VM, page->mapping
-     doesn't have stable value although it has PAGE_MAPPING_MOVABLE
-     (Look at __ClearPageMovable). But __PageMovable is cheap to catch whether
-     page is LRU or non-lru movable once the page has been isolated. Because
-     LRU pages never can have PAGE_MAPPING_MOVABLE in page->mapping. It is also
-     good for just peeking to test non-lru movable pages before more expensive
-     checking with lock_page in pfn scanning to select victim.
-
-     For guaranteeing non-lru movable page, VM provides PageMovable function.
-     Unlike __PageMovable, PageMovable functions validates page->mapping and
-     mapping->a_ops->isolate_page under lock_page. The lock_page prevents sudden
-     destroying of page->mapping.
-
-     Driver using __SetPageMovable should clear the flag via __ClearMovablePage
-     under page_lock before the releasing the page.
+     use page_mapping() which masks off the low two bits of page->mapping under
+     page lock so it can get the right struct address_space.
+
+     For testing of non-LRU movable pages, VM supports __PageMovable() function.
+     However, it doesn't guarantee to identify non-LRU movable pages because
+     the page->mapping field is unified with other variables in struct page.
+     If the driver releases the page after isolation by VM, page->mapping
+     doesn't have a stable value although it has PAGE_MAPPING_MOVABLE set
+     (look at __ClearPageMovable). But __PageMovable() is cheap to call whether
+     page is LRU or non-LRU movable once the page has been isolated because LRU
+     pages can never have PAGE_MAPPING_MOVABLE set in page->mapping. It is also
+     good for just peeking to test non-LRU movable pages before more expensive
+     checking with lock_page() in pfn scanning to select a victim.
+
+     For guaranteeing non-LRU movable page, VM provides PageMovable() function.
+     Unlike __PageMovable(), PageMovable() validates page->mapping and
+     mapping->a_ops->isolate_page under lock_page(). The lock_page() prevents
+     sudden destroying of page->mapping.
+
+     Drivers using __SetPageMovable() should clear the flag via
+     __ClearMovablePage() under page_lock() before the releasing the page.
 
    * PG_isolated
 
      To prevent concurrent isolation among several CPUs, VM marks isolated page
-     as PG_isolated under lock_page. So if a CPU encounters PG_isolated non-lru
-     movable page, it can skip it. Driver doesn't need to manipulate the flag
-     because VM will set/clear it automatically. Keep in mind that if driver
-     sees PG_isolated page, it means the page have been isolated by VM so it
-     shouldn't touch page.lru field.
-     PG_isolated is alias with PG_reclaim flag so driver shouldn't use the flag
-     for own purpose.
+     as PG_isolated under lock_page(). So if a CPU encounters PG_isolated
+     non-LRU movable page, it can skip it. Driver doesn't need to manipulate the
+     flag because VM will set/clear it automatically. Keep in mind that if the
+     driver sees a PG_isolated page, it means the page has been isolated by the
+     VM so it shouldn't touch the page.lru field.
+     The PG_isolated flag is aliased with the PG_reclaim flag so drivers
+     shouldn't use PG_isolated for its own purposes.
 
 Monitoring Migration
 =====================
@@ -266,8 +270,8 @@ The following events (counters) can be used to monitor page migration.
    512.
 
 2. PGMIGRATE_FAIL: Normal page migration failure. Same counting rules as for
-   _SUCCESS, above: this will be increased by the number of subpages, if it was
-   a THP.
+   PGMIGRATE_SUCCESS, above: this will be increased by the number of subpages,
+   if it was a THP.
 
 3. THP_MIGRATION_SUCCESS: A THP was migrated without being split.
 
index 849fad6..54f13ad 100644 (file)
@@ -103,8 +103,10 @@ watch that specific key).
 
 To manage a watch list, the following functions are provided:
 
-  * ``void init_watch_list(struct watch_list *wlist,
-                          void (*release_watch)(struct watch *wlist));``
+  * ::
+
+       void init_watch_list(struct watch_list *wlist,
+                            void (*release_watch)(struct watch *wlist));
 
     Initialise a watch list.  If ``release_watch`` is not NULL, then this
     indicates a function that should be called when the watch_list object is
@@ -179,9 +181,11 @@ The following functions are provided to manage watches:
     driver-settable fields in the watch struct must have been set before this
     is called.
 
-  * ``int remove_watch_from_object(struct watch_list *wlist,
-                                  struct watch_queue *wqueue,
-                                  u64 id, false);``
+  * ::
+
+       int remove_watch_from_object(struct watch_list *wlist,
+                                    struct watch_queue *wqueue,
+                                    u64 id, false);
 
     Remove a watch from a watch list, where the watch must match the specified
     watch queue (``wqueue``) and object identifier (``id``).  A notification
index 7fafc7a..abb9fc1 100644 (file)
@@ -1342,8 +1342,8 @@ follow::
 
 In addition to read/modify/write the setup header of the struct
 boot_params as that of 16-bit boot protocol, the boot loader should
-also fill the additional fields of the struct boot_params as that
-described in zero-page.txt.
+also fill the additional fields of the struct boot_params as
+described in chapter :doc:`zero-page`.
 
 After setting up the struct boot_params, the boot loader can load the
 32/64-bit kernel in the same way as that of 16-bit boot protocol.
@@ -1379,7 +1379,7 @@ can be calculated as follows::
 In addition to read/modify/write the setup header of the struct
 boot_params as that of 16-bit boot protocol, the boot loader should
 also fill the additional fields of the struct boot_params as described
-in zero-page.txt.
+in chapter :doc:`zero-page`.
 
 After setting up the struct boot_params, the boot loader can load
 64-bit kernel in the same way as that of 16-bit boot protocol, but
diff --git a/Documentation/x86/cpuinfo.rst b/Documentation/x86/cpuinfo.rst
new file mode 100644 (file)
index 0000000..5d54c39
--- /dev/null
@@ -0,0 +1,155 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=================
+x86 Feature Flags
+=================
+
+Introduction
+============
+
+On x86, flags appearing in /proc/cpuinfo have an X86_FEATURE definition
+in arch/x86/include/asm/cpufeatures.h. If the kernel cares about a feature
+or KVM want to expose the feature to a KVM guest, it can and should have
+an X86_FEATURE_* defined. These flags represent hardware features as
+well as software features.
+
+If users want to know if a feature is available on a given system, they
+try to find the flag in /proc/cpuinfo. If a given flag is present, it
+means that the kernel supports it and is currently making it available.
+If such flag represents a hardware feature, it also means that the
+hardware supports it.
+
+If the expected flag does not appear in /proc/cpuinfo, things are murkier.
+Users need to find out the reason why the flag is missing and find the way
+how to enable it, which is not always easy. There are several factors that
+can explain missing flags: the expected feature failed to enable, the feature
+is missing in hardware, platform firmware did not enable it, the feature is
+disabled at build or run time, an old kernel is in use, or the kernel does
+not support the feature and thus has not enabled it. In general, /proc/cpuinfo
+shows features which the kernel supports. For a full list of CPUID flags
+which the CPU supports, use tools/arch/x86/kcpuid.
+
+How are feature flags created?
+==============================
+
+a: Feature flags can be derived from the contents of CPUID leaves.
+------------------------------------------------------------------
+These feature definitions are organized mirroring the layout of CPUID
+leaves and grouped in words with offsets as mapped in enum cpuid_leafs
+in cpufeatures.h (see arch/x86/include/asm/cpufeatures.h for details).
+If a feature is defined with a X86_FEATURE_<name> definition in
+cpufeatures.h, and if it is detected at run time, the flags will be
+displayed accordingly in /proc/cpuinfo. For example, the flag "avx2"
+comes from X86_FEATURE_AVX2 in cpufeatures.h.
+
+b: Flags can be from scattered CPUID-based features.
+----------------------------------------------------
+Hardware features enumerated in sparsely populated CPUID leaves get
+software-defined values. Still, CPUID needs to be queried to determine
+if a given feature is present. This is done in init_scattered_cpuid_features().
+For instance, X86_FEATURE_CQM_LLC is defined as 11*32 + 0 and its presence is
+checked at runtime in the respective CPUID leaf [EAX=f, ECX=0] bit EDX[1].
+
+The intent of scattering CPUID leaves is to not bloat struct
+cpuinfo_x86.x86_capability[] unnecessarily. For instance, the CPUID leaf
+[EAX=7, ECX=0] has 30 features and is dense, but the CPUID leaf [EAX=7, EAX=1]
+has only one feature and would waste 31 bits of space in the x86_capability[]
+array. Since there is a struct cpuinfo_x86 for each possible CPU, the wasted
+memory is not trivial.
+
+c: Flags can be created synthetically under certain conditions for hardware features.
+-------------------------------------------------------------------------------------
+Examples of conditions include whether certain features are present in
+MSR_IA32_CORE_CAPS or specific CPU models are identified. If the needed
+conditions are met, the features are enabled by the set_cpu_cap or
+setup_force_cpu_cap macros. For example, if bit 5 is set in MSR_IA32_CORE_CAPS,
+the feature X86_FEATURE_SPLIT_LOCK_DETECT will be enabled and
+"split_lock_detect" will be displayed. The flag "ring3mwait" will be
+displayed only when running on INTEL_FAM6_XEON_PHI_[KNL|KNM] processors.
+
+d: Flags can represent purely software features.
+------------------------------------------------
+These flags do not represent hardware features. Instead, they represent a
+software feature implemented in the kernel. For example, Kernel Page Table
+Isolation is purely software feature and its feature flag X86_FEATURE_PTI is
+also defined in cpufeatures.h.
+
+Naming of Flags
+===============
+
+The script arch/x86/kernel/cpu/mkcapflags.sh processes the
+#define X86_FEATURE_<name> from cpufeatures.h and generates the
+x86_cap/bug_flags[] arrays in kernel/cpu/capflags.c. The names in the
+resulting x86_cap/bug_flags[] are used to populate /proc/cpuinfo. The naming
+of flags in the x86_cap/bug_flags[] are as follows:
+
+a: The name of the flag is from the string in X86_FEATURE_<name> by default.
+----------------------------------------------------------------------------
+By default, the flag <name> in /proc/cpuinfo is extracted from the respective
+X86_FEATURE_<name> in cpufeatures.h. For example, the flag "avx2" is from
+X86_FEATURE_AVX2.
+
+b: The naming can be overridden.
+--------------------------------
+If the comment on the line for the #define X86_FEATURE_* starts with a
+double-quote character (""), the string inside the double-quote characters
+will be the name of the flags. For example, the flag "sse4_1" comes from
+the comment "sse4_1" following the X86_FEATURE_XMM4_1 definition.
+
+There are situations in which overriding the displayed name of the flag is
+needed. For instance, /proc/cpuinfo is a userspace interface and must remain
+constant. If, for some reason, the naming of X86_FEATURE_<name> changes, one
+shall override the new naming with the name already used in /proc/cpuinfo.
+
+c: The naming override can be "", which means it will not appear in /proc/cpuinfo.
+----------------------------------------------------------------------------------
+The feature shall be omitted from /proc/cpuinfo if it does not make sense for
+the feature to be exposed to userspace. For example, X86_FEATURE_ALWAYS is
+defined in cpufeatures.h but that flag is an internal kernel feature used
+in the alternative runtime patching functionality. So, its name is overridden
+with "". Its flag will not appear in /proc/cpuinfo.
+
+Flags are missing when one or more of these happen
+==================================================
+
+a: The hardware does not enumerate support for it.
+--------------------------------------------------
+For example, when a new kernel is running on old hardware or the feature is
+not enabled by boot firmware. Even if the hardware is new, there might be a
+problem enabling the feature at run time, the flag will not be displayed.
+
+b: The kernel does not know about the flag.
+-------------------------------------------
+For example, when an old kernel is running on new hardware.
+
+c: The kernel disabled support for it at compile-time.
+------------------------------------------------------
+For example, if 5-level-paging is not enabled when building (i.e.,
+CONFIG_X86_5LEVEL is not selected) the flag "la57" will not show up [#f1]_.
+Even though the feature will still be detected via CPUID, the kernel disables
+it by clearing via setup_clear_cpu_cap(X86_FEATURE_LA57).
+
+d: The feature is disabled at boot-time.
+----------------------------------------
+A feature can be disabled either using a command-line parameter or because
+it failed to be enabled. The command-line parameter clearcpuid= can be used
+to disable features using the feature number as defined in
+/arch/x86/include/asm/cpufeatures.h. For instance, User Mode Instruction
+Protection can be disabled using clearcpuid=514. The number 514 is calculated
+from #define X86_FEATURE_UMIP (16*32 + 2).
+
+In addition, there exists a variety of custom command-line parameters that
+disable specific features. The list of parameters includes, but is not limited
+to, nofsgsbase, nosmap, and nosmep. 5-level paging can also be disabled using
+"no5lvl". SMAP and SMEP are disabled with the aforementioned parameters,
+respectively.
+
+e: The feature was known to be non-functional.
+----------------------------------------------
+The feature was known to be non-functional because a dependency was
+missing at runtime. For example, AVX flags will not show up if XSAVE feature
+is disabled since they depend on XSAVE feature. Another example would be broken
+CPUs and them missing microcode patches. Due to that, the kernel decides not to
+enable a feature.
+
+.. [#f1] 5-level paging uses linear address of 57 bits.
index 265d9e9..740ee7f 100644 (file)
@@ -9,6 +9,7 @@ x86-specific Documentation
    :numbered:
 
    boot
+   cpuinfo
    topology
    exception-tables
    kernel-stacks
@@ -30,3 +31,4 @@ x86-specific Documentation
    usb-legacy-support
    i386/index
    x86_64/index
+   sva
index 5368ced..e59b7b9 100644 (file)
@@ -138,6 +138,18 @@ with respect to allocation:
                non-linear. This field is purely informational
                only.
 
+"thread_throttle_mode":
+               Indicator on Intel systems of how tasks running on threads
+               of a physical core are throttled in cases where they
+               request different memory bandwidth percentages:
+
+               "max":
+                       the smallest percentage is applied
+                       to all threads
+               "per-thread":
+                       bandwidth percentages are directly applied to
+                       the threads running on the core
+
 If RDT monitoring is available there will be an "L3_MON" directory
 with the following files:
 
@@ -364,8 +376,10 @@ to the next control step available on the hardware.
 
 The bandwidth throttling is a core specific mechanism on some of Intel
 SKUs. Using a high bandwidth and a low bandwidth setting on two threads
-sharing a core will result in both threads being throttled to use the
-low bandwidth. The fact that Memory bandwidth allocation(MBA) is a core
+sharing a core may result in both threads being throttled to use the
+low bandwidth (see "thread_throttle_mode").
+
+The fact that Memory bandwidth allocation(MBA) may be a core
 specific mechanism where as memory bandwidth monitoring(MBM) is done at
 the package level may lead to confusion when users try to apply control
 via the MBA and then monitor the bandwidth to see if the controls are
diff --git a/Documentation/x86/sva.rst b/Documentation/x86/sva.rst
new file mode 100644 (file)
index 0000000..076efd5
--- /dev/null
@@ -0,0 +1,257 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================================
+Shared Virtual Addressing (SVA) with ENQCMD
+===========================================
+
+Background
+==========
+
+Shared Virtual Addressing (SVA) allows the processor and device to use the
+same virtual addresses avoiding the need for software to translate virtual
+addresses to physical addresses. SVA is what PCIe calls Shared Virtual
+Memory (SVM).
+
+In addition to the convenience of using application virtual addresses
+by the device, it also doesn't require pinning pages for DMA.
+PCIe Address Translation Services (ATS) along with Page Request Interface
+(PRI) allow devices to function much the same way as the CPU handling
+application page-faults. For more information please refer to the PCIe
+specification Chapter 10: ATS Specification.
+
+Use of SVA requires IOMMU support in the platform. IOMMU is also
+required to support the PCIe features ATS and PRI. ATS allows devices
+to cache translations for virtual addresses. The IOMMU driver uses the
+mmu_notifier() support to keep the device TLB cache and the CPU cache in
+sync. When an ATS lookup fails for a virtual address, the device should
+use the PRI in order to request the virtual address to be paged into the
+CPU page tables. The device must use ATS again in order the fetch the
+translation before use.
+
+Shared Hardware Workqueues
+==========================
+
+Unlike Single Root I/O Virtualization (SR-IOV), Scalable IOV (SIOV) permits
+the use of Shared Work Queues (SWQ) by both applications and Virtual
+Machines (VM's). This allows better hardware utilization vs. hard
+partitioning resources that could result in under utilization. In order to
+allow the hardware to distinguish the context for which work is being
+executed in the hardware by SWQ interface, SIOV uses Process Address Space
+ID (PASID), which is a 20-bit number defined by the PCIe SIG.
+
+PASID value is encoded in all transactions from the device. This allows the
+IOMMU to track I/O on a per-PASID granularity in addition to using the PCIe
+Resource Identifier (RID) which is the Bus/Device/Function.
+
+
+ENQCMD
+======
+
+ENQCMD is a new instruction on Intel platforms that atomically submits a
+work descriptor to a device. The descriptor includes the operation to be
+performed, virtual addresses of all parameters, virtual address of a completion
+record, and the PASID (process address space ID) of the current process.
+
+ENQCMD works with non-posted semantics and carries a status back if the
+command was accepted by hardware. This allows the submitter to know if the
+submission needs to be retried or other device specific mechanisms to
+implement fairness or ensure forward progress should be provided.
+
+ENQCMD is the glue that ensures applications can directly submit commands
+to the hardware and also permits hardware to be aware of application context
+to perform I/O operations via use of PASID.
+
+Process Address Space Tagging
+=============================
+
+A new thread-scoped MSR (IA32_PASID) provides the connection between
+user processes and the rest of the hardware. When an application first
+accesses an SVA-capable device, this MSR is initialized with a newly
+allocated PASID. The driver for the device calls an IOMMU-specific API
+that sets up the routing for DMA and page-requests.
+
+For example, the Intel Data Streaming Accelerator (DSA) uses
+iommu_sva_bind_device(), which will do the following:
+
+- Allocate the PASID, and program the process page-table (%cr3 register) in the
+  PASID context entries.
+- Register for mmu_notifier() to track any page-table invalidations to keep
+  the device TLB in sync. For example, when a page-table entry is invalidated,
+  the IOMMU propagates the invalidation to the device TLB. This will force any
+  future access by the device to this virtual address to participate in
+  ATS. If the IOMMU responds with proper response that a page is not
+  present, the device would request the page to be paged in via the PCIe PRI
+  protocol before performing I/O.
+
+This MSR is managed with the XSAVE feature set as "supervisor state" to
+ensure the MSR is updated during context switch.
+
+PASID Management
+================
+
+The kernel must allocate a PASID on behalf of each process which will use
+ENQCMD and program it into the new MSR to communicate the process identity to
+platform hardware.  ENQCMD uses the PASID stored in this MSR to tag requests
+from this process.  When a user submits a work descriptor to a device using the
+ENQCMD instruction, the PASID field in the descriptor is auto-filled with the
+value from MSR_IA32_PASID. Requests for DMA from the device are also tagged
+with the same PASID. The platform IOMMU uses the PASID in the transaction to
+perform address translation. The IOMMU APIs setup the corresponding PASID
+entry in IOMMU with the process address used by the CPU (e.g. %cr3 register in
+x86).
+
+The MSR must be configured on each logical CPU before any application
+thread can interact with a device. Threads that belong to the same
+process share the same page tables, thus the same MSR value.
+
+PASID is cleared when a process is created. The PASID allocation and MSR
+programming may occur long after a process and its threads have been created.
+One thread must call iommu_sva_bind_device() to allocate the PASID for the
+process. If a thread uses ENQCMD without the MSR first being populated, a #GP
+will be raised. The kernel will update the PASID MSR with the PASID for all
+threads in the process. A single process PASID can be used simultaneously
+with multiple devices since they all share the same address space.
+
+One thread can call iommu_sva_unbind_device() to free the allocated PASID.
+The kernel will clear the PASID MSR for all threads belonging to the process.
+
+New threads inherit the MSR value from the parent.
+
+Relationships
+=============
+
+ * Each process has many threads, but only one PASID.
+ * Devices have a limited number (~10's to 1000's) of hardware workqueues.
+   The device driver manages allocating hardware workqueues.
+ * A single mmap() maps a single hardware workqueue as a "portal" and
+   each portal maps down to a single workqueue.
+ * For each device with which a process interacts, there must be
+   one or more mmap()'d portals.
+ * Many threads within a process can share a single portal to access
+   a single device.
+ * Multiple processes can separately mmap() the same portal, in
+   which case they still share one device hardware workqueue.
+ * The single process-wide PASID is used by all threads to interact
+   with all devices.  There is not, for instance, a PASID for each
+   thread or each thread<->device pair.
+
+FAQ
+===
+
+* What is SVA/SVM?
+
+Shared Virtual Addressing (SVA) permits I/O hardware and the processor to
+work in the same address space, i.e., to share it. Some call it Shared
+Virtual Memory (SVM), but Linux community wanted to avoid confusing it with
+POSIX Shared Memory and Secure Virtual Machines which were terms already in
+circulation.
+
+* What is a PASID?
+
+A Process Address Space ID (PASID) is a PCIe-defined Transaction Layer Packet
+(TLP) prefix. A PASID is a 20-bit number allocated and managed by the OS.
+PASID is included in all transactions between the platform and the device.
+
+* How are shared workqueues different?
+
+Traditionally, in order for userspace applications to interact with hardware,
+there is a separate hardware instance required per process. For example,
+consider doorbells as a mechanism of informing hardware about work to process.
+Each doorbell is required to be spaced 4k (or page-size) apart for process
+isolation. This requires hardware to provision that space and reserve it in
+MMIO. This doesn't scale as the number of threads becomes quite large. The
+hardware also manages the queue depth for Shared Work Queues (SWQ), and
+consumers don't need to track queue depth. If there is no space to accept
+a command, the device will return an error indicating retry.
+
+A user should check Deferrable Memory Write (DMWr) capability on the device
+and only submits ENQCMD when the device supports it. In the new DMWr PCIe
+terminology, devices need to support DMWr completer capability. In addition,
+it requires all switch ports to support DMWr routing and must be enabled by
+the PCIe subsystem, much like how PCIe atomic operations are managed for
+instance.
+
+SWQ allows hardware to provision just a single address in the device. When
+used with ENQCMD to submit work, the device can distinguish the process
+submitting the work since it will include the PASID assigned to that
+process. This helps the device scale to a large number of processes.
+
+* Is this the same as a user space device driver?
+
+Communicating with the device via the shared workqueue is much simpler
+than a full blown user space driver. The kernel driver does all the
+initialization of the hardware. User space only needs to worry about
+submitting work and processing completions.
+
+* Is this the same as SR-IOV?
+
+Single Root I/O Virtualization (SR-IOV) focuses on providing independent
+hardware interfaces for virtualizing hardware. Hence, it's required to be
+almost fully functional interface to software supporting the traditional
+BARs, space for interrupts via MSI-X, its own register layout.
+Virtual Functions (VFs) are assisted by the Physical Function (PF)
+driver.
+
+Scalable I/O Virtualization builds on the PASID concept to create device
+instances for virtualization. SIOV requires host software to assist in
+creating virtual devices; each virtual device is represented by a PASID
+along with the bus/device/function of the device.  This allows device
+hardware to optimize device resource creation and can grow dynamically on
+demand. SR-IOV creation and management is very static in nature. Consult
+references below for more details.
+
+* Why not just create a virtual function for each app?
+
+Creating PCIe SR-IOV type Virtual Functions (VF) is expensive. VFs require
+duplicated hardware for PCI config space and interrupts such as MSI-X.
+Resources such as interrupts have to be hard partitioned between VFs at
+creation time, and cannot scale dynamically on demand. The VFs are not
+completely independent from the Physical Function (PF). Most VFs require
+some communication and assistance from the PF driver. SIOV, in contrast,
+creates a software-defined device where all the configuration and control
+aspects are mediated via the slow path. The work submission and completion
+happen without any mediation.
+
+* Does this support virtualization?
+
+ENQCMD can be used from within a guest VM. In these cases, the VMM helps
+with setting up a translation table to translate from Guest PASID to Host
+PASID. Please consult the ENQCMD instruction set reference for more
+details.
+
+* Does memory need to be pinned?
+
+When devices support SVA along with platform hardware such as IOMMU
+supporting such devices, there is no need to pin memory for DMA purposes.
+Devices that support SVA also support other PCIe features that remove the
+pinning requirement for memory.
+
+Device TLB support - Device requests the IOMMU to lookup an address before
+use via Address Translation Service (ATS) requests.  If the mapping exists
+but there is no page allocated by the OS, IOMMU hardware returns that no
+mapping exists.
+
+Device requests the virtual address to be mapped via Page Request
+Interface (PRI). Once the OS has successfully completed the mapping, it
+returns the response back to the device. The device requests again for
+a translation and continues.
+
+IOMMU works with the OS in managing consistency of page-tables with the
+device. When removing pages, it interacts with the device to remove any
+device TLB entry that might have been cached before removing the mappings from
+the OS.
+
+References
+==========
+
+VT-D:
+https://01.org/blogs/ashokraj/2018/recent-enhancements-intel-virtualization-technology-directed-i/o-intel-vt-d
+
+SIOV:
+https://01.org/blogs/2019/assignable-interfaces-intel-scalable-i/o-virtualization-linux
+
+ENQCMD in ISE:
+https://software.intel.com/sites/default/files/managed/c5/15/architecture-instruction-set-extensions-programming-reference.pdf
+
+DSA spec:
+https://software.intel.com/sites/default/files/341204-intel-data-streaming-accelerator-spec.pdf
index f0068bc..b81a3ed 100644 (file)
@@ -802,6 +802,13 @@ S: Maintained
 F:     Documentation/devicetree/bindings/interrupt-controller/amazon,al-fic.txt
 F:     drivers/irqchip/irq-al-fic.c
 
+AMAZON ANNAPURNA LABS MEMORY CONTROLLER EDAC
+M:     Talel Shenhar <talel@amazon.com>
+M:     Talel Shenhar <talelshenhar@gmail.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/edac/amazon,al-mc-edac.yaml
+F:     drivers/edac/al_mc_edac.c
+
 AMAZON ANNAPURNA LABS THERMAL MMIO DRIVER
 M:     Talel Shenhar <talel@amazon.com>
 S:     Maintained
@@ -1460,6 +1467,11 @@ S:       Odd Fixes
 F:     drivers/amba/
 F:     include/linux/amba/bus.h
 
+ARM PRIMECELL CLCD PL110 DRIVER
+M:     Russell King <linux@armlinux.org.uk>
+S:     Odd Fixes
+F:     drivers/video/fbdev/amba-clcd.*
+
 ARM PRIMECELL KMI PL050 DRIVER
 M:     Russell King <linux@armlinux.org.uk>
 S:     Odd Fixes
@@ -1525,6 +1537,7 @@ F:        Documentation/devicetree/bindings/arm/actions.yaml
 F:     Documentation/devicetree/bindings/clock/actions,owl-cmu.txt
 F:     Documentation/devicetree/bindings/dma/owl-dma.txt
 F:     Documentation/devicetree/bindings/i2c/i2c-owl.txt
+F:     Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml
 F:     Documentation/devicetree/bindings/mmc/owl-mmc.yaml
 F:     Documentation/devicetree/bindings/pinctrl/actions,s900-pinctrl.txt
 F:     Documentation/devicetree/bindings/power/actions,owl-sps.txt
@@ -1536,6 +1549,7 @@ F:        drivers/clk/actions/
 F:     drivers/clocksource/timer-owl*
 F:     drivers/dma/owl-dma.c
 F:     drivers/i2c/busses/i2c-owl.c
+F:     drivers/irqchip/irq-owl-sirq.c
 F:     drivers/mmc/host/owl-mmc.c
 F:     drivers/pinctrl/actions/*
 F:     drivers/soc/actions/
@@ -1623,7 +1637,7 @@ N:        meson
 
 ARM/Annapurna Labs ALPINE ARCHITECTURE
 M:     Tsahee Zidenberg <tsahee@annapurnalabs.com>
-M:     Antoine Tenart <antoine.tenart@bootlin.com>
+M:     Antoine Tenart <atenart@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/boot/dts/alpine*
@@ -1694,7 +1708,6 @@ F:        arch/arm/mach-cns3xxx/
 
 ARM/CAVIUM THUNDER NETWORK DRIVER
 M:     Sunil Goutham <sgoutham@marvell.com>
-M:     Robert Richter <rrichter@marvell.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
 F:     drivers/net/ethernet/cavium/thunder/
@@ -2505,7 +2518,7 @@ S:        Maintained
 F:     drivers/clk/socfpga/
 
 ARM/SOCFPGA EDAC SUPPORT
-M:     Thor Thayer <thor.thayer@linux.intel.com>
+M:     Dinh Nguyen <dinguyen@kernel.org>
 S:     Maintained
 F:     drivers/edac/altera_edac.
 
@@ -3205,6 +3218,7 @@ S:        Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 F:     block/
 F:     drivers/block/
+F:     include/linux/blk*
 F:     kernel/trace/blktrace.c
 F:     lib/sbitmap.c
 
@@ -3388,6 +3402,7 @@ M:        Florian Fainelli <f.fainelli@gmail.com>
 L:     netdev@vger.kernel.org
 L:     openwrt-devel@lists.openwrt.org (subscribers-only)
 S:     Supported
+F:     Documentation/devicetree/bindings/net/dsa/b53.txt
 F:     drivers/net/dsa/b53/*
 F:     include/linux/platform_data/b53.h
 
@@ -3573,13 +3588,28 @@ L:      bcm-kernel-feedback-list@broadcom.com
 S:     Maintained
 F:     drivers/phy/broadcom/phy-brcm-usb*
 
+BROADCOM ETHERNET PHY DRIVERS
+M:     Florian Fainelli <f.fainelli@gmail.com>
+L:     bcm-kernel-feedback-list@broadcom.com
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     Documentation/devicetree/bindings/net/broadcom-bcm87xx.txt
+F:     drivers/net/phy/bcm*.[ch]
+F:     drivers/net/phy/broadcom.c
+F:     include/linux/brcmphy.h
+
 BROADCOM GENET ETHERNET DRIVER
 M:     Doug Berger <opendmb@gmail.com>
 M:     Florian Fainelli <f.fainelli@gmail.com>
 L:     bcm-kernel-feedback-list@broadcom.com
 L:     netdev@vger.kernel.org
 S:     Supported
+F:     Documentation/devicetree/bindings/net/brcm,bcmgenet.txt
+F:     Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt
 F:     drivers/net/ethernet/broadcom/genet/
+F:     drivers/net/mdio/mdio-bcm-unimac.c
+F:     include/linux/platform_data/bcmgenet.h
+F:     include/linux/platform_data/mdio-bcm-unimac.h
 
 BROADCOM IPROC ARM ARCHITECTURE
 M:     Ray Jui <rjui@broadcom.com>
@@ -3931,8 +3961,8 @@ W:        https://wireless.wiki.kernel.org/en/users/Drivers/carl9170
 F:     drivers/net/wireless/ath/carl9170/
 
 CAVIUM I2C DRIVER
-M:     Robert Richter <rrichter@marvell.com>
-S:     Supported
+M:     Robert Richter <rric@kernel.org>
+S:     Odd Fixes
 W:     http://www.marvell.com
 F:     drivers/i2c/busses/i2c-octeon*
 F:     drivers/i2c/busses/i2c-thunderx*
@@ -3947,8 +3977,8 @@ W:        http://www.marvell.com
 F:     drivers/net/ethernet/cavium/liquidio/
 
 CAVIUM MMC DRIVER
-M:     Robert Richter <rrichter@marvell.com>
-S:     Supported
+M:     Robert Richter <rric@kernel.org>
+S:     Odd Fixes
 W:     http://www.marvell.com
 F:     drivers/mmc/host/cavium*
 
@@ -3960,9 +3990,9 @@ W:        http://www.marvell.com
 F:     drivers/crypto/cavium/cpt/
 
 CAVIUM THUNDERX2 ARM64 SOC
-M:     Robert Richter <rrichter@marvell.com>
+M:     Robert Richter <rric@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
+S:     Odd Fixes
 F:     Documentation/devicetree/bindings/arm/cavium-thunder2.txt
 F:     arch/arm64/boot/dts/cavium/thunder2-99xx*
 
@@ -4241,6 +4271,8 @@ S:        Maintained
 F:     .clang-format
 
 CLANG/LLVM BUILD SUPPORT
+M:     Nathan Chancellor <natechancellor@gmail.com>
+M:     Nick Desaulniers <ndesaulniers@google.com>
 L:     clang-built-linux@googlegroups.com
 S:     Supported
 W:     https://clangbuiltlinux.github.io/
@@ -4390,12 +4422,6 @@ T:       git git://git.infradead.org/users/hch/configfs.git
 F:     fs/configfs/
 F:     include/linux/configfs.h
 
-CONNECTOR
-M:     Evgeniy Polyakov <zbr@ioremap.net>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/connector/
-
 CONSOLE SUBSYSTEM
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 S:     Supported
@@ -5239,6 +5265,7 @@ DOCUMENTATION
 M:     Jonathan Corbet <corbet@lwn.net>
 L:     linux-doc@vger.kernel.org
 S:     Maintained
+P:     Documentation/doc-guide/maintainer-profile.rst
 T:     git git://git.lwn.net/linux.git docs-next
 F:     Documentation/
 F:     scripts/documentation-file-ref-check
@@ -6161,28 +6188,27 @@ F:      Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt
 F:     drivers/edac/aspeed_edac.c
 
 EDAC-BLUEFIELD
-M:     Shravan Kumar Ramani <sramani@nvidia.com>
+M:     Shravan Kumar Ramani <shravankr@nvidia.com>
 S:     Supported
 F:     drivers/edac/bluefield_edac.c
 
 EDAC-CALXEDA
-M:     Robert Richter <rric@kernel.org>
+M:     Andre Przywara <andre.przywara@arm.com>
 L:     linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/highbank*
 
 EDAC-CAVIUM OCTEON
 M:     Ralf Baechle <ralf@linux-mips.org>
-M:     Robert Richter <rrichter@marvell.com>
 L:     linux-edac@vger.kernel.org
 L:     linux-mips@vger.kernel.org
 S:     Supported
 F:     drivers/edac/octeon_edac*
 
 EDAC-CAVIUM THUNDERX
-M:     Robert Richter <rrichter@marvell.com>
+M:     Robert Richter <rric@kernel.org>
 L:     linux-edac@vger.kernel.org
-S:     Supported
+S:     Odd Fixes
 F:     drivers/edac/thunderx_edac*
 
 EDAC-CORE
@@ -6190,7 +6216,7 @@ M:        Borislav Petkov <bp@alien8.de>
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 M:     Tony Luck <tony.luck@intel.com>
 R:     James Morse <james.morse@arm.com>
-R:     Robert Richter <rrichter@marvell.com>
+R:     Robert Richter <rric@kernel.org>
 L:     linux-edac@vger.kernel.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git edac-for-next
@@ -6494,7 +6520,6 @@ F:        net/bridge/
 
 ETHERNET PHY LIBRARY
 M:     Andrew Lunn <andrew@lunn.ch>
-M:     Florian Fainelli <f.fainelli@gmail.com>
 M:     Heiner Kallweit <hkallweit1@gmail.com>
 R:     Russell King <linux@armlinux.org.uk>
 L:     netdev@vger.kernel.org
@@ -6884,6 +6909,14 @@ L:       linuxppc-dev@lists.ozlabs.org
 S:     Maintained
 F:     drivers/dma/fsldma.*
 
+FREESCALE DSPI DRIVER
+M:     Vladimir Oltean <olteanv@gmail.com>
+L:     linux-spi@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
+F:     drivers/spi/spi-fsl-dspi.c
+F:     include/linux/spi/spi-fsl-dspi.h
+
 FREESCALE ENETC ETHERNET DRIVERS
 M:     Claudiu Manoil <claudiu.manoil@nxp.com>
 L:     netdev@vger.kernel.org
@@ -7216,7 +7249,7 @@ F:        drivers/staging/gasket/
 GCC PLUGINS
 M:     Kees Cook <keescook@chromium.org>
 R:     Emese Revfy <re.emese@gmail.com>
-L:     kernel-hardening@lists.openwall.com
+L:     linux-hardening@vger.kernel.org
 S:     Maintained
 F:     Documentation/kbuild/gcc-plugins.rst
 F:     scripts/Makefile.gcc-plugins
@@ -8255,7 +8288,7 @@ IA64 (Itanium) PLATFORM
 M:     Tony Luck <tony.luck@intel.com>
 M:     Fenghua Yu <fenghua.yu@intel.com>
 L:     linux-ia64@vger.kernel.org
-S:     Maintained
+S:     Odd Fixes
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git
 F:     Documentation/ia64/
 F:     arch/ia64/
@@ -8304,8 +8337,9 @@ S:        Supported
 F:     drivers/pci/hotplug/rpaphp*
 
 IBM Power SRIOV Virtual NIC Device Driver
-M:     Thomas Falcon <tlfalcon@linux.ibm.com>
-M:     John Allen <jallen@linux.ibm.com>
+M:     Dany Madden <drt@linux.ibm.com>
+M:     Lijun Pan <ljp@linux.ibm.com>
+M:     Sukadev Bhattiprolu <sukadev@linux.ibm.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/ibm/ibmvnic.*
@@ -8319,7 +8353,7 @@ F:        arch/powerpc/platforms/powernv/copy-paste.h
 F:     arch/powerpc/platforms/powernv/vas*
 
 IBM Power Virtual Ethernet Device Driver
-M:     Thomas Falcon <tlfalcon@linux.ibm.com>
+M:     Cristobal Forno <cforno12@linux.ibm.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/ibm/ibmveth.*
@@ -8653,7 +8687,7 @@ F:        drivers/input/input-mt.c
 K:     \b(ABS|SYN)_MT_
 
 INSIDE SECURE CRYPTO DRIVER
-M:     Antoine Tenart <antoine.tenart@bootlin.com>
+M:     Antoine Tenart <atenart@kernel.org>
 L:     linux-crypto@vger.kernel.org
 S:     Maintained
 F:     drivers/crypto/inside-secure/
@@ -8732,7 +8766,8 @@ F:        include/drm/i915*
 F:     include/uapi/drm/i915_drm.h
 
 INTEL ETHERNET DRIVERS
-M:     Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+M:     Jesse Brandeburg <jesse.brandeburg@intel.com>
+M:     Tony Nguyen <anthony.l.nguyen@intel.com>
 L:     intel-wired-lan@lists.osuosl.org (moderated for non-subscribers)
 S:     Supported
 W:     http://www.intel.com/support/feedback.htm
@@ -9226,7 +9261,7 @@ F:        drivers/firmware/iscsi_ibft*
 
 ISCSI EXTENSIONS FOR RDMA (ISER) INITIATOR
 M:     Sagi Grimberg <sagi@grimberg.me>
-M:     Max Gurtovoy <maxg@nvidia.com>
+M:     Max Gurtovoy <mgurtovoy@nvidia.com>
 L:     linux-rdma@vger.kernel.org
 S:     Supported
 W:     http://www.openfabrics.org
@@ -9775,8 +9810,8 @@ F:        drivers/scsi/53c700*
 
 LEAKING_ADDRESSES
 M:     Tobin C. Harding <me@tobin.cc>
-M:     Tycho Andersen <tycho@tycho.ws>
-L:     kernel-hardening@lists.openwall.com
+M:     Tycho Andersen <tycho@tycho.pizza>
+L:     linux-hardening@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tobin/leaks.git
 F:     scripts/leaking_addresses.pl
@@ -11017,6 +11052,7 @@ F:      drivers/char/hw_random/mtk-rng.c
 
 MEDIATEK SWITCH DRIVER
 M:     Sean Wang <sean.wang@mediatek.com>
+M:     Landen Chao <Landen.Chao@mediatek.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/dsa/mt7530.*
@@ -11754,6 +11790,13 @@ Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
 F:     drivers/media/usb/msi2500/
 
+MSTAR INTERRUPT CONTROLLER DRIVER
+M:     Mark-PK Tsai <mark-pk.tsai@mediatek.com>
+M:     Daniel Palmer <daniel@thingy.jp>
+S:     Maintained
+F:     Documentation/devicetree/bindings/interrupt-controller/mstar,mst-intc.yaml
+F:     drivers/irqchip/irq-mst-intc.c
+
 MSYSTEMS DISKONCHIP G3 MTD DRIVER
 M:     Robert Jarzmik <robert.jarzmik@free.fr>
 L:     linux-mtd@lists.infradead.org
@@ -12030,6 +12073,7 @@ Q:      http://patchwork.ozlabs.org/project/netdev/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
 F:     Documentation/devicetree/bindings/net/
+F:     drivers/connector/
 F:     drivers/net/
 F:     include/linux/etherdevice.h
 F:     include/linux/fcdevice.h
@@ -12055,6 +12099,7 @@ NETWORKING [DSA]
 M:     Andrew Lunn <andrew@lunn.ch>
 M:     Vivien Didelot <vivien.didelot@gmail.com>
 M:     Florian Fainelli <f.fainelli@gmail.com>
+M:     Vladimir Oltean <olteanv@gmail.com>
 S:     Maintained
 F:     Documentation/devicetree/bindings/net/dsa/
 F:     drivers/net/dsa/
@@ -13023,7 +13068,9 @@ F:      lib/packing.c
 
 PADATA PARALLEL EXECUTION MECHANISM
 M:     Steffen Klassert <steffen.klassert@secunet.com>
+M:     Daniel Jordan <daniel.m.jordan@oracle.com>
 L:     linux-crypto@vger.kernel.org
+L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/core-api/padata.rst
 F:     include/linux/padata.h
@@ -13160,6 +13207,7 @@ F:      drivers/firmware/pcdp.*
 
 PCI DRIVER FOR AARDVARK (Marvell Armada 3700)
 M:     Thomas Petazzoni <thomas.petazzoni@bootlin.com>
+M:     Pali Rohár <pali@kernel.org>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
@@ -13429,10 +13477,10 @@ F:    Documentation/devicetree/bindings/pci/axis,artpec*
 F:     drivers/pci/controller/dwc/*artpec*
 
 PCIE DRIVER FOR CAVIUM THUNDERX
-M:     Robert Richter <rrichter@marvell.com>
+M:     Robert Richter <rric@kernel.org>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Supported
+S:     Odd Fixes
 F:     drivers/pci/controller/pci-thunder-*
 
 PCIE DRIVER FOR HISILICON
@@ -13569,12 +13617,18 @@ F:    kernel/events/*
 F:     tools/lib/perf/
 F:     tools/perf/
 
-PERFORMANCE EVENTS SUBSYSTEM ARM64 PMU EVENTS
+PERFORMANCE EVENTS TOOLING ARM64
 R:     John Garry <john.garry@huawei.com>
 R:     Will Deacon <will@kernel.org>
+R:     Mathieu Poirier <mathieu.poirier@linaro.org>
+R:     Leo Yan <leo.yan@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
+F:     tools/build/feature/test-libopencsd.c
+F:     tools/perf/arch/arm*/
 F:     tools/perf/pmu-events/arch/arm64/
+F:     tools/perf/util/arm-spe*
+F:     tools/perf/util/cs-etm*
 
 PERSONALITY HANDLING
 M:     Christoph Hellwig <hch@infradead.org>
@@ -14207,7 +14261,7 @@ QLOGIC QLA3XXX NETWORK DRIVER
 M:     GR-Linux-NIC-Dev@marvell.com
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     Documentation/networking/device_drivers/ethernet/qlogic/LICENSE.qla3xxx
+F:     Documentation/networking/device_drivers/qlogic/LICENSE.qla3xxx
 F:     drivers/net/ethernet/qlogic/qla3xxx.*
 
 QLOGIC QLA4XXX iSCSI DRIVER
@@ -14365,7 +14419,7 @@ M:      Rob Clark <robdclark@gmail.com>
 L:     iommu@lists.linux-foundation.org
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
-F:     drivers/iommu/qcom_iommu.c
+F:     drivers/iommu/arm/arm-smmu/qcom_iommu.c
 
 QUALCOMM IPCC MAILBOX DRIVER
 M:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
@@ -15355,6 +15409,7 @@ R:      Dietmar Eggemann <dietmar.eggemann@arm.com> (SCHED_NORMAL)
 R:     Steven Rostedt <rostedt@goodmis.org> (SCHED_FIFO/SCHED_RR)
 R:     Ben Segall <bsegall@google.com> (CONFIG_CFS_BANDWIDTH)
 R:     Mel Gorman <mgorman@suse.de> (CONFIG_NUMA_BALANCING)
+R:     Daniel Bristot de Oliveira <bristot@redhat.com> (SCHED_DEADLINE)
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core
@@ -15546,6 +15601,7 @@ F:      include/uapi/linux/sed*
 SECURITY CONTACT
 M:     Security Officers <security@kernel.org>
 S:     Supported
+F:     Documentation/admin-guide/security-bugs.rst
 
 SECURITY SUBSYSTEM
 M:     James Morris <jmorris@namei.org>
@@ -16125,7 +16181,7 @@ M:      Leon Luo <leonl@leopardimaging.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
 T:     git git://linuxtv.org/media_tree.git
-F:     Documentation/devicetree/bindings/media/i2c/imx274.txt
+F:     Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml
 F:     drivers/media/i2c/imx274.c
 
 SONY IMX290 SENSOR DRIVER
@@ -16695,6 +16751,13 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
 F:     drivers/gpio/gpio-dwapb.c
 
+SYNOPSYS DESIGNWARE APB SSI DRIVER
+M:     Serge Semin <fancer.lancer@gmail.com>
+L:     linux-spi@vger.kernel.org
+S:     Supported
+F:     Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
+F:     drivers/spi/spi-dw*
+
 SYNOPSYS DESIGNWARE AXI DMAC DRIVER
 M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
 S:     Maintained
@@ -17116,8 +17179,8 @@ S:      Maintained
 F:     Documentation/devicetree/bindings/arm/keystone/ti,k3-sci-common.yaml
 F:     Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
 F:     Documentation/devicetree/bindings/clock/ti,sci-clk.txt
-F:     Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
-F:     Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
+F:     Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.yaml
+F:     Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.yaml
 F:     Documentation/devicetree/bindings/reset/ti,sci-reset.txt
 F:     Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
 F:     drivers/clk/keystone/sci-clk.c
@@ -17214,8 +17277,8 @@ S:      Maintained
 F:     drivers/net/thunderbolt.c
 
 THUNDERX GPIO DRIVER
-M:     Robert Richter <rrichter@marvell.com>
-S:     Maintained
+M:     Robert Richter <rric@kernel.org>
+S:     Odd Fixes
 F:     drivers/gpio/gpio-thunderx.c
 
 TI AM437X VPFE DRIVER
@@ -17561,7 +17624,7 @@ L:      linux-integrity@vger.kernel.org
 S:     Maintained
 W:     https://kernsec.org/wiki/index.php/Linux_Kernel_Integrity
 Q:     https://patchwork.kernel.org/project/linux-integrity/list/
-T:     git git://git.infradead.org/users/jjs/linux-tpmdd.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git
 F:     drivers/char/tpm/
 
 TRACING
@@ -17698,6 +17761,7 @@ S:      Supported
 W:     http://www.linux-mtd.infradead.org/doc/ubifs.html
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git next
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git fixes
+F:     Documentation/filesystems/ubifs-authentication.rst
 F:     Documentation/filesystems/ubifs.rst
 F:     fs/ubifs/
 
@@ -18252,7 +18316,8 @@ F:      drivers/gpu/vga/vga_switcheroo.c
 F:     include/linux/vga_switcheroo.h
 
 VIA RHINE NETWORK DRIVER
-S:     Orphan
+S:     Maintained
+M:     Kevin Brace <kevinbrace@bracecomputerlab.com>
 F:     drivers/net/ethernet/via/via-rhine.c
 
 VIA SD/MMC CARD CONTROLLER DRIVER
@@ -18857,10 +18922,10 @@ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/mm
 F:     arch/x86/mm/
 
 X86 PLATFORM DRIVERS
-M:     Darren Hart <dvhart@infradead.org>
-M:     Andy Shevchenko <andy@infradead.org>
+M:     Hans de Goede <hdegoede@redhat.com>
+M:     Mark Gross <mgross@linux.intel.com>
 L:     platform-driver-x86@vger.kernel.org
-S:     Odd Fixes
+S:     Maintained
 T:     git git://git.infradead.org/linux-platform-drivers-x86.git
 F:     drivers/platform/olpc/
 F:     drivers/platform/x86/
@@ -18874,6 +18939,15 @@ S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
 F:     arch/x86/platform
 
+X86 PLATFORM UV HPE SUPERDOME FLEX
+M:     Steve Wahl <steve.wahl@hpe.com>
+R:     Dimitri Sivanich <dimitri.sivanich@hpe.com>
+R:     Russ Anderson <russ.anderson@hpe.com>
+S:     Supported
+F:     arch/x86/include/asm/uv/
+F:     arch/x86/kernel/apic/x2apic_uv_x.c
+F:     arch/x86/platform/uv/
+
 X86 VDSO
 M:     Andy Lutomirski <luto@kernel.org>
 L:     linux-kernel@vger.kernel.org
index f211681..51540b2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 9
 SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION =
 NAME = Kleptomaniac Octopus
 
 # *DOCUMENTATION*
@@ -882,10 +882,6 @@ KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
 LDFLAGS_vmlinux += --gc-sections
 endif
 
-ifdef CONFIG_LIVEPATCH
-KBUILD_CFLAGS += $(call cc-option, -flive-patching=inline-clone)
-endif
-
 ifdef CONFIG_SHADOW_CALL_STACK
 CC_FLAGS_SCS   := -fsanitize=shadow-call-stack
 KBUILD_CFLAGS  += $(CC_FLAGS_SCS)
index af14a56..76ec339 100644 (file)
@@ -106,6 +106,12 @@ config STATIC_KEYS_SELFTEST
        help
          Boot time self-test of the branch patching code.
 
+config STATIC_CALL_SELFTEST
+       bool "Static call selftest"
+       depends on HAVE_STATIC_CALL
+       help
+         Boot time self-test of the call patching code.
+
 config OPTPROBES
        def_bool y
        depends on KPROBES && HAVE_OPTPROBES
@@ -975,6 +981,13 @@ config HAVE_SPARSE_SYSCALL_NR
 config ARCH_HAS_VDSO_DATA
        bool
 
+config HAVE_STATIC_CALL
+       bool
+
+config HAVE_STATIC_CALL_INLINE
+       bool
+       depends on HAVE_STATIC_CALL
+
 source "kernel/gcov/Kconfig"
 
 source "scripts/gcc-plugins/Kconfig"
index 0eac816..99d631e 100644 (file)
@@ -42,9 +42,10 @@ extern __wsum csum_partial(const void *buff, int len, __wsum sum);
  * better 64-bit) boundary
  */
 #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
-__wsum csum_and_copy_from_user(const void __user *src, void *dst, int len, __wsum sum, int *errp);
+#define _HAVE_ARCH_CSUM_AND_COPY
+__wsum csum_and_copy_from_user(const void __user *src, void *dst, int len);
 
-__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum);
+__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
 
 
 /*
index ac110ae..5b60c24 100644 (file)
@@ -212,7 +212,7 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab,
                            STO_ALPHA_STD_GPLOAD)
                                /* Omit the prologue. */
                                value += 8;
-                       /* FALLTHRU */
+                       fallthrough;
                case R_ALPHA_BRADDR:
                        value -= (u64)location + 4;
                        if (value & 3)
index a813020..15bc9d1 100644 (file)
@@ -453,7 +453,7 @@ syscall_restart(unsigned long r0, unsigned long r19,
                        regs->r0 = EINTR;
                        break;
                }
-               /* fallthrough */
+               fallthrough;
        case ERESTARTNOINTR:
                regs->r0 = r0;  /* reset v0 and a3 and replay syscall */
                regs->r19 = r19;
index 49754e0..921d4b6 100644 (file)
@@ -883,7 +883,7 @@ do_entUnaUser(void __user * va, unsigned long opcode,
 
        case 0x26: /* sts */
                fake_reg = s_reg_to_mem(alpha_read_fp_reg(reg));
-               /* FALLTHRU */
+               fallthrough;
 
        case 0x2c: /* stl */
                __asm__ __volatile__(
@@ -911,7 +911,7 @@ do_entUnaUser(void __user * va, unsigned long opcode,
 
        case 0x27: /* stt */
                fake_reg = alpha_read_fp_reg(reg);
-               /* FALLTHRU */
+               fallthrough;
 
        case 0x2d: /* stq */
                __asm__ __volatile__(
index bc6f727..5b78d64 100644 (file)
@@ -72,6 +72,7 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        DISCARDS
 }
index af1dad7..dc68efb 100644 (file)
@@ -39,12 +39,11 @@ __asm__ __volatile__("insql %1,%2,%0":"=r" (z):"r" (x),"r" (y))
 #define insqh(x,y,z) \
 __asm__ __volatile__("insqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))
 
-
-#define __get_user_u(x,ptr)                            \
+#define __get_word(insn,x,ptr)                         \
 ({                                                     \
        long __guu_err;                                 \
        __asm__ __volatile__(                           \
-       "1:     ldq_u %0,%2\n"                          \
+       "1:     "#insn" %0,%2\n"                        \
        "2:\n"                                          \
        EXC(1b,2b,%0,%1)                                \
                : "=r"(x), "=r"(__guu_err)              \
@@ -52,19 +51,6 @@ __asm__ __volatile__("insqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))
        __guu_err;                                      \
 })
 
-#define __put_user_u(x,ptr)                            \
-({                                                     \
-       long __puu_err;                                 \
-       __asm__ __volatile__(                           \
-       "1:     stq_u %2,%1\n"                          \
-       "2:\n"                                          \
-       EXC(1b,2b,$31,%0)                               \
-               : "=r"(__puu_err)                       \
-               : "m"(__m(addr)), "rJ"(x), "0"(0));     \
-       __puu_err;                                      \
-})
-
-
 static inline unsigned short from64to16(unsigned long x)
 {
        /* Using extract instructions is a bit more efficient
@@ -95,15 +81,15 @@ static inline unsigned short from64to16(unsigned long x)
  */
 static inline unsigned long
 csum_partial_cfu_aligned(const unsigned long __user *src, unsigned long *dst,
-                        long len, unsigned long checksum,
-                        int *errp)
+                        long len)
 {
+       unsigned long checksum = ~0U;
        unsigned long carry = 0;
-       int err = 0;
 
        while (len >= 0) {
                unsigned long word;
-               err |= __get_user(word, src);
+               if (__get_word(ldq, word, src))
+                       return 0;
                checksum += carry;
                src++;
                checksum += word;
@@ -116,7 +102,8 @@ csum_partial_cfu_aligned(const unsigned long __user *src, unsigned long *dst,
        checksum += carry;
        if (len) {
                unsigned long word, tmp;
-               err |= __get_user(word, src);
+               if (__get_word(ldq, word, src))
+                       return 0;
                tmp = *dst;
                mskql(word, len, word);
                checksum += word;
@@ -125,7 +112,6 @@ csum_partial_cfu_aligned(const unsigned long __user *src, unsigned long *dst,
                *dst = word | tmp;
                checksum += carry;
        }
-       if (err && errp) *errp = err;
        return checksum;
 }
 
@@ -137,20 +123,21 @@ static inline unsigned long
 csum_partial_cfu_dest_aligned(const unsigned long __user *src,
                              unsigned long *dst,
                              unsigned long soff,
-                             long len, unsigned long checksum,
-                             int *errp)
+                             long len)
 {
        unsigned long first;
        unsigned long word, carry;
        unsigned long lastsrc = 7+len+(unsigned long)src;
-       int err = 0;
+       unsigned long checksum = ~0U;
 
-       err |= __get_user_u(first,src);
+       if (__get_word(ldq_u, first,src))
+               return 0;
        carry = 0;
        while (len >= 0) {
                unsigned long second;
 
-               err |= __get_user_u(second, src+1);
+               if (__get_word(ldq_u, second, src+1))
+                       return 0;
                extql(first, soff, word);
                len -= 8;
                src++;
@@ -168,7 +155,8 @@ csum_partial_cfu_dest_aligned(const unsigned long __user *src,
        if (len) {
                unsigned long tmp;
                unsigned long second;
-               err |= __get_user_u(second, lastsrc);
+               if (__get_word(ldq_u, second, lastsrc))
+                       return 0;
                tmp = *dst;
                extql(first, soff, word);
                extqh(second, soff, first);
@@ -180,7 +168,6 @@ csum_partial_cfu_dest_aligned(const unsigned long __user *src,
                *dst = word | tmp;
                checksum += carry;
        }
-       if (err && errp) *errp = err;
        return checksum;
 }
 
@@ -191,18 +178,18 @@ static inline unsigned long
 csum_partial_cfu_src_aligned(const unsigned long __user *src,
                             unsigned long *dst,
                             unsigned long doff,
-                            long len, unsigned long checksum,
-                            unsigned long partial_dest,
-                            int *errp)
+                            long len,
+                            unsigned long partial_dest)
 {
        unsigned long carry = 0;
        unsigned long word;
        unsigned long second_dest;
-       int err = 0;
+       unsigned long checksum = ~0U;
 
        mskql(partial_dest, doff, partial_dest);
        while (len >= 0) {
-               err |= __get_user(word, src);
+               if (__get_word(ldq, word, src))
+                       return 0;
                len -= 8;
                insql(word, doff, second_dest);
                checksum += carry;
@@ -216,7 +203,8 @@ csum_partial_cfu_src_aligned(const unsigned long __user *src,
        len += 8;
        if (len) {
                checksum += carry;
-               err |= __get_user(word, src);
+               if (__get_word(ldq, word, src))
+                       return 0;
                mskql(word, len, word);
                len -= 8;
                checksum += word;
@@ -237,7 +225,6 @@ csum_partial_cfu_src_aligned(const unsigned long __user *src,
        stq_u(partial_dest | second_dest, dst);
 out:
        checksum += carry;
-       if (err && errp) *errp = err;
        return checksum;
 }
 
@@ -249,23 +236,23 @@ static inline unsigned long
 csum_partial_cfu_unaligned(const unsigned long __user * src,
                           unsigned long * dst,
                           unsigned long soff, unsigned long doff,
-                          long len, unsigned long checksum,
-                          unsigned long partial_dest,
-                          int *errp)
+                          long len, unsigned long partial_dest)
 {
        unsigned long carry = 0;
        unsigned long first;
        unsigned long lastsrc;
-       int err = 0;
+       unsigned long checksum = ~0U;
 
-       err |= __get_user_u(first, src);
+       if (__get_word(ldq_u, first, src))
+               return 0;
        lastsrc = 7+len+(unsigned long)src;
        mskql(partial_dest, doff, partial_dest);
        while (len >= 0) {
                unsigned long second, word;
                unsigned long second_dest;
 
-               err |= __get_user_u(second, src+1);
+               if (__get_word(ldq_u, second, src+1))
+                       return 0;
                extql(first, soff, word);
                checksum += carry;
                len -= 8;
@@ -286,7 +273,8 @@ csum_partial_cfu_unaligned(const unsigned long __user * src,
                unsigned long second, word;
                unsigned long second_dest;
 
-               err |= __get_user_u(second, lastsrc);
+               if (__get_word(ldq_u, second, lastsrc))
+                       return 0;
                extql(first, soff, word);
                extqh(second, soff, first);
                word |= first;
@@ -307,7 +295,8 @@ csum_partial_cfu_unaligned(const unsigned long __user * src,
                unsigned long second, word;
                unsigned long second_dest;
 
-               err |= __get_user_u(second, lastsrc);
+               if (__get_word(ldq_u, second, lastsrc))
+                       return 0;
                extql(first, soff, word);
                extqh(second, soff, first);
                word |= first;
@@ -320,66 +309,55 @@ csum_partial_cfu_unaligned(const unsigned long __user * src,
                stq_u(partial_dest | word | second_dest, dst);
                checksum += carry;
        }
-       if (err && errp) *errp = err;
        return checksum;
 }
 
-__wsum
-csum_and_copy_from_user(const void __user *src, void *dst, int len,
-                              __wsum sum, int *errp)
+static __wsum __csum_and_copy(const void __user *src, void *dst, int len)
 {
-       unsigned long checksum = (__force u32) sum;
        unsigned long soff = 7 & (unsigned long) src;
        unsigned long doff = 7 & (unsigned long) dst;
-
-       if (len) {
-               if (!access_ok(src, len)) {
-                       if (errp) *errp = -EFAULT;
-                       memset(dst, 0, len);
-                       return sum;
-               }
-               if (!doff) {
-                       if (!soff)
-                               checksum = csum_partial_cfu_aligned(
-                                       (const unsigned long __user *) src,
-                                       (unsigned long *) dst,
-                                       len-8, checksum, errp);
-                       else
-                               checksum = csum_partial_cfu_dest_aligned(
-                                       (const unsigned long __user *) src,
-                                       (unsigned long *) dst,
-                                       soff, len-8, checksum, errp);
-               } else {
-                       unsigned long partial_dest;
-                       ldq_u(partial_dest, dst);
-                       if (!soff)
-                               checksum = csum_partial_cfu_src_aligned(
-                                       (const unsigned long __user *) src,
-                                       (unsigned long *) dst,
-                                       doff, len-8, checksum,
-                                       partial_dest, errp);
-                       else
-                               checksum = csum_partial_cfu_unaligned(
-                                       (const unsigned long __user *) src,
-                                       (unsigned long *) dst,
-                                       soff, doff, len-8, checksum,
-                                       partial_dest, errp);
-               }
-               checksum = from64to16 (checksum);
+       unsigned long checksum;
+
+       if (!doff) {
+               if (!soff)
+                       checksum = csum_partial_cfu_aligned(
+                               (const unsigned long __user *) src,
+                               (unsigned long *) dst, len-8);
+               else
+                       checksum = csum_partial_cfu_dest_aligned(
+                               (const unsigned long __user *) src,
+                               (unsigned long *) dst,
+                               soff, len-8);
+       } else {
+               unsigned long partial_dest;
+               ldq_u(partial_dest, dst);
+               if (!soff)
+                       checksum = csum_partial_cfu_src_aligned(
+                               (const unsigned long __user *) src,
+                               (unsigned long *) dst,
+                               doff, len-8, partial_dest);
+               else
+                       checksum = csum_partial_cfu_unaligned(
+                               (const unsigned long __user *) src,
+                               (unsigned long *) dst,
+                               soff, doff, len-8, partial_dest);
        }
-       return (__force __wsum)checksum;
+       return (__force __wsum)from64to16 (checksum);
+}
+
+__wsum
+csum_and_copy_from_user(const void __user *src, void *dst, int len)
+{
+       if (!access_ok(src, len))
+               return 0;
+       return __csum_and_copy(src, dst, len);
 }
 EXPORT_SYMBOL(csum_and_copy_from_user);
 
 __wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
+csum_partial_copy_nocheck(const void *src, void *dst, int len)
 {
-       __wsum checksum;
-       mm_segment_t oldfs = get_fs();
-       set_fs(KERNEL_DS);
-       checksum = csum_and_copy_from_user((__force const void __user *)src,
-                                               dst, len, sum, NULL);
-       set_fs(oldfs);
-       return checksum;
+       return __csum_and_copy((__force const void __user *)src,
+                                               dst, len);
 }
 EXPORT_SYMBOL(csum_partial_copy_nocheck);
index 9acbeba..dcaa44e 100644 (file)
@@ -88,6 +88,8 @@
 
        arcpct: pct {
                compatible = "snps,archs-pct";
+               interrupt-parent = <&cpu_intc>;
+               interrupts = <20>;
        };
 
        /* TIMER0 with interrupt for clockevent */
                        reg = <0x8000 0x2000>;
                        interrupts = <10>;
                        interrupt-names = "macirq";
-                       phy-mode = "rgmii";
+                       phy-mode = "rgmii-id";
                        snps,pbl = <32>;
                        snps,multicast-filter-bins = <256>;
                        clocks = <&gmacclk>;
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "snps,dwmac-mdio";
-                               phy0: ethernet-phy@0 {
+                               phy0: ethernet-phy@0 { /* Micrel KSZ9031 */
                                        reg = <0>;
                                };
                        };
index b747f2e..6147db9 100644 (file)
  * vineetg: April 2010
  *  -Switched pgtable_t from being struct page * to unsigned long
  *      =Needed so that Page Table allocator (pte_alloc_one) is not forced to
- *       to deal with struct page. Thay way in future we can make it allocate
+ *       deal with struct page. That way in future we can make it allocate
  *       multiple PG Tbls in one Page Frame
  *      =sweet side effect is avoiding calls to ugly page_address( ) from the
- *       pg-tlb allocator sub-sys (pte_alloc_one, ptr_free, pmd_populate
+ *       pg-tlb allocator sub-sys (pte_alloc_one, ptr_free, pmd_populate)
  *
  *  Amit Bhor, Sameer Dhavale: Codito Technologies 2004
  */
index d04837d..03f8b1b 100644 (file)
@@ -339,7 +339,7 @@ void __kprobes disasm_instr(unsigned long addr, struct disasm_state *state,
 
        case op_LDWX_S: /* LDWX_S c, [b, u6] */
                state->x = 1;
-               /* intentional fall-through */
+               fallthrough;
 
        case op_LDW_S:  /* LDW_S c, [b, u6] */
                state->zz = 2;
index 7d3efe8..cabef45 100644 (file)
@@ -388,6 +388,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 {
 
        ri->ret_addr = (kprobe_opcode_t *) regs->blink;
+       ri->fp = NULL;
 
        /* Replace the return addr with trampoline addr */
        regs->blink = (unsigned long)&kretprobe_trampoline;
@@ -396,58 +397,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 static int __kprobes trampoline_probe_handler(struct kprobe *p,
                                              struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because an multiple functions in the call path
-        * have a return probe installed on them, and/or more than one return
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               if (ri->rp && ri->rp->handler)
-                       ri->rp->handler(ri, regs);
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address) {
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-               }
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-       regs->ret = orig_ret_address;
-
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
+       regs->ret = __kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
 
        /* By returning a non zero value, we are telling the kprobe handler
         * that we don't want the post_handler to run
index 661fd84..79849f3 100644 (file)
@@ -562,7 +562,7 @@ static int arc_pmu_device_probe(struct platform_device *pdev)
 {
        struct arc_reg_pct_build pct_bcr;
        struct arc_reg_cc_build cc_bcr;
-       int i, has_interrupts;
+       int i, has_interrupts, irq;
        int counter_size;       /* in bits */
 
        union cc_name {
@@ -637,13 +637,7 @@ static int arc_pmu_device_probe(struct platform_device *pdev)
                .attr_groups    = arc_pmu->attr_groups,
        };
 
-       if (has_interrupts) {
-               int irq = platform_get_irq(pdev, 0);
-
-               if (irq < 0) {
-                       pr_err("Cannot get IRQ number for the platform\n");
-                       return -ENODEV;
-               }
+       if (has_interrupts && (irq = platform_get_irq(pdev, 0) >= 0)) {
 
                arc_pmu->irq = irq;
 
@@ -652,9 +646,9 @@ static int arc_pmu_device_probe(struct platform_device *pdev)
                                   this_cpu_ptr(&arc_pmu_cpu));
 
                on_each_cpu(arc_cpu_pmu_irq_init, &irq, 1);
-
-       } else
+       } else {
                arc_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
+       }
 
        /*
         * perf parser doesn't really like '-' symbol in events name, so let's
index 3d57ed0..8222f8c 100644 (file)
@@ -321,7 +321,7 @@ static void arc_restart_syscall(struct k_sigaction *ka, struct pt_regs *regs)
                        regs->r0 = -EINTR;
                        break;
                }
-               /* fallthrough */
+               fallthrough;
 
        case -ERESTARTNOINTR:
                /*
index 28e8bf0..a331bb5 100644 (file)
 
 #define ARC_PATH_MAX   256
 
-/*
- * Common routine to print scratch regs (r0-r12) or callee regs (r13-r25)
- *   -Prints 3 regs per line and a CR.
- *   -To continue, callee regs right after scratch, special handling of CR
- */
-static noinline void print_reg_file(long *reg_rev, int start_num)
+static noinline void print_regs_scratch(struct pt_regs *regs)
 {
-       unsigned int i;
-       char buf[512];
-       int n = 0, len = sizeof(buf);
-
-       for (i = start_num; i < start_num + 13; i++) {
-               n += scnprintf(buf + n, len - n, "r%02u: 0x%08lx\t",
-                              i, (unsigned long)*reg_rev);
-
-               if (((i + 1) % 3) == 0)
-                       n += scnprintf(buf + n, len - n, "\n");
-
-               /* because pt_regs has regs reversed: r12..r0, r25..r13 */
-               if (is_isa_arcv2() && start_num == 0)
-                       reg_rev++;
-               else
-                       reg_rev--;
-       }
-
-       if (start_num != 0)
-               n += scnprintf(buf + n, len - n, "\n\n");
+       pr_cont("BTA: 0x%08lx\n SP: 0x%08lx  FP: 0x%08lx BLK: %pS\n",
+               regs->bta, regs->sp, regs->fp, (void *)regs->blink);
+       pr_cont("LPS: 0x%08lx\tLPE: 0x%08lx\tLPC: 0x%08lx\n",
+               regs->lp_start, regs->lp_end, regs->lp_count);
 
-       /* To continue printing callee regs on same line as scratch regs */
-       if (start_num == 0)
-               pr_info("%s", buf);
-       else
-               pr_cont("%s\n", buf);
+       pr_info("r00: 0x%08lx\tr01: 0x%08lx\tr02: 0x%08lx\n"    \
+               "r03: 0x%08lx\tr04: 0x%08lx\tr05: 0x%08lx\n"    \
+               "r06: 0x%08lx\tr07: 0x%08lx\tr08: 0x%08lx\n"    \
+               "r09: 0x%08lx\tr10: 0x%08lx\tr11: 0x%08lx\n"    \
+               "r12: 0x%08lx\t",
+               regs->r0, regs->r1, regs->r2,
+               regs->r3, regs->r4, regs->r5,
+               regs->r6, regs->r7, regs->r8,
+               regs->r9, regs->r10, regs->r11,
+               regs->r12);
 }
 
-static void show_callee_regs(struct callee_regs *cregs)
+static void print_regs_callee(struct callee_regs *regs)
 {
-       print_reg_file(&(cregs->r13), 13);
+       pr_cont("r13: 0x%08lx\tr14: 0x%08lx\n"                  \
+               "r15: 0x%08lx\tr16: 0x%08lx\tr17: 0x%08lx\n"    \
+               "r18: 0x%08lx\tr19: 0x%08lx\tr20: 0x%08lx\n"    \
+               "r21: 0x%08lx\tr22: 0x%08lx\tr23: 0x%08lx\n"    \
+               "r24: 0x%08lx\tr25: 0x%08lx\n",
+               regs->r13, regs->r14,
+               regs->r15, regs->r16, regs->r17,
+               regs->r18, regs->r19, regs->r20,
+               regs->r21, regs->r22, regs->r23,
+               regs->r24, regs->r25);
 }
 
 static void print_task_path_n_nm(struct task_struct *tsk)
@@ -175,7 +168,7 @@ static void show_ecr_verbose(struct pt_regs *regs)
 void show_regs(struct pt_regs *regs)
 {
        struct task_struct *tsk = current;
-       struct callee_regs *cregs;
+       struct callee_regs *cregs = (struct callee_regs *)tsk->thread.callee_reg;
 
        /*
         * generic code calls us with preemption disabled, but some calls
@@ -204,25 +197,15 @@ void show_regs(struct pt_regs *regs)
                        STS_BIT(regs, A2), STS_BIT(regs, A1),
                        STS_BIT(regs, E2), STS_BIT(regs, E1));
 #else
-       pr_cont(" [%2s%2s%2s%2s]",
+       pr_cont(" [%2s%2s%2s%2s]   ",
                        STS_BIT(regs, IE),
                        (regs->status32 & STATUS_U_MASK) ? "U " : "K ",
                        STS_BIT(regs, DE), STS_BIT(regs, AE));
 #endif
-       pr_cont("  BTA: 0x%08lx\n  SP: 0x%08lx  FP: 0x%08lx BLK: %pS\n",
-               regs->bta, regs->sp, regs->fp, (void *)regs->blink);
-       pr_info("LPS: 0x%08lx\tLPE: 0x%08lx\tLPC: 0x%08lx\n",
-               regs->lp_start, regs->lp_end, regs->lp_count);
-
-       /* print regs->r0 thru regs->r12
-        * Sequential printing was generating horrible code
-        */
-       print_reg_file(&(regs->r0), 0);
 
-       /* If Callee regs were saved, display them too */
-       cregs = (struct callee_regs *)current->thread.callee_reg;
+       print_regs_scratch(regs);
        if (cregs)
-               show_callee_regs(cregs);
+               print_regs_callee(cregs);
 
        preempt_disable();
 }
index f87758a..74ad425 100644 (file)
@@ -572,7 +572,7 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end,
 #else
                BUILD_BUG_ON(sizeof(u32) != sizeof(value));
 #endif
-               /* Fall through */
+               fallthrough;
        case DW_EH_PE_native:
                if (end < (const void *)(ptr.pul + 1))
                        return 0;
@@ -827,7 +827,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
                        case DW_CFA_def_cfa:
                                state->cfa.reg = get_uleb128(&ptr.p8, end);
                                unw_debug("cfa_def_cfa: r%lu ", state->cfa.reg);
-                               /* fall through */
+                               fallthrough;
                        case DW_CFA_def_cfa_offset:
                                state->cfa.offs = get_uleb128(&ptr.p8, end);
                                unw_debug("cfa_def_cfa_offset: 0x%lx ",
@@ -835,7 +835,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
                                break;
                        case DW_CFA_def_cfa_sf:
                                state->cfa.reg = get_uleb128(&ptr.p8, end);
-                               /* fall through */
+                               fallthrough;
                        case DW_CFA_def_cfa_offset_sf:
                                state->cfa.offs = get_sleb128(&ptr.p8, end)
                                    * state->dataAlign;
index 54139a6..33ce59d 100644 (file)
@@ -122,6 +122,7 @@ SECTIONS
        _end = . ;
 
        STABS_DEBUG
+       ELF_DETAILS
        DISCARDS
 
        .arcextmap 0 : {
index f886ac6..3a35b82 100644 (file)
@@ -26,8 +26,8 @@ static unsigned long low_mem_sz;
 
 #ifdef CONFIG_HIGHMEM
 static unsigned long min_high_pfn, max_high_pfn;
-static u64 high_mem_start;
-static u64 high_mem_sz;
+static phys_addr_t high_mem_start;
+static phys_addr_t high_mem_sz;
 #endif
 
 #ifdef CONFIG_DISCONTIGMEM
@@ -69,6 +69,7 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
                high_mem_sz = size;
                in_use = 1;
                memblock_add_node(base, size, 1);
+               memblock_reserve(base, size);
 #endif
        }
 
@@ -157,7 +158,7 @@ void __init setup_arch_memory(void)
        min_high_pfn = PFN_DOWN(high_mem_start);
        max_high_pfn = PFN_DOWN(high_mem_start + high_mem_sz);
 
-       max_zone_pfn[ZONE_HIGHMEM] = max_high_pfn;
+       max_zone_pfn[ZONE_HIGHMEM] = min_low_pfn;
 
        high_memory = (void *)(min_high_pfn << PAGE_SHIFT);
        kmap_init();
@@ -166,22 +167,26 @@ void __init setup_arch_memory(void)
        free_area_init(max_zone_pfn);
 }
 
-/*
- * mem_init - initializes memory
- *
- * Frees up bootmem
- * Calculates and displays memory available/used
- */
-void __init mem_init(void)
+static void __init highmem_init(void)
 {
 #ifdef CONFIG_HIGHMEM
        unsigned long tmp;
 
-       reset_all_zones_managed_pages();
+       memblock_free(high_mem_start, high_mem_sz);
        for (tmp = min_high_pfn; tmp < max_high_pfn; tmp++)
                free_highmem_page(pfn_to_page(tmp));
 #endif
+}
 
+/*
+ * mem_init - initializes memory
+ *
+ * Frees up bootmem
+ * Calculates and displays memory available/used
+ */
+void __init mem_init(void)
+{
        memblock_free_all();
+       highmem_init();
        mem_init_print_info(NULL);
 }
index a4a6153..77712c5 100644 (file)
@@ -33,7 +33,6 @@
 #define CTOP_AUX_DPC                           (CTOP_AUX_BASE + 0x02C)
 #define CTOP_AUX_LPC                           (CTOP_AUX_BASE + 0x030)
 #define CTOP_AUX_EFLAGS                                (CTOP_AUX_BASE + 0x080)
-#define CTOP_AUX_IACK                          (CTOP_AUX_BASE + 0x088)
 #define CTOP_AUX_GPA1                          (CTOP_AUX_BASE + 0x08C)
 #define CTOP_AUX_UDMC                          (CTOP_AUX_BASE + 0x300)
 
index e00d94b..e67ef15 100644 (file)
@@ -49,6 +49,7 @@ config ARM
        select GENERIC_ARCH_TOPOLOGY if ARM_CPU_TOPOLOGY
        select GENERIC_ATOMIC64 if CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI
        select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+       select GENERIC_IRQ_IPI if SMP
        select GENERIC_CPU_AUTOPROBE
        select GENERIC_EARLY_IOREMAP
        select GENERIC_IDLE_POLL_SETUP
index 4e87735..e589da3 100644 (file)
@@ -16,6 +16,10 @@ LDFLAGS_vmlinux      += --be8
 KBUILD_LDFLAGS_MODULE  += --be8
 endif
 
+# We never want expected sections to be placed heuristically by the
+# linker. All sections should be explicitly named in the linker script.
+LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn)
+
 ifeq ($(CONFIG_ARM_MODULE_PLTS),y)
 KBUILD_LDS_MODULE      += $(srctree)/arch/arm/kernel/module.lds
 endif
index b1147b7..58028ab 100644 (file)
@@ -123,6 +123,8 @@ endif
 LDFLAGS_vmlinux += --no-undefined
 # Delete all temporary local symbols
 LDFLAGS_vmlinux += -X
+# Report orphan sections
+LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn)
 # Next argument is a linker script
 LDFLAGS_vmlinux += -T
 
index 09ac33f..b914be3 100644 (file)
@@ -2,6 +2,7 @@
 /*
  *  Copyright (C) 2000 Russell King
  */
+#include <asm/vmlinux.lds.h>
 
 #ifdef CONFIG_CPU_ENDIAN_BE8
 #define ZIMAGE_MAGIC(x) ( (((x) >> 24) & 0x000000ff) | \
@@ -17,8 +18,11 @@ ENTRY(_start)
 SECTIONS
 {
   /DISCARD/ : {
+    COMMON_DISCARDS
     *(.ARM.exidx*)
     *(.ARM.extab*)
+    *(.note.*)
+    *(.rel.*)
     /*
      * Discard any r/w data - this produces a link error if we have any,
      * which is required for PIC decompression.  Local data generates
@@ -36,9 +40,7 @@ SECTIONS
     *(.start)
     *(.text)
     *(.text.*)
-    *(.gnu.warning)
-    *(.glue_7t)
-    *(.glue_7)
+    ARM_STUBS_TEXT
   }
   .table : ALIGN(4) {
     _table_start = .;
@@ -128,12 +130,10 @@ SECTIONS
   PROVIDE(__pecoff_data_size = ALIGN(512) - ADDR(.data));
   PROVIDE(__pecoff_end = ALIGN(512));
 
-  .stab 0              : { *(.stab) }
-  .stabstr 0           : { *(.stabstr) }
-  .stab.excl 0         : { *(.stab.excl) }
-  .stab.exclstr 0      : { *(.stab.exclstr) }
-  .stab.index 0                : { *(.stab.index) }
-  .stab.indexstr 0     : { *(.stab.indexstr) }
-  .comment 0           : { *(.comment) }
+  STABS_DEBUG
+  DWARF_DEBUG
+  ARM_DETAILS
+
+  ARM_ASSERTS
 }
 ASSERT(_edata_real == _edata, "error: zImage file size is incorrect");
index 8d19925..6783cf1 100644 (file)
                switch0: ksz8563@0 {
                        compatible = "microchip,ksz8563";
                        reg = <0>;
-                       phy-mode = "mii";
                        reset-gpios = <&pioA PIN_PD4 GPIO_ACTIVE_LOW>;
 
                        spi-max-frequency = <500000>;
                                        reg = <2>;
                                        label = "cpu";
                                        ethernet = <&macb0>;
+                                       phy-mode = "mii";
                                        fixed-link {
                                                speed = <100>;
                                                full-duplex;
index cbebed5..e8df458 100644 (file)
                };
 
                qspi: spi@27200 {
-                       compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi";
+                       compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi";
                        reg = <0x027200 0x184>,
                              <0x027000 0x124>,
                              <0x11c408 0x004>,
index 0346ea6..c846fa3 100644 (file)
                };
 
                qspi: spi@27200 {
-                       compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi";
+                       compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi";
                        reg = <0x027200 0x184>,
                              <0x027000 0x124>,
                              <0x11c408 0x004>,
index f7ae5a4..d94357b 100644 (file)
@@ -13,7 +13,7 @@
 
        soc {
                firmware: firmware {
-                       compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
+                       compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
                        #address-cells = <1>;
                        #size-cells = <1>;
 
index 2d9b4dd..0016720 100644 (file)
        };
 
        spi@18029200 {
-               compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi";
+               compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi";
                reg = <0x18029200 0x184>,
                      <0x18029000 0x124>,
                      <0x1811b408 0x004>,
index 7a3d1d3..8f94364 100644 (file)
@@ -13,7 +13,7 @@
 
        backlight: backlight-lvds {
                compatible = "pwm-backlight";
-               pwms = <&pwm3 0 20000>;
+               pwms = <&pwm3 0 20000 0>;
                brightness-levels = <0 4 8 16 32 64 128 255>;
                default-brightness-level = <6>;
                power-supply = <&reg_lcd>;
index dffafbc..349959d 100644 (file)
@@ -30,7 +30,7 @@
        };
 
        /* PRTWD2 rev 1 bitbang I2C for Ethernet Switch */
-       i2c@4 {
+       i2c {
                compatible = "i2c-gpio";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_i2c4>;
index 7705285..4d01c33 100644 (file)
@@ -22,8 +22,6 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                user-pb {
                        label = "user_pb";
index 0b02c7e..f4dc462 100644 (file)
 #define MX6SX_PAD_QSPI1B_DQS__SIM_M_HADDR_15                      0x01B0 0x04F8 0x0000 0x7 0x0
 #define MX6SX_PAD_QSPI1B_SCLK__QSPI1_B_SCLK                       0x01B4 0x04FC 0x0000 0x0 0x0
 #define MX6SX_PAD_QSPI1B_SCLK__UART3_DCE_RX                       0x01B4 0x04FC 0x0840 0x1 0x4
-#define MX6SX_PAD_QSPI1B_SCLK__UART3_DTE_TX                       0x01B4 0x04FC 0x0000 0x0 0x0
+#define MX6SX_PAD_QSPI1B_SCLK__UART3_DTE_TX                       0x01B4 0x04FC 0x0000 0x1 0x0
 #define MX6SX_PAD_QSPI1B_SCLK__ECSPI3_SCLK                        0x01B4 0x04FC 0x0730 0x2 0x1
 #define MX6SX_PAD_QSPI1B_SCLK__ESAI_RX_HF_CLK                     0x01B4 0x04FC 0x0780 0x3 0x2
 #define MX6SX_PAD_QSPI1B_SCLK__CSI1_DATA_16                       0x01B4 0x04FC 0x06DC 0x4 0x1
index e5e20b0..7cb6153 100644 (file)
@@ -58,7 +58,7 @@
                          <&clks IMX7D_ENET1_TIME_ROOT_CLK>;
        assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>;
        assigned-clock-rates = <0>, <100000000>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
        phy-handle = <&fec1_phy>;
        status = "okay";
 
index 3674396..b7ea37a 100644 (file)
                        clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
                                 <&pcc3 IMX7ULP_CLK_PCTLC>;
                        clock-names = "gpio", "port";
-                       gpio-ranges = <&iomuxc1 0 0 32>;
+                       gpio-ranges = <&iomuxc1 0 0 20>;
                };
 
                gpio_ptd: gpio@40af0000 {
                        clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
                                 <&pcc3 IMX7ULP_CLK_PCTLD>;
                        clock-names = "gpio", "port";
-                       gpio-ranges = <&iomuxc1 0 32 32>;
+                       gpio-ranges = <&iomuxc1 0 32 12>;
                };
 
                gpio_pte: gpio@40b00000 {
                        clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
                                 <&pcc3 IMX7ULP_CLK_PCTLE>;
                        clock-names = "gpio", "port";
-                       gpio-ranges = <&iomuxc1 0 64 32>;
+                       gpio-ranges = <&iomuxc1 0 64 16>;
                };
 
                gpio_ptf: gpio@40b10000 {
                        clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
                                 <&pcc3 IMX7ULP_CLK_PCTLF>;
                        clock-names = "gpio", "port";
-                       gpio-ranges = <&iomuxc1 0 96 32>;
+                       gpio-ranges = <&iomuxc1 0 96 20>;
                };
        };
 
index 100396f..395e05f 100644 (file)
@@ -51,6 +51,8 @@
 
 &mcbsp2 {
        status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcbsp2_pins>;
 };
 
 &charger {
                regulator-max-microvolt = <3300000>;
        };
 
-       lcd0: display@0 {
-               compatible = "panel-dpi";
-               label = "28";
-               status = "okay";
-               /* default-on; */
+       lcd0: display {
+               /* This isn't the exact LCD, but the timings meet spec */
+               compatible = "logicpd,type28";
                pinctrl-names = "default";
                pinctrl-0 = <&lcd_enable_pin>;
-               enable-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;    /* gpio155, lcd INI */
+               backlight = <&bl>;
+               enable-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;
                port {
                        lcd_in: endpoint {
                                remote-endpoint = <&dpi_out>;
                        };
                };
-
-               panel-timing {
-                       clock-frequency = <9000000>;
-                       hactive = <480>;
-                       vactive = <272>;
-                       hfront-porch = <3>;
-                       hback-porch = <2>;
-                       hsync-len = <42>;
-                       vback-porch = <3>;
-                       vfront-porch = <2>;
-                       vsync-len = <11>;
-                       hsync-active = <1>;
-                       vsync-active = <1>;
-                       de-active = <1>;
-                       pixelclk-active = <0>;
-               };
        };
 
        bl: backlight {
index 381f0e8..b0f6613 100644 (file)
@@ -81,6 +81,8 @@
 };
 
 &mcbsp2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mcbsp2_pins>;
        status = "okay";
 };
 
index 069af9a..827373e 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0x0 0x1550000 0x0 0x10000>,
-                             <0x0 0x40000000 0x0 0x40000000>;
+                             <0x0 0x40000000 0x0 0x20000000>;
                        reg-names = "QuadSPI", "QuadSPI-memory";
                        interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
                        clock-names = "qspi_en", "qspi";
index 5da9cff..a82c962 100644 (file)
                                        };
                                };
 
-                               target-module@5000 {
+                               target-module@4000 {
                                        compatible = "ti,sysc-omap2", "ti,sysc";
-                                       reg = <0x5000 0x4>,
-                                             <0x5010 0x4>,
-                                             <0x5014 0x4>;
+                                       reg = <0x4000 0x4>,
+                                             <0x4010 0x4>,
+                                             <0x4014 0x4>;
                                        reg-names = "rev", "sysc", "syss";
                                        ti,sysc-sidle = <SYSC_IDLE_FORCE>,
                                                        <SYSC_IDLE_NO>,
                                        ti,syss-mask = <1>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
-                                       ranges = <0 0x5000 0x1000>;
+                                       ranges = <0 0x4000 0x1000>;
 
                                        dsi1: encoder@0 {
                                                compatible = "ti,omap5-dsi";
                                                reg-names = "proto", "phy", "pll";
                                                interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
                                                status = "disabled";
-                                               clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>;
-                                               clock-names = "fck";
+                                               clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>,
+                                                        <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>;
+                                               clock-names = "fck", "sys_clk";
                                        };
                                };
 
                                                reg-names = "proto", "phy", "pll";
                                                interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
                                                status = "disabled";
-                                               clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>;
-                                               clock-names = "fck";
+                                               clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>,
+                                                        <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>;
+                                               clock-names = "fck", "sys_clk";
                                        };
                                };
 
index fc4abef..0013ec3 100644 (file)
                timer3: timer3@ffd00100 {
                        compatible = "snps,dw-apb-timer";
                        interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>;
-                       reg = <0xffd01000 0x100>;
+                       reg = <0xffd00100 0x100>;
                        clocks = <&l4_sys_free_clk>;
                        clock-names = "timer";
                        resets = <&rst L4SYSTIMER1_RESET>;
index 0fe03aa..2259d11 100644 (file)
                        };
 
                        ocotp: ocotp@400a5000 {
-                               compatible = "fsl,vf610-ocotp";
+                               compatible = "fsl,vf610-ocotp", "syscon";
                                reg = <0x400a5000 0x1000>;
                                clocks = <&clks VF610_CLK_OCOTP>;
                        };
index a9755c5..b06e537 100644 (file)
@@ -1,13 +1,11 @@
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARCH_MULTI_V4T=y
 CONFIG_ARCH_MULTI_V5=y
 # CONFIG_ARCH_MULTI_V7 is not set
@@ -15,19 +13,17 @@ CONFIG_ARCH_INTEGRATOR=y
 CONFIG_ARCH_INTEGRATOR_AP=y
 CONFIG_INTEGRATOR_IMPD1=y
 CONFIG_ARCH_INTEGRATOR_CP=y
-CONFIG_PCI=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 # CONFIG_ATAGS is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyAM0,38400n8 root=/dev/nfs ip=bootp"
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPUFREQ_DT=y
-CONFIG_CMA=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -37,6 +33,7 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
+CONFIG_PCI=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_AFS_PARTS=y
@@ -52,9 +49,12 @@ CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_NETDEVICES=y
 CONFIG_E100=y
 CONFIG_SMC91X=y
+CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
 # CONFIG_SERIO_SERPORT is not set
 CONFIG_DRM=y
+CONFIG_DRM_DISPLAY_CONNECTOR=y
 CONFIG_DRM_SIMPLE_BRIDGE=y
 CONFIG_DRM_PL111=y
 CONFIG_FB_MODE_HELPERS=y
index cfaed4e..7d0cc7f 100644 (file)
        vldr            \out\()h, \sym + 8
        .endm
 
-       .macro          __adr, reg, lbl
-       adr             \reg, \lbl
-THUMB( orr             \reg, \reg, #1          )
-       .endm
-
        .macro          in_bs_ch, b0, b1, b2, b3, b4, b5, b6, b7
        veor            \b2, \b2, \b1
        veor            \b5, \b5, \b6
@@ -629,11 +624,11 @@ ENDPROC(aesbs_decrypt8)
        push            {r4-r6, lr}
        ldr             r5, [sp, #16]           // number of blocks
 
-99:    __adr           ip, 0f
+99:    adr             ip, 0f
        and             lr, r5, #7
        cmp             r5, #8
        sub             ip, ip, lr, lsl #2
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        vld1.8          {q0}, [r1]!
        vld1.8          {q1}, [r1]!
@@ -648,11 +643,11 @@ ENDPROC(aesbs_decrypt8)
        mov             rounds, r3
        bl              \do8
 
-       __adr           ip, 1f
+       adr             ip, 1f
        and             lr, r5, #7
        cmp             r5, #8
        sub             ip, ip, lr, lsl #2
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        vst1.8          {\o0}, [r0]!
        vst1.8          {\o1}, [r0]!
@@ -689,12 +684,12 @@ ENTRY(aesbs_cbc_decrypt)
        push            {r4-r6, lr}
        ldm             ip, {r5-r6}             // load args 4-5
 
-99:    __adr           ip, 0f
+99:    adr             ip, 0f
        and             lr, r5, #7
        cmp             r5, #8
        sub             ip, ip, lr, lsl #2
        mov             lr, r1
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        vld1.8          {q0}, [lr]!
        vld1.8          {q1}, [lr]!
@@ -718,11 +713,11 @@ ENTRY(aesbs_cbc_decrypt)
        vmov            q14, q8
        vmov            q15, q8
 
-       __adr           ip, 1f
+       adr             ip, 1f
        and             lr, r5, #7
        cmp             r5, #8
        sub             ip, ip, lr, lsl #2
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        vld1.8          {q9}, [r1]!
        vld1.8          {q10}, [r1]!
@@ -733,9 +728,9 @@ ENTRY(aesbs_cbc_decrypt)
        vld1.8          {q15}, [r1]!
        W(nop)
 
-1:     __adr           ip, 2f
+1:     adr             ip, 2f
        sub             ip, ip, lr, lsl #3
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        veor            q0, q0, q8
        vst1.8          {q0}, [r0]!
@@ -804,13 +799,13 @@ ENTRY(aesbs_ctr_encrypt)
        vmov            q6, q0
        vmov            q7, q0
 
-       __adr           ip, 0f
+       adr             ip, 0f
        sub             lr, r5, #1
        and             lr, lr, #7
        cmp             r5, #8
        sub             ip, ip, lr, lsl #5
        sub             ip, ip, lr, lsl #2
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        next_ctr        q1
        next_ctr        q2
@@ -824,13 +819,13 @@ ENTRY(aesbs_ctr_encrypt)
        mov             rounds, r3
        bl              aesbs_encrypt8
 
-       __adr           ip, 1f
+       adr             ip, 1f
        and             lr, r5, #7
        cmp             r5, #8
        movgt           r4, #0
        ldrle           r4, [sp, #40]           // load final in the last round
        sub             ip, ip, lr, lsl #2
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        vld1.8          {q8}, [r1]!
        vld1.8          {q9}, [r1]!
@@ -843,10 +838,10 @@ ENTRY(aesbs_ctr_encrypt)
 1:     bne             2f
        vld1.8          {q15}, [r1]!
 
-2:     __adr           ip, 3f
+2:     adr             ip, 3f
        cmp             r5, #8
        sub             ip, ip, lr, lsl #3
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        veor            q0, q0, q8
        vst1.8          {q0}, [r0]!
@@ -900,12 +895,12 @@ __xts_prepare8:
        vshr.u64        d30, d31, #7
        vmov            q12, q14
 
-       __adr           ip, 0f
+       adr             ip, 0f
        and             r4, r6, #7
        cmp             r6, #8
        sub             ip, ip, r4, lsl #5
        mov             r4, sp
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        vld1.8          {q0}, [r1]!
        next_tweak      q12, q14, q15, q13
@@ -961,8 +956,7 @@ ENDPROC(__xts_prepare8)
        push            {r4-r8, lr}
        mov             r5, sp                  // preserve sp
        ldrd            r6, r7, [sp, #24]       // get blocks and iv args
-       ldr             r8, [sp, #32]           // reorder final tweak?
-       rsb             r8, r8, #1
+       rsb             r8, ip, #1
        sub             ip, sp, #128            // make room for 8x tweak
        bic             ip, ip, #0xf            // align sp to 16 bytes
        mov             sp, ip
@@ -973,12 +967,12 @@ ENDPROC(__xts_prepare8)
        mov             rounds, r3
        bl              \do8
 
-       __adr           ip, 0f
+       adr             ip, 0f
        and             lr, r6, #7
        cmp             r6, #8
        sub             ip, ip, lr, lsl #2
        mov             r4, sp
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        vld1.8          {q8}, [r4, :128]!
        vld1.8          {q9}, [r4, :128]!
@@ -989,9 +983,9 @@ ENDPROC(__xts_prepare8)
        vld1.8          {q14}, [r4, :128]!
        vld1.8          {q15}, [r4, :128]
 
-0:     __adr           ip, 1f
+0:     adr             ip, 1f
        sub             ip, ip, lr, lsl #3
-       bxlt            ip                      // computed goto if blocks < 8
+       movlt           pc, ip                  // computed goto if blocks < 8
 
        veor            \o0, \o0, q8
        vst1.8          {\o0}, [r0]!
@@ -1018,9 +1012,11 @@ ENDPROC(__xts_prepare8)
        .endm
 
 ENTRY(aesbs_xts_encrypt)
+       mov             ip, #0                  // never reorder final tweak
        __xts_crypt     aesbs_encrypt8, q0, q1, q4, q6, q3, q7, q2, q5
 ENDPROC(aesbs_xts_encrypt)
 
 ENTRY(aesbs_xts_decrypt)
+       ldr             ip, [sp, #8]            // reorder final tweak?
        __xts_crypt     aesbs_decrypt8, q0, q1, q6, q4, q2, q7, q3, q5
 ENDPROC(aesbs_xts_decrypt)
index e6fd329..bda8bf1 100644 (file)
@@ -8,7 +8,6 @@
 #include <asm/neon.h>
 #include <asm/simd.h>
 #include <crypto/aes.h>
-#include <crypto/cbc.h>
 #include <crypto/ctr.h>
 #include <crypto/internal/simd.h>
 #include <crypto/internal/skcipher.h>
@@ -49,7 +48,7 @@ struct aesbs_ctx {
 
 struct aesbs_cbc_ctx {
        struct aesbs_ctx        key;
-       struct crypto_cipher    *enc_tfm;
+       struct crypto_skcipher  *enc_tfm;
 };
 
 struct aesbs_xts_ctx {
@@ -140,19 +139,23 @@ static int aesbs_cbc_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
        kernel_neon_end();
        memzero_explicit(&rk, sizeof(rk));
 
-       return crypto_cipher_setkey(ctx->enc_tfm, in_key, key_len);
+       return crypto_skcipher_setkey(ctx->enc_tfm, in_key, key_len);
 }
 
-static void cbc_encrypt_one(struct crypto_skcipher *tfm, const u8 *src, u8 *dst)
+static int cbc_encrypt(struct skcipher_request *req)
 {
+       struct skcipher_request *subreq = skcipher_request_ctx(req);
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
        struct aesbs_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-       crypto_cipher_encrypt_one(ctx->enc_tfm, dst, src);
-}
+       skcipher_request_set_tfm(subreq, ctx->enc_tfm);
+       skcipher_request_set_callback(subreq,
+                                     skcipher_request_flags(req),
+                                     NULL, NULL);
+       skcipher_request_set_crypt(subreq, req->src, req->dst,
+                                  req->cryptlen, req->iv);
 
-static int cbc_encrypt(struct skcipher_request *req)
-{
-       return crypto_cbc_encrypt_walk(req, cbc_encrypt_one);
+       return crypto_skcipher_encrypt(subreq);
 }
 
 static int cbc_decrypt(struct skcipher_request *req)
@@ -183,20 +186,27 @@ static int cbc_decrypt(struct skcipher_request *req)
        return err;
 }
 
-static int cbc_init(struct crypto_tfm *tfm)
+static int cbc_init(struct crypto_skcipher *tfm)
 {
-       struct aesbs_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct aesbs_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
+       unsigned int reqsize;
 
-       ctx->enc_tfm = crypto_alloc_cipher("aes", 0, 0);
+       ctx->enc_tfm = crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(ctx->enc_tfm))
+               return PTR_ERR(ctx->enc_tfm);
 
-       return PTR_ERR_OR_ZERO(ctx->enc_tfm);
+       reqsize = sizeof(struct skcipher_request);
+       reqsize += crypto_skcipher_reqsize(ctx->enc_tfm);
+       crypto_skcipher_set_reqsize(tfm, reqsize);
+
+       return 0;
 }
 
-static void cbc_exit(struct crypto_tfm *tfm)
+static void cbc_exit(struct crypto_skcipher *tfm)
 {
-       struct aesbs_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct aesbs_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
 
-       crypto_free_cipher(ctx->enc_tfm);
+       crypto_free_skcipher(ctx->enc_tfm);
 }
 
 static int aesbs_ctr_setkey_sync(struct crypto_skcipher *tfm, const u8 *in_key,
@@ -304,9 +314,9 @@ static int aesbs_xts_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
        return aesbs_setkey(tfm, in_key, key_len);
 }
 
-static int xts_init(struct crypto_tfm *tfm)
+static int xts_init(struct crypto_skcipher *tfm)
 {
-       struct aesbs_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct aesbs_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
        ctx->cts_tfm = crypto_alloc_cipher("aes", 0, 0);
        if (IS_ERR(ctx->cts_tfm))
@@ -319,9 +329,9 @@ static int xts_init(struct crypto_tfm *tfm)
        return PTR_ERR_OR_ZERO(ctx->tweak_tfm);
 }
 
-static void xts_exit(struct crypto_tfm *tfm)
+static void xts_exit(struct crypto_skcipher *tfm)
 {
-       struct aesbs_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct aesbs_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
 
        crypto_free_cipher(ctx->tweak_tfm);
        crypto_free_cipher(ctx->cts_tfm);
@@ -432,8 +442,6 @@ static struct skcipher_alg aes_algs[] = { {
        .base.cra_ctxsize       = sizeof(struct aesbs_cbc_ctx),
        .base.cra_module        = THIS_MODULE,
        .base.cra_flags         = CRYPTO_ALG_INTERNAL,
-       .base.cra_init          = cbc_init,
-       .base.cra_exit          = cbc_exit,
 
        .min_keysize            = AES_MIN_KEY_SIZE,
        .max_keysize            = AES_MAX_KEY_SIZE,
@@ -442,6 +450,8 @@ static struct skcipher_alg aes_algs[] = { {
        .setkey                 = aesbs_cbc_setkey,
        .encrypt                = cbc_encrypt,
        .decrypt                = cbc_decrypt,
+       .init                   = cbc_init,
+       .exit                   = cbc_exit,
 }, {
        .base.cra_name          = "__ctr(aes)",
        .base.cra_driver_name   = "__ctr-aes-neonbs",
@@ -483,8 +493,6 @@ static struct skcipher_alg aes_algs[] = { {
        .base.cra_ctxsize       = sizeof(struct aesbs_xts_ctx),
        .base.cra_module        = THIS_MODULE,
        .base.cra_flags         = CRYPTO_ALG_INTERNAL,
-       .base.cra_init          = xts_init,
-       .base.cra_exit          = xts_exit,
 
        .min_keysize            = 2 * AES_MIN_KEY_SIZE,
        .max_keysize            = 2 * AES_MAX_KEY_SIZE,
@@ -493,6 +501,8 @@ static struct skcipher_alg aes_algs[] = { {
        .setkey                 = aesbs_xts_setkey,
        .encrypt                = xts_encrypt,
        .decrypt                = xts_decrypt,
+       .init                   = xts_init,
+       .exit                   = xts_exit,
 } };
 
 static struct simd_skcipher_alg *aes_simd_algs[ARRAY_SIZE(aes_algs)];
index 776ae07..31eb75b 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/jump_label.h>
+#include <linux/scatterlist.h>
 #include <crypto/curve25519.h>
 
 asmlinkage void curve25519_neon(u8 mypublic[CURVE25519_KEY_SIZE],
index 13cfef4..3023c1a 100644 (file)
@@ -20,6 +20,7 @@
 
 void poly1305_init_arm(void *state, const u8 *key);
 void poly1305_blocks_arm(void *state, const u8 *src, u32 len, u32 hibit);
+void poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit);
 void poly1305_emit_arm(void *state, u8 *digest, const u32 *nonce);
 
 void __weak poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit)
index 9f96ff4..f3a2b54 100644 (file)
@@ -175,7 +175,6 @@ $code=<<___;
 #else
 .syntax unified
 # ifdef __thumb2__
-#  define adrl adr
 .thumb
 # else
 .code   32
@@ -471,7 +470,8 @@ sha256_block_data_order_neon:
        stmdb   sp!,{r4-r12,lr}
 
        sub     $H,sp,#16*4+16
-       adrl    $Ktbl,K256
+       adr     $Ktbl,.Lsha256_block_data_order
+       sub     $Ktbl,$Ktbl,#.Lsha256_block_data_order-K256
        bic     $H,$H,#15               @ align for 128-bit stores
        mov     $t2,sp
        mov     sp,$H                   @ alloca
index ea04b2a..6363014 100644 (file)
@@ -56,7 +56,6 @@
 #else
 .syntax unified
 # ifdef __thumb2__
-#  define adrl adr
 .thumb
 # else
 .code   32
@@ -1885,7 +1884,8 @@ sha256_block_data_order_neon:
        stmdb   sp!,{r4-r12,lr}
 
        sub     r11,sp,#16*4+16
-       adrl    r14,K256
+       adr     r14,.Lsha256_block_data_order
+       sub     r14,r14,#.Lsha256_block_data_order-K256
        bic     r11,r11,#15             @ align for 128-bit stores
        mov     r12,sp
        mov     sp,r11                  @ alloca
index 69df689..2fc3516 100644 (file)
@@ -212,7 +212,6 @@ $code=<<___;
 #else
 .syntax unified
 # ifdef __thumb2__
-#  define adrl adr
 .thumb
 # else
 .code   32
@@ -602,7 +601,8 @@ sha512_block_data_order_neon:
        dmb                             @ errata #451034 on early Cortex A8
        add     $len,$inp,$len,lsl#7    @ len to point at the end of inp
        VFP_ABI_PUSH
-       adrl    $Ktbl,K512
+       adr     $Ktbl,.Lsha512_block_data_order
+       sub     $Ktbl,$Ktbl,.Lsha512_block_data_order-K512
        vldmia  $ctx,{$A-$H}            @ load context
 .Loop_neon:
 ___
index cb147db..0301462 100644 (file)
@@ -79,7 +79,6 @@
 #else
 .syntax unified
 # ifdef __thumb2__
-#  define adrl adr
 .thumb
 # else
 .code   32
@@ -543,7 +542,8 @@ sha512_block_data_order_neon:
        dmb                             @ errata #451034 on early Cortex A8
        add     r2,r1,r2,lsl#7  @ len to point at the end of inp
        VFP_ABI_PUSH
-       adrl    r3,K512
+       adr     r3,.Lsha512_block_data_order
+       sub     r3,r3,.Lsha512_block_data_order-K512
        vldmia  r0,{d16-d23}            @ load context
 .Loop_neon:
        vshr.u64        d24,d20,#14     @ 0
index ed6073f..f0f54ae 100644 (file)
@@ -35,23 +35,20 @@ __wsum csum_partial(const void *buff, int len, __wsum sum);
  */
 
 __wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum);
+csum_partial_copy_nocheck(const void *src, void *dst, int len);
 
 __wsum
-csum_partial_copy_from_user(const void __user *src, void *dst, int len, __wsum sum, int *err_ptr);
+csum_partial_copy_from_user(const void __user *src, void *dst, int len);
 
 #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
+#define _HAVE_ARCH_CSUM_AND_COPY
 static inline
-__wsum csum_and_copy_from_user (const void __user *src, void *dst,
-                                     int len, __wsum sum, int *err_ptr)
+__wsum csum_and_copy_from_user(const void __user *src, void *dst, int len)
 {
-       if (access_ok(src, len))
-               return csum_partial_copy_from_user(src, dst, len, sum, err_ptr);
+       if (!access_ok(src, len))
+               return 0;
 
-       if (len)
-               *err_ptr = -EFAULT;
-
-       return sum;
+       return csum_partial_copy_from_user(src, dst, len);
 }
 
 /*
index 5dcf3c6..3ee4f43 100644 (file)
@@ -66,25 +66,24 @@ static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
 #define MAX_UNCOMP_KERNEL_SIZE SZ_32M
 
 /*
- * The kernel zImage should preferably be located between 32 MB and 128 MB
- * from the base of DRAM. The min address leaves space for a maximal size
- * uncompressed image, and the max address is due to how the zImage decompressor
- * picks a destination address.
+ * phys-to-virt patching requires that the physical to virtual offset fits
+ * into the immediate field of an add/sub instruction, which comes down to the
+ * 24 least significant bits being zero, and so the offset should be a multiple
+ * of 16 MB. Since PAGE_OFFSET itself is a multiple of 16 MB, the physical
+ * base should be aligned to 16 MB as well.
  */
-#define ZIMAGE_OFFSET_LIMIT    SZ_128M
-#define MIN_ZIMAGE_OFFSET      MAX_UNCOMP_KERNEL_SIZE
+#define EFI_PHYS_ALIGN         SZ_16M
 
-/* on ARM, the FDT should be located in the first 128 MB of RAM */
-static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
+/* on ARM, the FDT should be located in a lowmem region */
+static inline unsigned long efi_get_max_fdt_addr(unsigned long image_addr)
 {
-       return dram_base + ZIMAGE_OFFSET_LIMIT;
+       return round_down(image_addr, EFI_PHYS_ALIGN) + SZ_512M;
 }
 
 /* on ARM, the initrd should be loaded in a lowmem region */
-static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
-                                                   unsigned long image_addr)
+static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
 {
-       return dram_base + SZ_512M;
+       return round_down(image_addr, EFI_PHYS_ALIGN) + SZ_512M;
 }
 
 struct efi_arm_entry_state {
index 7a88f16..b95848e 100644 (file)
@@ -6,29 +6,12 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-/* number of IPIS _not_ including IPI_CPU_BACKTRACE */
-#define NR_IPI 7
-
 typedef struct {
        unsigned int __softirq_pending;
-#ifdef CONFIG_SMP
-       unsigned int ipi_irqs[NR_IPI];
-#endif
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
 
-#define __inc_irq_stat(cpu, member)    __IRQ_STAT(cpu, member)++
-#define __get_irq_stat(cpu, member)    __IRQ_STAT(cpu, member)
-
-#ifdef CONFIG_SMP
-u64 smp_irq_stat_cpu(unsigned int cpu);
-#else
-#define smp_irq_stat_cpu(cpu)  0
-#endif
-
-#define arch_irq_stat_cpu      smp_irq_stat_cpu
-
 #define __ARCH_IRQ_EXIT_IRQS_DISABLED  1
 
 #endif /* __ASM_HARDIRQ_H */
index a91f21e..0ca55a6 100644 (file)
@@ -39,11 +39,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs);
  */
 extern void smp_init_cpus(void);
 
-
 /*
- * Provide a function to raise an IPI cross call on CPUs in callmap.
+ * Register IPI interrupts with the arch SMP code
  */
-extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int));
+extern void set_smp_ipi_range(int ipi_base, int nr_ipi);
 
 /*
  * Called from platform specific assembly code, this is the
similarity index 84%
rename from arch/arm/kernel/vmlinux.lds.h
rename to arch/arm/include/asm/vmlinux.lds.h
index 381a8e1..4a91428 100644 (file)
@@ -1,4 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
+#include <asm-generic/vmlinux.lds.h>
 
 #ifdef CONFIG_HOTPLUG_CPU
 #define ARM_CPU_DISCARD(x)
                EXIT_CALL                                               \
                ARM_MMU_DISCARD(*(.text.fixup))                         \
                ARM_MMU_DISCARD(*(__ex_table))                          \
-               *(.discard)                                             \
-               *(.discard.*)
+               COMMON_DISCARDS
+
+/*
+ * Sections that should stay zero sized, which is safer to explicitly
+ * check instead of blindly discarding.
+ */
+#define ARM_ASSERTS                                                    \
+       .plt : {                                                        \
+               *(.iplt) *(.rel.iplt) *(.iplt) *(.igot.plt)             \
+       }                                                               \
+       ASSERT(SIZEOF(.plt) == 0,                                       \
+              "Unexpected run-time procedure linkages detected!")
+
+#define ARM_DETAILS                                                    \
+               ELF_DETAILS                                             \
+               .ARM.attributes 0 : { *(.ARM.attributes) }
+
+#define ARM_STUBS_TEXT                                                 \
+               *(.gnu.warning)                                         \
+               *(.glue_7)                                              \
+               *(.glue_7t)                                             \
+               *(.vfp11_veneer)                                        \
+               *(.v4_bx)
 
 #define ARM_TEXT                                                       \
                IDMAP_TEXT                                              \
@@ -64,9 +86,7 @@
                CPUIDLE_TEXT                                            \
                LOCK_TEXT                                               \
                KPROBES_TEXT                                            \
-               *(.gnu.warning)                                         \
-               *(.glue_7)                                              \
-               *(.glue_7t)                                             \
+               ARM_STUBS_TEXT                                          \
                . = ALIGN(4);                                           \
                *(.got)                 /* Global offset table */       \
                ARM_CPU_KEEP(PROC_INFO)
index 7fff88e..7a4853b 100644 (file)
@@ -547,7 +547,7 @@ static int arch_build_bp_info(struct perf_event *bp,
                if ((hw->ctrl.type != ARM_BREAKPOINT_EXECUTE)
                        && max_watchpoint_len >= 8)
                        break;
-               /* Else, fall through */
+               fallthrough;
        default:
                return -EINVAL;
        }
@@ -612,12 +612,12 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
                /* Allow halfword watchpoints and breakpoints. */
                if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2)
                        break;
-               /* Else, fall through */
+               fallthrough;
        case 3:
                /* Allow single byte watchpoint. */
                if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1)
                        break;
-               /* Else, fall through */
+               fallthrough;
        default:
                ret = -EINVAL;
                goto out;
@@ -884,7 +884,7 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
                break;
        case ARM_ENTRY_ASYNC_WATCHPOINT:
                WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n");
-               /* Fall through */
+               fallthrough;
        case ARM_ENTRY_SYNC_WATCHPOINT:
                watchpoint_handler(addr, fsr, regs);
                break;
@@ -933,7 +933,7 @@ static bool core_has_os_save_restore(void)
                ARM_DBG_READ(c1, c1, 4, oslsr);
                if (oslsr & ARM_OSLSR_OSLM0)
                        return true;
-               /* Else, fall through */
+               fallthrough;
        default:
                return false;
        }
index ee51403..698b6f6 100644 (file)
@@ -18,7 +18,6 @@
  *  IRQ's are in fact implemented a bit like signal handlers for the kernel.
  *  Naturally it's not a 1:1 relation, but there are similarities.
  */
-#include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
index c9dc912..c1892f7 100644 (file)
@@ -596,7 +596,7 @@ static int do_signal(struct pt_regs *regs, int syscall)
                switch (retval) {
                case -ERESTART_RESTARTBLOCK:
                        restart -= 2;
-                       /* Fall through */
+                       fallthrough;
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
index 5d9da61..48099c6 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/completion.h>
 #include <linux/cpufreq.h>
 #include <linux/irq_work.h>
+#include <linux/kernel_stat.h>
 
 #include <linux/atomic.h>
 #include <asm/bugs.h>
@@ -65,18 +66,26 @@ enum ipi_msg_type {
        IPI_CPU_STOP,
        IPI_IRQ_WORK,
        IPI_COMPLETION,
+       NR_IPI,
        /*
         * CPU_BACKTRACE is special and not included in NR_IPI
         * or tracable with trace_ipi_*
         */
-       IPI_CPU_BACKTRACE,
+       IPI_CPU_BACKTRACE = NR_IPI,
        /*
         * SGI8-15 can be reserved by secure firmware, and thus may
         * not be usable by the kernel. Please keep the above limited
         * to at most 8 entries.
         */
+       MAX_IPI
 };
 
+static int ipi_irq_base __read_mostly;
+static int nr_ipi __read_mostly = NR_IPI;
+static struct irq_desc *ipi_desc[MAX_IPI] __read_mostly;
+
+static void ipi_setup(int cpu);
+
 static DECLARE_COMPLETION(cpu_running);
 
 static struct smp_operations smp_ops __ro_after_init;
@@ -226,6 +235,17 @@ int platform_can_hotplug_cpu(unsigned int cpu)
        return cpu != 0;
 }
 
+static void ipi_teardown(int cpu)
+{
+       int i;
+
+       if (WARN_ON_ONCE(!ipi_irq_base))
+               return;
+
+       for (i = 0; i < nr_ipi; i++)
+               disable_percpu_irq(ipi_irq_base + i);
+}
+
 /*
  * __cpu_disable runs on the processor to be shutdown.
  */
@@ -247,6 +267,7 @@ int __cpu_disable(void)
         * and we must not schedule until we're ready to give up the cpu.
         */
        set_cpu_online(cpu, false);
+       ipi_teardown(cpu);
 
        /*
         * OK - migrate IRQs away from this CPU
@@ -422,6 +443,8 @@ asmlinkage void secondary_start_kernel(void)
 
        notify_cpu_starting(cpu);
 
+       ipi_setup(cpu);
+
        calibrate_delay();
 
        smp_store_cpu_info(cpu);
@@ -500,14 +523,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        }
 }
 
-static void (*__smp_cross_call)(const struct cpumask *, unsigned int);
-
-void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
-{
-       if (!__smp_cross_call)
-               __smp_cross_call = fn;
-}
-
 static const char *ipi_types[NR_IPI] __tracepoint_string = {
 #define S(x,s) [x] = s
        S(IPI_WAKEUP, "CPU wakeup interrupts"),
@@ -519,38 +534,28 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
        S(IPI_COMPLETION, "completion interrupts"),
 };
 
-static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
-{
-       trace_ipi_raise_rcuidle(target, ipi_types[ipinr]);
-       __smp_cross_call(target, ipinr);
-}
+static void smp_cross_call(const struct cpumask *target, unsigned int ipinr);
 
 void show_ipi_list(struct seq_file *p, int prec)
 {
        unsigned int cpu, i;
 
        for (i = 0; i < NR_IPI; i++) {
+               unsigned int irq;
+
+               if (!ipi_desc[i])
+                       continue;
+
+               irq = irq_desc_get_irq(ipi_desc[i]);
                seq_printf(p, "%*s%u: ", prec - 1, "IPI", i);
 
                for_each_online_cpu(cpu)
-                       seq_printf(p, "%10u ",
-                                  __get_irq_stat(cpu, ipi_irqs[i]));
+                       seq_printf(p, "%10u ", kstat_irqs_cpu(irq, cpu));
 
                seq_printf(p, " %s\n", ipi_types[i]);
        }
 }
 
-u64 smp_irq_stat_cpu(unsigned int cpu)
-{
-       u64 sum = 0;
-       int i;
-
-       for (i = 0; i < NR_IPI; i++)
-               sum += __get_irq_stat(cpu, ipi_irqs[i]);
-
-       return sum;
-}
-
 void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 {
        smp_cross_call(mask, IPI_CALL_FUNC);
@@ -627,15 +632,12 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
        handle_IPI(ipinr, regs);
 }
 
-void handle_IPI(int ipinr, struct pt_regs *regs)
+static void do_handle_IPI(int ipinr)
 {
        unsigned int cpu = smp_processor_id();
-       struct pt_regs *old_regs = set_irq_regs(regs);
 
-       if ((unsigned)ipinr < NR_IPI) {
+       if ((unsigned)ipinr < NR_IPI)
                trace_ipi_entry_rcuidle(ipi_types[ipinr]);
-               __inc_irq_stat(cpu, ipi_irqs[ipinr]);
-       }
 
        switch (ipinr) {
        case IPI_WAKEUP:
@@ -643,9 +645,7 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 
 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
        case IPI_TIMER:
-               irq_enter();
                tick_receive_broadcast();
-               irq_exit();
                break;
 #endif
 
@@ -654,36 +654,26 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
                break;
 
        case IPI_CALL_FUNC:
-               irq_enter();
                generic_smp_call_function_interrupt();
-               irq_exit();
                break;
 
        case IPI_CPU_STOP:
-               irq_enter();
                ipi_cpu_stop(cpu);
-               irq_exit();
                break;
 
 #ifdef CONFIG_IRQ_WORK
        case IPI_IRQ_WORK:
-               irq_enter();
                irq_work_run();
-               irq_exit();
                break;
 #endif
 
        case IPI_COMPLETION:
-               irq_enter();
                ipi_complete(cpu);
-               irq_exit();
                break;
 
        case IPI_CPU_BACKTRACE:
                printk_nmi_enter();
-               irq_enter();
-               nmi_cpu_backtrace(regs);
-               irq_exit();
+               nmi_cpu_backtrace(get_irq_regs());
                printk_nmi_exit();
                break;
 
@@ -695,9 +685,67 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 
        if ((unsigned)ipinr < NR_IPI)
                trace_ipi_exit_rcuidle(ipi_types[ipinr]);
+}
+
+/* Legacy version, should go away once all irqchips have been converted */
+void handle_IPI(int ipinr, struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
+
+       irq_enter();
+       do_handle_IPI(ipinr);
+       irq_exit();
+
        set_irq_regs(old_regs);
 }
 
+static irqreturn_t ipi_handler(int irq, void *data)
+{
+       do_handle_IPI(irq - ipi_irq_base);
+       return IRQ_HANDLED;
+}
+
+static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
+{
+       trace_ipi_raise_rcuidle(target, ipi_types[ipinr]);
+       __ipi_send_mask(ipi_desc[ipinr], target);
+}
+
+static void ipi_setup(int cpu)
+{
+       int i;
+
+       if (WARN_ON_ONCE(!ipi_irq_base))
+               return;
+
+       for (i = 0; i < nr_ipi; i++)
+               enable_percpu_irq(ipi_irq_base + i, 0);
+}
+
+void __init set_smp_ipi_range(int ipi_base, int n)
+{
+       int i;
+
+       WARN_ON(n < MAX_IPI);
+       nr_ipi = min(n, MAX_IPI);
+
+       for (i = 0; i < nr_ipi; i++) {
+               int err;
+
+               err = request_percpu_irq(ipi_base + i, ipi_handler,
+                                        "IPI", &irq_stat);
+               WARN_ON(err);
+
+               ipi_desc[i] = irq_to_desc(ipi_base + i);
+               irq_set_status_flags(ipi_base + i, IRQ_HIDDEN);
+       }
+
+       ipi_irq_base = ipi_base;
+
+       /* Setup the boot CPU immediately */
+       ipi_setup(smp_processor_id());
+}
+
 void smp_send_reschedule(int cpu)
 {
        smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
@@ -805,7 +853,7 @@ core_initcall(register_cpufreq_notifier);
 
 static void raise_nmi(cpumask_t *mask)
 {
-       __smp_cross_call(mask, IPI_CPU_BACKTRACE);
+       __ipi_send_mask(ipi_desc[IPI_CPU_BACKTRACE], mask);
 }
 
 void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
index b5adaf7..ef0058d 100644 (file)
@@ -178,15 +178,6 @@ static inline void update_cpu_capacity(unsigned int cpuid) {}
 #endif
 
 /*
- * The current assumption is that we can power gate each core independently.
- * This will be superseded by DT binding once available.
- */
-const struct cpumask *cpu_corepower_mask(int cpu)
-{
-       return &cpu_topology[cpu].thread_sibling;
-}
-
-/*
  * store_cpu_topology is called at boot when only one cpu is running
  * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
  * which prevents simultaneous write access to cpu_topology array
@@ -241,20 +232,6 @@ topology_populated:
        update_siblings_masks(cpuid);
 }
 
-static inline int cpu_corepower_flags(void)
-{
-       return SD_SHARE_PKG_RESOURCES  | SD_SHARE_POWERDOMAIN;
-}
-
-static struct sched_domain_topology_level arm_topology[] = {
-#ifdef CONFIG_SCHED_MC
-       { cpu_corepower_mask, cpu_corepower_flags, SD_INIT_NAME(GMC) },
-       { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
-#endif
-       { cpu_cpu_mask, SD_INIT_NAME(DIE) },
-       { NULL, },
-};
-
 /*
  * init_cpu_topology is called at boot when only one cpu is running
  * which prevent simultaneous write access to cpu_topology array
@@ -265,7 +242,4 @@ void __init init_cpu_topology(void)
        smp_wmb();
 
        parse_dt_topology();
-
-       /* Set scheduler topology descriptor */
-       set_sched_topology(arm_topology);
 }
index 6d2be99..5013682 100644 (file)
@@ -9,15 +9,13 @@
 
 #include <linux/sizes.h>
 
-#include <asm-generic/vmlinux.lds.h>
+#include <asm/vmlinux.lds.h>
 #include <asm/cache.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
 #include <asm/mpu.h>
 #include <asm/page.h>
 
-#include "vmlinux.lds.h"
-
 OUTPUT_ARCH(arm)
 ENTRY(stext)
 
@@ -152,6 +150,10 @@ SECTIONS
        _end = .;
 
        STABS_DEBUG
+       DWARF_DEBUG
+       ARM_DETAILS
+
+       ARM_ASSERTS
 }
 
 /*
index 7f24bc0..5f4922e 100644 (file)
@@ -9,15 +9,13 @@
 #else
 
 #include <linux/pgtable.h>
-#include <asm-generic/vmlinux.lds.h>
+#include <asm/vmlinux.lds.h>
 #include <asm/cache.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
 #include <asm/mpu.h>
 #include <asm/page.h>
 
-#include "vmlinux.lds.h"
-
 OUTPUT_ARCH(arm)
 ENTRY(stext)
 
@@ -151,6 +149,10 @@ SECTIONS
        _end = .;
 
        STABS_DEBUG
+       DWARF_DEBUG
+       ARM_DETAILS
+
+       ARM_ASSERTS
 }
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
index 184d972..1ca6aad 100644 (file)
@@ -9,8 +9,8 @@
 
                .text
 
-/* Function: __u32 csum_partial_copy_nocheck(const char *src, char *dst, int len, __u32 sum)
- * Params  : r0 = src, r1 = dst, r2 = len, r3 = checksum
+/* Function: __u32 csum_partial_copy_nocheck(const char *src, char *dst, int len)
+ * Params  : r0 = src, r1 = dst, r2 = len
  * Returns : r0 = new checksum
  */
 
index 0b706a3..0fd5c10 100644 (file)
@@ -86,6 +86,7 @@ sum   .req    r3
 
 FN_ENTRY
                save_regs
+               mov     sum, #-1
 
                cmp     len, #8                 @ Ensure that we have at least
                blo     .Lless8                 @ 8 bytes to copy.
index 6bd3a93..6928781 100644 (file)
@@ -62,9 +62,9 @@
 
 /*
  * unsigned int
- * csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *err_ptr)
- *  r0 = src, r1 = dst, r2 = len, r3 = sum, [sp] = *err_ptr
- *  Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT
+ * csum_partial_copy_from_user(const char *src, char *dst, int len)
+ *  r0 = src, r1 = dst, r2 = len
+ *  Returns : r0 = checksum or 0
  */
 
 #define FN_ENTRY       ENTRY(csum_partial_copy_from_user)
 #include "csumpartialcopygeneric.S"
 
 /*
- * FIXME: minor buglet here
- * We don't return the checksum for the data present in the buffer.  To do
- * so properly, we would have to add in whatever registers were loaded before
- * the fault, which, with the current asm above is not predictable.
+ * We report fault by returning 0 csum - impossible in normal case, since
+ * we start with 0xffffffff for initial sum.
  */
                .pushsection .text.fixup,"ax"
                .align  4
-9001:          mov     r4, #-EFAULT
-#ifdef CONFIG_CPU_SW_DOMAIN_PAN
-               ldr     r5, [sp, #9*4]          @ *err_ptr
-#else
-               ldr     r5, [sp, #8*4]          @ *err_ptr
-#endif
-               str     r4, [r5]
-               ldmia   sp, {r1, r2}            @ retrieve dst, len
-               add     r2, r2, r1
-               mov     r0, #0                  @ zero the buffer
-9002:          teq     r2, r1
-               strbne  r0, [r1], #1
-               bne     9002b
+9001:          mov     r0, #0
                load_regs
                .popsection
index 1c05c5b..757032d 100644 (file)
@@ -49,7 +49,7 @@ static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
                 * FALLTHROUGH: Ensure we don't try to overwrite our newly
                 * initialised state information on the first fault.
                 */
-               /* Fall through */
+               fallthrough;
 
        case THREAD_NOTIFY_EXIT:
                crunch_task_release(thread);
index 24dd5bb..094337d 100644 (file)
@@ -24,7 +24,9 @@ static int imx6q_enter_wait(struct cpuidle_device *dev,
                imx6_set_lpm(WAIT_UNCLOCKED);
        raw_spin_unlock(&cpuidle_lock);
 
+       rcu_idle_enter();
        cpu_do_idle();
+       rcu_idle_exit();
 
        raw_spin_lock(&cpuidle_lock);
        if (num_idle_cpus-- == num_online_cpus())
@@ -44,7 +46,7 @@ static struct cpuidle_driver imx6q_cpuidle_driver = {
                {
                        .exit_latency = 50,
                        .target_residency = 75,
-                       .flags = CPUIDLE_FLAG_TIMER_STOP,
+                       .flags = CPUIDLE_FLAG_TIMER_STOP | CPUIDLE_FLAG_RCU_IDLE,
                        .enter = imx6q_enter_wait,
                        .name = "WAIT",
                        .desc = "Clock off",
index 2d86381..7a6f74c 100644 (file)
@@ -123,19 +123,19 @@ void mmp2_pm_enter_lowpower_mode(int state)
        case POWER_MODE_SYS_SLEEP:
                apcr |= MPMU_PCR_PJ_SLPEN;              /* set the SLPEN bit */
                apcr |= MPMU_PCR_PJ_VCTCXOSD;           /* set VCTCXOSD */
-               /* fall through */
+               fallthrough;
        case POWER_MODE_CHIP_SLEEP:
                apcr |= MPMU_PCR_PJ_SLPEN;
-               /* fall through */
+               fallthrough;
        case POWER_MODE_APPS_SLEEP:
                apcr |= MPMU_PCR_PJ_APBSD;              /* set APBSD */
-               /* fall through */
+               fallthrough;
        case POWER_MODE_APPS_IDLE:
                apcr |= MPMU_PCR_PJ_AXISD;              /* set AXISDD bit */
                apcr |= MPMU_PCR_PJ_DDRCORSD;           /* set DDRCORSD bit */
                idle_cfg |= APMU_PJ_IDLE_CFG_PJ_PWRDWN; /* PJ power down */
                apcr |= MPMU_PCR_PJ_SPSD;
-               /* fall through */
+               fallthrough;
        case POWER_MODE_CORE_EXTIDLE:
                idle_cfg |= APMU_PJ_IDLE_CFG_PJ_IDLE;   /* set the IDLE bit */
                idle_cfg &= ~APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK;
index 69ebe18..1d71d73 100644 (file)
@@ -145,23 +145,23 @@ void pxa910_pm_enter_lowpower_mode(int state)
        case POWER_MODE_UDR:
                /* only shutdown APB in UDR */
                apcr |= MPMU_APCR_STBYEN | MPMU_APCR_APBSD;
-               /* fall through */
+               fallthrough;
        case POWER_MODE_SYS_SLEEP:
                apcr |= MPMU_APCR_SLPEN;                /* set the SLPEN bit */
                apcr |= MPMU_APCR_VCTCXOSD;             /* set VCTCXOSD */
-               /* fall through */
+               fallthrough;
        case POWER_MODE_APPS_SLEEP:
                apcr |= MPMU_APCR_DDRCORSD;             /* set DDRCORSD */
-               /* fall through */
+               fallthrough;
        case POWER_MODE_APPS_IDLE:
                apcr |= MPMU_APCR_AXISD;                /* set AXISDD bit */
-               /* fall through */
+               fallthrough;
        case POWER_MODE_CORE_EXTIDLE:
                idle_cfg |= APMU_MOH_IDLE_CFG_MOH_IDLE;
                idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN;
                idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWR_SW(3)
                        | APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(3);
-               /* fall through */
+               fallthrough;
        case POWER_MODE_CORE_INTIDLE:
                break;
        }
index 1d119b9..59755b5 100644 (file)
@@ -396,7 +396,6 @@ void __init omap3xxx_check_revision(void)
                        cpu_rev = "3.1";
                        break;
                case 7:
-               /* FALLTHROUGH */
                default:
                        /* Use the latest known revision as default */
                        omap_revision = OMAP3430_REV_ES3_1_2;
@@ -416,7 +415,6 @@ void __init omap3xxx_check_revision(void)
                        cpu_rev = "1.0";
                        break;
                case 1:
-               /* FALLTHROUGH */
                default:
                        omap_revision = AM35XX_REV_ES1_1;
                        cpu_rev = "1.1";
@@ -435,7 +433,6 @@ void __init omap3xxx_check_revision(void)
                        cpu_rev = "1.1";
                        break;
                case 2:
-               /* FALLTHROUGH */
                default:
                        omap_revision = OMAP3630_REV_ES1_2;
                        cpu_rev = "1.2";
@@ -456,7 +453,6 @@ void __init omap3xxx_check_revision(void)
                        cpu_rev = "2.0";
                        break;
                case 3:
-                       /* FALLTHROUGH */
                default:
                        omap_revision = TI8168_REV_ES2_1;
                        cpu_rev = "2.1";
@@ -473,7 +469,6 @@ void __init omap3xxx_check_revision(void)
                        cpu_rev = "2.0";
                        break;
                case 2:
-               /* FALLTHROUGH */
                default:
                        omap_revision = AM335X_REV_ES2_1;
                        cpu_rev = "2.1";
@@ -491,7 +486,6 @@ void __init omap3xxx_check_revision(void)
                        cpu_rev = "1.1";
                        break;
                case 2:
-               /* FALLTHROUGH */
                default:
                        omap_revision = AM437X_REV_ES1_2;
                        cpu_rev = "1.2";
@@ -502,7 +496,6 @@ void __init omap3xxx_check_revision(void)
        case 0xb968:
                switch (rev) {
                case 0:
-               /* FALLTHROUGH */
                case 1:
                        omap_revision = TI8148_REV_ES1_0;
                        cpu_rev = "1.0";
@@ -512,7 +505,6 @@ void __init omap3xxx_check_revision(void)
                        cpu_rev = "2.0";
                        break;
                case 3:
-               /* FALLTHROUGH */
                default:
                        omap_revision = TI8148_REV_ES2_1;
                        cpu_rev = "2.1";
index 54aff33..bfa5e1b 100644 (file)
@@ -74,7 +74,7 @@ static struct powerdomain *_get_pwrdm(struct device *dev)
                return pwrdm;
 
        clk = of_clk_get(dev->of_node->parent, 0);
-       if (!clk) {
+       if (IS_ERR(clk)) {
                dev_err(dev, "no fck found\n");
                return NULL;
        }
index 6b4548f..fc7bb2c 100644 (file)
@@ -240,7 +240,7 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
                if (pdev->dev.of_node)
                        omap_device_build_from_dt(pdev);
                omap_auxdata_legacy_init(dev);
-               /* fall through */
+               fallthrough;
        default:
                od = to_omap_device(pdev);
                if (od)
index 6df395f..f5dfddf 100644 (file)
@@ -298,11 +298,7 @@ static void omap3_pm_idle(void)
        if (omap_irq_pending())
                return;
 
-       trace_cpu_idle_rcuidle(1, smp_processor_id());
-
        omap_sram_idle();
-
-       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 }
 
 #ifdef CONFIG_SUSPEND
index d13344b..87cb472 100644 (file)
@@ -624,7 +624,7 @@ static void __init dns323_init(void)
                 dns323ab_leds[0].active_low = 1;
                 gpio_request(DNS323_GPIO_LED_POWER1, "Power Led Enable");
                 gpio_direction_output(DNS323_GPIO_LED_POWER1, 0);
-               /* Fall through */
+               fallthrough;
        case DNS323_REV_B1:
                i2c_register_board_info(0, dns323ab_i2c_devices,
                                ARRAY_SIZE(dns323ab_i2c_devices));
index ea2c842..d23970b 100644 (file)
@@ -46,7 +46,7 @@ static int __init parse_tag_acorn(const struct tag *tag)
        switch (tag->u.acorn.vram_pages) {
        case 512:
                vram_size += PAGE_SIZE * 256;
-               /* Fall through - ??? */
+               fallthrough;    /* ??? */
        case 256:
                vram_size += PAGE_SIZE * 256;
        default:
index 76a65df..d5c805a 100644 (file)
@@ -70,7 +70,7 @@ static void __init tegra_cpu_reset_handler_enable(void)
        switch (err) {
        case -ENOSYS:
                tegra_cpu_reset_handler_set(reset_address);
-               /* fall through */
+               fallthrough;
        case 0:
                is_enabled = true;
                break;
index f4bfc1c..ea81e89 100644 (file)
@@ -694,7 +694,7 @@ thumb2arm(u16 tinstr)
                        return subset[(L<<1) | ((tinstr & (1<<8)) >> 8)] |
                            (tinstr & 255);             /* register_list */
                }
-               /* Else, fall through - for illegal instruction case */
+               fallthrough;    /* for illegal instruction case */
 
        default:
                return BAD_INSTR;
@@ -750,7 +750,7 @@ do_alignment_t32_to_handler(u32 *pinstr, struct pt_regs *regs,
        case 0xe8e0:
        case 0xe9e0:
                poffset->un = (tinst2 & 0xff) << 2;
-               /* Fall through */
+               fallthrough;
 
        case 0xe940:
        case 0xe9c0:
index c0fbfca..114c05a 100644 (file)
@@ -71,7 +71,7 @@ static void cpu_v7_spectre_init(void)
                /* Other ARM CPUs require no workaround */
                if (read_cpuid_implementor() == ARM_CPU_IMP_ARM)
                        break;
-               /* fallthrough */
+               fallthrough;
                /* Cortex A57/A72 require firmware workaround */
        case ARM_CPU_PART_CORTEX_A57:
        case ARM_CPU_PART_CORTEX_A72: {
index b2e9e82..1eb5900 100644 (file)
@@ -309,14 +309,14 @@ void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
                 * not supported by current hardware on OMAP1
                 * w |= (0x03 << 7);
                 */
-               /* fall through */
+               fallthrough;
        case OMAP_DMA_DATA_BURST_16:
                if (dma_omap2plus()) {
                        burst = 0x3;
                        break;
                }
                /* OMAP1 don't support burst 16 */
-               /* fall through */
+               fallthrough;
        default:
                BUG();
        }
@@ -393,7 +393,7 @@ void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
                        break;
                }
                /* OMAP1 don't support burst 16 */
-               /* fall through */
+               fallthrough;
        default:
                printk(KERN_ERR "Invalid DMA burst mode\n");
                BUG();
index fe81a9c..c84053a 100644 (file)
@@ -307,7 +307,7 @@ static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs, bool modify)
                case REG_TYPE_NOPCWB:
                        if (!is_writeback(insn))
                                break; /* No writeback, so any register is OK */
-                       /* fall through... */
+                       fallthrough;
                case REG_TYPE_NOPC:
                case REG_TYPE_NOPCX:
                        /* Reject PC (R15) */
index 90b5bc7..a965311 100644 (file)
@@ -280,7 +280,7 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
                                /* A nested probe was hit in FIQ, it is a BUG */
                                pr_warn("Unrecoverable kprobe detected.\n");
                                dump_kprobe(p);
-                               /* fall through */
+                               fallthrough;
                        default:
                                /* impossible cases */
                                BUG();
@@ -413,87 +413,15 @@ void __naked __kprobes kretprobe_trampoline(void)
 /* Called from kretprobe_trampoline */
 static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
-       kprobe_opcode_t *correct_ret_addr = NULL;
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because multiple functions in the call path have
-        * a return probe installed on them, and/or more than one return
-        * probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
-       correct_ret_addr = ri->ret_addr;
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               if (ri->rp && ri->rp->handler) {
-                       __this_cpu_write(current_kprobe, &ri->rp->kp);
-                       get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
-                       ri->ret_addr = correct_ret_addr;
-                       ri->rp->handler(ri, regs);
-                       __this_cpu_write(current_kprobe, NULL);
-               }
-
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
-
-       return (void *)orig_ret_address;
+       return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline,
+                                                   (void *)regs->ARM_fp);
 }
 
 void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                      struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr;
+       ri->fp = (void *)regs->ARM_fp;
 
        /* Replace the return addr with trampoline addr. */
        regs->ARM_lr = (unsigned long)&kretprobe_trampoline;
index e93145d..a6ab368 100644 (file)
@@ -150,7 +150,7 @@ static int xen_starting_cpu(unsigned int cpu)
        pr_info("Xen: initializing cpu%d\n", cpu);
        vcpup = per_cpu_ptr(xen_vcpu_info, cpu);
 
-       info.mfn = virt_to_gfn(vcpup);
+       info.mfn = percpu_to_gfn(vcpup);
        info.offset = xen_offset_in_page(vcpup);
 
        err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, xen_vcpu_nr(cpu),
index 6d23283..4b136e9 100644 (file)
@@ -29,6 +29,7 @@ config ARM64
        select ARCH_HAS_SETUP_DMA_OPS
        select ARCH_HAS_SET_DIRECT_MAP
        select ARCH_HAS_SET_MEMORY
+       select ARCH_STACKWALK
        select ARCH_HAS_STRICT_KERNEL_RWX
        select ARCH_HAS_STRICT_MODULE_RWX
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE
@@ -106,6 +107,7 @@ config ARM64
        select GENERIC_CPU_VULNERABILITIES
        select GENERIC_EARLY_IOREMAP
        select GENERIC_IDLE_POLL_SETUP
+       select GENERIC_IRQ_IPI
        select GENERIC_IRQ_MULTI_HANDLER
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
@@ -211,12 +213,18 @@ config ARM64_PAGE_SHIFT
        default 14 if ARM64_16K_PAGES
        default 12
 
-config ARM64_CONT_SHIFT
+config ARM64_CONT_PTE_SHIFT
        int
        default 5 if ARM64_64K_PAGES
        default 7 if ARM64_16K_PAGES
        default 4
 
+config ARM64_CONT_PMD_SHIFT
+       int
+       default 5 if ARM64_64K_PAGES
+       default 5 if ARM64_16K_PAGES
+       default 4
+
 config ARCH_MMAP_RND_BITS_MIN
        default 14 if ARM64_64K_PAGES
        default 16 if ARM64_16K_PAGES
@@ -1165,32 +1173,6 @@ config UNMAP_KERNEL_AT_EL0
 
          If unsure, say Y.
 
-config HARDEN_BRANCH_PREDICTOR
-       bool "Harden the branch predictor against aliasing attacks" if EXPERT
-       default y
-       help
-         Speculation attacks against some high-performance processors rely on
-         being able to manipulate the branch predictor for a victim context by
-         executing aliasing branches in the attacker context.  Such attacks
-         can be partially mitigated against by clearing internal branch
-         predictor state and limiting the prediction logic in some situations.
-
-         This config option will take CPU-specific actions to harden the
-         branch predictor against aliasing attacks and may rely on specific
-         instruction sequences or control bits being set by the system
-         firmware.
-
-         If unsure, say Y.
-
-config ARM64_SSBD
-       bool "Speculative Store Bypass Disable" if EXPERT
-       default y
-       help
-         This enables mitigation of the bypassing of previous stores
-         by speculative loads.
-
-         If unsure, say Y.
-
 config RODATA_FULL_DEFAULT_ENABLED
        bool "Apply r/o permissions of VM areas also to their linear aliases"
        default y
@@ -1664,6 +1646,39 @@ config ARCH_RANDOM
          provides a high bandwidth, cryptographically secure
          hardware random number generator.
 
+config ARM64_AS_HAS_MTE
+       # Initial support for MTE went in binutils 2.32.0, checked with
+       # ".arch armv8.5-a+memtag" below. However, this was incomplete
+       # as a late addition to the final architecture spec (LDGM/STGM)
+       # is only supported in the newer 2.32.x and 2.33 binutils
+       # versions, hence the extra "stgm" instruction check below.
+       def_bool $(as-instr,.arch armv8.5-a+memtag\nstgm xzr$(comma)[x0])
+
+config ARM64_MTE
+       bool "Memory Tagging Extension support"
+       default y
+       depends on ARM64_AS_HAS_MTE && ARM64_TAGGED_ADDR_ABI
+       select ARCH_USES_HIGH_VMA_FLAGS
+       help
+         Memory Tagging (part of the ARMv8.5 Extensions) provides
+         architectural support for run-time, always-on detection of
+         various classes of memory error to aid with software debugging
+         to eliminate vulnerabilities arising from memory-unsafe
+         languages.
+
+         This option enables the support for the Memory Tagging
+         Extension at EL0 (i.e. for userspace).
+
+         Selecting this option allows the feature to be detected at
+         runtime. Any secondary CPU not implementing this feature will
+         not be allowed a late bring-up.
+
+         Userspace binaries that want to use this feature must
+         explicitly opt in. The mechanism for the userspace is
+         described in:
+
+         Documentation/arm64/memory-tagging-extension.rst.
+
 endmenu
 
 config ARM64_SVE
@@ -1876,6 +1891,10 @@ config ARCH_ENABLE_HUGEPAGE_MIGRATION
        def_bool y
        depends on HUGETLB_PAGE && MIGRATION
 
+config ARCH_ENABLE_THP_MIGRATION
+       def_bool y
+       depends on TRANSPARENT_HUGEPAGE
+
 menu "Power management options"
 
 source "kernel/power/Kconfig"
index b45f012..f4717fa 100644 (file)
@@ -11,7 +11,6 @@
 # Copyright (C) 1995-2001 by Russell King
 
 LDFLAGS_vmlinux        :=--no-undefined -X
-CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
 
 ifeq ($(CONFIG_RELOCATABLE), y)
 # Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour
@@ -29,6 +28,10 @@ LDFLAGS_vmlinux      += --fix-cortex-a53-843419
   endif
 endif
 
+# We never want expected sections to be placed heuristically by the
+# linker. All sections should be explicitly named in the linker script.
+LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn)
+
 ifeq ($(CONFIG_ARM64_USE_LSE_ATOMICS), y)
   ifneq ($(CONFIG_ARM64_LSE_ATOMICS), y)
 $(warning LSE atomics not supported by binutils)
@@ -47,13 +50,16 @@ endif
 
 KBUILD_CFLAGS  += -mgeneral-regs-only  \
                   $(compat_vdso) $(cc_has_k_constraint)
-KBUILD_CFLAGS  += -fno-asynchronous-unwind-tables
 KBUILD_CFLAGS  += $(call cc-disable-warning, psabi)
 KBUILD_AFLAGS  += $(compat_vdso)
 
 KBUILD_CFLAGS  += $(call cc-option,-mabi=lp64)
 KBUILD_AFLAGS  += $(call cc-option,-mabi=lp64)
 
+# Avoid generating .eh_frame* sections.
+KBUILD_CFLAGS  += -fno-asynchronous-unwind-tables -fno-unwind-tables
+KBUILD_AFLAGS  += -fno-asynchronous-unwind-tables -fno-unwind-tables
+
 ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
 prepare: stack_protector_prepare
 stack_protector_prepare: prepare0
@@ -82,8 +88,8 @@ endif
 # compiler to generate them and consequently to break the single image contract
 # we pass it only to the assembler. This option is utilized only in case of non
 # integrated assemblers.
-ifneq ($(CONFIG_AS_HAS_ARMV8_4), y)
-branch-prot-flags-$(CONFIG_AS_HAS_PAC) += -Wa,-march=armv8.3-a
+ifeq ($(CONFIG_AS_HAS_PAC), y)
+asm-arch := armv8.3-a
 endif
 endif
 
@@ -91,7 +97,12 @@ KBUILD_CFLAGS += $(branch-prot-flags-y)
 
 ifeq ($(CONFIG_AS_HAS_ARMV8_4), y)
 # make sure to pass the newest target architecture to -march.
-KBUILD_CFLAGS  += -Wa,-march=armv8.4-a
+asm-arch := armv8.4-a
+endif
+
+ifdef asm-arch
+KBUILD_CFLAGS  += -Wa,-march=$(asm-arch) \
+                  -DARM64_ASM_ARCH='"$(asm-arch)"'
 endif
 
 ifeq ($(CONFIG_SHADOW_CALL_STACK), y)
@@ -127,9 +138,6 @@ endif
 # Default value
 head-y         := arch/arm64/kernel/head.o
 
-# The byte offset of the kernel image in RAM from the start of RAM.
-TEXT_OFFSET := 0x0
-
 ifeq ($(CONFIG_KASAN_SW_TAGS), y)
 KASAN_SHADOW_SCALE_SHIFT := 4
 else
@@ -140,8 +148,6 @@ KBUILD_CFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
 KBUILD_CPPFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
 KBUILD_AFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
 
-export TEXT_OFFSET
-
 core-y         += arch/arm64/
 libs-y         := arch/arm64/lib/ $(libs-y)
 libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
@@ -165,7 +171,8 @@ zinstall install:
 PHONY += vdso_install
 vdso_install:
        $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@
-       $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@
+       $(if $(CONFIG_COMPAT_VDSO), \
+               $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@)
 
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
index 15f7b0e..3980206 100644 (file)
                };
 
                qspi: spi@66470200 {
-                       compatible = "brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi";
+                       compatible = "brcm,spi-ns2-qspi", "brcm,spi-bcm-qspi";
                        reg = <0x66470200 0x184>,
                                <0x66470000 0x124>,
                                <0x67017408 0x004>,
index a39f0a1..903c0eb 100644 (file)
@@ -28,6 +28,7 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-honeycomb.dtb
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-qds.dtb
 dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-rdb.dtb
 
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-beacon-kit.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb
index 9de2aa1..a5154f1 100644 (file)
                                reg = <0x30bd0000 0x10000>;
                                interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clk IMX8MP_CLK_SDMA1_ROOT>,
-                                        <&clk IMX8MP_CLK_SDMA1_ROOT>;
+                                        <&clk IMX8MP_CLK_AHB>;
                                clock-names = "ipg", "ahb";
                                #dma-cells = <3>;
                                fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
index f70435c..561fa79 100644 (file)
                        tmu: tmu@30260000 {
                                compatible = "fsl,imx8mq-tmu";
                                reg = <0x30260000 0x10000>;
-                               interrupt = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clk IMX8MQ_CLK_TMU_ROOT>;
                                little-endian;
                                fsl,tmu-range = <0xb0000 0xa0026 0x80048 0x70061>;
index 1a39e0e..5b9ec03 100644 (file)
                clocks = <&pericfg CLK_PERI_MSDC30_0_PD>,
                         <&topckgen CLK_TOP_MSDC50_0_SEL>;
                clock-names = "source", "hclk";
+               resets = <&pericfg MT7622_PERI_MSDC0_SW_RST>;
+               reset-names = "hrst";
                status = "disabled";
        };
 
index 34d249d..8eb61dd 100644 (file)
                compatible = "nvidia,tegra186-sdhci";
                reg = <0x0 0x03400000 0x0 0x10000>;
                interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&bpmp TEGRA186_CLK_SDMMC1>;
-               clock-names = "sdhci";
+               clocks = <&bpmp TEGRA186_CLK_SDMMC1>,
+                        <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
+               clock-names = "sdhci", "tmclk";
                resets = <&bpmp TEGRA186_RESET_SDMMC1>;
                reset-names = "sdhci";
                interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCRA &emc>,
                compatible = "nvidia,tegra186-sdhci";
                reg = <0x0 0x03420000 0x0 0x10000>;
                interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&bpmp TEGRA186_CLK_SDMMC2>;
-               clock-names = "sdhci";
+               clocks = <&bpmp TEGRA186_CLK_SDMMC2>,
+                        <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
+               clock-names = "sdhci", "tmclk";
                resets = <&bpmp TEGRA186_RESET_SDMMC2>;
                reset-names = "sdhci";
                interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCRAA &emc>,
                compatible = "nvidia,tegra186-sdhci";
                reg = <0x0 0x03440000 0x0 0x10000>;
                interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&bpmp TEGRA186_CLK_SDMMC3>;
-               clock-names = "sdhci";
+               clocks = <&bpmp TEGRA186_CLK_SDMMC3>,
+                        <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
+               clock-names = "sdhci", "tmclk";
                resets = <&bpmp TEGRA186_RESET_SDMMC3>;
                reset-names = "sdhci";
                interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCR &emc>,
                compatible = "nvidia,tegra186-sdhci";
                reg = <0x0 0x03460000 0x0 0x10000>;
                interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&bpmp TEGRA186_CLK_SDMMC4>;
-               clock-names = "sdhci";
+               clocks = <&bpmp TEGRA186_CLK_SDMMC4>,
+                        <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
+               clock-names = "sdhci", "tmclk";
                assigned-clocks = <&bpmp TEGRA186_CLK_SDMMC4>,
                                  <&bpmp TEGRA186_CLK_PLLC4_VCO>;
                assigned-clock-parents = <&bpmp TEGRA186_CLK_PLLC4_VCO>;
index 48160f4..ca5cb6a 100644 (file)
                        compatible = "nvidia,tegra194-sdhci";
                        reg = <0x03400000 0x10000>;
                        interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&bpmp TEGRA194_CLK_SDMMC1>;
-                       clock-names = "sdhci";
+                       clocks = <&bpmp TEGRA194_CLK_SDMMC1>,
+                                <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
+                       clock-names = "sdhci", "tmclk";
                        resets = <&bpmp TEGRA194_RESET_SDMMC1>;
                        reset-names = "sdhci";
                        interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCRA &emc>,
                        compatible = "nvidia,tegra194-sdhci";
                        reg = <0x03440000 0x10000>;
                        interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&bpmp TEGRA194_CLK_SDMMC3>;
-                       clock-names = "sdhci";
+                       clocks = <&bpmp TEGRA194_CLK_SDMMC3>,
+                                <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
+                       clock-names = "sdhci", "tmclk";
                        resets = <&bpmp TEGRA194_RESET_SDMMC3>;
                        reset-names = "sdhci";
                        interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCR &emc>,
                        compatible = "nvidia,tegra194-sdhci";
                        reg = <0x03460000 0x10000>;
                        interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&bpmp TEGRA194_CLK_SDMMC4>;
-                       clock-names = "sdhci";
+                       clocks = <&bpmp TEGRA194_CLK_SDMMC4>,
+                                <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
+                       clock-names = "sdhci", "tmclk";
                        assigned-clocks = <&bpmp TEGRA194_CLK_SDMMC4>,
                                          <&bpmp TEGRA194_CLK_PLLC4>;
                        assigned-clock-parents =
index 829f786..8cca216 100644 (file)
                compatible = "nvidia,tegra210-sdhci";
                reg = <0x0 0x700b0000 0x0 0x200>;
                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&tegra_car TEGRA210_CLK_SDMMC1>;
-               clock-names = "sdhci";
+               clocks = <&tegra_car TEGRA210_CLK_SDMMC1>,
+                        <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
+               clock-names = "sdhci", "tmclk";
                resets = <&tegra_car 14>;
                reset-names = "sdhci";
                pinctrl-names = "sdmmc-3v3", "sdmmc-1v8",
                compatible = "nvidia,tegra210-sdhci";
                reg = <0x0 0x700b0200 0x0 0x200>;
                interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&tegra_car TEGRA210_CLK_SDMMC2>;
-               clock-names = "sdhci";
+               clocks = <&tegra_car TEGRA210_CLK_SDMMC2>,
+                        <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
+               clock-names = "sdhci", "tmclk";
                resets = <&tegra_car 9>;
                reset-names = "sdhci";
                pinctrl-names = "sdmmc-1v8-drv";
                compatible = "nvidia,tegra210-sdhci";
                reg = <0x0 0x700b0400 0x0 0x200>;
                interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&tegra_car TEGRA210_CLK_SDMMC3>;
-               clock-names = "sdhci";
+               clocks = <&tegra_car TEGRA210_CLK_SDMMC3>,
+                        <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
+               clock-names = "sdhci", "tmclk";
                resets = <&tegra_car 69>;
                reset-names = "sdhci";
                pinctrl-names = "sdmmc-3v3", "sdmmc-1v8",
                compatible = "nvidia,tegra210-sdhci";
                reg = <0x0 0x700b0600 0x0 0x200>;
                interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&tegra_car TEGRA210_CLK_SDMMC4>;
-               clock-names = "sdhci";
+               clocks = <&tegra_car TEGRA210_CLK_SDMMC4>,
+                        <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
+               clock-names = "sdhci", "tmclk";
                resets = <&tegra_car 15>;
                reset-names = "sdhci";
                pinctrl-names = "sdmmc-3v3-drv", "sdmmc-1v8-drv";
index 9edfae5..24ef18f 100644 (file)
                ti,intr-trigger-type = <1>;
                interrupt-controller;
                interrupt-parent = <&gic500>;
-               #interrupt-cells = <2>;
+               #interrupt-cells = <1>;
                ti,sci = <&dmsc>;
-               ti,sci-dst-id = <56>;
-               ti,sci-rm-range-girq = <0x1>;
+               ti,sci-dev-id = <100>;
+               ti,interrupt-ranges = <0 392 32>;
        };
 
        main_navss {
                        ti,intr-trigger-type = <4>;
                        interrupt-controller;
                        interrupt-parent = <&gic500>;
-                       #interrupt-cells = <2>;
+                       #interrupt-cells = <1>;
                        ti,sci = <&dmsc>;
-                       ti,sci-dst-id = <56>;
-                       ti,sci-rm-range-girq = <0x0>, <0x2>;
+                       ti,sci-dev-id = <182>;
+                       ti,interrupt-ranges = <0 64 64>,
+                                             <64 448 64>;
                };
 
                inta_main_udmass: interrupt-controller@33d00000 {
                        msi-controller;
                        ti,sci = <&dmsc>;
                        ti,sci-dev-id = <179>;
-                       ti,sci-rm-range-vint = <0x0>;
-                       ti,sci-rm-range-global-event = <0x1>;
+                       ti,interrupt-ranges = <0 0 256>;
                };
 
                secure_proxy_main: mailbox@32c00000 {
                                <0x0 0x33000000 0x0 0x40000>;
                        reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target";
                        ti,num-rings = <818>;
-                       ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */
+                       ti,sci-rm-range-gp-rings = <0x1>; /* GP ring range */
                        ti,dma-ring-reset-quirk;
                        ti,sci = <&dmsc>;
                        ti,sci-dev-id = <187>;
                        ti,sci-dev-id = <188>;
                        ti,ringacc = <&ringacc>;
 
-                       ti,sci-rm-range-tchan = <0x1>, /* TX_HCHAN */
-                                               <0x2>; /* TX_CHAN */
-                       ti,sci-rm-range-rchan = <0x4>, /* RX_HCHAN */
-                                               <0x5>; /* RX_CHAN */
-                       ti,sci-rm-range-rflow = <0x6>; /* GP RFLOW */
+                       ti,sci-rm-range-tchan = <0xf>, /* TX_HCHAN */
+                                               <0xd>; /* TX_CHAN */
+                       ti,sci-rm-range-rchan = <0xb>, /* RX_HCHAN */
+                                               <0xa>; /* RX_CHAN */
+                       ti,sci-rm-range-rflow = <0x0>; /* GP RFLOW */
                };
 
                cpts@310d0000 {
                        reg-names = "cpts";
                        clocks = <&main_cpts_mux>;
                        clock-names = "cpts";
-                       interrupts-extended = <&intr_main_navss 163 0>;
+                       interrupts-extended = <&intr_main_navss 391>;
                        interrupt-names = "cpts";
                        ti,cpts-periodic-outputs = <6>;
                        ti,cpts-ext-ts-inputs = <8>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&intr_main_gpio>;
-               interrupts = <57 256>, <57 257>, <57 258>, <57 259>, <57 260>,
-                               <57 261>;
+               interrupts = <192>, <193>, <194>, <195>, <196>, <197>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <96>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&intr_main_gpio>;
-               interrupts = <58 256>, <58 257>, <58 258>, <58 259>, <58 260>,
-                               <58 261>;
+               interrupts = <200>, <201>, <202>, <203>, <204>, <205>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <90>;
index 8c1abcf..51ca4b4 100644 (file)
                                <0x0 0x2a500000 0x0 0x40000>;
                        reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target";
                        ti,num-rings = <286>;
-                       ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */
+                       ti,sci-rm-range-gp-rings = <0x1>; /* GP ring range */
                        ti,dma-ring-reset-quirk;
                        ti,sci = <&dmsc>;
                        ti,sci-dev-id = <195>;
                        ti,sci-dev-id = <194>;
                        ti,ringacc = <&mcu_ringacc>;
 
-                       ti,sci-rm-range-tchan = <0x1>, /* TX_HCHAN */
-                                               <0x2>; /* TX_CHAN */
-                       ti,sci-rm-range-rchan = <0x3>, /* RX_HCHAN */
-                                               <0x4>; /* RX_CHAN */
-                       ti,sci-rm-range-rflow = <0x5>; /* GP RFLOW */
+                       ti,sci-rm-range-tchan = <0xf>, /* TX_HCHAN */
+                                               <0xd>; /* TX_CHAN */
+                       ti,sci-rm-range-rchan = <0xb>, /* RX_HCHAN */
+                                               <0xa>; /* RX_CHAN */
+                       ti,sci-rm-range-rflow = <0x0>; /* GP RFLOW */
                };
        };
 
index 5f55b9e..a1ffe88 100644 (file)
                ti,intr-trigger-type = <1>;
                interrupt-controller;
                interrupt-parent = <&gic500>;
-               #interrupt-cells = <2>;
+               #interrupt-cells = <1>;
                ti,sci = <&dmsc>;
-               ti,sci-dst-id = <56>;
-               ti,sci-rm-range-girq = <0x4>;
+               ti,sci-dev-id = <156>;
+               ti,interrupt-ranges = <0 712 16>;
        };
 
        wkup_gpio0: wkup_gpio0@42110000 {
@@ -86,7 +86,7 @@
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&intr_wkup_gpio>;
-               interrupts = <59 128>, <59 129>, <59 130>, <59 131>;
+               interrupts = <60>, <61>, <62>, <63>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <56>;
index 611e662..b8a8a0f 100644 (file)
 };
 
 &mailbox0_cluster0 {
-       interrupts = <164 0>;
+       interrupts = <436>;
 
        mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
                ti,mbox-tx = <1 0 0>;
 };
 
 &mailbox0_cluster1 {
-       interrupts = <165 0>;
+       interrupts = <432>;
 
        mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 {
                ti,mbox-tx = <1 0 0>;
index 8bc1e6e..e8fc01d 100644 (file)
 };
 
 &mailbox0_cluster0 {
-       interrupts = <214 0>;
+       interrupts = <436>;
 
        mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
                ti,mbox-rx = <0 0 0>;
 };
 
 &mailbox0_cluster1 {
-       interrupts = <215 0>;
+       interrupts = <432>;
 
        mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 {
                ti,mbox-rx = <0 0 0>;
 };
 
 &mailbox0_cluster2 {
-       interrupts = <216 0>;
+       interrupts = <428>;
 
        mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 {
                ti,mbox-rx = <0 0 0>;
 };
 
 &mailbox0_cluster3 {
-       interrupts = <217 0>;
+       interrupts = <424>;
 
        mbox_c66_0: mbox-c66-0 {
                ti,mbox-rx = <0 0 0>;
 };
 
 &mailbox0_cluster4 {
-       interrupts = <218 0>;
+       interrupts = <420>;
 
        mbox_c71_0: mbox-c71-0 {
                ti,mbox-rx = <0 0 0>;
index d140602..12ceea9 100644 (file)
                ti,intr-trigger-type = <1>;
                interrupt-controller;
                interrupt-parent = <&gic500>;
-               #interrupt-cells = <2>;
+               #interrupt-cells = <1>;
                ti,sci = <&dmsc>;
-               ti,sci-dst-id = <14>;
-               ti,sci-rm-range-girq = <0x1>;
+               ti,sci-dev-id = <131>;
+               ti,interrupt-ranges = <8 392 56>;
        };
 
        main_navss {
                        ti,intr-trigger-type = <4>;
                        interrupt-controller;
                        interrupt-parent = <&gic500>;
-                       #interrupt-cells = <2>;
+                       #interrupt-cells = <1>;
                        ti,sci = <&dmsc>;
-                       ti,sci-dst-id = <14>;
-                       ti,sci-rm-range-girq = <0>, <2>;
+                       ti,sci-dev-id = <213>;
+                       ti,interrupt-ranges = <0 64 64>,
+                                             <64 448 64>,
+                                             <128 672 64>;
                };
 
                main_udmass_inta: interrupt-controller@33d00000 {
                        msi-controller;
                        ti,sci = <&dmsc>;
                        ti,sci-dev-id = <209>;
-                       ti,sci-rm-range-vint = <0xa>;
-                       ti,sci-rm-range-global-event = <0xd>;
+                       ti,interrupt-ranges = <0 0 256>;
                };
 
                secure_proxy_main: mailbox@32c00000 {
                        reg-names = "cpts";
                        clocks = <&k3_clks 201 1>;
                        clock-names = "cpts";
-                       interrupts-extended = <&main_navss_intr 201 0>;
+                       interrupts-extended = <&main_navss_intr 391>;
                        interrupt-names = "cpts";
                        ti,cpts-periodic-outputs = <6>;
                        ti,cpts-ext-ts-inputs = <8>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&main_gpio_intr>;
-               interrupts = <105 0>, <105 1>, <105 2>, <105 3>,
-                            <105 4>, <105 5>, <105 6>, <105 7>;
+               interrupts = <256>, <257>, <258>, <259>,
+                            <260>, <261>, <262>, <263>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <128>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&main_gpio_intr>;
-               interrupts = <106 0>, <106 1>, <106 2>;
+               interrupts = <288>, <289>, <290>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <36>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&main_gpio_intr>;
-               interrupts = <107 0>, <107 1>, <107 2>, <107 3>,
-                            <107 4>, <107 5>, <107 6>, <107 7>;
+               interrupts = <264>, <265>, <266>, <267>,
+                            <268>, <269>, <270>, <271>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <128>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&main_gpio_intr>;
-               interrupts = <108 0>, <108 1>, <108 2>;
+               interrupts = <292>, <293>, <294>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <36>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&main_gpio_intr>;
-               interrupts = <109 0>, <109 1>, <109 2>, <109 3>,
-                            <109 4>, <109 5>, <109 6>, <109 7>;
+               interrupts = <272>, <273>, <274>, <275>,
+                            <276>, <277>, <278>, <279>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <128>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&main_gpio_intr>;
-               interrupts = <110 0>, <110 1>, <110 2>;
+               interrupts = <296>, <297>, <298>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <36>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&main_gpio_intr>;
-               interrupts = <111 0>, <111 1>, <111 2>, <111 3>,
-                            <111 4>, <111 5>, <111 6>, <111 7>;
+               interrupts = <280>, <281>, <282>, <283>,
+                            <284>, <285>, <286>, <287>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <128>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&main_gpio_intr>;
-               interrupts = <112 0>, <112 1>, <112 2>;
+               interrupts = <300>, <301>, <302>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <36>;
index 30a735b..c4a48e8 100644 (file)
                ti,intr-trigger-type = <1>;
                interrupt-controller;
                interrupt-parent = <&gic500>;
-               #interrupt-cells = <2>;
+               #interrupt-cells = <1>;
                ti,sci = <&dmsc>;
-               ti,sci-dst-id = <14>;
-               ti,sci-rm-range-girq = <0x5>;
+               ti,sci-dev-id = <137>;
+               ti,interrupt-ranges = <16 960 16>;
        };
 
        wkup_gpio0: gpio@42110000 {
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&wkup_gpio_intr>;
-               interrupts = <113 0>, <113 1>, <113 2>,
-                            <113 3>, <113 4>, <113 5>;
+               interrupts = <103>, <104>, <105>, <106>, <107>, <108>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <84>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-parent = <&wkup_gpio_intr>;
-               interrupts = <114 0>, <114 1>, <114 2>,
-                            <114 3>, <114 4>, <114 5>;
+               interrupts = <112>, <113>, <114>, <115>, <116>, <117>;
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,ngpio = <84>;
index 9174ddc..3ec99f1 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <dt-bindings/power/xlnx-zynqmp-power.h>
+#include <dt-bindings/reset/xlnx-zynqmp-resets.h>
 
 / {
        compatible = "xlnx,zynqmp";
                        };
                };
 
+               psgtr: phy@fd400000 {
+                       compatible = "xlnx,zynqmp-psgtr-v1.1";
+                       status = "disabled";
+                       reg = <0x0 0xfd400000 0x0 0x40000>,
+                             <0x0 0xfd3d0000 0x0 0x1000>;
+                       reg-names = "serdes", "siou";
+                       #phy-cells = <4>;
+               };
+
                rtc: rtc@ffa60000 {
                        compatible = "xlnx,zynqmp-rtc";
                        status = "disabled";
                        power-domains = <&zynqmp_firmware PD_SD_1>;
                };
 
-               smmu: smmu@fd800000 {
+               smmu: iommu@fd800000 {
                        compatible = "arm,mmu-500";
                        reg = <0x0 0xfd800000 0x0 0x20000>;
                        status = "disabled";
index e0f3382..6d04b95 100644 (file)
@@ -724,6 +724,17 @@ CONFIG_USB_GADGET=y
 CONFIG_USB_RENESAS_USBHS_UDC=m
 CONFIG_USB_RENESAS_USB3=m
 CONFIG_USB_TEGRA_XUDC=m
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
 CONFIG_TYPEC=m
 CONFIG_TYPEC_TCPM=m
 CONFIG_TYPEC_FUSB302=m
@@ -914,6 +925,7 @@ CONFIG_ARCH_TEGRA_194_SOC=y
 CONFIG_ARCH_K3_AM6_SOC=y
 CONFIG_ARCH_K3_J721E_SOC=y
 CONFIG_TI_SCI_PM_DOMAINS=y
+CONFIG_EXTCON_PTN5150=m
 CONFIG_EXTCON_USB_GPIO=y
 CONFIG_EXTCON_USBC_CROS_EC=y
 CONFIG_IIO=y
index b357164..63a52ad 100644 (file)
@@ -788,7 +788,7 @@ SYM_FUNC_START_LOCAL(__xts_crypt8)
 
 0:     mov             bskey, x21
        mov             rounds, x22
-       br              x7
+       br              x16
 SYM_FUNC_END(__xts_crypt8)
 
        .macro          __xts_crypt, do8, o0, o1, o2, o3, o4, o5, o6, o7
@@ -806,7 +806,7 @@ SYM_FUNC_END(__xts_crypt8)
        uzp1            v30.4s, v30.4s, v25.4s
        ld1             {v25.16b}, [x24]
 
-99:    adr             x7, \do8
+99:    adr             x16, \do8
        bl              __xts_crypt8
 
        ldp             q16, q17, [sp, #.Lframe_local_offset]
index da10348..8536008 100644 (file)
@@ -347,7 +347,7 @@ static int gcm_encrypt(struct aead_request *req)
        u8 buf[AES_BLOCK_SIZE];
        u8 iv[AES_BLOCK_SIZE];
        u64 dg[2] = {};
-       u128 lengths;
+       be128 lengths;
        u8 *tag;
        int err;
 
@@ -461,7 +461,7 @@ static int gcm_decrypt(struct aead_request *req)
        u8 buf[AES_BLOCK_SIZE];
        u8 iv[AES_BLOCK_SIZE];
        u64 dg[2] = {};
-       u128 lengths;
+       be128 lengths;
        u8 *tag;
        int err;
 
index 565ef60..c63b992 100644 (file)
@@ -25,6 +25,9 @@ struct sha1_ce_state {
        u32                     finalize;
 };
 
+extern const u32 sha1_ce_offsetof_count;
+extern const u32 sha1_ce_offsetof_finalize;
+
 asmlinkage void sha1_ce_transform(struct sha1_ce_state *sst, u8 const *src,
                                  int blocks);
 
index 9450d19..5e956d7 100644 (file)
@@ -25,6 +25,9 @@ struct sha256_ce_state {
        u32                     finalize;
 };
 
+extern const u32 sha256_ce_offsetof_count;
+extern const u32 sha256_ce_offsetof_finalize;
+
 asmlinkage void sha2_ce_transform(struct sha256_ce_state *sst, u8 const *src,
                                  int blocks);
 
index 6647ae4..880b905 100644 (file)
@@ -153,7 +153,7 @@ static inline bool gic_prio_masking_enabled(void)
 
 static inline void gic_pmr_mask_irqs(void)
 {
-       BUILD_BUG_ON(GICD_INT_DEF_PRI < (GIC_PRIO_IRQOFF |
+       BUILD_BUG_ON(GICD_INT_DEF_PRI < (__GIC_PRIO_IRQOFF |
                                         GIC_PRIO_PSR_I_SET));
        BUILD_BUG_ON(GICD_INT_DEF_PRI >= GIC_PRIO_IRQON);
        /*
@@ -162,6 +162,12 @@ static inline void gic_pmr_mask_irqs(void)
         * are applied to IRQ priorities
         */
        BUILD_BUG_ON((0x80 | (GICD_INT_DEF_PRI >> 1)) >= GIC_PRIO_IRQON);
+       /*
+        * Same situation as above, but now we make sure that we can mask
+        * regular interrupts.
+        */
+       BUILD_BUG_ON((0x80 | (GICD_INT_DEF_PRI >> 1)) < (__GIC_PRIO_IRQOFF_NS |
+                                                        GIC_PRIO_PSR_I_SET));
        gic_write_pmr(GIC_PRIO_IRQOFF);
 }
 
index 44209f6..ffb1a40 100644 (file)
@@ -79,10 +79,5 @@ arch_get_random_seed_long_early(unsigned long *v)
 }
 #define arch_get_random_seed_long_early arch_get_random_seed_long_early
 
-#else
-
-static inline bool __arm64_rndr(unsigned long *v) { return false; }
-static inline bool __init __early_cpu_has_rndr(void) { return false; }
-
 #endif /* CONFIG_ARCH_RANDOM */
 #endif /* _ASM_ARCHRANDOM_H */
index c7f67da..3e7943f 100644 (file)
@@ -13,8 +13,7 @@
 #define MAX_FDT_SIZE           SZ_2M
 
 /*
- * arm64 requires the kernel image to placed
- * TEXT_OFFSET bytes beyond a 2 MB aligned base
+ * arm64 requires the kernel image to placed at a 2 MB aligned base address
  */
 #define MIN_KIMG_ALIGN         SZ_2M
 
index 935d2aa..23a9fb7 100644 (file)
@@ -35,8 +35,6 @@ typedef s32           compat_nlink_t;
 typedef u16            compat_ipc_pid_t;
 typedef u32            compat_caddr_t;
 typedef __kernel_fsid_t        compat_fsid_t;
-typedef s64            compat_s64;
-typedef u64            compat_u64;
 
 struct compat_stat {
 #ifdef __AARCH64EB__
index 51a7ce8..6fb2e6b 100644 (file)
@@ -2,6 +2,12 @@
 #ifndef __ASM_COMPILER_H
 #define __ASM_COMPILER_H
 
+#ifdef ARM64_ASM_ARCH
+#define ARM64_ASM_PREAMBLE ".arch " ARM64_ASM_ARCH "\n"
+#else
+#define ARM64_ASM_PREAMBLE
+#endif
+
 /*
  * The EL0/EL1 pointer bits used by a pointer authentication code.
  * This is dependent on TBI0/TBI1 being enabled, or bits 63:56 would also apply.
index d28e8f3..e95c4df 100644 (file)
@@ -21,7 +21,7 @@
  *             mechanism for doing so, tests whether it is possible to boot
  *             the given CPU.
  * @cpu_boot:  Boots a cpu into the kernel.
- * @cpu_postboot: Optionally, perform any post-boot cleanup or necesary
+ * @cpu_postboot: Optionally, perform any post-boot cleanup or necessary
  *             synchronisation. Called from the cpu being booted.
  * @cpu_can_disable: Determines whether a CPU can be disabled based on
  *             mechanism-specific information.
index 07b643a..42868db 100644 (file)
 #define ARM64_HAS_DCPOP                                21
 #define ARM64_SVE                              22
 #define ARM64_UNMAP_KERNEL_AT_EL0              23
-#define ARM64_HARDEN_BRANCH_PREDICTOR          24
+#define ARM64_SPECTRE_V2                       24
 #define ARM64_HAS_RAS_EXTN                     25
 #define ARM64_WORKAROUND_843419                        26
 #define ARM64_HAS_CACHE_IDC                    27
 #define ARM64_HAS_CACHE_DIC                    28
 #define ARM64_HW_DBM                           29
-#define ARM64_SSBD                             30
+#define ARM64_SPECTRE_V4                       30
 #define ARM64_MISMATCHED_CACHE_TYPE            31
 #define ARM64_HAS_STAGE2_FWB                   32
 #define ARM64_HAS_CRC32                                33
@@ -64,7 +64,8 @@
 #define ARM64_BTI                              54
 #define ARM64_HAS_ARMv8_4_TTL                  55
 #define ARM64_HAS_TLB_RANGE                    56
+#define ARM64_MTE                              57
 
-#define ARM64_NCAPS                            57
+#define ARM64_NCAPS                            58
 
 #endif /* __ASM_CPUCAPS_H */
index 89b4f01..f7e7144 100644 (file)
@@ -358,7 +358,7 @@ static inline int cpucap_default_scope(const struct arm64_cpu_capabilities *cap)
 }
 
 /*
- * Generic helper for handling capabilties with multiple (match,enable) pairs
+ * Generic helper for handling capabilities with multiple (match,enable) pairs
  * of call backs, sharing the same capability bit.
  * Iterate over each entry to see if at least one matches.
  */
@@ -681,6 +681,12 @@ static __always_inline bool system_uses_irq_prio_masking(void)
               cpus_have_const_cap(ARM64_HAS_IRQ_PRIO_MASKING);
 }
 
+static inline bool system_supports_mte(void)
+{
+       return IS_ENABLED(CONFIG_ARM64_MTE) &&
+               cpus_have_const_cap(ARM64_MTE);
+}
+
 static inline bool system_has_prio_mask_debugging(void)
 {
        return IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING) &&
@@ -698,30 +704,6 @@ static inline bool system_supports_tlb_range(void)
                cpus_have_const_cap(ARM64_HAS_TLB_RANGE);
 }
 
-#define ARM64_BP_HARDEN_UNKNOWN                -1
-#define ARM64_BP_HARDEN_WA_NEEDED      0
-#define ARM64_BP_HARDEN_NOT_REQUIRED   1
-
-int get_spectre_v2_workaround_state(void);
-
-#define ARM64_SSBD_UNKNOWN             -1
-#define ARM64_SSBD_FORCE_DISABLE       0
-#define ARM64_SSBD_KERNEL              1
-#define ARM64_SSBD_FORCE_ENABLE                2
-#define ARM64_SSBD_MITIGATED           3
-
-static inline int arm64_get_ssbd_state(void)
-{
-#ifdef CONFIG_ARM64_SSBD
-       extern int ssbd_state;
-       return ssbd_state;
-#else
-       return ARM64_SSBD_UNKNOWN;
-#endif
-}
-
-void arm64_set_ssbd_mitigation(bool state);
-
 extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
 
 static inline u32 id_aa64mmfr0_parange_to_phys_shift(int parange)
index d4ab3f7..973b144 100644 (file)
@@ -65,7 +65,7 @@ efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
        (SEGMENT_ALIGN > THREAD_ALIGN ? SEGMENT_ALIGN : THREAD_ALIGN)
 
 /* on arm64, the FDT may be located anywhere in system RAM */
-static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
+static inline unsigned long efi_get_max_fdt_addr(unsigned long image_addr)
 {
        return ULONG_MAX;
 }
@@ -80,8 +80,7 @@ static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
  * apply to other bootloaders, and are required for some kernel
  * configurations.
  */
-static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
-                                                   unsigned long image_addr)
+static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
 {
        return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS_MIN - 1));
 }
index 035003a..22c81f1 100644 (file)
@@ -35,7 +35,9 @@
 #define ESR_ELx_EC_SYS64       (0x18)
 #define ESR_ELx_EC_SVE         (0x19)
 #define ESR_ELx_EC_ERET                (0x1a)  /* EL2 only */
-/* Unallocated EC: 0x1b - 0x1E */
+/* Unallocated EC: 0x1B */
+#define ESR_ELx_EC_FPAC                (0x1C)  /* EL1 and above */
+/* Unallocated EC: 0x1D - 0x1E */
 #define ESR_ELx_EC_IMP_DEF     (0x1f)  /* EL3 only */
 #define ESR_ELx_EC_IABT_LOW    (0x20)
 #define ESR_ELx_EC_IABT_CUR    (0x21)
index 7577a75..99b9383 100644 (file)
@@ -47,4 +47,5 @@ void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr);
 void do_cp15instr(unsigned int esr, struct pt_regs *regs);
 void do_el0_svc(struct pt_regs *regs);
 void do_el0_svc_compat(struct pt_regs *regs);
+void do_ptrauth_fault(struct pt_regs *regs, unsigned int esr);
 #endif /* __ASM_EXCEPTION_H */
index 840a35e..b15eb4a 100644 (file)
@@ -22,6 +22,15 @@ struct exception_table_entry
 
 #define ARCH_HAS_RELATIVE_EXTABLE
 
+static inline bool in_bpf_jit(struct pt_regs *regs)
+{
+       if (!IS_ENABLED(CONFIG_BPF_JIT))
+               return false;
+
+       return regs->pc >= BPF_JIT_REGION_START &&
+              regs->pc < BPF_JIT_REGION_END;
+}
+
 #ifdef CONFIG_BPF_JIT
 int arm64_bpf_fixup_exception(const struct exception_table_entry *ex,
                              struct pt_regs *regs);
index 59f10dd..bec5f14 100644 (file)
@@ -69,6 +69,9 @@ static inline void *sve_pffr(struct thread_struct *thread)
 extern void sve_save_state(void *state, u32 *pfpsr);
 extern void sve_load_state(void const *state, u32 const *pfpsr,
                           unsigned long vq_minus_1);
+extern void sve_flush_live(void);
+extern void sve_load_from_fpsimd_state(struct user_fpsimd_state const *state,
+                                      unsigned long vq_minus_1);
 extern unsigned int sve_get_vl(void);
 
 struct arm64_cpu_capabilities;
index 636e9d9..af43367 100644 (file)
                | ((\np) << 5)
 .endm
 
+/* PFALSE P\np.B */
+.macro _sve_pfalse np
+       _sve_check_preg \np
+       .inst   0x2518e400                      \
+               | (\np)
+.endm
+
 .macro __for from:req, to:req
        .if (\from) == (\to)
-               _for__body \from
+               _for__body %\from
        .else
-               __for \from, (\from) + ((\to) - (\from)) / 2
-               __for (\from) + ((\to) - (\from)) / 2 + 1, \to
+               __for %\from, %((\from) + ((\to) - (\from)) / 2)
+               __for %((\from) + ((\to) - (\from)) / 2 + 1), %\to
        .endif
 .endm
 
 .macro _for var:req, from:req, to:req, insn:vararg
        .macro _for__body \var:req
+               .noaltmacro
                \insn
+               .altmacro
        .endm
 
+       .altmacro
        __for \from, \to
+       .noaltmacro
 
        .purgem _for__body
 .endm
 
+/* Update ZCR_EL1.LEN with the new VQ */
+.macro sve_load_vq xvqminus1, xtmp, xtmp2
+               mrs_s           \xtmp, SYS_ZCR_EL1
+               bic             \xtmp2, \xtmp, ZCR_ELx_LEN_MASK
+               orr             \xtmp2, \xtmp2, \xvqminus1
+               cmp             \xtmp2, \xtmp
+               b.eq            921f
+               msr_s           SYS_ZCR_EL1, \xtmp2     //self-synchronising
+921:
+.endm
+
+/* Preserve the first 128-bits of Znz and zero the rest. */
+.macro _sve_flush_z nz
+       _sve_check_zreg \nz
+       mov     v\nz\().16b, v\nz\().16b
+.endm
+
+.macro sve_flush
+ _for n, 0, 31, _sve_flush_z   \n
+ _for n, 0, 15, _sve_pfalse    \n
+               _sve_wrffr      0
+.endm
+
 .macro sve_save nxbase, xpfpsr, nxtmp
  _for n, 0, 31,        _sve_str_v      \n, \nxbase, \n - 34
  _for n, 0, 15,        _sve_str_p      \n, \nxbase, \n - 16
 .endm
 
 .macro sve_load nxbase, xpfpsr, xvqminus1, nxtmp, xtmp2
-               mrs_s           x\nxtmp, SYS_ZCR_EL1
-               bic             \xtmp2, x\nxtmp, ZCR_ELx_LEN_MASK
-               orr             \xtmp2, \xtmp2, \xvqminus1
-               cmp             \xtmp2, x\nxtmp
-               b.eq            921f
-               msr_s           SYS_ZCR_EL1, \xtmp2     // self-synchronising
-921:
+               sve_load_vq     \xvqminus1, x\nxtmp, \xtmp2
  _for n, 0, 31,        _sve_ldr_v      \n, \nxbase, \n - 34
                _sve_ldr_p      0, \nxbase
                _sve_wrffr      0
index 985493a..5ffa4ba 100644 (file)
 #include <asm/kvm_arm.h>
 #include <asm/sysreg.h>
 
-#define NR_IPI 7
-
 typedef struct {
        unsigned int __softirq_pending;
-       unsigned int ipi_irqs[NR_IPI];
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
 
-#define __inc_irq_stat(cpu, member)    __IRQ_STAT(cpu, member)++
-#define __get_irq_stat(cpu, member)    __IRQ_STAT(cpu, member)
-
-u64 smp_irq_stat_cpu(unsigned int cpu);
-#define arch_irq_stat_cpu      smp_irq_stat_cpu
-
 #define __ARCH_IRQ_EXIT_IRQS_DISABLED  1
 
 struct nmi_ctx {
index 22f73fe..9a5498c 100644 (file)
@@ -8,18 +8,27 @@
 #include <uapi/asm/hwcap.h>
 #include <asm/cpufeature.h>
 
+#define COMPAT_HWCAP_SWP       (1 << 0)
 #define COMPAT_HWCAP_HALF      (1 << 1)
 #define COMPAT_HWCAP_THUMB     (1 << 2)
+#define COMPAT_HWCAP_26BIT     (1 << 3)
 #define COMPAT_HWCAP_FAST_MULT (1 << 4)
+#define COMPAT_HWCAP_FPA       (1 << 5)
 #define COMPAT_HWCAP_VFP       (1 << 6)
 #define COMPAT_HWCAP_EDSP      (1 << 7)
+#define COMPAT_HWCAP_JAVA      (1 << 8)
+#define COMPAT_HWCAP_IWMMXT    (1 << 9)
+#define COMPAT_HWCAP_CRUNCH    (1 << 10)
+#define COMPAT_HWCAP_THUMBEE   (1 << 11)
 #define COMPAT_HWCAP_NEON      (1 << 12)
 #define COMPAT_HWCAP_VFPv3     (1 << 13)
+#define COMPAT_HWCAP_VFPV3D16  (1 << 14)
 #define COMPAT_HWCAP_TLS       (1 << 15)
 #define COMPAT_HWCAP_VFPv4     (1 << 16)
 #define COMPAT_HWCAP_IDIVA     (1 << 17)
 #define COMPAT_HWCAP_IDIVT     (1 << 18)
 #define COMPAT_HWCAP_IDIV      (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT)
+#define COMPAT_HWCAP_VFPD32    (1 << 19)
 #define COMPAT_HWCAP_LPAE      (1 << 20)
 #define COMPAT_HWCAP_EVTSTRM   (1 << 21)
 
 #define KERNEL_HWCAP_DGH               __khwcap2_feature(DGH)
 #define KERNEL_HWCAP_RNG               __khwcap2_feature(RNG)
 #define KERNEL_HWCAP_BTI               __khwcap2_feature(BTI)
-/* reserved for KERNEL_HWCAP_MTE       __khwcap2_feature(MTE) */
+#define KERNEL_HWCAP_MTE               __khwcap2_feature(MTE)
 
 /*
  * This yields a mask that user programs can use to figure out what
index 0bc4614..4b39293 100644 (file)
@@ -359,9 +359,13 @@ __AARCH64_INSN_FUNCS(brk,  0xFFE0001F, 0xD4200000)
 __AARCH64_INSN_FUNCS(exception,        0xFF000000, 0xD4000000)
 __AARCH64_INSN_FUNCS(hint,     0xFFFFF01F, 0xD503201F)
 __AARCH64_INSN_FUNCS(br,       0xFFFFFC1F, 0xD61F0000)
+__AARCH64_INSN_FUNCS(br_auth,  0xFEFFF800, 0xD61F0800)
 __AARCH64_INSN_FUNCS(blr,      0xFFFFFC1F, 0xD63F0000)
+__AARCH64_INSN_FUNCS(blr_auth, 0xFEFFF800, 0xD63F0800)
 __AARCH64_INSN_FUNCS(ret,      0xFFFFFC1F, 0xD65F0000)
+__AARCH64_INSN_FUNCS(ret_auth, 0xFFFFFBFF, 0xD65F0BFF)
 __AARCH64_INSN_FUNCS(eret,     0xFFFFFFFF, 0xD69F03E0)
+__AARCH64_INSN_FUNCS(eret_auth,        0xFFFFFBFF, 0xD69F0BFF)
 __AARCH64_INSN_FUNCS(mrs,      0xFFF00000, 0xD5300000)
 __AARCH64_INSN_FUNCS(msr_imm,  0xFFF8F01F, 0xD500401F)
 __AARCH64_INSN_FUNCS(msr_reg,  0xFFF00000, 0xD5100000)
index 8a1ef19..a102028 100644 (file)
@@ -2,11 +2,9 @@
 #ifndef __ASM_IRQ_WORK_H
 #define __ASM_IRQ_WORK_H
 
-#include <asm/smp.h>
-
 static inline bool arch_irq_work_has_interrupt(void)
 {
-       return !!__smp_cross_call;
+       return true;
 }
 
 #endif /* __ASM_IRQ_WORK_H */
index aa4b652..ff328e5 100644 (file)
@@ -95,6 +95,11 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
        return res;
 }
 
+static inline int arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
 static inline unsigned long arch_local_irq_save(void)
 {
        unsigned long flags;
index 329fb15..19ca76e 100644 (file)
@@ -86,7 +86,7 @@
                        + EARLY_PGDS((vstart), (vend))  /* each PGDIR needs a next level page table */  \
                        + EARLY_PUDS((vstart), (vend))  /* each PUD needs a next level page table */    \
                        + EARLY_PMDS((vstart), (vend))) /* each PMD needs a next level page table */
-#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR + TEXT_OFFSET, _end))
+#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end))
 #define IDMAP_DIR_SIZE         (IDMAP_PGTABLE_LEVELS * PAGE_SIZE)
 
 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
index 51c1d99..64ce293 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/types.h>
 
 /* Hyp Configuration Register (HCR) bits */
+#define HCR_ATA                (UL(1) << 56)
 #define HCR_FWB                (UL(1) << 46)
 #define HCR_API                (UL(1) << 41)
 #define HCR_APK                (UL(1) << 40)
  * TWI:                Trap WFI
  * TIDCP:      Trap L2CTLR/L2ECTLR
  * BSU_IS:     Upgrade barriers to the inner shareable domain
- * FB:         Force broadcast of all maintainance operations
+ * FB:         Force broadcast of all maintenance operations
  * AMO:                Override CPSR.A and enable signaling with VA
  * IMO:                Override CPSR.I and enable signaling with VI
  * FMO:                Override CPSR.F and enable signaling with VF
  * SWIO:       Turn set/way invalidates into set/way clean+invalidate
+ * PTW:                Take a stage2 fault if a stage1 walk steps in device memory
  */
 #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
                         HCR_BSU_IS | HCR_FB | HCR_TAC | \
                         HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \
-                        HCR_FMO | HCR_IMO)
+                        HCR_FMO | HCR_IMO | HCR_PTW )
 #define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF)
-#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK)
+#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA)
 #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
 
 /* TCR_EL2 Registers bits */
index fb1a922..7f7072f 100644 (file)
@@ -9,9 +9,6 @@
 
 #include <asm/virt.h>
 
-#define        VCPU_WORKAROUND_2_FLAG_SHIFT    0
-#define        VCPU_WORKAROUND_2_FLAG          (_AC(1, UL) << VCPU_WORKAROUND_2_FLAG_SHIFT)
-
 #define ARM_EXIT_WITH_SERROR_BIT  31
 #define ARM_EXCEPTION_CODE(x)    ((x) & ~(1U << ARM_EXIT_WITH_SERROR_BIT))
 #define ARM_EXCEPTION_IS_TRAP(x)  (ARM_EXCEPTION_CODE((x)) == ARM_EXCEPTION_TRAP)
@@ -102,11 +99,9 @@ DECLARE_KVM_HYP_SYM(__kvm_hyp_vector);
 #define __kvm_hyp_init         CHOOSE_NVHE_SYM(__kvm_hyp_init)
 #define __kvm_hyp_vector       CHOOSE_HYP_SYM(__kvm_hyp_vector)
 
-#ifdef CONFIG_KVM_INDIRECT_VECTORS
 extern atomic_t arm64_el2_vector_last_slot;
 DECLARE_KVM_HYP_SYM(__bp_harden_hyp_vecs);
 #define __bp_harden_hyp_vecs   CHOOSE_HYP_SYM(__bp_harden_hyp_vecs)
-#endif
 
 extern void __kvm_flush_vm_context(void);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu, phys_addr_t ipa,
@@ -169,6 +164,34 @@ extern char __smccc_workaround_1_smc[__SMCCC_WORKAROUND_1_SMC_SZ];
                *__hyp_this_cpu_ptr(sym);                               \
         })
 
+#define __KVM_EXTABLE(from, to)                                                \
+       "       .pushsection    __kvm_ex_table, \"a\"\n"                \
+       "       .align          3\n"                                    \
+       "       .long           (" #from " - .), (" #to " - .)\n"       \
+       "       .popsection\n"
+
+
+#define __kvm_at(at_op, addr)                                          \
+( {                                                                    \
+       int __kvm_at_err = 0;                                           \
+       u64 spsr, elr;                                                  \
+       asm volatile(                                                   \
+       "       mrs     %1, spsr_el2\n"                                 \
+       "       mrs     %2, elr_el2\n"                                  \
+       "1:     at      "at_op", %3\n"                                  \
+       "       isb\n"                                                  \
+       "       b       9f\n"                                           \
+       "2:     msr     spsr_el2, %1\n"                                 \
+       "       msr     elr_el2, %2\n"                                  \
+       "       mov     %w0, %4\n"                                      \
+       "9:\n"                                                          \
+       __KVM_EXTABLE(1b, 2b)                                           \
+       : "+r" (__kvm_at_err), "=&r" (spsr), "=&r" (elr)                \
+       : "r" (addr), "i" (-EFAULT));                                   \
+       __kvm_at_err;                                                   \
+} )
+
+
 #else /* __ASSEMBLY__ */
 
 .macro hyp_adr_this_cpu reg, sym, tmp
@@ -193,6 +216,21 @@ extern char __smccc_workaround_1_smc[__SMCCC_WORKAROUND_1_SMC_SZ];
        ldr     \vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
 .endm
 
+/*
+ * KVM extable for unexpected exceptions.
+ * In the same format _asm_extable, but output to a different section so that
+ * it can be mapped to EL2. The KVM version is not sorted. The caller must
+ * ensure:
+ * x18 has the hypervisor value to allow any Shadow-Call-Stack instrumented
+ * code to write to it, and that SPSR_EL2 and ELR_EL2 are restored by the fixup.
+ */
+.macro _kvm_extable, from, to
+       .pushsection    __kvm_ex_table, "a"
+       .align          3
+       .long           (\from - .), (\to - .)
+       .popsection
+.endm
+
 #endif
 
 #endif /* __ARM_KVM_ASM_H__ */
index 49a55be..5ef2669 100644 (file)
@@ -298,15 +298,15 @@ static __always_inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
        return (kvm_vcpu_get_esr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
 }
 
-static __always_inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_abt_iss1tw(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_S1PTW);
 }
 
+/* Always check for S1PTW *before* using this. */
 static __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
 {
-       return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_WNR) ||
-               kvm_vcpu_dabt_iss1tw(vcpu); /* AF/DBM update */
+       return kvm_vcpu_get_esr(vcpu) & ESR_ELx_WNR;
 }
 
 static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
@@ -335,6 +335,11 @@ static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
        return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
 }
 
+static inline bool kvm_vcpu_trap_is_exec_fault(const struct kvm_vcpu *vcpu)
+{
+       return kvm_vcpu_trap_is_iabt(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu);
+}
+
 static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
 {
        return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
@@ -372,6 +377,9 @@ static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
 
 static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
 {
+       if (kvm_vcpu_abt_iss1tw(vcpu))
+               return true;
+
        if (kvm_vcpu_trap_is_iabt(vcpu))
                return false;
 
@@ -383,20 +391,6 @@ static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
        return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
 }
 
-static inline bool kvm_arm_get_vcpu_workaround_2_flag(struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.workaround_flags & VCPU_WORKAROUND_2_FLAG;
-}
-
-static inline void kvm_arm_set_vcpu_workaround_2_flag(struct kvm_vcpu *vcpu,
-                                                     bool flag)
-{
-       if (flag)
-               vcpu->arch.workaround_flags |= VCPU_WORKAROUND_2_FLAG;
-       else
-               vcpu->arch.workaround_flags &= ~VCPU_WORKAROUND_2_FLAG;
-}
-
 static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
 {
        if (vcpu_mode_is_32bit(vcpu)) {
index e52c927..bb5e5b8 100644 (file)
@@ -368,7 +368,6 @@ struct kvm_vcpu_arch {
 
        /* Guest PV state */
        struct {
-               u64 steal;
                u64 last_steal;
                gpa_t base;
        } steal;
@@ -544,6 +543,7 @@ long kvm_hypercall_pv_features(struct kvm_vcpu *vcpu);
 gpa_t kvm_init_stolen_time(struct kvm_vcpu *vcpu);
 void kvm_update_stolen_time(struct kvm_vcpu *vcpu);
 
+bool kvm_arm_pvtime_supported(void);
 int kvm_arm_pvtime_set_attr(struct kvm_vcpu *vcpu,
                            struct kvm_device_attr *attr);
 int kvm_arm_pvtime_get_attr(struct kvm_vcpu *vcpu,
@@ -631,46 +631,6 @@ static inline void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) {}
 static inline void kvm_clr_pmu_events(u32 clr) {}
 #endif
 
-#define KVM_BP_HARDEN_UNKNOWN          -1
-#define KVM_BP_HARDEN_WA_NEEDED                0
-#define KVM_BP_HARDEN_NOT_REQUIRED     1
-
-static inline int kvm_arm_harden_branch_predictor(void)
-{
-       switch (get_spectre_v2_workaround_state()) {
-       case ARM64_BP_HARDEN_WA_NEEDED:
-               return KVM_BP_HARDEN_WA_NEEDED;
-       case ARM64_BP_HARDEN_NOT_REQUIRED:
-               return KVM_BP_HARDEN_NOT_REQUIRED;
-       case ARM64_BP_HARDEN_UNKNOWN:
-       default:
-               return KVM_BP_HARDEN_UNKNOWN;
-       }
-}
-
-#define KVM_SSBD_UNKNOWN               -1
-#define KVM_SSBD_FORCE_DISABLE         0
-#define KVM_SSBD_KERNEL                1
-#define KVM_SSBD_FORCE_ENABLE          2
-#define KVM_SSBD_MITIGATED             3
-
-static inline int kvm_arm_have_ssbd(void)
-{
-       switch (arm64_get_ssbd_state()) {
-       case ARM64_SSBD_FORCE_DISABLE:
-               return KVM_SSBD_FORCE_DISABLE;
-       case ARM64_SSBD_KERNEL:
-               return KVM_SSBD_KERNEL;
-       case ARM64_SSBD_FORCE_ENABLE:
-               return KVM_SSBD_FORCE_ENABLE;
-       case ARM64_SSBD_MITIGATED:
-               return KVM_SSBD_MITIGATED;
-       case ARM64_SSBD_UNKNOWN:
-       default:
-               return KVM_SSBD_UNKNOWN;
-       }
-}
-
 void kvm_vcpu_load_sysregs_vhe(struct kvm_vcpu *vcpu);
 void kvm_vcpu_put_sysregs_vhe(struct kvm_vcpu *vcpu);
 
index 189839c..cff1ceb 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <asm/page.h>
 #include <asm/memory.h>
+#include <asm/mmu.h>
 #include <asm/cpufeature.h>
 
 /*
@@ -430,19 +431,17 @@ static inline int kvm_write_guest_lock(struct kvm *kvm, gpa_t gpa,
        return ret;
 }
 
-#ifdef CONFIG_KVM_INDIRECT_VECTORS
 /*
  * EL2 vectors can be mapped and rerouted in a number of ways,
  * depending on the kernel configuration and CPU present:
  *
- * - If the CPU has the ARM64_HARDEN_BRANCH_PREDICTOR cap, the
- *   hardening sequence is placed in one of the vector slots, which is
- *   executed before jumping to the real vectors.
+ * - If the CPU is affected by Spectre-v2, the hardening sequence is
+ *   placed in one of the vector slots, which is executed before jumping
+ *   to the real vectors.
  *
- * - If the CPU has both the ARM64_HARDEN_EL2_VECTORS cap and the
- *   ARM64_HARDEN_BRANCH_PREDICTOR cap, the slot containing the
- *   hardening sequence is mapped next to the idmap page, and executed
- *   before jumping to the real vectors.
+ * - If the CPU also has the ARM64_HARDEN_EL2_VECTORS cap, the slot
+ *   containing the hardening sequence is mapped next to the idmap page,
+ *   and executed before jumping to the real vectors.
  *
  * - If the CPU only has the ARM64_HARDEN_EL2_VECTORS cap, then an
  *   empty slot is selected, mapped next to the idmap page, and
@@ -452,19 +451,16 @@ static inline int kvm_write_guest_lock(struct kvm *kvm, gpa_t gpa,
  * VHE, as we don't have hypervisor-specific mappings. If the system
  * is VHE and yet selects this capability, it will be ignored.
  */
-#include <asm/mmu.h>
-
 extern void *__kvm_bp_vect_base;
 extern int __kvm_harden_el2_vector_slot;
 
-/*  This is called on both VHE and !VHE systems */
 static inline void *kvm_get_hyp_vector(void)
 {
        struct bp_hardening_data *data = arm64_get_bp_hardening_data();
        void *vect = kern_hyp_va(kvm_ksym_ref(__kvm_hyp_vector));
        int slot = -1;
 
-       if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR) && data->fn) {
+       if (cpus_have_const_cap(ARM64_SPECTRE_V2) && data->fn) {
                vect = kern_hyp_va(kvm_ksym_ref(__bp_harden_hyp_vecs));
                slot = data->hyp_vectors_slot;
        }
@@ -481,76 +477,6 @@ static inline void *kvm_get_hyp_vector(void)
        return vect;
 }
 
-/*  This is only called on a !VHE system */
-static inline int kvm_map_vectors(void)
-{
-       /*
-        * HBP  = ARM64_HARDEN_BRANCH_PREDICTOR
-        * HEL2 = ARM64_HARDEN_EL2_VECTORS
-        *
-        * !HBP + !HEL2 -> use direct vectors
-        *  HBP + !HEL2 -> use hardened vectors in place
-        * !HBP +  HEL2 -> allocate one vector slot and use exec mapping
-        *  HBP +  HEL2 -> use hardened vertors and use exec mapping
-        */
-       if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR)) {
-               __kvm_bp_vect_base = kvm_ksym_ref(__bp_harden_hyp_vecs);
-               __kvm_bp_vect_base = kern_hyp_va(__kvm_bp_vect_base);
-       }
-
-       if (cpus_have_const_cap(ARM64_HARDEN_EL2_VECTORS)) {
-               phys_addr_t vect_pa = __pa_symbol(__bp_harden_hyp_vecs);
-               unsigned long size = __BP_HARDEN_HYP_VECS_SZ;
-
-               /*
-                * Always allocate a spare vector slot, as we don't
-                * know yet which CPUs have a BP hardening slot that
-                * we can reuse.
-                */
-               __kvm_harden_el2_vector_slot = atomic_inc_return(&arm64_el2_vector_last_slot);
-               BUG_ON(__kvm_harden_el2_vector_slot >= BP_HARDEN_EL2_SLOTS);
-               return create_hyp_exec_mappings(vect_pa, size,
-                                               &__kvm_bp_vect_base);
-       }
-
-       return 0;
-}
-#else
-static inline void *kvm_get_hyp_vector(void)
-{
-       return kern_hyp_va(kvm_ksym_ref(__kvm_hyp_vector));
-}
-
-static inline int kvm_map_vectors(void)
-{
-       return 0;
-}
-#endif
-
-#ifdef CONFIG_ARM64_SSBD
-DECLARE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required);
-
-static inline int hyp_map_aux_data(void)
-{
-       int cpu, err;
-
-       for_each_possible_cpu(cpu) {
-               u64 *ptr;
-
-               ptr = per_cpu_ptr(&arm64_ssbd_callback_required, cpu);
-               err = create_hyp_mappings(ptr, ptr + 1, PAGE_HYP);
-               if (err)
-                       return err;
-       }
-       return 0;
-}
-#else
-static inline int hyp_map_aux_data(void)
-{
-       return 0;
-}
-#endif
-
 #define kvm_phys_to_vttbr(addr)                phys_to_ttbr(addr)
 
 /*
index afa7225..43640d7 100644 (file)
 
 /*
  * Memory types available.
+ *
+ * IMPORTANT: MT_NORMAL must be index 0 since vm_get_page_prot() may 'or' in
+ *           the MT_NORMAL_TAGGED memory type for PROT_MTE mappings. Note
+ *           that protection_map[] only contains MT_NORMAL attributes.
  */
-#define MT_DEVICE_nGnRnE       0
-#define MT_DEVICE_nGnRE                1
-#define MT_DEVICE_GRE          2
-#define MT_NORMAL_NC           3
-#define MT_NORMAL              4
-#define MT_NORMAL_WT           5
+#define MT_NORMAL              0
+#define MT_NORMAL_TAGGED       1
+#define MT_NORMAL_NC           2
+#define MT_NORMAL_WT           3
+#define MT_DEVICE_nGnRnE       4
+#define MT_DEVICE_nGnRE                5
+#define MT_DEVICE_GRE          6
 
 /*
  * Memory types for Stage-2 translation
@@ -169,7 +174,7 @@ extern s64                  memstart_addr;
 /* PHYS_OFFSET - the physical address of the start of memory. */
 #define PHYS_OFFSET            ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; })
 
-/* the virtual base of the kernel image (minus TEXT_OFFSET) */
+/* the virtual base of the kernel image */
 extern u64                     kimage_vaddr;
 
 /* the offset between the kernel virtual and physical mappings */
index 081ec8d..e3e28f7 100644 (file)
@@ -9,16 +9,53 @@
 static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
        unsigned long pkey __always_unused)
 {
+       unsigned long ret = 0;
+
        if (system_supports_bti() && (prot & PROT_BTI))
-               return VM_ARM64_BTI;
+               ret |= VM_ARM64_BTI;
 
-       return 0;
+       if (system_supports_mte() && (prot & PROT_MTE))
+               ret |= VM_MTE;
+
+       return ret;
 }
 #define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey)
 
+static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags)
+{
+       /*
+        * Only allow MTE on anonymous mappings as these are guaranteed to be
+        * backed by tags-capable memory. The vm_flags may be overridden by a
+        * filesystem supporting MTE (RAM-based).
+        */
+       if (system_supports_mte() && (flags & MAP_ANONYMOUS))
+               return VM_MTE_ALLOWED;
+
+       return 0;
+}
+#define arch_calc_vm_flag_bits(flags) arch_calc_vm_flag_bits(flags)
+
 static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags)
 {
-       return (vm_flags & VM_ARM64_BTI) ? __pgprot(PTE_GP) : __pgprot(0);
+       pteval_t prot = 0;
+
+       if (vm_flags & VM_ARM64_BTI)
+               prot |= PTE_GP;
+
+       /*
+        * There are two conditions required for returning a Normal Tagged
+        * memory type: (1) the user requested it via PROT_MTE passed to
+        * mmap() or mprotect() and (2) the corresponding vma supports MTE. We
+        * register (1) as VM_MTE in the vma->vm_flags and (2) as
+        * VM_MTE_ALLOWED. Note that the latter can only be set during the
+        * mmap() call since mprotect() does not accept MAP_* flags.
+        * Checking for VM_MTE only is sufficient since arch_validate_flags()
+        * does not permit (VM_MTE & !VM_MTE_ALLOWED).
+        */
+       if (vm_flags & VM_MTE)
+               prot |= PTE_ATTRINDX(MT_NORMAL_TAGGED);
+
+       return __pgprot(prot);
 }
 #define arch_vm_get_page_prot(vm_flags) arch_vm_get_page_prot(vm_flags)
 
@@ -30,8 +67,21 @@ static inline bool arch_validate_prot(unsigned long prot,
        if (system_supports_bti())
                supported |= PROT_BTI;
 
+       if (system_supports_mte())
+               supported |= PROT_MTE;
+
        return (prot & ~supported) == 0;
 }
 #define arch_validate_prot(prot, addr) arch_validate_prot(prot, addr)
 
+static inline bool arch_validate_flags(unsigned long vm_flags)
+{
+       if (!system_supports_mte())
+               return true;
+
+       /* only allow VM_MTE if VM_MTE_ALLOWED has been set previously */
+       return !(vm_flags & VM_MTE) || (vm_flags & VM_MTE_ALLOWED);
+}
+#define arch_validate_flags(vm_flags) arch_validate_flags(vm_flags)
+
 #endif /* ! __ASM_MMAN_H__ */
index a7a5eca..b2e91c1 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#include <linux/refcount.h>
+
 typedef struct {
        atomic64_t      id;
 #ifdef CONFIG_COMPAT
        void            *sigpage;
 #endif
+       refcount_t      pinned;
        void            *vdso;
        unsigned long   flags;
 } mm_context_t;
@@ -45,7 +48,6 @@ struct bp_hardening_data {
        bp_hardening_cb_t       fn;
 };
 
-#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
 DECLARE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
 
 static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void)
@@ -57,21 +59,13 @@ static inline void arm64_apply_bp_hardening(void)
 {
        struct bp_hardening_data *d;
 
-       if (!cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR))
+       if (!cpus_have_const_cap(ARM64_SPECTRE_V2))
                return;
 
        d = arm64_get_bp_hardening_data();
        if (d->fn)
                d->fn();
 }
-#else
-static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void)
-{
-       return NULL;
-}
-
-static inline void arm64_apply_bp_hardening(void)      { }
-#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
 
 extern void arm64_memblock_init(void);
 extern void paging_init(void);
index f2d7537..0672236 100644 (file)
@@ -177,7 +177,13 @@ static inline void cpu_replace_ttbr1(pgd_t *pgdp)
 #define destroy_context(mm)            do { } while(0)
 void check_and_switch_context(struct mm_struct *mm);
 
-#define init_new_context(tsk,mm)       ({ atomic64_set(&(mm)->context.id, 0); 0; })
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+       atomic64_set(&mm->context.id, 0);
+       refcount_set(&mm->context.pinned, 0);
+       return 0;
+}
 
 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
 static inline void update_saved_ttbr0(struct task_struct *tsk,
@@ -248,6 +254,9 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
 void verify_cpu_asid_bits(void);
 void post_ttbr_update_workaround(void);
 
+unsigned long arm64_mm_context_get(struct mm_struct *mm);
+void arm64_mm_context_put(struct mm_struct *mm);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* !__ASM_MMU_CONTEXT_H */
diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h
new file mode 100644 (file)
index 0000000..1c99fca
--- /dev/null
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 ARM Ltd.
+ */
+#ifndef __ASM_MTE_H
+#define __ASM_MTE_H
+
+#define MTE_GRANULE_SIZE       UL(16)
+#define MTE_GRANULE_MASK       (~(MTE_GRANULE_SIZE - 1))
+#define MTE_TAG_SHIFT          56
+#define MTE_TAG_SIZE           4
+
+#ifndef __ASSEMBLY__
+
+#include <linux/page-flags.h>
+
+#include <asm/pgtable-types.h>
+
+void mte_clear_page_tags(void *addr);
+unsigned long mte_copy_tags_from_user(void *to, const void __user *from,
+                                     unsigned long n);
+unsigned long mte_copy_tags_to_user(void __user *to, void *from,
+                                   unsigned long n);
+int mte_save_tags(struct page *page);
+void mte_save_page_tags(const void *page_addr, void *tag_storage);
+bool mte_restore_tags(swp_entry_t entry, struct page *page);
+void mte_restore_page_tags(void *page_addr, const void *tag_storage);
+void mte_invalidate_tags(int type, pgoff_t offset);
+void mte_invalidate_tags_area(int type);
+void *mte_allocate_tag_storage(void);
+void mte_free_tag_storage(char *storage);
+
+#ifdef CONFIG_ARM64_MTE
+
+/* track which pages have valid allocation tags */
+#define PG_mte_tagged  PG_arch_2
+
+void mte_sync_tags(pte_t *ptep, pte_t pte);
+void mte_copy_page_tags(void *kto, const void *kfrom);
+void flush_mte_state(void);
+void mte_thread_switch(struct task_struct *next);
+void mte_suspend_exit(void);
+long set_mte_ctrl(struct task_struct *task, unsigned long arg);
+long get_mte_ctrl(struct task_struct *task);
+int mte_ptrace_copy_tags(struct task_struct *child, long request,
+                        unsigned long addr, unsigned long data);
+
+#else
+
+/* unused if !CONFIG_ARM64_MTE, silence the compiler */
+#define PG_mte_tagged  0
+
+static inline void mte_sync_tags(pte_t *ptep, pte_t pte)
+{
+}
+static inline void mte_copy_page_tags(void *kto, const void *kfrom)
+{
+}
+static inline void flush_mte_state(void)
+{
+}
+static inline void mte_thread_switch(struct task_struct *next)
+{
+}
+static inline void mte_suspend_exit(void)
+{
+}
+static inline long set_mte_ctrl(struct task_struct *task, unsigned long arg)
+{
+       return 0;
+}
+static inline long get_mte_ctrl(struct task_struct *task)
+{
+       return 0;
+}
+static inline int mte_ptrace_copy_tags(struct task_struct *child,
+                                      long request, unsigned long addr,
+                                      unsigned long data)
+{
+       return -EIO;
+}
+
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_MTE_H  */
index 626ad01..dd87039 100644 (file)
@@ -25,6 +25,9 @@ const struct cpumask *cpumask_of_node(int node);
 /* Returns a pointer to the cpumask of CPUs on Node 'node'. */
 static inline const struct cpumask *cpumask_of_node(int node)
 {
+       if (node == NUMA_NO_NODE)
+               return cpu_all_mask;
+
        return node_to_cpumask_map[node];
 }
 #endif
index f99d48e..2403f7b 100644 (file)
 #include <linux/const.h>
 
 /* PAGE_SHIFT determines the page size */
-/* CONT_SHIFT determines the number of pages which can be tracked together  */
 #define PAGE_SHIFT             CONFIG_ARM64_PAGE_SHIFT
-#define CONT_SHIFT             CONFIG_ARM64_CONT_SHIFT
 #define PAGE_SIZE              (_AC(1, UL) << PAGE_SHIFT)
 #define PAGE_MASK              (~(PAGE_SIZE-1))
 
-#define CONT_SIZE              (_AC(1, UL) << (CONT_SHIFT + PAGE_SHIFT))
-#define CONT_MASK              (~(CONT_SIZE-1))
-
 #endif /* __ASM_PAGE_DEF_H */
index c01b52a..012cffc 100644 (file)
 #include <linux/personality.h> /* for READ_IMPLIES_EXEC */
 #include <asm/pgtable-types.h>
 
-extern void __cpu_clear_user_page(void *p, unsigned long user);
-extern void __cpu_copy_user_page(void *to, const void *from,
-                                unsigned long user);
+struct page;
+struct vm_area_struct;
+
 extern void copy_page(void *to, const void *from);
 extern void clear_page(void *to);
 
+void copy_user_highpage(struct page *to, struct page *from,
+                       unsigned long vaddr, struct vm_area_struct *vma);
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
+
+void copy_highpage(struct page *to, struct page *from);
+#define __HAVE_ARCH_COPY_HIGHPAGE
+
 #define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
        alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
 
-#define clear_user_page(addr,vaddr,pg)  __cpu_clear_user_page(addr, vaddr)
-#define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr)
+#define clear_user_page(page, vaddr, pg)       clear_page(page)
+#define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
 
 typedef struct page *pgtable_t;
 
@@ -36,7 +43,7 @@ extern int pfn_valid(unsigned long);
 
 #endif /* !__ASSEMBLY__ */
 
-#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_TSK_EXEC
+#define VM_DATA_DEFAULT_FLAGS  (VM_DATA_FLAGS_TSK_EXEC | VM_MTE_ALLOWED)
 
 #include <asm-generic/getorder.h>
 
index 70b323c..b33ca26 100644 (file)
@@ -17,6 +17,7 @@
 #define pcibios_assign_all_busses() \
        (pci_has_flag(PCI_REASSIGN_ALL_BUS))
 
+#define arch_can_pci_mmap_wc() 1
 #define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
 
 extern int isa_dma_bridge_buggy;
index 2c2d7db..60731f6 100644 (file)
 #define ARMV8_PMU_USERENR_CR   (1 << 2) /* Cycle counter can be read at EL0 */
 #define ARMV8_PMU_USERENR_ER   (1 << 3) /* Event counter can be read at EL0 */
 
+/* PMMIR_EL1.SLOTS mask */
+#define ARMV8_PMU_SLOTS_MASK   0xff
+
 #ifdef CONFIG_PERF_EVENTS
 struct pt_regs;
 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
index d400a4d..94b3f2a 100644 (file)
 /*
  * Contiguous page definitions.
  */
-#ifdef CONFIG_ARM64_64K_PAGES
-#define CONT_PTE_SHIFT         (5 + PAGE_SHIFT)
-#define CONT_PMD_SHIFT         (5 + PMD_SHIFT)
-#elif defined(CONFIG_ARM64_16K_PAGES)
-#define CONT_PTE_SHIFT         (7 + PAGE_SHIFT)
-#define CONT_PMD_SHIFT         (5 + PMD_SHIFT)
-#else
-#define CONT_PTE_SHIFT         (4 + PAGE_SHIFT)
-#define CONT_PMD_SHIFT         (4 + PMD_SHIFT)
-#endif
-
+#define CONT_PTE_SHIFT         (CONFIG_ARM64_CONT_PTE_SHIFT + PAGE_SHIFT)
 #define CONT_PTES              (1 << (CONT_PTE_SHIFT - PAGE_SHIFT))
 #define CONT_PTE_SIZE          (CONT_PTES * PAGE_SIZE)
 #define CONT_PTE_MASK          (~(CONT_PTE_SIZE - 1))
+
+#define CONT_PMD_SHIFT         (CONFIG_ARM64_CONT_PMD_SHIFT + PMD_SHIFT)
 #define CONT_PMDS              (1 << (CONT_PMD_SHIFT - PMD_SHIFT))
 #define CONT_PMD_SIZE          (CONT_PMDS * PMD_SIZE)
 #define CONT_PMD_MASK          (~(CONT_PMD_SIZE - 1))
-/* the numerical offset of the PTE within a range of CONT_PTES */
-#define CONT_RANGE_OFFSET(addr) (((addr)>>PAGE_SHIFT)&(CONT_PTES-1))
 
 /*
  * Hardware page table definitions.
index 4d867c6..4cd0d6c 100644 (file)
 #define PTE_DEVMAP             (_AT(pteval_t, 1) << 57)
 #define PTE_PROT_NONE          (_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */
 
+/*
+ * This bit indicates that the entry is present i.e. pmd_page()
+ * still points to a valid huge page in memory even if the pmd
+ * has been invalidated.
+ */
+#define PMD_PRESENT_INVALID    (_AT(pteval_t, 1) << 59) /* only when !PMD_SECT_VALID */
+
 #ifndef __ASSEMBLY__
 
 #include <asm/cpufeature.h>
@@ -50,6 +57,7 @@ extern bool arm64_use_ng_mappings;
 #define PROT_NORMAL_NC         (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC))
 #define PROT_NORMAL_WT         (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT))
 #define PROT_NORMAL            (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
+#define PROT_NORMAL_TAGGED     (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_TAGGED))
 
 #define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
 #define PROT_SECT_NORMAL       (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
@@ -59,6 +67,7 @@ extern bool arm64_use_ng_mappings;
 #define _HYP_PAGE_DEFAULT      _PAGE_DEFAULT
 
 #define PAGE_KERNEL            __pgprot(PROT_NORMAL)
+#define PAGE_KERNEL_TAGGED     __pgprot(PROT_NORMAL_TAGGED)
 #define PAGE_KERNEL_RO         __pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
 #define PAGE_KERNEL_ROX                __pgprot((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY)
 #define PAGE_KERNEL_EXEC       __pgprot(PROT_NORMAL & ~PTE_PXN)
index d5d3fbe..a11bf52 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/proc-fns.h>
 
 #include <asm/memory.h>
+#include <asm/mte.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable-prot.h>
 #include <asm/tlbflush.h>
 
 extern struct page *vmemmap;
 
-extern void __pte_error(const char *file, int line, unsigned long val);
-extern void __pmd_error(const char *file, int line, unsigned long val);
-extern void __pud_error(const char *file, int line, unsigned long val);
-extern void __pgd_error(const char *file, int line, unsigned long val);
-
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 #define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
 
@@ -51,13 +47,22 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 /*
+ * Outside of a few very special situations (e.g. hibernation), we always
+ * use broadcast TLB invalidation instructions, therefore a spurious page
+ * fault on one CPU which has been handled concurrently by another CPU
+ * does not need to perform additional invalidation.
+ */
+#define flush_tlb_fix_spurious_fault(vma, address) do { } while (0)
+
+/*
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
 extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 #define ZERO_PAGE(vaddr)       phys_to_page(__pa_symbol(empty_zero_page))
 
-#define pte_ERROR(pte)         __pte_error(__FILE__, __LINE__, pte_val(pte))
+#define pte_ERROR(e)   \
+       pr_err("%s:%d: bad pte %016llx.\n", __FILE__, __LINE__, pte_val(e))
 
 /*
  * Macros to convert between a physical address and its placement in a
@@ -90,6 +95,8 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 #define pte_user_exec(pte)     (!(pte_val(pte) & PTE_UXN))
 #define pte_cont(pte)          (!!(pte_val(pte) & PTE_CONT))
 #define pte_devmap(pte)                (!!(pte_val(pte) & PTE_DEVMAP))
+#define pte_tagged(pte)                ((pte_val(pte) & PTE_ATTRINDX_MASK) == \
+                                PTE_ATTRINDX(MT_NORMAL_TAGGED))
 
 #define pte_cont_addr_end(addr, end)                                           \
 ({     unsigned long __boundary = ((addr) + CONT_PTE_SIZE) & CONT_PTE_MASK;    \
@@ -145,6 +152,18 @@ static inline pte_t set_pte_bit(pte_t pte, pgprot_t prot)
        return pte;
 }
 
+static inline pmd_t clear_pmd_bit(pmd_t pmd, pgprot_t prot)
+{
+       pmd_val(pmd) &= ~pgprot_val(prot);
+       return pmd;
+}
+
+static inline pmd_t set_pmd_bit(pmd_t pmd, pgprot_t prot)
+{
+       pmd_val(pmd) |= pgprot_val(prot);
+       return pmd;
+}
+
 static inline pte_t pte_wrprotect(pte_t pte)
 {
        pte = clear_pte_bit(pte, __pgprot(PTE_WRITE));
@@ -284,6 +303,10 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
        if (pte_present(pte) && pte_user_exec(pte) && !pte_special(pte))
                __sync_icache_dcache(pte);
 
+       if (system_supports_mte() &&
+           pte_present(pte) && pte_tagged(pte) && !pte_special(pte))
+               mte_sync_tags(ptep, pte);
+
        __check_racy_pte_update(mm, ptep, pte);
 
        set_pte(ptep, pte);
@@ -363,15 +386,24 @@ static inline int pmd_protnone(pmd_t pmd)
 }
 #endif
 
+#define pmd_present_invalid(pmd)     (!!(pmd_val(pmd) & PMD_PRESENT_INVALID))
+
+static inline int pmd_present(pmd_t pmd)
+{
+       return pte_present(pmd_pte(pmd)) || pmd_present_invalid(pmd);
+}
+
 /*
  * THP definitions.
  */
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-#define pmd_trans_huge(pmd)    (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
+static inline int pmd_trans_huge(pmd_t pmd)
+{
+       return pmd_val(pmd) && pmd_present(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
+}
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-#define pmd_present(pmd)       pte_present(pmd_pte(pmd))
 #define pmd_dirty(pmd)         pte_dirty(pmd_pte(pmd))
 #define pmd_young(pmd)         pte_young(pmd_pte(pmd))
 #define pmd_valid(pmd)         pte_valid(pmd_pte(pmd))
@@ -381,7 +413,14 @@ static inline int pmd_protnone(pmd_t pmd)
 #define pmd_mkclean(pmd)       pte_pmd(pte_mkclean(pmd_pte(pmd)))
 #define pmd_mkdirty(pmd)       pte_pmd(pte_mkdirty(pmd_pte(pmd)))
 #define pmd_mkyoung(pmd)       pte_pmd(pte_mkyoung(pmd_pte(pmd)))
-#define pmd_mkinvalid(pmd)     (__pmd(pmd_val(pmd) & ~PMD_SECT_VALID))
+
+static inline pmd_t pmd_mkinvalid(pmd_t pmd)
+{
+       pmd = set_pmd_bit(pmd, __pgprot(PMD_PRESENT_INVALID));
+       pmd = clear_pmd_bit(pmd, __pgprot(PMD_SECT_VALID));
+
+       return pmd;
+}
 
 #define pmd_thp_or_huge(pmd)   (pmd_huge(pmd) || pmd_trans_huge(pmd))
 
@@ -541,7 +580,8 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
 
 #if CONFIG_PGTABLE_LEVELS > 2
 
-#define pmd_ERROR(pmd)         __pmd_error(__FILE__, __LINE__, pmd_val(pmd))
+#define pmd_ERROR(e)   \
+       pr_err("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e))
 
 #define pud_none(pud)          (!pud_val(pud))
 #define pud_bad(pud)           (!(pud_val(pud) & PUD_TABLE_BIT))
@@ -608,7 +648,8 @@ static inline unsigned long pud_page_vaddr(pud_t pud)
 
 #if CONFIG_PGTABLE_LEVELS > 3
 
-#define pud_ERROR(pud)         __pud_error(__FILE__, __LINE__, pud_val(pud))
+#define pud_ERROR(e)   \
+       pr_err("%s:%d: bad pud %016llx.\n", __FILE__, __LINE__, pud_val(e))
 
 #define p4d_none(p4d)          (!p4d_val(p4d))
 #define p4d_bad(p4d)           (!(p4d_val(p4d) & 2))
@@ -667,15 +708,21 @@ static inline unsigned long p4d_page_vaddr(p4d_t p4d)
 
 #endif  /* CONFIG_PGTABLE_LEVELS > 3 */
 
-#define pgd_ERROR(pgd)         __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
+#define pgd_ERROR(e)   \
+       pr_err("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e))
 
 #define pgd_set_fixmap(addr)   ((pgd_t *)set_fixmap_offset(FIX_PGD, addr))
 #define pgd_clear_fixmap()     clear_fixmap(FIX_PGD)
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
+       /*
+        * Normal and Normal-Tagged are two different memory types and indices
+        * in MAIR_EL1. The mask below has to include PTE_ATTRINDX_MASK.
+        */
        const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
-                             PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP;
+                             PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP |
+                             PTE_ATTRINDX_MASK;
        /* preserve the hardware dirty information */
        if (pte_hw_dirty(pte))
                pte = pte_mkdirty(pte);
@@ -847,6 +894,11 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
 #define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(swp)        ((pte_t) { (swp).val })
 
+#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#define __pmd_to_swp_entry(pmd)                ((swp_entry_t) { pmd_val(pmd) })
+#define __swp_entry_to_pmd(swp)                __pmd((swp).val)
+#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
+
 /*
  * Ensure that there are not more swap files than can be encoded in the kernel
  * PTEs.
@@ -855,6 +907,38 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
 
 extern int kern_addr_valid(unsigned long addr);
 
+#ifdef CONFIG_ARM64_MTE
+
+#define __HAVE_ARCH_PREPARE_TO_SWAP
+static inline int arch_prepare_to_swap(struct page *page)
+{
+       if (system_supports_mte())
+               return mte_save_tags(page);
+       return 0;
+}
+
+#define __HAVE_ARCH_SWAP_INVALIDATE
+static inline void arch_swap_invalidate_page(int type, pgoff_t offset)
+{
+       if (system_supports_mte())
+               mte_invalidate_tags(type, offset);
+}
+
+static inline void arch_swap_invalidate_area(int type)
+{
+       if (system_supports_mte())
+               mte_invalidate_tags_area(type);
+}
+
+#define __HAVE_ARCH_SWAP_RESTORE
+static inline void arch_swap_restore(swp_entry_t entry, struct page *page)
+{
+       if (system_supports_mte() && mte_restore_tags(entry, page))
+               set_bit(PG_mte_tagged, &page->flags);
+}
+
+#endif /* CONFIG_ARM64_MTE */
+
 /*
  * On AArch64, the cache coherency is handled via the set_pte_at() function.
  */
index 240fe5e..fce8cbe 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/pgtable-hwdef.h>
 #include <asm/pointer_auth.h>
 #include <asm/ptrace.h>
+#include <asm/spectre.h>
 #include <asm/types.h>
 
 /*
@@ -151,6 +152,10 @@ struct thread_struct {
        struct ptrauth_keys_user        keys_user;
        struct ptrauth_keys_kernel      keys_kernel;
 #endif
+#ifdef CONFIG_ARM64_MTE
+       u64                     sctlr_tcf0;
+       u64                     gcr_user_incl;
+#endif
 };
 
 static inline void arch_thread_struct_whitelist(unsigned long *offset,
@@ -197,40 +202,15 @@ static inline void start_thread_common(struct pt_regs *regs, unsigned long pc)
                regs->pmr_save = GIC_PRIO_IRQON;
 }
 
-static inline void set_ssbs_bit(struct pt_regs *regs)
-{
-       regs->pstate |= PSR_SSBS_BIT;
-}
-
-static inline void set_compat_ssbs_bit(struct pt_regs *regs)
-{
-       regs->pstate |= PSR_AA32_SSBS_BIT;
-}
-
 static inline void start_thread(struct pt_regs *regs, unsigned long pc,
                                unsigned long sp)
 {
        start_thread_common(regs, pc);
        regs->pstate = PSR_MODE_EL0t;
-
-       if (arm64_get_ssbd_state() != ARM64_SSBD_FORCE_ENABLE)
-               set_ssbs_bit(regs);
-
+       spectre_v4_enable_task_mitigation(current);
        regs->sp = sp;
 }
 
-static inline bool is_ttbr0_addr(unsigned long addr)
-{
-       /* entry assembly clears tags for TTBR0 addrs */
-       return addr < TASK_SIZE;
-}
-
-static inline bool is_ttbr1_addr(unsigned long addr)
-{
-       /* TTBR1 addresses may have a tag if KASAN_SW_TAGS is in use */
-       return arch_kasan_reset_tag(addr) >= PAGE_OFFSET;
-}
-
 #ifdef CONFIG_COMPAT
 static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc,
                                       unsigned long sp)
@@ -244,13 +224,23 @@ static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc,
        regs->pstate |= PSR_AA32_E_BIT;
 #endif
 
-       if (arm64_get_ssbd_state() != ARM64_SSBD_FORCE_ENABLE)
-               set_compat_ssbs_bit(regs);
-
+       spectre_v4_enable_task_mitigation(current);
        regs->compat_sp = sp;
 }
 #endif
 
+static inline bool is_ttbr0_addr(unsigned long addr)
+{
+       /* entry assembly clears tags for TTBR0 addrs */
+       return addr < TASK_SIZE;
+}
+
+static inline bool is_ttbr1_addr(unsigned long addr)
+{
+       /* TTBR1 addresses may have a tag if KASAN_SW_TAGS is in use */
+       return arch_kasan_reset_tag(addr) >= PAGE_OFFSET;
+}
+
 /* Forward declaration, a strange C thing */
 struct task_struct;
 
@@ -315,10 +305,10 @@ extern void __init minsigstksz_setup(void);
 
 #ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
 /* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */
-long set_tagged_addr_ctrl(unsigned long arg);
-long get_tagged_addr_ctrl(void);
-#define SET_TAGGED_ADDR_CTRL(arg)      set_tagged_addr_ctrl(arg)
-#define GET_TAGGED_ADDR_CTRL()         get_tagged_addr_ctrl()
+long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg);
+long get_tagged_addr_ctrl(struct task_struct *task);
+#define SET_TAGGED_ADDR_CTRL(arg)      set_tagged_addr_ctrl(current, arg)
+#define GET_TAGGED_ADDR_CTRL()         get_tagged_addr_ctrl(current)
 #endif
 
 /*
index 966ed30..997cf8c 100644 (file)
  * interrupt disabling temporarily does not rely on IRQ priorities.
  */
 #define GIC_PRIO_IRQON                 0xe0
-#define GIC_PRIO_IRQOFF                        (GIC_PRIO_IRQON & ~0x80)
+#define __GIC_PRIO_IRQOFF              (GIC_PRIO_IRQON & ~0x80)
+#define __GIC_PRIO_IRQOFF_NS           0xa0
 #define GIC_PRIO_PSR_I_SET             (1 << 4)
 
+#define GIC_PRIO_IRQOFF                                                        \
+       ({                                                              \
+               extern struct static_key_false gic_nonsecure_priorities;\
+               u8 __prio = __GIC_PRIO_IRQOFF;                          \
+                                                                       \
+               if (static_branch_unlikely(&gic_nonsecure_priorities))  \
+                       __prio = __GIC_PRIO_IRQOFF_NS;                  \
+                                                                       \
+               __prio;                                                 \
+       })
+
 /* Additional SPSR bits not exposed in the UABI */
 #define PSR_MODE_THREAD_BIT    (1 << 0)
 #define PSR_IL_BIT             (1 << 20)
index 0eadbf9..2e7f529 100644 (file)
@@ -56,27 +56,15 @@ static inline void set_cpu_logical_map(int cpu, u64 hwid)
 struct seq_file;
 
 /*
- * generate IPI list text
- */
-extern void show_ipi_list(struct seq_file *p, int prec);
-
-/*
- * Called from C code, this handles an IPI.
- */
-extern void handle_IPI(int ipinr, struct pt_regs *regs);
-
-/*
  * Discover the set of possible CPUs and determine their
  * SMP operations.
  */
 extern void smp_init_cpus(void);
 
 /*
- * Provide a function to raise an IPI cross call on CPUs in callmap.
+ * Register IPI interrupts with the arch SMP code
  */
-extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int));
-
-extern void (*__smp_cross_call)(const struct cpumask *, unsigned int);
+extern void set_smp_ipi_range(int ipi_base, int nr_ipi);
 
 /*
  * Called from the secondary holding pen, this is the secondary CPU entry point.
diff --git a/arch/arm64/include/asm/spectre.h b/arch/arm64/include/asm/spectre.h
new file mode 100644 (file)
index 0000000..fcdfbce
--- /dev/null
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Interface for managing mitigations for Spectre vulnerabilities.
+ *
+ * Copyright (C) 2020 Google LLC
+ * Author: Will Deacon <will@kernel.org>
+ */
+
+#ifndef __ASM_SPECTRE_H
+#define __ASM_SPECTRE_H
+
+#include <asm/cpufeature.h>
+
+/* Watch out, ordering is important here. */
+enum mitigation_state {
+       SPECTRE_UNAFFECTED,
+       SPECTRE_MITIGATED,
+       SPECTRE_VULNERABLE,
+};
+
+struct task_struct;
+
+enum mitigation_state arm64_get_spectre_v2_state(void);
+bool has_spectre_v2(const struct arm64_cpu_capabilities *cap, int scope);
+void spectre_v2_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
+
+enum mitigation_state arm64_get_spectre_v4_state(void);
+bool has_spectre_v4(const struct arm64_cpu_capabilities *cap, int scope);
+void spectre_v4_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
+void spectre_v4_enable_task_mitigation(struct task_struct *tsk);
+
+#endif /* __ASM_SPECTRE_H */
index fc76130..eb29b1f 100644 (file)
@@ -63,7 +63,7 @@ struct stackframe {
 
 extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame);
 extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
-                           int (*fn)(struct stackframe *, void *), void *data);
+                           bool (*fn)(void *, unsigned long), void *data);
 extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
                           const char *loglvl);
 
index 554a7e8..d52c1b3 100644 (file)
 #define PSTATE_PAN                     pstate_field(0, 4)
 #define PSTATE_UAO                     pstate_field(0, 3)
 #define PSTATE_SSBS                    pstate_field(3, 1)
+#define PSTATE_TCO                     pstate_field(3, 4)
 
 #define SET_PSTATE_PAN(x)              __emit_inst(0xd500401f | PSTATE_PAN | ((!!x) << PSTATE_Imm_shift))
 #define SET_PSTATE_UAO(x)              __emit_inst(0xd500401f | PSTATE_UAO | ((!!x) << PSTATE_Imm_shift))
 #define SET_PSTATE_SSBS(x)             __emit_inst(0xd500401f | PSTATE_SSBS | ((!!x) << PSTATE_Imm_shift))
+#define SET_PSTATE_TCO(x)              __emit_inst(0xd500401f | PSTATE_TCO | ((!!x) << PSTATE_Imm_shift))
 
 #define __SYS_BARRIER_INSN(CRm, op2, Rt) \
        __emit_inst(0xd5000000 | sys_insn(0, 3, 3, (CRm), (op2)) | ((Rt) & 0x1f))
 #define SYS_SCTLR_EL1                  sys_reg(3, 0, 1, 0, 0)
 #define SYS_ACTLR_EL1                  sys_reg(3, 0, 1, 0, 1)
 #define SYS_CPACR_EL1                  sys_reg(3, 0, 1, 0, 2)
+#define SYS_RGSR_EL1                   sys_reg(3, 0, 1, 0, 5)
+#define SYS_GCR_EL1                    sys_reg(3, 0, 1, 0, 6)
 
 #define SYS_ZCR_EL1                    sys_reg(3, 0, 1, 2, 0)
 
 #define SYS_ERXADDR_EL1                        sys_reg(3, 0, 5, 4, 3)
 #define SYS_ERXMISC0_EL1               sys_reg(3, 0, 5, 5, 0)
 #define SYS_ERXMISC1_EL1               sys_reg(3, 0, 5, 5, 1)
+#define SYS_TFSR_EL1                   sys_reg(3, 0, 5, 6, 0)
+#define SYS_TFSRE0_EL1                 sys_reg(3, 0, 5, 6, 1)
 
 #define SYS_FAR_EL1                    sys_reg(3, 0, 6, 0, 0)
 #define SYS_PAR_EL1                    sys_reg(3, 0, 7, 4, 0)
 #define SYS_PMINTENSET_EL1             sys_reg(3, 0, 9, 14, 1)
 #define SYS_PMINTENCLR_EL1             sys_reg(3, 0, 9, 14, 2)
 
+#define SYS_PMMIR_EL1                  sys_reg(3, 0, 9, 14, 6)
+
 #define SYS_MAIR_EL1                   sys_reg(3, 0, 10, 2, 0)
 #define SYS_AMAIR_EL1                  sys_reg(3, 0, 10, 3, 0)
 
 
 #define SYS_CCSIDR_EL1                 sys_reg(3, 1, 0, 0, 0)
 #define SYS_CLIDR_EL1                  sys_reg(3, 1, 0, 0, 1)
+#define SYS_GMID_EL1                   sys_reg(3, 1, 0, 0, 4)
 #define SYS_AIDR_EL1                   sys_reg(3, 1, 0, 0, 7)
 
 #define SYS_CSSELR_EL1                 sys_reg(3, 2, 0, 0, 0)
 #define SYS_ESR_EL2                    sys_reg(3, 4, 5, 2, 0)
 #define SYS_VSESR_EL2                  sys_reg(3, 4, 5, 2, 3)
 #define SYS_FPEXC32_EL2                        sys_reg(3, 4, 5, 3, 0)
+#define SYS_TFSR_EL2                   sys_reg(3, 4, 5, 6, 0)
 #define SYS_FAR_EL2                    sys_reg(3, 4, 6, 0, 0)
 
 #define SYS_VDISR_EL2                  sys_reg(3, 4, 12, 1,  1)
 #define SYS_AFSR0_EL12                 sys_reg(3, 5, 5, 1, 0)
 #define SYS_AFSR1_EL12                 sys_reg(3, 5, 5, 1, 1)
 #define SYS_ESR_EL12                   sys_reg(3, 5, 5, 2, 0)
+#define SYS_TFSR_EL12                  sys_reg(3, 5, 5, 6, 0)
 #define SYS_FAR_EL12                   sys_reg(3, 5, 6, 0, 0)
 #define SYS_MAIR_EL12                  sys_reg(3, 5, 10, 2, 0)
 #define SYS_AMAIR_EL12                 sys_reg(3, 5, 10, 3, 0)
 
 /* Common SCTLR_ELx flags. */
 #define SCTLR_ELx_DSSBS        (BIT(44))
+#define SCTLR_ELx_ATA  (BIT(43))
+
+#define SCTLR_ELx_TCF_SHIFT    40
+#define SCTLR_ELx_TCF_NONE     (UL(0x0) << SCTLR_ELx_TCF_SHIFT)
+#define SCTLR_ELx_TCF_SYNC     (UL(0x1) << SCTLR_ELx_TCF_SHIFT)
+#define SCTLR_ELx_TCF_ASYNC    (UL(0x2) << SCTLR_ELx_TCF_SHIFT)
+#define SCTLR_ELx_TCF_MASK     (UL(0x3) << SCTLR_ELx_TCF_SHIFT)
+
+#define SCTLR_ELx_ITFSB        (BIT(37))
 #define SCTLR_ELx_ENIA (BIT(31))
 #define SCTLR_ELx_ENIB (BIT(30))
 #define SCTLR_ELx_ENDA (BIT(27))
 #endif
 
 /* SCTLR_EL1 specific flags. */
+#define SCTLR_EL1_ATA0         (BIT(42))
+
+#define SCTLR_EL1_TCF0_SHIFT   38
+#define SCTLR_EL1_TCF0_NONE    (UL(0x0) << SCTLR_EL1_TCF0_SHIFT)
+#define SCTLR_EL1_TCF0_SYNC    (UL(0x1) << SCTLR_EL1_TCF0_SHIFT)
+#define SCTLR_EL1_TCF0_ASYNC   (UL(0x2) << SCTLR_EL1_TCF0_SHIFT)
+#define SCTLR_EL1_TCF0_MASK    (UL(0x3) << SCTLR_EL1_TCF0_SHIFT)
+
 #define SCTLR_EL1_BT1          (BIT(36))
 #define SCTLR_EL1_BT0          (BIT(35))
 #define SCTLR_EL1_UCI          (BIT(26))
                         SCTLR_EL1_SA0  | SCTLR_EL1_SED  | SCTLR_ELx_I    |\
                         SCTLR_EL1_DZE  | SCTLR_EL1_UCT                   |\
                         SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN |\
+                        SCTLR_ELx_ITFSB| SCTLR_ELx_ATA  | SCTLR_EL1_ATA0 |\
                         ENDIAN_SET_EL1 | SCTLR_EL1_UCI  | SCTLR_EL1_RES1)
 
 /* MAIR_ELx memory attributes (used by Linux) */
 #define MAIR_ATTR_DEVICE_GRE           UL(0x0c)
 #define MAIR_ATTR_NORMAL_NC            UL(0x44)
 #define MAIR_ATTR_NORMAL_WT            UL(0xbb)
+#define MAIR_ATTR_NORMAL_TAGGED                UL(0xf0)
 #define MAIR_ATTR_NORMAL               UL(0xff)
 #define MAIR_ATTR_MASK                 UL(0xff)
 
 #define ID_AA64ISAR1_APA_SHIFT         4
 #define ID_AA64ISAR1_DPB_SHIFT         0
 
-#define ID_AA64ISAR1_APA_NI            0x0
-#define ID_AA64ISAR1_APA_ARCHITECTED   0x1
-#define ID_AA64ISAR1_API_NI            0x0
-#define ID_AA64ISAR1_API_IMP_DEF       0x1
-#define ID_AA64ISAR1_GPA_NI            0x0
-#define ID_AA64ISAR1_GPA_ARCHITECTED   0x1
-#define ID_AA64ISAR1_GPI_NI            0x0
-#define ID_AA64ISAR1_GPI_IMP_DEF       0x1
+#define ID_AA64ISAR1_APA_NI                    0x0
+#define ID_AA64ISAR1_APA_ARCHITECTED           0x1
+#define ID_AA64ISAR1_APA_ARCH_EPAC             0x2
+#define ID_AA64ISAR1_APA_ARCH_EPAC2            0x3
+#define ID_AA64ISAR1_APA_ARCH_EPAC2_FPAC       0x4
+#define ID_AA64ISAR1_APA_ARCH_EPAC2_FPAC_CMB   0x5
+#define ID_AA64ISAR1_API_NI                    0x0
+#define ID_AA64ISAR1_API_IMP_DEF               0x1
+#define ID_AA64ISAR1_API_IMP_DEF_EPAC          0x2
+#define ID_AA64ISAR1_API_IMP_DEF_EPAC2         0x3
+#define ID_AA64ISAR1_API_IMP_DEF_EPAC2_FPAC    0x4
+#define ID_AA64ISAR1_API_IMP_DEF_EPAC2_FPAC_CMB        0x5
+#define ID_AA64ISAR1_GPA_NI                    0x0
+#define ID_AA64ISAR1_GPA_ARCHITECTED           0x1
+#define ID_AA64ISAR1_GPI_NI                    0x0
+#define ID_AA64ISAR1_GPI_IMP_DEF               0x1
 
 /* id_aa64pfr0 */
 #define ID_AA64PFR0_CSV3_SHIFT         60
 #define ID_AA64PFR1_SSBS_PSTATE_INSNS  2
 #define ID_AA64PFR1_BT_BTI             0x1
 
+#define ID_AA64PFR1_MTE_NI             0x0
+#define ID_AA64PFR1_MTE_EL0            0x1
+#define ID_AA64PFR1_MTE                        0x2
+
 /* id_aa64zfr0 */
 #define ID_AA64ZFR0_F64MM_SHIFT                56
 #define ID_AA64ZFR0_F32MM_SHIFT                52
 #define CPACR_EL1_ZEN_EL0EN    (BIT(17)) /* enable EL0 access, if EL1EN set */
 #define CPACR_EL1_ZEN          (CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN)
 
+/* TCR EL1 Bit Definitions */
+#define SYS_TCR_EL1_TCMA1      (BIT(58))
+#define SYS_TCR_EL1_TCMA0      (BIT(57))
+
+/* GCR_EL1 Definitions */
+#define SYS_GCR_EL1_RRND       (BIT(16))
+#define SYS_GCR_EL1_EXCL_MASK  0xffffUL
+
+/* RGSR_EL1 Definitions */
+#define SYS_RGSR_EL1_TAG_MASK  0xfUL
+#define SYS_RGSR_EL1_SEED_SHIFT        8
+#define SYS_RGSR_EL1_SEED_MASK 0xffffUL
+
+/* GMID_EL1 field definitions */
+#define SYS_GMID_EL1_BS_SHIFT  0
+#define SYS_GMID_EL1_BS_SIZE   4
+
+/* TFSR{,E0}_EL1 bit definitions */
+#define SYS_TFSR_EL1_TF0_SHIFT 0
+#define SYS_TFSR_EL1_TF1_SHIFT 1
+#define SYS_TFSR_EL1_TF0       (UL(1) << SYS_TFSR_EL1_TF0_SHIFT)
+#define SYS_TFSR_EL1_TF1       (UK(2) << SYS_TFSR_EL1_TF1_SHIFT)
 
 /* Safe value for MPIDR_EL1: Bit31:RES1, Bit30:U:0, Bit24:MT:0 */
 #define SYS_MPIDR_SAFE_VAL     (BIT(31))
                write_sysreg(__scs_new, sysreg);                        \
 } while (0)
 
+#define sysreg_clear_set_s(sysreg, clear, set) do {                    \
+       u64 __scs_val = read_sysreg_s(sysreg);                          \
+       u64 __scs_new = (__scs_val & ~(u64)(clear)) | (set);            \
+       if (__scs_new != __scs_val)                                     \
+               write_sysreg_s(__scs_new, sysreg);                      \
+} while (0)
+
 #endif
 
 #endif /* __ASM_SYSREG_H */
index 5e784e1..1fbab85 100644 (file)
@@ -67,6 +67,7 @@ void arch_release_task_struct(struct task_struct *tsk);
 #define TIF_FOREIGN_FPSTATE    3       /* CPU's FP state is not current's */
 #define TIF_UPROBE             4       /* uprobe breakpoint or singlestep */
 #define TIF_FSCHECK            5       /* Check FS is USER_DS on return */
+#define TIF_MTE_ASYNC_FAULT    6       /* MTE Asynchronous Tag Check Fault */
 #define TIF_SYSCALL_TRACE      8       /* syscall trace active */
 #define TIF_SYSCALL_AUDIT      9       /* syscall auditing */
 #define TIF_SYSCALL_TRACEPOINT 10      /* syscall tracepoint for ftrace */
@@ -96,10 +97,11 @@ void arch_release_task_struct(struct task_struct *tsk);
 #define _TIF_SINGLESTEP                (1 << TIF_SINGLESTEP)
 #define _TIF_32BIT             (1 << TIF_32BIT)
 #define _TIF_SVE               (1 << TIF_SVE)
+#define _TIF_MTE_ASYNC_FAULT   (1 << TIF_MTE_ASYNC_FAULT)
 
 #define _TIF_WORK_MASK         (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
                                 _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \
-                                _TIF_UPROBE | _TIF_FSCHECK)
+                                _TIF_UPROBE | _TIF_FSCHECK | _TIF_MTE_ASYNC_FAULT)
 
 #define _TIF_SYSCALL_WORK      (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
                                 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
index d493174..cc3f5a3 100644 (file)
  * not. The macros handles invoking the asm with or without the
  * register argument as appropriate.
  */
-#define __TLBI_0(op, arg) asm ("tlbi " #op "\n"                                       \
+#define __TLBI_0(op, arg) asm (ARM64_ASM_PREAMBLE                             \
+                              "tlbi " #op "\n"                                \
                   ALTERNATIVE("nop\n                   nop",                  \
                               "dsb ish\n               tlbi " #op,            \
                               ARM64_WORKAROUND_REPEAT_TLBI,                   \
                               CONFIG_ARM64_WORKAROUND_REPEAT_TLBI)            \
                            : : )
 
-#define __TLBI_1(op, arg) asm ("tlbi " #op ", %0\n"                           \
+#define __TLBI_1(op, arg) asm (ARM64_ASM_PREAMBLE                             \
+                              "tlbi " #op ", %0\n"                            \
                   ALTERNATIVE("nop\n                   nop",                  \
                               "dsb ish\n               tlbi " #op ", %0",     \
                               ARM64_WORKAROUND_REPEAT_TLBI,                   \
index cee5928..d96dc2c 100644 (file)
@@ -24,7 +24,7 @@ struct undef_hook {
 
 void register_undef_hook(struct undef_hook *hook);
 void unregister_undef_hook(struct undef_hook *hook);
-void force_signal_inject(int signal, int code, unsigned long address);
+void force_signal_inject(int signal, int code, unsigned long address, unsigned int err);
 void arm64_notify_segfault(unsigned long addr);
 void arm64_force_sig_fault(int signo, int code, void __user *addr, const char *str);
 void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, const char *str);
index 734860a..2a3ad9b 100644 (file)
@@ -53,7 +53,7 @@ __SYSCALL(__NR_lseek, compat_sys_lseek)
 #define __NR_getpid 20
 __SYSCALL(__NR_getpid, sys_getpid)
 #define __NR_mount 21
-__SYSCALL(__NR_mount, compat_sys_mount)
+__SYSCALL(__NR_mount, sys_mount)
                        /* 22 was sys_umount */
 __SYSCALL(22, sys_ni_syscall)
 #define __NR_setuid 23
@@ -301,9 +301,9 @@ __SYSCALL(__NR_flock, sys_flock)
 #define __NR_msync 144
 __SYSCALL(__NR_msync, sys_msync)
 #define __NR_readv 145
-__SYSCALL(__NR_readv, compat_sys_readv)
+__SYSCALL(__NR_readv, sys_readv)
 #define __NR_writev 146
-__SYSCALL(__NR_writev, compat_sys_writev)
+__SYSCALL(__NR_writev, sys_writev)
 #define __NR_getsid 147
 __SYSCALL(__NR_getsid, sys_getsid)
 #define __NR_fdatasync 148
@@ -697,7 +697,7 @@ __SYSCALL(__NR_sync_file_range2, compat_sys_aarch32_sync_file_range2)
 #define __NR_tee 342
 __SYSCALL(__NR_tee, sys_tee)
 #define __NR_vmsplice 343
-__SYSCALL(__NR_vmsplice, compat_sys_vmsplice)
+__SYSCALL(__NR_vmsplice, sys_vmsplice)
 #define __NR_move_pages 344
 __SYSCALL(__NR_move_pages, compat_sys_move_pages)
 #define __NR_getcpu 345
@@ -763,9 +763,9 @@ __SYSCALL(__NR_sendmmsg, compat_sys_sendmmsg)
 #define __NR_setns 375
 __SYSCALL(__NR_setns, sys_setns)
 #define __NR_process_vm_readv 376
-__SYSCALL(__NR_process_vm_readv, compat_sys_process_vm_readv)
+__SYSCALL(__NR_process_vm_readv, sys_process_vm_readv)
 #define __NR_process_vm_writev 377
-__SYSCALL(__NR_process_vm_writev, compat_sys_process_vm_writev)
+__SYSCALL(__NR_process_vm_writev, sys_process_vm_writev)
 #define __NR_kcmp 378
 __SYSCALL(__NR_kcmp, sys_kcmp)
 #define __NR_finit_module 379
index 912162f..b8f41aa 100644 (file)
@@ -74,6 +74,6 @@
 #define HWCAP2_DGH             (1 << 15)
 #define HWCAP2_RNG             (1 << 16)
 #define HWCAP2_BTI             (1 << 17)
-/* reserved for HWCAP2_MTE     (1 << 18) */
+#define HWCAP2_MTE             (1 << 18)
 
 #endif /* _UAPI__ASM_HWCAP_H */
index ba85bb2..7d804fd 100644 (file)
@@ -242,6 +242,15 @@ struct kvm_vcpu_events {
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL          0
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL              1
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED       2
+
+/*
+ * Only two states can be presented by the host kernel:
+ * - NOT_REQUIRED: the guest doesn't need to do anything
+ * - NOT_AVAIL: the guest isn't mitigated (it can still use SSBS if available)
+ *
+ * All the other values are deprecated. The host still accepts all
+ * values (they are ABI), but will narrow them to the above two.
+ */
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2    KVM_REG_ARM_FW_REG(2)
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL          0
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN            1
index 6fdd71e..1e6482a 100644 (file)
@@ -5,5 +5,6 @@
 #include <asm-generic/mman.h>
 
 #define PROT_BTI       0x10            /* BTI guarded page */
+#define PROT_MTE       0x20            /* Normal Tagged mapping */
 
 #endif /* ! _UAPI__ASM_MMAN_H */
index 42cbe34..758ae98 100644 (file)
@@ -51,6 +51,7 @@
 #define PSR_PAN_BIT    0x00400000
 #define PSR_UAO_BIT    0x00800000
 #define PSR_DIT_BIT    0x01000000
+#define PSR_TCO_BIT    0x02000000
 #define PSR_V_BIT      0x10000000
 #define PSR_C_BIT      0x20000000
 #define PSR_Z_BIT      0x40000000
@@ -75,6 +76,9 @@
 /* syscall emulation path in ptrace */
 #define PTRACE_SYSEMU            31
 #define PTRACE_SYSEMU_SINGLESTEP  32
+/* MTE allocation tag access */
+#define PTRACE_PEEKMTETAGS       33
+#define PTRACE_POKEMTETAGS       34
 
 #ifndef __ASSEMBLY__
 
index a561cbb..bbaf0bc 100644 (file)
@@ -3,8 +3,6 @@
 # Makefile for the linux kernel.
 #
 
-CPPFLAGS_vmlinux.lds   := -DTEXT_OFFSET=$(TEXT_OFFSET)
-AFLAGS_head.o          := -DTEXT_OFFSET=$(TEXT_OFFSET)
 CFLAGS_armv8_deprecated.o := -I$(src)
 
 CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
@@ -19,7 +17,7 @@ obj-y                 := debug-monitors.o entry.o irq.o fpsimd.o              \
                           return_address.o cpuinfo.o cpu_errata.o              \
                           cpufeature.o alternative.o cacheinfo.o               \
                           smp.o smp_spin_table.o topology.o smccc-call.o       \
-                          syscall.o
+                          syscall.o proton-pack.o
 
 targets                        += efi-entry.o
 
@@ -59,9 +57,9 @@ arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
 obj-$(CONFIG_CRASH_DUMP)               += crash_dump.o
 obj-$(CONFIG_CRASH_CORE)               += crash_core.o
 obj-$(CONFIG_ARM_SDE_INTERFACE)                += sdei.o
-obj-$(CONFIG_ARM64_SSBD)               += ssbd.o
 obj-$(CONFIG_ARM64_PTR_AUTH)           += pointer_auth.o
 obj-$(CONFIG_SHADOW_CALL_STACK)                += scs.o
+obj-$(CONFIG_ARM64_MTE)                        += mte.o
 
 obj-y                                  += vdso/ probes/
 obj-$(CONFIG_COMPAT_VDSO)              += vdso32/
index 4559664..cada0b8 100644 (file)
@@ -298,8 +298,21 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
                case EFI_BOOT_SERVICES_DATA:
                case EFI_CONVENTIONAL_MEMORY:
                case EFI_PERSISTENT_MEMORY:
-                       pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys);
-                       return NULL;
+                       if (memblock_is_map_memory(phys) ||
+                           !memblock_is_region_memory(phys, size)) {
+                               pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys);
+                               return NULL;
+                       }
+                       /*
+                        * Mapping kernel memory is permitted if the region in
+                        * question is covered by a single memblock with the
+                        * NOMAP attribute set: this enables the use of ACPI
+                        * table overrides passed via initramfs, which are
+                        * reserved in memory using arch_reserve_mem_area()
+                        * below. As this particular use case only requires
+                        * read access, fall through to the R/O mapping case.
+                        */
+                       fallthrough;
 
                case EFI_RUNTIME_SERVICES_CODE:
                        /*
@@ -322,7 +335,7 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
                         */
                        if (memblock_is_map_memory(phys))
                                return (void __iomem *)__phys_to_virt(phys);
-                       /* fall through */
+                       fallthrough;
 
                default:
                        if (region->attribute & EFI_MEMORY_WB)
@@ -388,3 +401,8 @@ int apei_claim_sea(struct pt_regs *regs)
 
        return err;
 }
+
+void arch_reserve_mem_area(acpi_physical_address addr, size_t size)
+{
+       memblock_mark_nomap(addr, size);
+}
index 4a18055..37721eb 100644 (file)
@@ -35,6 +35,10 @@ SYM_CODE_START(__cpu_soft_restart)
        mov_q   x13, SCTLR_ELx_FLAGS
        bic     x12, x12, x13
        pre_disable_mmu_workaround
+       /*
+        * either disable EL1&0 translation regime or disable EL2&0 translation
+        * regime if HCR_EL2.E2H == 1
+        */
        msr     sctlr_el1, x12
        isb
 
index c332d49..24d75af 100644 (file)
@@ -106,365 +106,6 @@ cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *cap)
                sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
 }
 
-atomic_t arm64_el2_vector_last_slot = ATOMIC_INIT(-1);
-
-#include <asm/mmu_context.h>
-#include <asm/cacheflush.h>
-
-DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
-
-#ifdef CONFIG_KVM_INDIRECT_VECTORS
-static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
-                               const char *hyp_vecs_end)
-{
-       void *dst = lm_alias(__bp_harden_hyp_vecs + slot * SZ_2K);
-       int i;
-
-       for (i = 0; i < SZ_2K; i += 0x80)
-               memcpy(dst + i, hyp_vecs_start, hyp_vecs_end - hyp_vecs_start);
-
-       __flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K);
-}
-
-static void install_bp_hardening_cb(bp_hardening_cb_t fn,
-                                   const char *hyp_vecs_start,
-                                   const char *hyp_vecs_end)
-{
-       static DEFINE_RAW_SPINLOCK(bp_lock);
-       int cpu, slot = -1;
-
-       /*
-        * detect_harden_bp_fw() passes NULL for the hyp_vecs start/end if
-        * we're a guest. Skip the hyp-vectors work.
-        */
-       if (!hyp_vecs_start) {
-               __this_cpu_write(bp_hardening_data.fn, fn);
-               return;
-       }
-
-       raw_spin_lock(&bp_lock);
-       for_each_possible_cpu(cpu) {
-               if (per_cpu(bp_hardening_data.fn, cpu) == fn) {
-                       slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu);
-                       break;
-               }
-       }
-
-       if (slot == -1) {
-               slot = atomic_inc_return(&arm64_el2_vector_last_slot);
-               BUG_ON(slot >= BP_HARDEN_EL2_SLOTS);
-               __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end);
-       }
-
-       __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
-       __this_cpu_write(bp_hardening_data.fn, fn);
-       raw_spin_unlock(&bp_lock);
-}
-#else
-static void install_bp_hardening_cb(bp_hardening_cb_t fn,
-                                     const char *hyp_vecs_start,
-                                     const char *hyp_vecs_end)
-{
-       __this_cpu_write(bp_hardening_data.fn, fn);
-}
-#endif /* CONFIG_KVM_INDIRECT_VECTORS */
-
-#include <linux/arm-smccc.h>
-
-static void __maybe_unused call_smc_arch_workaround_1(void)
-{
-       arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
-}
-
-static void call_hvc_arch_workaround_1(void)
-{
-       arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
-}
-
-static void qcom_link_stack_sanitization(void)
-{
-       u64 tmp;
-
-       asm volatile("mov       %0, x30         \n"
-                    ".rept     16              \n"
-                    "bl        . + 4           \n"
-                    ".endr                     \n"
-                    "mov       x30, %0         \n"
-                    : "=&r" (tmp));
-}
-
-static bool __nospectre_v2;
-static int __init parse_nospectre_v2(char *str)
-{
-       __nospectre_v2 = true;
-       return 0;
-}
-early_param("nospectre_v2", parse_nospectre_v2);
-
-/*
- * -1: No workaround
- *  0: No workaround required
- *  1: Workaround installed
- */
-static int detect_harden_bp_fw(void)
-{
-       bp_hardening_cb_t cb;
-       void *smccc_start, *smccc_end;
-       struct arm_smccc_res res;
-       u32 midr = read_cpuid_id();
-
-       arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
-                            ARM_SMCCC_ARCH_WORKAROUND_1, &res);
-
-       switch ((int)res.a0) {
-       case 1:
-               /* Firmware says we're just fine */
-               return 0;
-       case 0:
-               break;
-       default:
-               return -1;
-       }
-
-       switch (arm_smccc_1_1_get_conduit()) {
-       case SMCCC_CONDUIT_HVC:
-               cb = call_hvc_arch_workaround_1;
-               /* This is a guest, no need to patch KVM vectors */
-               smccc_start = NULL;
-               smccc_end = NULL;
-               break;
-
-#if IS_ENABLED(CONFIG_KVM)
-       case SMCCC_CONDUIT_SMC:
-               cb = call_smc_arch_workaround_1;
-               smccc_start = __smccc_workaround_1_smc;
-               smccc_end = __smccc_workaround_1_smc +
-                       __SMCCC_WORKAROUND_1_SMC_SZ;
-               break;
-#endif
-
-       default:
-               return -1;
-       }
-
-       if (((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR) ||
-           ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1))
-               cb = qcom_link_stack_sanitization;
-
-       if (IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR))
-               install_bp_hardening_cb(cb, smccc_start, smccc_end);
-
-       return 1;
-}
-
-DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required);
-
-int ssbd_state __read_mostly = ARM64_SSBD_KERNEL;
-static bool __ssb_safe = true;
-
-static const struct ssbd_options {
-       const char      *str;
-       int             state;
-} ssbd_options[] = {
-       { "force-on",   ARM64_SSBD_FORCE_ENABLE, },
-       { "force-off",  ARM64_SSBD_FORCE_DISABLE, },
-       { "kernel",     ARM64_SSBD_KERNEL, },
-};
-
-static int __init ssbd_cfg(char *buf)
-{
-       int i;
-
-       if (!buf || !buf[0])
-               return -EINVAL;
-
-       for (i = 0; i < ARRAY_SIZE(ssbd_options); i++) {
-               int len = strlen(ssbd_options[i].str);
-
-               if (strncmp(buf, ssbd_options[i].str, len))
-                       continue;
-
-               ssbd_state = ssbd_options[i].state;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-early_param("ssbd", ssbd_cfg);
-
-void __init arm64_update_smccc_conduit(struct alt_instr *alt,
-                                      __le32 *origptr, __le32 *updptr,
-                                      int nr_inst)
-{
-       u32 insn;
-
-       BUG_ON(nr_inst != 1);
-
-       switch (arm_smccc_1_1_get_conduit()) {
-       case SMCCC_CONDUIT_HVC:
-               insn = aarch64_insn_get_hvc_value();
-               break;
-       case SMCCC_CONDUIT_SMC:
-               insn = aarch64_insn_get_smc_value();
-               break;
-       default:
-               return;
-       }
-
-       *updptr = cpu_to_le32(insn);
-}
-
-void __init arm64_enable_wa2_handling(struct alt_instr *alt,
-                                     __le32 *origptr, __le32 *updptr,
-                                     int nr_inst)
-{
-       BUG_ON(nr_inst != 1);
-       /*
-        * Only allow mitigation on EL1 entry/exit and guest
-        * ARCH_WORKAROUND_2 handling if the SSBD state allows it to
-        * be flipped.
-        */
-       if (arm64_get_ssbd_state() == ARM64_SSBD_KERNEL)
-               *updptr = cpu_to_le32(aarch64_insn_gen_nop());
-}
-
-void arm64_set_ssbd_mitigation(bool state)
-{
-       int conduit;
-
-       if (!IS_ENABLED(CONFIG_ARM64_SSBD)) {
-               pr_info_once("SSBD disabled by kernel configuration\n");
-               return;
-       }
-
-       if (this_cpu_has_cap(ARM64_SSBS)) {
-               if (state)
-                       asm volatile(SET_PSTATE_SSBS(0));
-               else
-                       asm volatile(SET_PSTATE_SSBS(1));
-               return;
-       }
-
-       conduit = arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_WORKAROUND_2, state,
-                                      NULL);
-
-       WARN_ON_ONCE(conduit == SMCCC_CONDUIT_NONE);
-}
-
-static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry,
-                                   int scope)
-{
-       struct arm_smccc_res res;
-       bool required = true;
-       s32 val;
-       bool this_cpu_safe = false;
-       int conduit;
-
-       WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
-
-       if (cpu_mitigations_off())
-               ssbd_state = ARM64_SSBD_FORCE_DISABLE;
-
-       /* delay setting __ssb_safe until we get a firmware response */
-       if (is_midr_in_range_list(read_cpuid_id(), entry->midr_range_list))
-               this_cpu_safe = true;
-
-       if (this_cpu_has_cap(ARM64_SSBS)) {
-               if (!this_cpu_safe)
-                       __ssb_safe = false;
-               required = false;
-               goto out_printmsg;
-       }
-
-       conduit = arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
-                                      ARM_SMCCC_ARCH_WORKAROUND_2, &res);
-
-       if (conduit == SMCCC_CONDUIT_NONE) {
-               ssbd_state = ARM64_SSBD_UNKNOWN;
-               if (!this_cpu_safe)
-                       __ssb_safe = false;
-               return false;
-       }
-
-       val = (s32)res.a0;
-
-       switch (val) {
-       case SMCCC_RET_NOT_SUPPORTED:
-               ssbd_state = ARM64_SSBD_UNKNOWN;
-               if (!this_cpu_safe)
-                       __ssb_safe = false;
-               return false;
-
-       /* machines with mixed mitigation requirements must not return this */
-       case SMCCC_RET_NOT_REQUIRED:
-               pr_info_once("%s mitigation not required\n", entry->desc);
-               ssbd_state = ARM64_SSBD_MITIGATED;
-               return false;
-
-       case SMCCC_RET_SUCCESS:
-               __ssb_safe = false;
-               required = true;
-               break;
-
-       case 1: /* Mitigation not required on this CPU */
-               required = false;
-               break;
-
-       default:
-               WARN_ON(1);
-               if (!this_cpu_safe)
-                       __ssb_safe = false;
-               return false;
-       }
-
-       switch (ssbd_state) {
-       case ARM64_SSBD_FORCE_DISABLE:
-               arm64_set_ssbd_mitigation(false);
-               required = false;
-               break;
-
-       case ARM64_SSBD_KERNEL:
-               if (required) {
-                       __this_cpu_write(arm64_ssbd_callback_required, 1);
-                       arm64_set_ssbd_mitigation(true);
-               }
-               break;
-
-       case ARM64_SSBD_FORCE_ENABLE:
-               arm64_set_ssbd_mitigation(true);
-               required = true;
-               break;
-
-       default:
-               WARN_ON(1);
-               break;
-       }
-
-out_printmsg:
-       switch (ssbd_state) {
-       case ARM64_SSBD_FORCE_DISABLE:
-               pr_info_once("%s disabled from command-line\n", entry->desc);
-               break;
-
-       case ARM64_SSBD_FORCE_ENABLE:
-               pr_info_once("%s forced from command-line\n", entry->desc);
-               break;
-       }
-
-       return required;
-}
-
-/* known invulnerable cores */
-static const struct midr_range arm64_ssb_cpus[] = {
-       MIDR_ALL_VERSIONS(MIDR_CORTEX_A35),
-       MIDR_ALL_VERSIONS(MIDR_CORTEX_A53),
-       MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
-       MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53),
-       MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER),
-       MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER),
-       {},
-};
-
 #ifdef CONFIG_ARM64_ERRATUM_1463225
 DEFINE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa);
 
@@ -519,83 +160,6 @@ cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused)
        .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,                 \
        CAP_MIDR_RANGE_LIST(midr_list)
 
-/* Track overall mitigation state. We are only mitigated if all cores are ok */
-static bool __hardenbp_enab = true;
-static bool __spectrev2_safe = true;
-
-int get_spectre_v2_workaround_state(void)
-{
-       if (__spectrev2_safe)
-               return ARM64_BP_HARDEN_NOT_REQUIRED;
-
-       if (!__hardenbp_enab)
-               return ARM64_BP_HARDEN_UNKNOWN;
-
-       return ARM64_BP_HARDEN_WA_NEEDED;
-}
-
-/*
- * List of CPUs that do not need any Spectre-v2 mitigation at all.
- */
-static const struct midr_range spectre_v2_safe_list[] = {
-       MIDR_ALL_VERSIONS(MIDR_CORTEX_A35),
-       MIDR_ALL_VERSIONS(MIDR_CORTEX_A53),
-       MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
-       MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53),
-       MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
-       MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER),
-       MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER),
-       { /* sentinel */ }
-};
-
-/*
- * Track overall bp hardening for all heterogeneous cores in the machine.
- * We are only considered "safe" if all booted cores are known safe.
- */
-static bool __maybe_unused
-check_branch_predictor(const struct arm64_cpu_capabilities *entry, int scope)
-{
-       int need_wa;
-
-       WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
-
-       /* If the CPU has CSV2 set, we're safe */
-       if (cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64PFR0_EL1),
-                                                ID_AA64PFR0_CSV2_SHIFT))
-               return false;
-
-       /* Alternatively, we have a list of unaffected CPUs */
-       if (is_midr_in_range_list(read_cpuid_id(), spectre_v2_safe_list))
-               return false;
-
-       /* Fallback to firmware detection */
-       need_wa = detect_harden_bp_fw();
-       if (!need_wa)
-               return false;
-
-       __spectrev2_safe = false;
-
-       if (!IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR)) {
-               pr_warn_once("spectrev2 mitigation disabled by kernel configuration\n");
-               __hardenbp_enab = false;
-               return false;
-       }
-
-       /* forced off */
-       if (__nospectre_v2 || cpu_mitigations_off()) {
-               pr_info_once("spectrev2 mitigation disabled by command line option\n");
-               __hardenbp_enab = false;
-               return false;
-       }
-
-       if (need_wa < 0) {
-               pr_warn_once("ARM_SMCCC_ARCH_WORKAROUND_1 missing from firmware\n");
-               __hardenbp_enab = false;
-       }
-
-       return (need_wa > 0);
-}
-
 static const __maybe_unused struct midr_range tx2_family_cpus[] = {
        MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN),
        MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2),
@@ -887,9 +451,11 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
        },
 #endif
        {
-               .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+               .desc = "Spectre-v2",
+               .capability = ARM64_SPECTRE_V2,
                .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
-               .matches = check_branch_predictor,
+               .matches = has_spectre_v2,
+               .cpu_enable = spectre_v2_enable_mitigation,
        },
 #ifdef CONFIG_RANDOMIZE_BASE
        {
@@ -899,19 +465,23 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
        },
 #endif
        {
-               .desc = "Speculative Store Bypass Disable",
-               .capability = ARM64_SSBD,
+               .desc = "Spectre-v4",
+               .capability = ARM64_SPECTRE_V4,
                .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
-               .matches = has_ssbd_mitigation,
-               .midr_range_list = arm64_ssb_cpus,
+               .matches = has_spectre_v4,
+               .cpu_enable = spectre_v4_enable_mitigation,
        },
 #ifdef CONFIG_ARM64_ERRATUM_1418040
        {
                .desc = "ARM erratum 1418040",
                .capability = ARM64_WORKAROUND_1418040,
                ERRATA_MIDR_RANGE_LIST(erratum_1418040_list),
-               .type = (ARM64_CPUCAP_SCOPE_LOCAL_CPU |
-                        ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU),
+               /*
+                * We need to allow affected CPUs to come in late, but
+                * also need the non-affected CPUs to be able to come
+                * in at any point in time. Wonderful.
+                */
+               .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
        },
 #endif
 #ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT
@@ -956,40 +526,3 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
        {
        }
 };
-
-ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr,
-                           char *buf)
-{
-       return sprintf(buf, "Mitigation: __user pointer sanitization\n");
-}
-
-ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       switch (get_spectre_v2_workaround_state()) {
-       case ARM64_BP_HARDEN_NOT_REQUIRED:
-               return sprintf(buf, "Not affected\n");
-        case ARM64_BP_HARDEN_WA_NEEDED:
-               return sprintf(buf, "Mitigation: Branch predictor hardening\n");
-        case ARM64_BP_HARDEN_UNKNOWN:
-       default:
-               return sprintf(buf, "Vulnerable\n");
-       }
-}
-
-ssize_t cpu_show_spec_store_bypass(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       if (__ssb_safe)
-               return sprintf(buf, "Not affected\n");
-
-       switch (ssbd_state) {
-       case ARM64_SSBD_KERNEL:
-       case ARM64_SSBD_FORCE_ENABLE:
-               if (IS_ENABLED(CONFIG_ARM64_SSBD))
-                       return sprintf(buf,
-                           "Mitigation: Speculative Store Bypass disabled via prctl\n");
-       }
-
-       return sprintf(buf, "Vulnerable\n");
-}
index a389b99..dcc165b 100644 (file)
@@ -75,6 +75,7 @@
 #include <asm/cpu_ops.h>
 #include <asm/fpsimd.h>
 #include <asm/mmu_context.h>
+#include <asm/mte.h>
 #include <asm/processor.h>
 #include <asm/sysreg.h>
 #include <asm/traps.h>
@@ -197,9 +198,9 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_FCMA_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_JSCVT_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_API_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_API_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_APA_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_APA_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_DPB_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
@@ -227,7 +228,9 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
 static const struct arm64_ftr_bits ftr_id_aa64pfr1[] = {
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_MPAMFRAC_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_RASFRAC_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_SSBS_SHIFT, 4, ID_AA64PFR1_SSBS_PSTATE_NI),
+       ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_MTE),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_MTE_SHIFT, 4, ID_AA64PFR1_MTE_NI),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR1_SSBS_SHIFT, 4, ID_AA64PFR1_SSBS_PSTATE_NI),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_BTI),
                                    FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_BT_SHIFT, 4, 0),
        ARM64_FTR_END,
@@ -487,7 +490,7 @@ static const struct arm64_ftr_bits ftr_id_pfr1[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_pfr2[] = {
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_PFR2_SSBS_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR2_SSBS_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR2_CSV3_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
@@ -686,7 +689,7 @@ static s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new,
        case FTR_HIGHER_OR_ZERO_SAFE:
                if (!cur || !new)
                        break;
-               /* Fallthrough */
+               fallthrough;
        case FTR_HIGHER_SAFE:
                ret = new > cur ? new : cur;
                break;
@@ -1111,6 +1114,7 @@ u64 read_sanitised_ftr_reg(u32 id)
                return 0;
        return regp->sys_val;
 }
+EXPORT_SYMBOL_GPL(read_sanitised_ftr_reg);
 
 #define read_sysreg_case(r)    \
        case r:         return read_sysreg_s(r)
@@ -1443,6 +1447,7 @@ static inline void __cpu_enable_hw_dbm(void)
 
        write_sysreg(tcr, tcr_el1);
        isb();
+       local_flush_tlb_all();
 }
 
 static bool cpu_has_broken_dbm(void)
@@ -1583,48 +1588,6 @@ static void cpu_has_fwb(const struct arm64_cpu_capabilities *__unused)
        WARN_ON(val & (7 << 27 | 7 << 21));
 }
 
-#ifdef CONFIG_ARM64_SSBD
-static int ssbs_emulation_handler(struct pt_regs *regs, u32 instr)
-{
-       if (user_mode(regs))
-               return 1;
-
-       if (instr & BIT(PSTATE_Imm_shift))
-               regs->pstate |= PSR_SSBS_BIT;
-       else
-               regs->pstate &= ~PSR_SSBS_BIT;
-
-       arm64_skip_faulting_instruction(regs, 4);
-       return 0;
-}
-
-static struct undef_hook ssbs_emulation_hook = {
-       .instr_mask     = ~(1U << PSTATE_Imm_shift),
-       .instr_val      = 0xd500401f | PSTATE_SSBS,
-       .fn             = ssbs_emulation_handler,
-};
-
-static void cpu_enable_ssbs(const struct arm64_cpu_capabilities *__unused)
-{
-       static bool undef_hook_registered = false;
-       static DEFINE_RAW_SPINLOCK(hook_lock);
-
-       raw_spin_lock(&hook_lock);
-       if (!undef_hook_registered) {
-               register_undef_hook(&ssbs_emulation_hook);
-               undef_hook_registered = true;
-       }
-       raw_spin_unlock(&hook_lock);
-
-       if (arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE) {
-               sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_DSSBS);
-               arm64_set_ssbd_mitigation(false);
-       } else {
-               arm64_set_ssbd_mitigation(true);
-       }
-}
-#endif /* CONFIG_ARM64_SSBD */
-
 #ifdef CONFIG_ARM64_PAN
 static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
 {
@@ -1648,11 +1611,37 @@ static void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused)
 #endif /* CONFIG_ARM64_RAS_EXTN */
 
 #ifdef CONFIG_ARM64_PTR_AUTH
-static bool has_address_auth(const struct arm64_cpu_capabilities *entry,
-                            int __unused)
+static bool has_address_auth_cpucap(const struct arm64_cpu_capabilities *entry, int scope)
 {
-       return __system_matches_cap(ARM64_HAS_ADDRESS_AUTH_ARCH) ||
-              __system_matches_cap(ARM64_HAS_ADDRESS_AUTH_IMP_DEF);
+       int boot_val, sec_val;
+
+       /* We don't expect to be called with SCOPE_SYSTEM */
+       WARN_ON(scope == SCOPE_SYSTEM);
+       /*
+        * The ptr-auth feature levels are not intercompatible with lower
+        * levels. Hence we must match ptr-auth feature level of the secondary
+        * CPUs with that of the boot CPU. The level of boot cpu is fetched
+        * from the sanitised register whereas direct register read is done for
+        * the secondary CPUs.
+        * The sanitised feature state is guaranteed to match that of the
+        * boot CPU as a mismatched secondary CPU is parked before it gets
+        * a chance to update the state, with the capability.
+        */
+       boot_val = cpuid_feature_extract_field(read_sanitised_ftr_reg(entry->sys_reg),
+                                              entry->field_pos, entry->sign);
+       if (scope & SCOPE_BOOT_CPU)
+               return boot_val >= entry->min_field_value;
+       /* Now check for the secondary CPUs with SCOPE_LOCAL_CPU scope */
+       sec_val = cpuid_feature_extract_field(__read_sysreg_by_encoding(entry->sys_reg),
+                                             entry->field_pos, entry->sign);
+       return sec_val == boot_val;
+}
+
+static bool has_address_auth_metacap(const struct arm64_cpu_capabilities *entry,
+                                    int scope)
+{
+       return has_address_auth_cpucap(cpu_hwcaps_ptrs[ARM64_HAS_ADDRESS_AUTH_ARCH], scope) ||
+              has_address_auth_cpucap(cpu_hwcaps_ptrs[ARM64_HAS_ADDRESS_AUTH_IMP_DEF], scope);
 }
 
 static bool has_generic_auth(const struct arm64_cpu_capabilities *entry,
@@ -1702,6 +1691,22 @@ static void bti_enable(const struct arm64_cpu_capabilities *__unused)
 }
 #endif /* CONFIG_ARM64_BTI */
 
+#ifdef CONFIG_ARM64_MTE
+static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap)
+{
+       static bool cleared_zero_page = false;
+
+       /*
+        * Clear the tags in the zero page. This needs to be done via the
+        * linear map which has the Tagged attribute.
+        */
+       if (!cleared_zero_page) {
+               cleared_zero_page = true;
+               mte_clear_page_tags(lm_alias(empty_zero_page));
+       }
+}
+#endif /* CONFIG_ARM64_MTE */
+
 /* Internal helper functions to match cpu capability type */
 static bool
 cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap)
@@ -1976,19 +1981,16 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .field_pos = ID_AA64ISAR0_CRC32_SHIFT,
                .min_field_value = 1,
        },
-#ifdef CONFIG_ARM64_SSBD
        {
                .desc = "Speculative Store Bypassing Safe (SSBS)",
                .capability = ARM64_SSBS,
-               .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
+               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
                .matches = has_cpuid_feature,
                .sys_reg = SYS_ID_AA64PFR1_EL1,
                .field_pos = ID_AA64PFR1_SSBS_SHIFT,
                .sign = FTR_UNSIGNED,
                .min_field_value = ID_AA64PFR1_SSBS_PSTATE_ONLY,
-               .cpu_enable = cpu_enable_ssbs,
        },
-#endif
 #ifdef CONFIG_ARM64_CNP
        {
                .desc = "Common not Private translations",
@@ -2021,7 +2023,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .sign = FTR_UNSIGNED,
                .field_pos = ID_AA64ISAR1_APA_SHIFT,
                .min_field_value = ID_AA64ISAR1_APA_ARCHITECTED,
-               .matches = has_cpuid_feature,
+               .matches = has_address_auth_cpucap,
        },
        {
                .desc = "Address authentication (IMP DEF algorithm)",
@@ -2031,12 +2033,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .sign = FTR_UNSIGNED,
                .field_pos = ID_AA64ISAR1_API_SHIFT,
                .min_field_value = ID_AA64ISAR1_API_IMP_DEF,
-               .matches = has_cpuid_feature,
+               .matches = has_address_auth_cpucap,
        },
        {
                .capability = ARM64_HAS_ADDRESS_AUTH,
                .type = ARM64_CPUCAP_BOOT_CPU_FEATURE,
-               .matches = has_address_auth,
+               .matches = has_address_auth_metacap,
        },
        {
                .desc = "Generic authentication (architected algorithm)",
@@ -2121,6 +2123,19 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .sign = FTR_UNSIGNED,
        },
 #endif
+#ifdef CONFIG_ARM64_MTE
+       {
+               .desc = "Memory Tagging Extension",
+               .capability = ARM64_MTE,
+               .type = ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE,
+               .matches = has_cpuid_feature,
+               .sys_reg = SYS_ID_AA64PFR1_EL1,
+               .field_pos = ID_AA64PFR1_MTE_SHIFT,
+               .min_field_value = ID_AA64PFR1_MTE,
+               .sign = FTR_UNSIGNED,
+               .cpu_enable = cpu_enable_mte,
+       },
+#endif /* CONFIG_ARM64_MTE */
        {},
 };
 
@@ -2237,6 +2252,9 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
        HWCAP_MULTI_CAP(ptr_auth_hwcap_addr_matches, CAP_HWCAP, KERNEL_HWCAP_PACA),
        HWCAP_MULTI_CAP(ptr_auth_hwcap_gen_matches, CAP_HWCAP, KERNEL_HWCAP_PACG),
 #endif
+#ifdef CONFIG_ARM64_MTE
+       HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_MTE_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_MTE, CAP_HWCAP, KERNEL_HWCAP_MTE),
+#endif /* CONFIG_ARM64_MTE */
        {},
 };
 
index 393c6fb..6a7bb37 100644 (file)
@@ -43,94 +43,93 @@ static const char *icache_policy_str[] = {
 unsigned long __icache_flags;
 
 static const char *const hwcap_str[] = {
-       "fp",
-       "asimd",
-       "evtstrm",
-       "aes",
-       "pmull",
-       "sha1",
-       "sha2",
-       "crc32",
-       "atomics",
-       "fphp",
-       "asimdhp",
-       "cpuid",
-       "asimdrdm",
-       "jscvt",
-       "fcma",
-       "lrcpc",
-       "dcpop",
-       "sha3",
-       "sm3",
-       "sm4",
-       "asimddp",
-       "sha512",
-       "sve",
-       "asimdfhm",
-       "dit",
-       "uscat",
-       "ilrcpc",
-       "flagm",
-       "ssbs",
-       "sb",
-       "paca",
-       "pacg",
-       "dcpodp",
-       "sve2",
-       "sveaes",
-       "svepmull",
-       "svebitperm",
-       "svesha3",
-       "svesm4",
-       "flagm2",
-       "frint",
-       "svei8mm",
-       "svef32mm",
-       "svef64mm",
-       "svebf16",
-       "i8mm",
-       "bf16",
-       "dgh",
-       "rng",
-       "bti",
-       /* reserved for "mte" */
-       NULL
+       [KERNEL_HWCAP_FP]               = "fp",
+       [KERNEL_HWCAP_ASIMD]            = "asimd",
+       [KERNEL_HWCAP_EVTSTRM]          = "evtstrm",
+       [KERNEL_HWCAP_AES]              = "aes",
+       [KERNEL_HWCAP_PMULL]            = "pmull",
+       [KERNEL_HWCAP_SHA1]             = "sha1",
+       [KERNEL_HWCAP_SHA2]             = "sha2",
+       [KERNEL_HWCAP_CRC32]            = "crc32",
+       [KERNEL_HWCAP_ATOMICS]          = "atomics",
+       [KERNEL_HWCAP_FPHP]             = "fphp",
+       [KERNEL_HWCAP_ASIMDHP]          = "asimdhp",
+       [KERNEL_HWCAP_CPUID]            = "cpuid",
+       [KERNEL_HWCAP_ASIMDRDM]         = "asimdrdm",
+       [KERNEL_HWCAP_JSCVT]            = "jscvt",
+       [KERNEL_HWCAP_FCMA]             = "fcma",
+       [KERNEL_HWCAP_LRCPC]            = "lrcpc",
+       [KERNEL_HWCAP_DCPOP]            = "dcpop",
+       [KERNEL_HWCAP_SHA3]             = "sha3",
+       [KERNEL_HWCAP_SM3]              = "sm3",
+       [KERNEL_HWCAP_SM4]              = "sm4",
+       [KERNEL_HWCAP_ASIMDDP]          = "asimddp",
+       [KERNEL_HWCAP_SHA512]           = "sha512",
+       [KERNEL_HWCAP_SVE]              = "sve",
+       [KERNEL_HWCAP_ASIMDFHM]         = "asimdfhm",
+       [KERNEL_HWCAP_DIT]              = "dit",
+       [KERNEL_HWCAP_USCAT]            = "uscat",
+       [KERNEL_HWCAP_ILRCPC]           = "ilrcpc",
+       [KERNEL_HWCAP_FLAGM]            = "flagm",
+       [KERNEL_HWCAP_SSBS]             = "ssbs",
+       [KERNEL_HWCAP_SB]               = "sb",
+       [KERNEL_HWCAP_PACA]             = "paca",
+       [KERNEL_HWCAP_PACG]             = "pacg",
+       [KERNEL_HWCAP_DCPODP]           = "dcpodp",
+       [KERNEL_HWCAP_SVE2]             = "sve2",
+       [KERNEL_HWCAP_SVEAES]           = "sveaes",
+       [KERNEL_HWCAP_SVEPMULL]         = "svepmull",
+       [KERNEL_HWCAP_SVEBITPERM]       = "svebitperm",
+       [KERNEL_HWCAP_SVESHA3]          = "svesha3",
+       [KERNEL_HWCAP_SVESM4]           = "svesm4",
+       [KERNEL_HWCAP_FLAGM2]           = "flagm2",
+       [KERNEL_HWCAP_FRINT]            = "frint",
+       [KERNEL_HWCAP_SVEI8MM]          = "svei8mm",
+       [KERNEL_HWCAP_SVEF32MM]         = "svef32mm",
+       [KERNEL_HWCAP_SVEF64MM]         = "svef64mm",
+       [KERNEL_HWCAP_SVEBF16]          = "svebf16",
+       [KERNEL_HWCAP_I8MM]             = "i8mm",
+       [KERNEL_HWCAP_BF16]             = "bf16",
+       [KERNEL_HWCAP_DGH]              = "dgh",
+       [KERNEL_HWCAP_RNG]              = "rng",
+       [KERNEL_HWCAP_BTI]              = "bti",
+       [KERNEL_HWCAP_MTE]              = "mte",
 };
 
 #ifdef CONFIG_COMPAT
+#define COMPAT_KERNEL_HWCAP(x) const_ilog2(COMPAT_HWCAP_ ## x)
 static const char *const compat_hwcap_str[] = {
-       "swp",
-       "half",
-       "thumb",
-       "26bit",
-       "fastmult",
-       "fpa",
-       "vfp",
-       "edsp",
-       "java",
-       "iwmmxt",
-       "crunch",
-       "thumbee",
-       "neon",
-       "vfpv3",
-       "vfpv3d16",
-       "tls",
-       "vfpv4",
-       "idiva",
-       "idivt",
-       "vfpd32",
-       "lpae",
-       "evtstrm",
-       NULL
+       [COMPAT_KERNEL_HWCAP(SWP)]      = "swp",
+       [COMPAT_KERNEL_HWCAP(HALF)]     = "half",
+       [COMPAT_KERNEL_HWCAP(THUMB)]    = "thumb",
+       [COMPAT_KERNEL_HWCAP(26BIT)]    = NULL, /* Not possible on arm64 */
+       [COMPAT_KERNEL_HWCAP(FAST_MULT)] = "fastmult",
+       [COMPAT_KERNEL_HWCAP(FPA)]      = NULL, /* Not possible on arm64 */
+       [COMPAT_KERNEL_HWCAP(VFP)]      = "vfp",
+       [COMPAT_KERNEL_HWCAP(EDSP)]     = "edsp",
+       [COMPAT_KERNEL_HWCAP(JAVA)]     = NULL, /* Not possible on arm64 */
+       [COMPAT_KERNEL_HWCAP(IWMMXT)]   = NULL, /* Not possible on arm64 */
+       [COMPAT_KERNEL_HWCAP(CRUNCH)]   = NULL, /* Not possible on arm64 */
+       [COMPAT_KERNEL_HWCAP(THUMBEE)]  = NULL, /* Not possible on arm64 */
+       [COMPAT_KERNEL_HWCAP(NEON)]     = "neon",
+       [COMPAT_KERNEL_HWCAP(VFPv3)]    = "vfpv3",
+       [COMPAT_KERNEL_HWCAP(VFPV3D16)] = NULL, /* Not possible on arm64 */
+       [COMPAT_KERNEL_HWCAP(TLS)]      = "tls",
+       [COMPAT_KERNEL_HWCAP(VFPv4)]    = "vfpv4",
+       [COMPAT_KERNEL_HWCAP(IDIVA)]    = "idiva",
+       [COMPAT_KERNEL_HWCAP(IDIVT)]    = "idivt",
+       [COMPAT_KERNEL_HWCAP(VFPD32)]   = NULL, /* Not possible on arm64 */
+       [COMPAT_KERNEL_HWCAP(LPAE)]     = "lpae",
+       [COMPAT_KERNEL_HWCAP(EVTSTRM)]  = "evtstrm",
 };
 
+#define COMPAT_KERNEL_HWCAP2(x)        const_ilog2(COMPAT_HWCAP2_ ## x)
 static const char *const compat_hwcap2_str[] = {
-       "aes",
-       "pmull",
-       "sha1",
-       "sha2",
-       "crc32",
-       NULL
+       [COMPAT_KERNEL_HWCAP2(AES)]     = "aes",
+       [COMPAT_KERNEL_HWCAP2(PMULL)]   = "pmull",
+       [COMPAT_KERNEL_HWCAP2(SHA1)]    = "sha1",
+       [COMPAT_KERNEL_HWCAP2(SHA2)]    = "sha2",
+       [COMPAT_KERNEL_HWCAP2(CRC32)]   = "crc32",
 };
 #endif /* CONFIG_COMPAT */
 
@@ -166,16 +165,25 @@ static int c_show(struct seq_file *m, void *v)
                seq_puts(m, "Features\t:");
                if (compat) {
 #ifdef CONFIG_COMPAT
-                       for (j = 0; compat_hwcap_str[j]; j++)
-                               if (compat_elf_hwcap & (1 << j))
+                       for (j = 0; j < ARRAY_SIZE(compat_hwcap_str); j++) {
+                               if (compat_elf_hwcap & (1 << j)) {
+                                       /*
+                                        * Warn once if any feature should not
+                                        * have been present on arm64 platform.
+                                        */
+                                       if (WARN_ON_ONCE(!compat_hwcap_str[j]))
+                                               continue;
+
                                        seq_printf(m, " %s", compat_hwcap_str[j]);
+                               }
+                       }
 
-                       for (j = 0; compat_hwcap2_str[j]; j++)
+                       for (j = 0; j < ARRAY_SIZE(compat_hwcap2_str); j++)
                                if (compat_elf_hwcap2 & (1 << j))
                                        seq_printf(m, " %s", compat_hwcap2_str[j]);
 #endif /* CONFIG_COMPAT */
                } else {
-                       for (j = 0; hwcap_str[j]; j++)
+                       for (j = 0; j < ARRAY_SIZE(hwcap_str); j++)
                                if (cpu_have_feature(j))
                                        seq_printf(m, " %s", hwcap_str[j]);
                }
@@ -327,7 +335,6 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
                set_bit(ICACHEF_VPIPT, &__icache_flags);
                break;
        default:
-               /* Fallthrough */
        case ICACHE_POLICY_VIPT:
                /* Assume aliasing */
                set_bit(ICACHEF_ALIASING, &__icache_flags);
index 7310a4f..fa76151 100644 (file)
@@ -384,7 +384,7 @@ void __init debug_traps_init(void)
        hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP,
                              TRAP_TRACE, "single-step handler");
        hook_debug_fault_code(DBG_ESR_EVT_BRK, brk_handler, SIGTRAP,
-                             TRAP_BRKPT, "ptrace BRK handler");
+                             TRAP_BRKPT, "BRK handler");
 }
 
 /* Re-enable single step for syscall restarting. */
index d3be9db..43d4c32 100644 (file)
@@ -66,6 +66,13 @@ static void notrace el1_dbg(struct pt_regs *regs, unsigned long esr)
 }
 NOKPROBE_SYMBOL(el1_dbg);
 
+static void notrace el1_fpac(struct pt_regs *regs, unsigned long esr)
+{
+       local_daif_inherit(regs);
+       do_ptrauth_fault(regs, esr);
+}
+NOKPROBE_SYMBOL(el1_fpac);
+
 asmlinkage void notrace el1_sync_handler(struct pt_regs *regs)
 {
        unsigned long esr = read_sysreg(esr_el1);
@@ -92,6 +99,9 @@ asmlinkage void notrace el1_sync_handler(struct pt_regs *regs)
        case ESR_ELx_EC_BRK64:
                el1_dbg(regs, esr);
                break;
+       case ESR_ELx_EC_FPAC:
+               el1_fpac(regs, esr);
+               break;
        default:
                el1_inv(regs, esr);
        }
@@ -227,6 +237,14 @@ static void notrace el0_svc(struct pt_regs *regs)
 }
 NOKPROBE_SYMBOL(el0_svc);
 
+static void notrace el0_fpac(struct pt_regs *regs, unsigned long esr)
+{
+       user_exit_irqoff();
+       local_daif_restore(DAIF_PROCCTX);
+       do_ptrauth_fault(regs, esr);
+}
+NOKPROBE_SYMBOL(el0_fpac);
+
 asmlinkage void notrace el0_sync_handler(struct pt_regs *regs)
 {
        unsigned long esr = read_sysreg(esr_el1);
@@ -272,6 +290,9 @@ asmlinkage void notrace el0_sync_handler(struct pt_regs *regs)
        case ESR_ELx_EC_BRK64:
                el0_dbg(regs, esr);
                break;
+       case ESR_ELx_EC_FPAC:
+               el0_fpac(regs, esr);
+               break;
        default:
                el0_inv(regs, esr);
        }
index f880dd6..2ca395c 100644 (file)
@@ -32,6 +32,7 @@ SYM_FUNC_START(fpsimd_load_state)
 SYM_FUNC_END(fpsimd_load_state)
 
 #ifdef CONFIG_ARM64_SVE
+
 SYM_FUNC_START(sve_save_state)
        sve_save 0, x1, 2
        ret
@@ -46,4 +47,28 @@ SYM_FUNC_START(sve_get_vl)
        _sve_rdvl       0, 1
        ret
 SYM_FUNC_END(sve_get_vl)
+
+/*
+ * Load SVE state from FPSIMD state.
+ *
+ * x0 = pointer to struct fpsimd_state
+ * x1 = VQ - 1
+ *
+ * Each SVE vector will be loaded with the first 128-bits taken from FPSIMD
+ * and the rest zeroed. All the other SVE registers will be zeroed.
+ */
+SYM_FUNC_START(sve_load_from_fpsimd_state)
+               sve_load_vq     x1, x2, x3
+               fpsimd_restore  x0, 8
+ _for n, 0, 15, _sve_pfalse    \n
+               _sve_wrffr      0
+               ret
+SYM_FUNC_END(sve_load_from_fpsimd_state)
+
+/* Zero all SVE registers but the first 128-bits of each vector */
+SYM_FUNC_START(sve_flush_live)
+       sve_flush
+       ret
+SYM_FUNC_END(sve_flush_live)
+
 #endif /* CONFIG_ARM64_SVE */
index 55af8b5..f30007d 100644 (file)
@@ -132,9 +132,8 @@ alternative_else_nop_endif
         * them if required.
         */
        .macro  apply_ssbd, state, tmp1, tmp2
-#ifdef CONFIG_ARM64_SSBD
-alternative_cb arm64_enable_wa2_handling
-       b       .L__asm_ssbd_skip\@
+alternative_cb spectre_v4_patch_fw_mitigation_enable
+       b       .L__asm_ssbd_skip\@             // Patched to NOP
 alternative_cb_end
        ldr_this_cpu    \tmp2, arm64_ssbd_callback_required, \tmp1
        cbz     \tmp2,  .L__asm_ssbd_skip\@
@@ -142,10 +141,35 @@ alternative_cb_end
        tbnz    \tmp2, #TIF_SSBD, .L__asm_ssbd_skip\@
        mov     w0, #ARM_SMCCC_ARCH_WORKAROUND_2
        mov     w1, #\state
-alternative_cb arm64_update_smccc_conduit
+alternative_cb spectre_v4_patch_fw_mitigation_conduit
        nop                                     // Patched to SMC/HVC #0
 alternative_cb_end
 .L__asm_ssbd_skip\@:
+       .endm
+
+       /* Check for MTE asynchronous tag check faults */
+       .macro check_mte_async_tcf, flgs, tmp
+#ifdef CONFIG_ARM64_MTE
+alternative_if_not ARM64_MTE
+       b       1f
+alternative_else_nop_endif
+       mrs_s   \tmp, SYS_TFSRE0_EL1
+       tbz     \tmp, #SYS_TFSR_EL1_TF0_SHIFT, 1f
+       /* Asynchronous TCF occurred for TTBR0 access, set the TI flag */
+       orr     \flgs, \flgs, #_TIF_MTE_ASYNC_FAULT
+       str     \flgs, [tsk, #TSK_TI_FLAGS]
+       msr_s   SYS_TFSRE0_EL1, xzr
+1:
+#endif
+       .endm
+
+       /* Clear the MTE asynchronous tag check faults */
+       .macro clear_mte_async_tcf
+#ifdef CONFIG_ARM64_MTE
+alternative_if ARM64_MTE
+       dsb     ish
+       msr_s   SYS_TFSRE0_EL1, xzr
+alternative_else_nop_endif
 #endif
        .endm
 
@@ -182,6 +206,8 @@ alternative_cb_end
        ldr     x19, [tsk, #TSK_TI_FLAGS]
        disable_step_tsk x19, x20
 
+       /* Check for asynchronous tag check faults in user space */
+       check_mte_async_tcf x19, x22
        apply_ssbd 1, x22, x23
 
        ptrauth_keys_install_kernel tsk, x20, x22, x23
@@ -233,6 +259,13 @@ alternative_if ARM64_HAS_IRQ_PRIO_MASKING
        str     x20, [sp, #S_PMR_SAVE]
 alternative_else_nop_endif
 
+       /* Re-enable tag checking (TCO set on exception entry) */
+#ifdef CONFIG_ARM64_MTE
+alternative_if ARM64_MTE
+       SET_PSTATE_TCO(0)
+alternative_else_nop_endif
+#endif
+
        /*
         * Registers that may be useful after this macro is invoked:
         *
@@ -697,11 +730,9 @@ el0_irq_naked:
        bl      trace_hardirqs_off
 #endif
 
-#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
        tbz     x22, #55, 1f
        bl      do_el0_irq_bp_hardening
 1:
-#endif
        irq_handler
 
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -744,6 +775,8 @@ SYM_CODE_START_LOCAL(ret_to_user)
        and     x2, x1, #_TIF_WORK_MASK
        cbnz    x2, work_pending
 finish_ret_to_user:
+       /* Ignore asynchronous tag check faults in the uaccess routines */
+       clear_mte_async_tcf
        enable_step_tsk x1, x2
 #ifdef CONFIG_GCC_PLUGIN_STACKLEAK
        bl      stackleak_erase
index 55c8f3e..a6d688c 100644 (file)
 #include <linux/swab.h>
 
 #include <asm/esr.h>
+#include <asm/exception.h>
 #include <asm/fpsimd.h>
 #include <asm/cpufeature.h>
 #include <asm/cputype.h>
+#include <asm/neon.h>
 #include <asm/processor.h>
 #include <asm/simd.h>
 #include <asm/sigcontext.h>
@@ -312,7 +314,7 @@ static void fpsimd_save(void)
                                 * re-enter user with corrupt state.
                                 * There's no way to recover, so kill it:
                                 */
-                               force_signal_inject(SIGKILL, SI_KERNEL, 0);
+                               force_signal_inject(SIGKILL, SI_KERNEL, 0, 0);
                                return;
                        }
 
@@ -928,7 +930,7 @@ void fpsimd_release_task(struct task_struct *dead_task)
  * the SVE access trap will be disabled the next time this task
  * reaches ret_to_user.
  *
- * TIF_SVE should be clear on entry: otherwise, task_fpsimd_load()
+ * TIF_SVE should be clear on entry: otherwise, fpsimd_restore_current_state()
  * would have disabled the SVE access trap for userspace during
  * ret_to_user, making an SVE access trap impossible in that case.
  */
@@ -936,7 +938,7 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 {
        /* Even if we chose not to use SVE, the hardware could still trap: */
        if (unlikely(!system_supports_sve()) || WARN_ON(is_compat_task())) {
-               force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc);
+               force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);
                return;
        }
 
index 037421c..d8d9caf 100644 (file)
 
 #include "efi-header.S"
 
-#define __PHYS_OFFSET  (KERNEL_START - TEXT_OFFSET)
+#define __PHYS_OFFSET  KERNEL_START
 
-#if (TEXT_OFFSET & 0xfff) != 0
-#error TEXT_OFFSET must be at least 4KB aligned
-#elif (PAGE_OFFSET & 0x1fffff) != 0
+#if (PAGE_OFFSET & 0x1fffff) != 0
 #error PAGE_OFFSET must be at least 2MB aligned
-#elif TEXT_OFFSET > 0x1fffff
-#error TEXT_OFFSET must be less than 2MB
 #endif
 
 /*
@@ -55,7 +51,7 @@
  *   x0 = physical address to the FDT blob.
  *
  * This code is mostly position independent so you call this at
- * __pa(PAGE_OFFSET + TEXT_OFFSET).
+ * __pa(PAGE_OFFSET).
  *
  * Note that the callee-saved registers are used for storing variables
  * that are useful before the MMU is enabled. The allocations are described
@@ -77,7 +73,7 @@ _head:
        b       primary_entry                   // branch to kernel start, magic
        .long   0                               // reserved
 #endif
-       le64sym _kernel_offset_le               // Image load offset from start of RAM, little-endian
+       .quad   0                               // Image load offset from start of RAM, little-endian
        le64sym _kernel_size_le                 // Effective size of kernel image, little-endian
        le64sym _kernel_flags_le                // Informative flags, little-endian
        .quad   0                               // reserved
@@ -382,7 +378,7 @@ SYM_FUNC_START_LOCAL(__create_page_tables)
         * Map the kernel image (starting with PHYS_OFFSET).
         */
        adrp    x0, init_pg_dir
-       mov_q   x5, KIMAGE_VADDR + TEXT_OFFSET  // compile time __va(_text)
+       mov_q   x5, KIMAGE_VADDR                // compile time __va(_text)
        add     x5, x5, x23                     // add KASLR displacement
        mov     x4, PTRS_PER_PGD
        adrp    x6, _end                        // runtime __pa(_end)
@@ -474,7 +470,7 @@ SYM_FUNC_END(__primary_switched)
 
        .pushsection ".rodata", "a"
 SYM_DATA_START(kimage_vaddr)
-       .quad           _text - TEXT_OFFSET
+       .quad           _text
 SYM_DATA_END(kimage_vaddr)
 EXPORT_SYMBOL(kimage_vaddr)
        .popsection
index 68e1415..4200377 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/sched.h>
 #include <linux/suspend.h>
 #include <linux/utsname.h>
-#include <linux/version.h>
 
 #include <asm/barrier.h>
 #include <asm/cacheflush.h>
@@ -31,6 +30,7 @@
 #include <asm/kexec.h>
 #include <asm/memory.h>
 #include <asm/mmu_context.h>
+#include <asm/mte.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/sections.h>
@@ -285,6 +285,117 @@ static int create_safe_exec_page(void *src_start, size_t length,
 
 #define dcache_clean_range(start, end) __flush_dcache_area(start, (end - start))
 
+#ifdef CONFIG_ARM64_MTE
+
+static DEFINE_XARRAY(mte_pages);
+
+static int save_tags(struct page *page, unsigned long pfn)
+{
+       void *tag_storage, *ret;
+
+       tag_storage = mte_allocate_tag_storage();
+       if (!tag_storage)
+               return -ENOMEM;
+
+       mte_save_page_tags(page_address(page), tag_storage);
+
+       ret = xa_store(&mte_pages, pfn, tag_storage, GFP_KERNEL);
+       if (WARN(xa_is_err(ret), "Failed to store MTE tags")) {
+               mte_free_tag_storage(tag_storage);
+               return xa_err(ret);
+       } else if (WARN(ret, "swsusp: %s: Duplicate entry", __func__)) {
+               mte_free_tag_storage(ret);
+       }
+
+       return 0;
+}
+
+static void swsusp_mte_free_storage(void)
+{
+       XA_STATE(xa_state, &mte_pages, 0);
+       void *tags;
+
+       xa_lock(&mte_pages);
+       xas_for_each(&xa_state, tags, ULONG_MAX) {
+               mte_free_tag_storage(tags);
+       }
+       xa_unlock(&mte_pages);
+
+       xa_destroy(&mte_pages);
+}
+
+static int swsusp_mte_save_tags(void)
+{
+       struct zone *zone;
+       unsigned long pfn, max_zone_pfn;
+       int ret = 0;
+       int n = 0;
+
+       if (!system_supports_mte())
+               return 0;
+
+       for_each_populated_zone(zone) {
+               max_zone_pfn = zone_end_pfn(zone);
+               for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) {
+                       struct page *page = pfn_to_online_page(pfn);
+
+                       if (!page)
+                               continue;
+
+                       if (!test_bit(PG_mte_tagged, &page->flags))
+                               continue;
+
+                       ret = save_tags(page, pfn);
+                       if (ret) {
+                               swsusp_mte_free_storage();
+                               goto out;
+                       }
+
+                       n++;
+               }
+       }
+       pr_info("Saved %d MTE pages\n", n);
+
+out:
+       return ret;
+}
+
+static void swsusp_mte_restore_tags(void)
+{
+       XA_STATE(xa_state, &mte_pages, 0);
+       int n = 0;
+       void *tags;
+
+       xa_lock(&mte_pages);
+       xas_for_each(&xa_state, tags, ULONG_MAX) {
+               unsigned long pfn = xa_state.xa_index;
+               struct page *page = pfn_to_online_page(pfn);
+
+               mte_restore_page_tags(page_address(page), tags);
+
+               mte_free_tag_storage(tags);
+               n++;
+       }
+       xa_unlock(&mte_pages);
+
+       pr_info("Restored %d MTE pages\n", n);
+
+       xa_destroy(&mte_pages);
+}
+
+#else  /* CONFIG_ARM64_MTE */
+
+static int swsusp_mte_save_tags(void)
+{
+       return 0;
+}
+
+static void swsusp_mte_restore_tags(void)
+{
+}
+
+#endif /* CONFIG_ARM64_MTE */
+
 int swsusp_arch_suspend(void)
 {
        int ret = 0;
@@ -302,6 +413,10 @@ int swsusp_arch_suspend(void)
                /* make the crash dump kernel image visible/saveable */
                crash_prepare_suspend();
 
+               ret = swsusp_mte_save_tags();
+               if (ret)
+                       return ret;
+
                sleep_cpu = smp_processor_id();
                ret = swsusp_save();
        } else {
@@ -315,6 +430,8 @@ int swsusp_arch_suspend(void)
                        dcache_clean_range(__hyp_text_start, __hyp_text_end);
                }
 
+               swsusp_mte_restore_tags();
+
                /* make the crash dump kernel image protected again */
                crash_post_resume();
 
@@ -332,11 +449,7 @@ int swsusp_arch_suspend(void)
                 * mitigation off behind our back, let's set the state
                 * to what we expect it to be.
                 */
-               switch (arm64_get_ssbd_state()) {
-               case ARM64_SSBD_FORCE_ENABLE:
-               case ARM64_SSBD_KERNEL:
-                       arm64_set_ssbd_mitigation(true);
-               }
+               spectre_v4_enable_mitigation(NULL);
        }
 
        local_daif_restore(flags);
index af234a1..712e97c 100644 (file)
@@ -257,7 +257,7 @@ static int hw_breakpoint_control(struct perf_event *bp,
                 * level.
                 */
                enable_debug_monitors(dbg_el);
-               /* Fall through */
+               fallthrough;
        case HW_BREAKPOINT_RESTORE:
                /* Setup the address register. */
                write_wb_reg(val_reg, i, info->address);
@@ -541,13 +541,13 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
                        if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2)
                                break;
 
-                       /* Fallthrough */
+                       fallthrough;
                case 3:
                        /* Allow single byte watchpoint. */
                        if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1)
                                break;
 
-                       /* Fallthrough */
+                       fallthrough;
                default:
                        return -EINVAL;
                }
index 9e897c5..843ecfb 100644 (file)
@@ -64,12 +64,10 @@ __efistub__ctype            = _ctype;
 #define KVM_NVHE_ALIAS(sym) __kvm_nvhe_##sym = sym;
 
 /* Alternative callbacks for init-time patching of nVHE hyp code. */
-KVM_NVHE_ALIAS(arm64_enable_wa2_handling);
 KVM_NVHE_ALIAS(kvm_patch_vector_branch);
 KVM_NVHE_ALIAS(kvm_update_va_mask);
 
 /* Global kernel state accessed by nVHE hyp code. */
-KVM_NVHE_ALIAS(arm64_ssbd_callback_required);
 KVM_NVHE_ALIAS(kvm_host_data);
 KVM_NVHE_ALIAS(kvm_vgic_global_state);
 
@@ -101,8 +99,14 @@ KVM_NVHE_ALIAS(vgic_v3_cpuif_trap);
 /* Static key checked in pmr_sync(). */
 #ifdef CONFIG_ARM64_PSEUDO_NMI
 KVM_NVHE_ALIAS(gic_pmr_sync);
+/* Static key checked in GIC_PRIO_IRQOFF. */
+KVM_NVHE_ALIAS(gic_nonsecure_priorities);
 #endif
 
+/* EL2 exception handling */
+KVM_NVHE_ALIAS(__start___kvm_ex_table);
+KVM_NVHE_ALIAS(__stop___kvm_ex_table);
+
 #endif /* CONFIG_KVM */
 
 #endif /* __ARM64_KERNEL_IMAGE_VARS_H */
index c7d38c6..7bc3ba8 100644 (file)
@@ -62,7 +62,6 @@
  */
 #define HEAD_SYMBOLS                                           \
        DEFINE_IMAGE_LE64(_kernel_size_le, _end - _text);       \
-       DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET);      \
        DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);
 
 #endif /* __ARM64_KERNEL_IMAGE_H */
index a107375..6c0de2f 100644 (file)
@@ -60,16 +60,10 @@ bool __kprobes aarch64_insn_is_steppable_hint(u32 insn)
        case AARCH64_INSN_HINT_XPACLRI:
        case AARCH64_INSN_HINT_PACIA_1716:
        case AARCH64_INSN_HINT_PACIB_1716:
-       case AARCH64_INSN_HINT_AUTIA_1716:
-       case AARCH64_INSN_HINT_AUTIB_1716:
        case AARCH64_INSN_HINT_PACIAZ:
        case AARCH64_INSN_HINT_PACIASP:
        case AARCH64_INSN_HINT_PACIBZ:
        case AARCH64_INSN_HINT_PACIBSP:
-       case AARCH64_INSN_HINT_AUTIAZ:
-       case AARCH64_INSN_HINT_AUTIASP:
-       case AARCH64_INSN_HINT_AUTIBZ:
-       case AARCH64_INSN_HINT_AUTIBSP:
        case AARCH64_INSN_HINT_BTI:
        case AARCH64_INSN_HINT_BTIC:
        case AARCH64_INSN_HINT_BTIJ:
@@ -176,7 +170,7 @@ bool __kprobes aarch64_insn_uses_literal(u32 insn)
 
 bool __kprobes aarch64_insn_is_branch(u32 insn)
 {
-       /* b, bl, cb*, tb*, b.cond, br, blr */
+       /* b, bl, cb*, tb*, ret*, b.cond, br*, blr* */
 
        return aarch64_insn_is_b(insn) ||
                aarch64_insn_is_bl(insn) ||
@@ -185,8 +179,11 @@ bool __kprobes aarch64_insn_is_branch(u32 insn)
                aarch64_insn_is_tbz(insn) ||
                aarch64_insn_is_tbnz(insn) ||
                aarch64_insn_is_ret(insn) ||
+               aarch64_insn_is_ret_auth(insn) ||
                aarch64_insn_is_br(insn) ||
+               aarch64_insn_is_br_auth(insn) ||
                aarch64_insn_is_blr(insn) ||
+               aarch64_insn_is_blr_auth(insn) ||
                aarch64_insn_is_bcond(insn);
 }
 
index 04a327c..9cf2fb8 100644 (file)
  * Copyright (C) 2012 ARM Ltd.
  */
 
-#include <linux/kernel_stat.h>
 #include <linux/irq.h>
 #include <linux/memory.h>
 #include <linux/smp.h>
+#include <linux/hardirq.h>
 #include <linux/init.h>
 #include <linux/irqchip.h>
 #include <linux/kprobes.h>
 #include <asm/daifflags.h>
 #include <asm/vmap_stack.h>
 
-unsigned long irq_err_count;
-
 /* Only access this in an NMI enter/exit */
 DEFINE_PER_CPU(struct nmi_ctx, nmi_contexts);
 
 DEFINE_PER_CPU(unsigned long *, irq_stack_ptr);
 
-int arch_show_interrupts(struct seq_file *p, int prec)
-{
-       show_ipi_list(p, prec);
-       seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
-       return 0;
-}
-
 #ifdef CONFIG_VMAP_STACK
 static void init_irq_stacks(void)
 {
index 0ce3a28..2e22443 100644 (file)
@@ -305,8 +305,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
                        mod->arch.core.plt_shndx = i;
                else if (!strcmp(secstrings + sechdrs[i].sh_name, ".init.plt"))
                        mod->arch.init.plt_shndx = i;
-               else if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) &&
-                        !strcmp(secstrings + sechdrs[i].sh_name,
+               else if (!strcmp(secstrings + sechdrs[i].sh_name,
                                 ".text.ftrace_trampoline"))
                        tramp = sechdrs + i;
                else if (sechdrs[i].sh_type == SHT_SYMTAB)
index 1cd1a4d..2a1ad95 100644 (file)
@@ -315,21 +315,21 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                /* MOVW instruction relocations. */
                case R_AARCH64_MOVW_UABS_G0_NC:
                        overflow_check = false;
-                       /* Fall through */
+                       fallthrough;
                case R_AARCH64_MOVW_UABS_G0:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0,
                                              AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_UABS_G1_NC:
                        overflow_check = false;
-                       /* Fall through */
+                       fallthrough;
                case R_AARCH64_MOVW_UABS_G1:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16,
                                              AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_UABS_G2_NC:
                        overflow_check = false;
-                       /* Fall through */
+                       fallthrough;
                case R_AARCH64_MOVW_UABS_G2:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32,
                                              AARCH64_INSN_IMM_MOVKZ);
@@ -397,7 +397,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        break;
                case R_AARCH64_ADR_PREL_PG_HI21_NC:
                        overflow_check = false;
-                       /* Fall through */
+                       fallthrough;
                case R_AARCH64_ADR_PREL_PG_HI21:
                        ovf = reloc_insn_adrp(me, sechdrs, loc, val);
                        if (ovf && ovf != -ERANGE)
diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
new file mode 100644 (file)
index 0000000..52a0638
--- /dev/null
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 ARM Ltd.
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/prctl.h>
+#include <linux/sched.h>
+#include <linux/sched/mm.h>
+#include <linux/string.h>
+#include <linux/swap.h>
+#include <linux/swapops.h>
+#include <linux/thread_info.h>
+#include <linux/uio.h>
+
+#include <asm/cpufeature.h>
+#include <asm/mte.h>
+#include <asm/ptrace.h>
+#include <asm/sysreg.h>
+
+static void mte_sync_page_tags(struct page *page, pte_t *ptep, bool check_swap)
+{
+       pte_t old_pte = READ_ONCE(*ptep);
+
+       if (check_swap && is_swap_pte(old_pte)) {
+               swp_entry_t entry = pte_to_swp_entry(old_pte);
+
+               if (!non_swap_entry(entry) && mte_restore_tags(entry, page))
+                       return;
+       }
+
+       mte_clear_page_tags(page_address(page));
+}
+
+void mte_sync_tags(pte_t *ptep, pte_t pte)
+{
+       struct page *page = pte_page(pte);
+       long i, nr_pages = compound_nr(page);
+       bool check_swap = nr_pages == 1;
+
+       /* if PG_mte_tagged is set, tags have already been initialised */
+       for (i = 0; i < nr_pages; i++, page++) {
+               if (!test_and_set_bit(PG_mte_tagged, &page->flags))
+                       mte_sync_page_tags(page, ptep, check_swap);
+       }
+}
+
+int memcmp_pages(struct page *page1, struct page *page2)
+{
+       char *addr1, *addr2;
+       int ret;
+
+       addr1 = page_address(page1);
+       addr2 = page_address(page2);
+       ret = memcmp(addr1, addr2, PAGE_SIZE);
+
+       if (!system_supports_mte() || ret)
+               return ret;
+
+       /*
+        * If the page content is identical but at least one of the pages is
+        * tagged, return non-zero to avoid KSM merging. If only one of the
+        * pages is tagged, set_pte_at() may zero or change the tags of the
+        * other page via mte_sync_tags().
+        */
+       if (test_bit(PG_mte_tagged, &page1->flags) ||
+           test_bit(PG_mte_tagged, &page2->flags))
+               return addr1 != addr2;
+
+       return ret;
+}
+
+static void update_sctlr_el1_tcf0(u64 tcf0)
+{
+       /* ISB required for the kernel uaccess routines */
+       sysreg_clear_set(sctlr_el1, SCTLR_EL1_TCF0_MASK, tcf0);
+       isb();
+}
+
+static void set_sctlr_el1_tcf0(u64 tcf0)
+{
+       /*
+        * mte_thread_switch() checks current->thread.sctlr_tcf0 as an
+        * optimisation. Disable preemption so that it does not see
+        * the variable update before the SCTLR_EL1.TCF0 one.
+        */
+       preempt_disable();
+       current->thread.sctlr_tcf0 = tcf0;
+       update_sctlr_el1_tcf0(tcf0);
+       preempt_enable();
+}
+
+static void update_gcr_el1_excl(u64 incl)
+{
+       u64 excl = ~incl & SYS_GCR_EL1_EXCL_MASK;
+
+       /*
+        * Note that 'incl' is an include mask (controlled by the user via
+        * prctl()) while GCR_EL1 accepts an exclude mask.
+        * No need for ISB since this only affects EL0 currently, implicit
+        * with ERET.
+        */
+       sysreg_clear_set_s(SYS_GCR_EL1, SYS_GCR_EL1_EXCL_MASK, excl);
+}
+
+static void set_gcr_el1_excl(u64 incl)
+{
+       current->thread.gcr_user_incl = incl;
+       update_gcr_el1_excl(incl);
+}
+
+void flush_mte_state(void)
+{
+       if (!system_supports_mte())
+               return;
+
+       /* clear any pending asynchronous tag fault */
+       dsb(ish);
+       write_sysreg_s(0, SYS_TFSRE0_EL1);
+       clear_thread_flag(TIF_MTE_ASYNC_FAULT);
+       /* disable tag checking */
+       set_sctlr_el1_tcf0(SCTLR_EL1_TCF0_NONE);
+       /* reset tag generation mask */
+       set_gcr_el1_excl(0);
+}
+
+void mte_thread_switch(struct task_struct *next)
+{
+       if (!system_supports_mte())
+               return;
+
+       /* avoid expensive SCTLR_EL1 accesses if no change */
+       if (current->thread.sctlr_tcf0 != next->thread.sctlr_tcf0)
+               update_sctlr_el1_tcf0(next->thread.sctlr_tcf0);
+       update_gcr_el1_excl(next->thread.gcr_user_incl);
+}
+
+void mte_suspend_exit(void)
+{
+       if (!system_supports_mte())
+               return;
+
+       update_gcr_el1_excl(current->thread.gcr_user_incl);
+}
+
+long set_mte_ctrl(struct task_struct *task, unsigned long arg)
+{
+       u64 tcf0;
+       u64 gcr_incl = (arg & PR_MTE_TAG_MASK) >> PR_MTE_TAG_SHIFT;
+
+       if (!system_supports_mte())
+               return 0;
+
+       switch (arg & PR_MTE_TCF_MASK) {
+       case PR_MTE_TCF_NONE:
+               tcf0 = SCTLR_EL1_TCF0_NONE;
+               break;
+       case PR_MTE_TCF_SYNC:
+               tcf0 = SCTLR_EL1_TCF0_SYNC;
+               break;
+       case PR_MTE_TCF_ASYNC:
+               tcf0 = SCTLR_EL1_TCF0_ASYNC;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (task != current) {
+               task->thread.sctlr_tcf0 = tcf0;
+               task->thread.gcr_user_incl = gcr_incl;
+       } else {
+               set_sctlr_el1_tcf0(tcf0);
+               set_gcr_el1_excl(gcr_incl);
+       }
+
+       return 0;
+}
+
+long get_mte_ctrl(struct task_struct *task)
+{
+       unsigned long ret;
+
+       if (!system_supports_mte())
+               return 0;
+
+       ret = task->thread.gcr_user_incl << PR_MTE_TAG_SHIFT;
+
+       switch (task->thread.sctlr_tcf0) {
+       case SCTLR_EL1_TCF0_NONE:
+               return PR_MTE_TCF_NONE;
+       case SCTLR_EL1_TCF0_SYNC:
+               ret |= PR_MTE_TCF_SYNC;
+               break;
+       case SCTLR_EL1_TCF0_ASYNC:
+               ret |= PR_MTE_TCF_ASYNC;
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * Access MTE tags in another process' address space as given in mm. Update
+ * the number of tags copied. Return 0 if any tags copied, error otherwise.
+ * Inspired by __access_remote_vm().
+ */
+static int __access_remote_tags(struct mm_struct *mm, unsigned long addr,
+                               struct iovec *kiov, unsigned int gup_flags)
+{
+       struct vm_area_struct *vma;
+       void __user *buf = kiov->iov_base;
+       size_t len = kiov->iov_len;
+       int ret;
+       int write = gup_flags & FOLL_WRITE;
+
+       if (!access_ok(buf, len))
+               return -EFAULT;
+
+       if (mmap_read_lock_killable(mm))
+               return -EIO;
+
+       while (len) {
+               unsigned long tags, offset;
+               void *maddr;
+               struct page *page = NULL;
+
+               ret = get_user_pages_remote(mm, addr, 1, gup_flags, &page,
+                                           &vma, NULL);
+               if (ret <= 0)
+                       break;
+
+               /*
+                * Only copy tags if the page has been mapped as PROT_MTE
+                * (PG_mte_tagged set). Otherwise the tags are not valid and
+                * not accessible to user. Moreover, an mprotect(PROT_MTE)
+                * would cause the existing tags to be cleared if the page
+                * was never mapped with PROT_MTE.
+                */
+               if (!test_bit(PG_mte_tagged, &page->flags)) {
+                       ret = -EOPNOTSUPP;
+                       put_page(page);
+                       break;
+               }
+
+               /* limit access to the end of the page */
+               offset = offset_in_page(addr);
+               tags = min(len, (PAGE_SIZE - offset) / MTE_GRANULE_SIZE);
+
+               maddr = page_address(page);
+               if (write) {
+                       tags = mte_copy_tags_from_user(maddr + offset, buf, tags);
+                       set_page_dirty_lock(page);
+               } else {
+                       tags = mte_copy_tags_to_user(buf, maddr + offset, tags);
+               }
+               put_page(page);
+
+               /* error accessing the tracer's buffer */
+               if (!tags)
+                       break;
+
+               len -= tags;
+               buf += tags;
+               addr += tags * MTE_GRANULE_SIZE;
+       }
+       mmap_read_unlock(mm);
+
+       /* return an error if no tags copied */
+       kiov->iov_len = buf - kiov->iov_base;
+       if (!kiov->iov_len) {
+               /* check for error accessing the tracee's address space */
+               if (ret <= 0)
+                       return -EIO;
+               else
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*
+ * Copy MTE tags in another process' address space at 'addr' to/from tracer's
+ * iovec buffer. Return 0 on success. Inspired by ptrace_access_vm().
+ */
+static int access_remote_tags(struct task_struct *tsk, unsigned long addr,
+                             struct iovec *kiov, unsigned int gup_flags)
+{
+       struct mm_struct *mm;
+       int ret;
+
+       mm = get_task_mm(tsk);
+       if (!mm)
+               return -EPERM;
+
+       if (!tsk->ptrace || (current != tsk->parent) ||
+           ((get_dumpable(mm) != SUID_DUMP_USER) &&
+            !ptracer_capable(tsk, mm->user_ns))) {
+               mmput(mm);
+               return -EPERM;
+       }
+
+       ret = __access_remote_tags(mm, addr, kiov, gup_flags);
+       mmput(mm);
+
+       return ret;
+}
+
+int mte_ptrace_copy_tags(struct task_struct *child, long request,
+                        unsigned long addr, unsigned long data)
+{
+       int ret;
+       struct iovec kiov;
+       struct iovec __user *uiov = (void __user *)data;
+       unsigned int gup_flags = FOLL_FORCE;
+
+       if (!system_supports_mte())
+               return -EIO;
+
+       if (get_user(kiov.iov_base, &uiov->iov_base) ||
+           get_user(kiov.iov_len, &uiov->iov_len))
+               return -EFAULT;
+
+       if (request == PTRACE_POKEMTETAGS)
+               gup_flags |= FOLL_WRITE;
+
+       /* align addr to the MTE tag granule */
+       addr &= MTE_GRANULE_MASK;
+
+       ret = access_remote_tags(child, addr, &kiov, gup_flags);
+       if (!ret)
+               ret = put_user(kiov.iov_len, &uiov->iov_len);
+
+       return ret;
+}
index 295d664..c07d7a0 100644 (file)
@@ -50,16 +50,19 @@ static u64 pv_steal_clock(int cpu)
        struct pv_time_stolen_time_region *reg;
 
        reg = per_cpu_ptr(&stolen_time_region, cpu);
-       if (!reg->kaddr) {
-               pr_warn_once("stolen time enabled but not configured for cpu %d\n",
-                            cpu);
+
+       /*
+        * paravirt_steal_clock() may be called before the CPU
+        * online notification callback runs. Until the callback
+        * has run we just return zero.
+        */
+       if (!reg->kaddr)
                return 0;
-       }
 
        return le64_to_cpu(READ_ONCE(reg->kaddr->stolen_time));
 }
 
-static int stolen_time_dying_cpu(unsigned int cpu)
+static int stolen_time_cpu_down_prepare(unsigned int cpu)
 {
        struct pv_time_stolen_time_region *reg;
 
@@ -73,7 +76,7 @@ static int stolen_time_dying_cpu(unsigned int cpu)
        return 0;
 }
 
-static int init_stolen_time_cpu(unsigned int cpu)
+static int stolen_time_cpu_online(unsigned int cpu)
 {
        struct pv_time_stolen_time_region *reg;
        struct arm_smccc_res res;
@@ -103,19 +106,20 @@ static int init_stolen_time_cpu(unsigned int cpu)
        return 0;
 }
 
-static int pv_time_init_stolen_time(void)
+static int __init pv_time_init_stolen_time(void)
 {
        int ret;
 
-       ret = cpuhp_setup_state(CPUHP_AP_ARM_KVMPV_STARTING,
-                               "hypervisor/arm/pvtime:starting",
-                               init_stolen_time_cpu, stolen_time_dying_cpu);
+       ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+                               "hypervisor/arm/pvtime:online",
+                               stolen_time_cpu_online,
+                               stolen_time_cpu_down_prepare);
        if (ret < 0)
                return ret;
        return 0;
 }
 
-static bool has_pv_steal_clock(void)
+static bool __init has_pv_steal_clock(void)
 {
        struct arm_smccc_res res;
 
index b0e03e0..88ff471 100644 (file)
@@ -137,11 +137,11 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
  * whist unwinding the stackframe and is like a subroutine return so we use
  * the PC.
  */
-static int callchain_trace(struct stackframe *frame, void *data)
+static bool callchain_trace(void *data, unsigned long pc)
 {
        struct perf_callchain_entry_ctx *entry = data;
-       perf_callchain_store(entry, frame->pc);
-       return 0;
+       perf_callchain_store(entry, pc);
+       return true;
 }
 
 void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
index 462f9a9..3605f77 100644 (file)
@@ -69,6 +69,9 @@ static const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
        [C(ITLB)][C(OP_READ)][C(RESULT_MISS)]   = ARMV8_PMUV3_PERFCTR_L1I_TLB_REFILL,
        [C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1I_TLB,
 
+       [C(LL)][C(OP_READ)][C(RESULT_MISS)]     = ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS_RD,
+       [C(LL)][C(OP_READ)][C(RESULT_ACCESS)]   = ARMV8_PMUV3_PERFCTR_LL_CACHE_RD,
+
        [C(BPU)][C(OP_READ)][C(RESULT_ACCESS)]  = ARMV8_PMUV3_PERFCTR_BR_PRED,
        [C(BPU)][C(OP_READ)][C(RESULT_MISS)]    = ARMV8_PMUV3_PERFCTR_BR_MIS_PRED,
 };
@@ -302,13 +305,33 @@ static struct attribute_group armv8_pmuv3_format_attr_group = {
        .attrs = armv8_pmuv3_format_attrs,
 };
 
+static ssize_t slots_show(struct device *dev, struct device_attribute *attr,
+                         char *page)
+{
+       struct pmu *pmu = dev_get_drvdata(dev);
+       struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu);
+       u32 slots = cpu_pmu->reg_pmmir & ARMV8_PMU_SLOTS_MASK;
+
+       return snprintf(page, PAGE_SIZE, "0x%08x\n", slots);
+}
+
+static DEVICE_ATTR_RO(slots);
+
+static struct attribute *armv8_pmuv3_caps_attrs[] = {
+       &dev_attr_slots.attr,
+       NULL,
+};
+
+static struct attribute_group armv8_pmuv3_caps_attr_group = {
+       .name = "caps",
+       .attrs = armv8_pmuv3_caps_attrs,
+};
+
 /*
  * Perf Events' indices
  */
 #define        ARMV8_IDX_CYCLE_COUNTER 0
 #define        ARMV8_IDX_COUNTER0      1
-#define        ARMV8_IDX_COUNTER_LAST(cpu_pmu) \
-       (ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
 
 
 /*
@@ -348,6 +371,73 @@ static inline bool armv8pmu_event_is_chained(struct perf_event *event)
 #define        ARMV8_IDX_TO_COUNTER(x) \
        (((x) - ARMV8_IDX_COUNTER0) & ARMV8_PMU_COUNTER_MASK)
 
+/*
+ * This code is really good
+ */
+
+#define PMEVN_CASE(n, case_macro) \
+       case n: case_macro(n); break
+
+#define PMEVN_SWITCH(x, case_macro)                            \
+       do {                                                    \
+               switch (x) {                                    \
+               PMEVN_CASE(0,  case_macro);                     \
+               PMEVN_CASE(1,  case_macro);                     \
+               PMEVN_CASE(2,  case_macro);                     \
+               PMEVN_CASE(3,  case_macro);                     \
+               PMEVN_CASE(4,  case_macro);                     \
+               PMEVN_CASE(5,  case_macro);                     \
+               PMEVN_CASE(6,  case_macro);                     \
+               PMEVN_CASE(7,  case_macro);                     \
+               PMEVN_CASE(8,  case_macro);                     \
+               PMEVN_CASE(9,  case_macro);                     \
+               PMEVN_CASE(10, case_macro);                     \
+               PMEVN_CASE(11, case_macro);                     \
+               PMEVN_CASE(12, case_macro);                     \
+               PMEVN_CASE(13, case_macro);                     \
+               PMEVN_CASE(14, case_macro);                     \
+               PMEVN_CASE(15, case_macro);                     \
+               PMEVN_CASE(16, case_macro);                     \
+               PMEVN_CASE(17, case_macro);                     \
+               PMEVN_CASE(18, case_macro);                     \
+               PMEVN_CASE(19, case_macro);                     \
+               PMEVN_CASE(20, case_macro);                     \
+               PMEVN_CASE(21, case_macro);                     \
+               PMEVN_CASE(22, case_macro);                     \
+               PMEVN_CASE(23, case_macro);                     \
+               PMEVN_CASE(24, case_macro);                     \
+               PMEVN_CASE(25, case_macro);                     \
+               PMEVN_CASE(26, case_macro);                     \
+               PMEVN_CASE(27, case_macro);                     \
+               PMEVN_CASE(28, case_macro);                     \
+               PMEVN_CASE(29, case_macro);                     \
+               PMEVN_CASE(30, case_macro);                     \
+               default: WARN(1, "Invalid PMEV* index\n");      \
+               }                                               \
+       } while (0)
+
+#define RETURN_READ_PMEVCNTRN(n) \
+       return read_sysreg(pmevcntr##n##_el0)
+static unsigned long read_pmevcntrn(int n)
+{
+       PMEVN_SWITCH(n, RETURN_READ_PMEVCNTRN);
+       return 0;
+}
+
+#define WRITE_PMEVCNTRN(n) \
+       write_sysreg(val, pmevcntr##n##_el0)
+static void write_pmevcntrn(int n, unsigned long val)
+{
+       PMEVN_SWITCH(n, WRITE_PMEVCNTRN);
+}
+
+#define WRITE_PMEVTYPERN(n) \
+       write_sysreg(val, pmevtyper##n##_el0)
+static void write_pmevtypern(int n, unsigned long val)
+{
+       PMEVN_SWITCH(n, WRITE_PMEVTYPERN);
+}
+
 static inline u32 armv8pmu_pmcr_read(void)
 {
        return read_sysreg(pmcr_el0);
@@ -365,28 +455,16 @@ static inline int armv8pmu_has_overflowed(u32 pmovsr)
        return pmovsr & ARMV8_PMU_OVERFLOWED_MASK;
 }
 
-static inline int armv8pmu_counter_valid(struct arm_pmu *cpu_pmu, int idx)
-{
-       return idx >= ARMV8_IDX_CYCLE_COUNTER &&
-               idx <= ARMV8_IDX_COUNTER_LAST(cpu_pmu);
-}
-
 static inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx)
 {
        return pmnc & BIT(ARMV8_IDX_TO_COUNTER(idx));
 }
 
-static inline void armv8pmu_select_counter(int idx)
+static inline u32 armv8pmu_read_evcntr(int idx)
 {
        u32 counter = ARMV8_IDX_TO_COUNTER(idx);
-       write_sysreg(counter, pmselr_el0);
-       isb();
-}
 
-static inline u64 armv8pmu_read_evcntr(int idx)
-{
-       armv8pmu_select_counter(idx);
-       return read_sysreg(pmxevcntr_el0);
+       return read_pmevcntrn(counter);
 }
 
 static inline u64 armv8pmu_read_hw_counter(struct perf_event *event)
@@ -440,15 +518,11 @@ static u64 armv8pmu_unbias_long_counter(struct perf_event *event, u64 value)
 
 static u64 armv8pmu_read_counter(struct perf_event *event)
 {
-       struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
        u64 value = 0;
 
-       if (!armv8pmu_counter_valid(cpu_pmu, idx))
-               pr_err("CPU%u reading wrong counter %d\n",
-                       smp_processor_id(), idx);
-       else if (idx == ARMV8_IDX_CYCLE_COUNTER)
+       if (idx == ARMV8_IDX_CYCLE_COUNTER)
                value = read_sysreg(pmccntr_el0);
        else
                value = armv8pmu_read_hw_counter(event);
@@ -458,8 +532,9 @@ static u64 armv8pmu_read_counter(struct perf_event *event)
 
 static inline void armv8pmu_write_evcntr(int idx, u64 value)
 {
-       armv8pmu_select_counter(idx);
-       write_sysreg(value, pmxevcntr_el0);
+       u32 counter = ARMV8_IDX_TO_COUNTER(idx);
+
+       write_pmevcntrn(counter, value);
 }
 
 static inline void armv8pmu_write_hw_counter(struct perf_event *event,
@@ -477,16 +552,12 @@ static inline void armv8pmu_write_hw_counter(struct perf_event *event,
 
 static void armv8pmu_write_counter(struct perf_event *event, u64 value)
 {
-       struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
 
        value = armv8pmu_bias_long_counter(event, value);
 
-       if (!armv8pmu_counter_valid(cpu_pmu, idx))
-               pr_err("CPU%u writing wrong counter %d\n",
-                       smp_processor_id(), idx);
-       else if (idx == ARMV8_IDX_CYCLE_COUNTER)
+       if (idx == ARMV8_IDX_CYCLE_COUNTER)
                write_sysreg(value, pmccntr_el0);
        else
                armv8pmu_write_hw_counter(event, value);
@@ -494,9 +565,10 @@ static void armv8pmu_write_counter(struct perf_event *event, u64 value)
 
 static inline void armv8pmu_write_evtype(int idx, u32 val)
 {
-       armv8pmu_select_counter(idx);
+       u32 counter = ARMV8_IDX_TO_COUNTER(idx);
+
        val &= ARMV8_PMU_EVTYPE_MASK;
-       write_sysreg(val, pmxevtyper_el0);
+       write_pmevtypern(counter, val);
 }
 
 static inline void armv8pmu_write_event_type(struct perf_event *event)
@@ -516,7 +588,10 @@ static inline void armv8pmu_write_event_type(struct perf_event *event)
                armv8pmu_write_evtype(idx - 1, hwc->config_base);
                armv8pmu_write_evtype(idx, chain_evt);
        } else {
-               armv8pmu_write_evtype(idx, hwc->config_base);
+               if (idx == ARMV8_IDX_CYCLE_COUNTER)
+                       write_sysreg(hwc->config_base, pmccfiltr_el0);
+               else
+                       armv8pmu_write_evtype(idx, hwc->config_base);
        }
 }
 
@@ -532,6 +607,11 @@ static u32 armv8pmu_event_cnten_mask(struct perf_event *event)
 
 static inline void armv8pmu_enable_counter(u32 mask)
 {
+       /*
+        * Make sure event configuration register writes are visible before we
+        * enable the counter.
+        * */
+       isb();
        write_sysreg(mask, pmcntenset_el0);
 }
 
@@ -550,6 +630,11 @@ static inline void armv8pmu_enable_event_counter(struct perf_event *event)
 static inline void armv8pmu_disable_counter(u32 mask)
 {
        write_sysreg(mask, pmcntenclr_el0);
+       /*
+        * Make sure the effects of disabling the counter are visible before we
+        * start configuring the event.
+        */
+       isb();
 }
 
 static inline void armv8pmu_disable_event_counter(struct perf_event *event)
@@ -606,15 +691,10 @@ static inline u32 armv8pmu_getreset_flags(void)
 
 static void armv8pmu_enable_event(struct perf_event *event)
 {
-       unsigned long flags;
-       struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
-       struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
-
        /*
         * Enable counter and interrupt, and set the counter to count
         * the event that we're interested in.
         */
-       raw_spin_lock_irqsave(&events->pmu_lock, flags);
 
        /*
         * Disable counter
@@ -622,7 +702,7 @@ static void armv8pmu_enable_event(struct perf_event *event)
        armv8pmu_disable_event_counter(event);
 
        /*
-        * Set event (if destined for PMNx counters).
+        * Set event.
         */
        armv8pmu_write_event_type(event);
 
@@ -635,21 +715,10 @@ static void armv8pmu_enable_event(struct perf_event *event)
         * Enable counter
         */
        armv8pmu_enable_event_counter(event);
-
-       raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
 }
 
 static void armv8pmu_disable_event(struct perf_event *event)
 {
-       unsigned long flags;
-       struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
-       struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
-
-       /*
-        * Disable counter and interrupt
-        */
-       raw_spin_lock_irqsave(&events->pmu_lock, flags);
-
        /*
         * Disable counter
         */
@@ -659,30 +728,18 @@ static void armv8pmu_disable_event(struct perf_event *event)
         * Disable interrupt for this counter
         */
        armv8pmu_disable_event_irq(event);
-
-       raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
 }
 
 static void armv8pmu_start(struct arm_pmu *cpu_pmu)
 {
-       unsigned long flags;
-       struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
-
-       raw_spin_lock_irqsave(&events->pmu_lock, flags);
        /* Enable all counters */
        armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E);
-       raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
 }
 
 static void armv8pmu_stop(struct arm_pmu *cpu_pmu)
 {
-       unsigned long flags;
-       struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
-
-       raw_spin_lock_irqsave(&events->pmu_lock, flags);
        /* Disable all counters */
        armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMU_PMCR_E);
-       raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
 }
 
 static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
@@ -735,20 +792,16 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu)
                if (!armpmu_event_set_period(event))
                        continue;
 
+               /*
+                * Perf event overflow will queue the processing of the event as
+                * an irq_work which will be taken care of in the handling of
+                * IPI_IRQ_WORK.
+                */
                if (perf_event_overflow(event, &data, regs))
                        cpu_pmu->disable(event);
        }
        armv8pmu_start(cpu_pmu);
 
-       /*
-        * Handle the pending perf events.
-        *
-        * Note: this call *must* be run with interrupts disabled. For
-        * platforms that can have the PMU interrupts raised as an NMI, this
-        * will not work.
-        */
-       irq_work_run();
-
        return IRQ_HANDLED;
 }
 
@@ -997,6 +1050,12 @@ static void __armv8pmu_probe_pmu(void *info)
 
        bitmap_from_arr32(cpu_pmu->pmceid_ext_bitmap,
                             pmceid, ARMV8_PMUV3_MAX_COMMON_EVENTS);
+
+       /* store PMMIR_EL1 register for sysfs */
+       if (pmuver >= ID_AA64DFR0_PMUVER_8_4 && (pmceid_raw[1] & BIT(31)))
+               cpu_pmu->reg_pmmir = read_cpuid(PMMIR_EL1);
+       else
+               cpu_pmu->reg_pmmir = 0;
 }
 
 static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu)
@@ -1019,7 +1078,8 @@ static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu)
 static int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name,
                          int (*map_event)(struct perf_event *event),
                          const struct attribute_group *events,
-                         const struct attribute_group *format)
+                         const struct attribute_group *format,
+                         const struct attribute_group *caps)
 {
        int ret = armv8pmu_probe_pmu(cpu_pmu);
        if (ret)
@@ -1044,104 +1104,112 @@ static int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name,
                        events : &armv8_pmuv3_events_attr_group;
        cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = format ?
                        format : &armv8_pmuv3_format_attr_group;
+       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_CAPS] = caps ?
+                       caps : &armv8_pmuv3_caps_attr_group;
 
        return 0;
 }
 
+static int armv8_pmu_init_nogroups(struct arm_pmu *cpu_pmu, char *name,
+                                  int (*map_event)(struct perf_event *event))
+{
+       return armv8_pmu_init(cpu_pmu, name, map_event, NULL, NULL, NULL);
+}
+
 static int armv8_pmuv3_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_pmuv3",
-                             armv8_pmuv3_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_pmuv3",
+                                      armv8_pmuv3_map_event);
 }
 
 static int armv8_a34_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a34",
-                             armv8_pmuv3_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a34",
+                                      armv8_pmuv3_map_event);
 }
 
 static int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a35",
-                             armv8_a53_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a35",
+                                      armv8_a53_map_event);
 }
 
 static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a53",
-                             armv8_a53_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a53",
+                                      armv8_a53_map_event);
 }
 
 static int armv8_a55_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a55",
-                             armv8_pmuv3_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a55",
+                                      armv8_pmuv3_map_event);
 }
 
 static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a57",
-                             armv8_a57_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a57",
+                                      armv8_a57_map_event);
 }
 
 static int armv8_a65_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a65",
-                             armv8_pmuv3_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a65",
+                                      armv8_pmuv3_map_event);
 }
 
 static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a72",
-                             armv8_a57_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a72",
+                                      armv8_a57_map_event);
 }
 
 static int armv8_a73_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a73",
-                             armv8_a73_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a73",
+                                      armv8_a73_map_event);
 }
 
 static int armv8_a75_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a75",
-                             armv8_pmuv3_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a75",
+                                      armv8_pmuv3_map_event);
 }
 
 static int armv8_a76_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a76",
-                             armv8_pmuv3_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a76",
+                                      armv8_pmuv3_map_event);
 }
 
 static int armv8_a77_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a77",
-                             armv8_pmuv3_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a77",
+                                      armv8_pmuv3_map_event);
 }
 
 static int armv8_e1_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_neoverse_e1",
-                             armv8_pmuv3_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_neoverse_e1",
+                                      armv8_pmuv3_map_event);
 }
 
 static int armv8_n1_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_neoverse_n1",
-                             armv8_pmuv3_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_neoverse_n1",
+                                      armv8_pmuv3_map_event);
 }
 
 static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_cavium_thunder",
-                             armv8_thunder_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cavium_thunder",
+                                      armv8_thunder_map_event);
 }
 
 static int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       return armv8_pmu_init(cpu_pmu, "armv8_brcm_vulcan",
-                             armv8_vulcan_map_event, NULL, NULL);
+       return armv8_pmu_init_nogroups(cpu_pmu, "armv8_brcm_vulcan",
+                                      armv8_vulcan_map_event);
 }
 
 static const struct of_device_id armv8_pmu_of_device_ids[] = {
index 666b225..94e8718 100644 (file)
@@ -16,7 +16,7 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
 
        /*
         * Our handling of compat tasks (PERF_SAMPLE_REGS_ABI_32) is weird, but
-        * we're stuck with it for ABI compatability reasons.
+        * we're stuck with it for ABI compatibility reasons.
         *
         * For a 32-bit consumer inspecting a 32-bit task, then it will look at
         * the first 16 registers (see arch/arm/include/uapi/asm/perf_regs.h).
index 263d5fb..104101f 100644 (file)
@@ -29,7 +29,8 @@ static bool __kprobes aarch64_insn_is_steppable(u32 insn)
                    aarch64_insn_is_msr_imm(insn) ||
                    aarch64_insn_is_msr_reg(insn) ||
                    aarch64_insn_is_exception(insn) ||
-                   aarch64_insn_is_eret(insn))
+                   aarch64_insn_is_eret(insn) ||
+                   aarch64_insn_is_eret_auth(insn))
                        return false;
 
                /*
@@ -42,8 +43,10 @@ static bool __kprobes aarch64_insn_is_steppable(u32 insn)
                             != AARCH64_INSN_SPCLREG_DAIF;
 
                /*
-                * The HINT instruction is is problematic when single-stepping,
-                * except for the NOP case.
+                * The HINT instruction is steppable only if it is in whitelist
+                * and the rest of other such instructions are blocked for
+                * single stepping as they may cause exception or other
+                * unintended behaviour.
                 */
                if (aarch64_insn_is_hint(insn))
                        return aarch64_insn_is_steppable_hint(insn);
index 5290f17..deba738 100644 (file)
@@ -464,87 +464,15 @@ int __init arch_populate_kprobe_blacklist(void)
 
 void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address =
-               (unsigned long)&kretprobe_trampoline;
-       kprobe_opcode_t *correct_ret_addr = NULL;
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because multiple functions in the call path have
-        * return probes installed on them, and/or more than one
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always pushed into the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the (chronologically) first instance's ret_addr
-        *       will be the real return address, and all the rest will
-        *       point to kretprobe_trampoline.
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
-       correct_ret_addr = ri->ret_addr;
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               if (ri->rp && ri->rp->handler) {
-                       __this_cpu_write(current_kprobe, &ri->rp->kp);
-                       get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
-                       ri->ret_addr = correct_ret_addr;
-                       ri->rp->handler(ri, regs);
-                       __this_cpu_write(current_kprobe, NULL);
-               }
-
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
-       return (void *)orig_ret_address;
+       return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline,
+                                       (void *)kernel_stack_pointer(regs));
 }
 
 void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                      struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *)regs->regs[30];
+       ri->fp = (void *)kernel_stack_pointer(regs);
 
        /* replace return addr (x30) with trampoline */
        regs->regs[30] = (long)&kretprobe_trampoline;
index b63ce4c..4784011 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/lockdep.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/nospec.h>
 #include <linux/stddef.h>
 #include <linux/sysctl.h>
 #include <linux/unistd.h>
@@ -52,6 +53,7 @@
 #include <asm/exec.h>
 #include <asm/fpsimd.h>
 #include <asm/mmu_context.h>
+#include <asm/mte.h>
 #include <asm/processor.h>
 #include <asm/pointer_auth.h>
 #include <asm/stacktrace.h>
@@ -123,10 +125,8 @@ void arch_cpu_idle(void)
         * This should do all the clock switching and wait for interrupt
         * tricks
         */
-       trace_cpu_idle_rcuidle(1, smp_processor_id());
        cpu_do_idle();
        local_irq_enable();
-       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -241,7 +241,7 @@ static void print_pstate(struct pt_regs *regs)
                const char *btype_str = btypes[(pstate & PSR_BTYPE_MASK) >>
                                               PSR_BTYPE_SHIFT];
 
-               printk("pstate: %08llx (%c%c%c%c %c%c%c%c %cPAN %cUAO BTYPE=%s)\n",
+               printk("pstate: %08llx (%c%c%c%c %c%c%c%c %cPAN %cUAO %cTCO BTYPE=%s)\n",
                        pstate,
                        pstate & PSR_N_BIT ? 'N' : 'n',
                        pstate & PSR_Z_BIT ? 'Z' : 'z',
@@ -253,6 +253,7 @@ static void print_pstate(struct pt_regs *regs)
                        pstate & PSR_F_BIT ? 'F' : 'f',
                        pstate & PSR_PAN_BIT ? '+' : '-',
                        pstate & PSR_UAO_BIT ? '+' : '-',
+                       pstate & PSR_TCO_BIT ? '+' : '-',
                        btype_str);
        }
 }
@@ -338,6 +339,7 @@ void flush_thread(void)
        tls_thread_flush();
        flush_ptrace_hw_breakpoint(current);
        flush_tagged_addr_state();
+       flush_mte_state();
 }
 
 void release_thread(struct task_struct *dead_task)
@@ -370,6 +372,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
        dst->thread.sve_state = NULL;
        clear_tsk_thread_flag(dst, TIF_SVE);
 
+       /* clear any pending asynchronous tag fault raised by the parent */
+       clear_tsk_thread_flag(dst, TIF_MTE_ASYNC_FAULT);
+
        return 0;
 }
 
@@ -423,8 +428,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
                    cpus_have_const_cap(ARM64_HAS_UAO))
                        childregs->pstate |= PSR_UAO_BIT;
 
-               if (arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE)
-                       set_ssbs_bit(childregs);
+               spectre_v4_enable_task_mitigation(p);
 
                if (system_uses_irq_prio_masking())
                        childregs->pmr_save = GIC_PRIO_IRQON;
@@ -474,8 +478,6 @@ void uao_thread_switch(struct task_struct *next)
  */
 static void ssbs_thread_switch(struct task_struct *next)
 {
-       struct pt_regs *regs = task_pt_regs(next);
-
        /*
         * Nothing to do for kernel threads, but 'regs' may be junk
         * (e.g. idle task) so check the flags and bail early.
@@ -487,18 +489,10 @@ static void ssbs_thread_switch(struct task_struct *next)
         * If all CPUs implement the SSBS extension, then we just need to
         * context-switch the PSTATE field.
         */
-       if (cpu_have_feature(cpu_feature(SSBS)))
+       if (cpus_have_const_cap(ARM64_SSBS))
                return;
 
-       /* If the mitigation is enabled, then we leave SSBS clear. */
-       if ((arm64_get_ssbd_state() == ARM64_SSBD_FORCE_ENABLE) ||
-           test_tsk_thread_flag(next, TIF_SSBD))
-               return;
-
-       if (compat_user_mode(regs))
-               set_compat_ssbs_bit(regs);
-       else if (user_mode(regs))
-               set_ssbs_bit(regs);
+       spectre_v4_enable_task_mitigation(next);
 }
 
 /*
@@ -573,6 +567,13 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
         */
        dsb(ish);
 
+       /*
+        * MTE thread switching must happen after the DSB above to ensure that
+        * any asynchronous tag check faults have been logged in the TFSR*_EL1
+        * registers.
+        */
+       mte_thread_switch(next);
+
        /* the actual thread switch */
        last = cpu_switch_to(prev, next);
 
@@ -622,6 +623,11 @@ void arch_setup_new_exec(void)
        current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
 
        ptrauth_thread_init_user(current);
+
+       if (task_spec_ssb_noexec(current)) {
+               arch_prctl_spec_ctrl_set(current, PR_SPEC_STORE_BYPASS,
+                                        PR_SPEC_ENABLE);
+       }
 }
 
 #ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
@@ -630,11 +636,18 @@ void arch_setup_new_exec(void)
  */
 static unsigned int tagged_addr_disabled;
 
-long set_tagged_addr_ctrl(unsigned long arg)
+long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
 {
-       if (is_compat_task())
+       unsigned long valid_mask = PR_TAGGED_ADDR_ENABLE;
+       struct thread_info *ti = task_thread_info(task);
+
+       if (is_compat_thread(ti))
                return -EINVAL;
-       if (arg & ~PR_TAGGED_ADDR_ENABLE)
+
+       if (system_supports_mte())
+               valid_mask |= PR_MTE_TCF_MASK | PR_MTE_TAG_MASK;
+
+       if (arg & ~valid_mask)
                return -EINVAL;
 
        /*
@@ -644,20 +657,28 @@ long set_tagged_addr_ctrl(unsigned long arg)
        if (arg & PR_TAGGED_ADDR_ENABLE && tagged_addr_disabled)
                return -EINVAL;
 
-       update_thread_flag(TIF_TAGGED_ADDR, arg & PR_TAGGED_ADDR_ENABLE);
+       if (set_mte_ctrl(task, arg) != 0)
+               return -EINVAL;
+
+       update_ti_thread_flag(ti, TIF_TAGGED_ADDR, arg & PR_TAGGED_ADDR_ENABLE);
 
        return 0;
 }
 
-long get_tagged_addr_ctrl(void)
+long get_tagged_addr_ctrl(struct task_struct *task)
 {
-       if (is_compat_task())
+       long ret = 0;
+       struct thread_info *ti = task_thread_info(task);
+
+       if (is_compat_thread(ti))
                return -EINVAL;
 
-       if (test_thread_flag(TIF_TAGGED_ADDR))
-               return PR_TAGGED_ADDR_ENABLE;
+       if (test_ti_thread_flag(ti, TIF_TAGGED_ADDR))
+               ret = PR_TAGGED_ADDR_ENABLE;
 
-       return 0;
+       ret |= get_mte_ctrl(task);
+
+       return ret;
 }
 
 /*
diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c
new file mode 100644 (file)
index 0000000..68b710f
--- /dev/null
@@ -0,0 +1,792 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Handle detection, reporting and mitigation of Spectre v1, v2 and v4, as
+ * detailed at:
+ *
+ *   https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability
+ *
+ * This code was originally written hastily under an awful lot of stress and so
+ * aspects of it are somewhat hacky. Unfortunately, changing anything in here
+ * instantly makes me feel ill. Thanks, Jann. Thann.
+ *
+ * Copyright (C) 2018 ARM Ltd, All Rights Reserved.
+ * Copyright (C) 2020 Google LLC
+ *
+ * "If there's something strange in your neighbourhood, who you gonna call?"
+ *
+ * Authors: Will Deacon <will@kernel.org> and Marc Zyngier <maz@kernel.org>
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/cpu.h>
+#include <linux/device.h>
+#include <linux/nospec.h>
+#include <linux/prctl.h>
+#include <linux/sched/task_stack.h>
+
+#include <asm/spectre.h>
+#include <asm/traps.h>
+
+/*
+ * We try to ensure that the mitigation state can never change as the result of
+ * onlining a late CPU.
+ */
+static void update_mitigation_state(enum mitigation_state *oldp,
+                                   enum mitigation_state new)
+{
+       enum mitigation_state state;
+
+       do {
+               state = READ_ONCE(*oldp);
+               if (new <= state)
+                       break;
+
+               /* Userspace almost certainly can't deal with this. */
+               if (WARN_ON(system_capabilities_finalized()))
+                       break;
+       } while (cmpxchg_relaxed(oldp, state, new) != state);
+}
+
+/*
+ * Spectre v1.
+ *
+ * The kernel can't protect userspace for this one: it's each person for
+ * themselves. Advertise what we're doing and be done with it.
+ */
+ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "Mitigation: __user pointer sanitization\n");
+}
+
+/*
+ * Spectre v2.
+ *
+ * This one sucks. A CPU is either:
+ *
+ * - Mitigated in hardware and advertised by ID_AA64PFR0_EL1.CSV2.
+ * - Mitigated in hardware and listed in our "safe list".
+ * - Mitigated in software by firmware.
+ * - Mitigated in software by a CPU-specific dance in the kernel.
+ * - Vulnerable.
+ *
+ * It's not unlikely for different CPUs in a big.LITTLE system to fall into
+ * different camps.
+ */
+static enum mitigation_state spectre_v2_state;
+
+static bool __read_mostly __nospectre_v2;
+static int __init parse_spectre_v2_param(char *str)
+{
+       __nospectre_v2 = true;
+       return 0;
+}
+early_param("nospectre_v2", parse_spectre_v2_param);
+
+static bool spectre_v2_mitigations_off(void)
+{
+       bool ret = __nospectre_v2 || cpu_mitigations_off();
+
+       if (ret)
+               pr_info_once("spectre-v2 mitigation disabled by command line option\n");
+
+       return ret;
+}
+
+ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       switch (spectre_v2_state) {
+       case SPECTRE_UNAFFECTED:
+               return sprintf(buf, "Not affected\n");
+       case SPECTRE_MITIGATED:
+               return sprintf(buf, "Mitigation: Branch predictor hardening\n");
+       case SPECTRE_VULNERABLE:
+               fallthrough;
+       default:
+               return sprintf(buf, "Vulnerable\n");
+       }
+}
+
+static enum mitigation_state spectre_v2_get_cpu_hw_mitigation_state(void)
+{
+       u64 pfr0;
+       static const struct midr_range spectre_v2_safe_list[] = {
+               MIDR_ALL_VERSIONS(MIDR_CORTEX_A35),
+               MIDR_ALL_VERSIONS(MIDR_CORTEX_A53),
+               MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
+               MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53),
+               MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
+               MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER),
+               MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER),
+               { /* sentinel */ }
+       };
+
+       /* If the CPU has CSV2 set, we're safe */
+       pfr0 = read_cpuid(ID_AA64PFR0_EL1);
+       if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT))
+               return SPECTRE_UNAFFECTED;
+
+       /* Alternatively, we have a list of unaffected CPUs */
+       if (is_midr_in_range_list(read_cpuid_id(), spectre_v2_safe_list))
+               return SPECTRE_UNAFFECTED;
+
+       return SPECTRE_VULNERABLE;
+}
+
+#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED   (1)
+
+static enum mitigation_state spectre_v2_get_cpu_fw_mitigation_state(void)
+{
+       int ret;
+       struct arm_smccc_res res;
+
+       arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+                            ARM_SMCCC_ARCH_WORKAROUND_1, &res);
+
+       ret = res.a0;
+       switch (ret) {
+       case SMCCC_RET_SUCCESS:
+               return SPECTRE_MITIGATED;
+       case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED:
+               return SPECTRE_UNAFFECTED;
+       default:
+               fallthrough;
+       case SMCCC_RET_NOT_SUPPORTED:
+               return SPECTRE_VULNERABLE;
+       }
+}
+
+bool has_spectre_v2(const struct arm64_cpu_capabilities *entry, int scope)
+{
+       WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
+
+       if (spectre_v2_get_cpu_hw_mitigation_state() == SPECTRE_UNAFFECTED)
+               return false;
+
+       if (spectre_v2_get_cpu_fw_mitigation_state() == SPECTRE_UNAFFECTED)
+               return false;
+
+       return true;
+}
+
+DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
+
+enum mitigation_state arm64_get_spectre_v2_state(void)
+{
+       return spectre_v2_state;
+}
+
+#ifdef CONFIG_KVM
+#include <asm/cacheflush.h>
+#include <asm/kvm_asm.h>
+
+atomic_t arm64_el2_vector_last_slot = ATOMIC_INIT(-1);
+
+static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
+                               const char *hyp_vecs_end)
+{
+       void *dst = lm_alias(__bp_harden_hyp_vecs + slot * SZ_2K);
+       int i;
+
+       for (i = 0; i < SZ_2K; i += 0x80)
+               memcpy(dst + i, hyp_vecs_start, hyp_vecs_end - hyp_vecs_start);
+
+       __flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K);
+}
+
+static void install_bp_hardening_cb(bp_hardening_cb_t fn)
+{
+       static DEFINE_RAW_SPINLOCK(bp_lock);
+       int cpu, slot = -1;
+       const char *hyp_vecs_start = __smccc_workaround_1_smc;
+       const char *hyp_vecs_end = __smccc_workaround_1_smc +
+                                  __SMCCC_WORKAROUND_1_SMC_SZ;
+
+       /*
+        * detect_harden_bp_fw() passes NULL for the hyp_vecs start/end if
+        * we're a guest. Skip the hyp-vectors work.
+        */
+       if (!is_hyp_mode_available()) {
+               __this_cpu_write(bp_hardening_data.fn, fn);
+               return;
+       }
+
+       raw_spin_lock(&bp_lock);
+       for_each_possible_cpu(cpu) {
+               if (per_cpu(bp_hardening_data.fn, cpu) == fn) {
+                       slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu);
+                       break;
+               }
+       }
+
+       if (slot == -1) {
+               slot = atomic_inc_return(&arm64_el2_vector_last_slot);
+               BUG_ON(slot >= BP_HARDEN_EL2_SLOTS);
+               __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end);
+       }
+
+       __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
+       __this_cpu_write(bp_hardening_data.fn, fn);
+       raw_spin_unlock(&bp_lock);
+}
+#else
+static void install_bp_hardening_cb(bp_hardening_cb_t fn)
+{
+       __this_cpu_write(bp_hardening_data.fn, fn);
+}
+#endif /* CONFIG_KVM */
+
+static void call_smc_arch_workaround_1(void)
+{
+       arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
+}
+
+static void call_hvc_arch_workaround_1(void)
+{
+       arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
+}
+
+static void qcom_link_stack_sanitisation(void)
+{
+       u64 tmp;
+
+       asm volatile("mov       %0, x30         \n"
+                    ".rept     16              \n"
+                    "bl        . + 4           \n"
+                    ".endr                     \n"
+                    "mov       x30, %0         \n"
+                    : "=&r" (tmp));
+}
+
+static enum mitigation_state spectre_v2_enable_fw_mitigation(void)
+{
+       bp_hardening_cb_t cb;
+       enum mitigation_state state;
+
+       state = spectre_v2_get_cpu_fw_mitigation_state();
+       if (state != SPECTRE_MITIGATED)
+               return state;
+
+       if (spectre_v2_mitigations_off())
+               return SPECTRE_VULNERABLE;
+
+       switch (arm_smccc_1_1_get_conduit()) {
+       case SMCCC_CONDUIT_HVC:
+               cb = call_hvc_arch_workaround_1;
+               break;
+
+       case SMCCC_CONDUIT_SMC:
+               cb = call_smc_arch_workaround_1;
+               break;
+
+       default:
+               return SPECTRE_VULNERABLE;
+       }
+
+       install_bp_hardening_cb(cb);
+       return SPECTRE_MITIGATED;
+}
+
+static enum mitigation_state spectre_v2_enable_sw_mitigation(void)
+{
+       u32 midr;
+
+       if (spectre_v2_mitigations_off())
+               return SPECTRE_VULNERABLE;
+
+       midr = read_cpuid_id();
+       if (((midr & MIDR_CPU_MODEL_MASK) != MIDR_QCOM_FALKOR) &&
+           ((midr & MIDR_CPU_MODEL_MASK) != MIDR_QCOM_FALKOR_V1))
+               return SPECTRE_VULNERABLE;
+
+       install_bp_hardening_cb(qcom_link_stack_sanitisation);
+       return SPECTRE_MITIGATED;
+}
+
+void spectre_v2_enable_mitigation(const struct arm64_cpu_capabilities *__unused)
+{
+       enum mitigation_state state;
+
+       WARN_ON(preemptible());
+
+       state = spectre_v2_get_cpu_hw_mitigation_state();
+       if (state == SPECTRE_VULNERABLE)
+               state = spectre_v2_enable_fw_mitigation();
+       if (state == SPECTRE_VULNERABLE)
+               state = spectre_v2_enable_sw_mitigation();
+
+       update_mitigation_state(&spectre_v2_state, state);
+}
+
+/*
+ * Spectre v4.
+ *
+ * If you thought Spectre v2 was nasty, wait until you see this mess. A CPU is
+ * either:
+ *
+ * - Mitigated in hardware and listed in our "safe list".
+ * - Mitigated in hardware via PSTATE.SSBS.
+ * - Mitigated in software by firmware (sometimes referred to as SSBD).
+ *
+ * Wait, that doesn't sound so bad, does it? Keep reading...
+ *
+ * A major source of headaches is that the software mitigation is enabled both
+ * on a per-task basis, but can also be forced on for the kernel, necessitating
+ * both context-switch *and* entry/exit hooks. To make it even worse, some CPUs
+ * allow EL0 to toggle SSBS directly, which can end up with the prctl() state
+ * being stale when re-entering the kernel. The usual big.LITTLE caveats apply,
+ * so you can have systems that have both firmware and SSBS mitigations. This
+ * means we actually have to reject late onlining of CPUs with mitigations if
+ * all of the currently onlined CPUs are safelisted, as the mitigation tends to
+ * be opt-in for userspace. Yes, really, the cure is worse than the disease.
+ *
+ * The only good part is that if the firmware mitigation is present, then it is
+ * present for all CPUs, meaning we don't have to worry about late onlining of a
+ * vulnerable CPU if one of the boot CPUs is using the firmware mitigation.
+ *
+ * Give me a VAX-11/780 any day of the week...
+ */
+static enum mitigation_state spectre_v4_state;
+
+/* This is the per-cpu state tracking whether we need to talk to firmware */
+DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required);
+
+enum spectre_v4_policy {
+       SPECTRE_V4_POLICY_MITIGATION_DYNAMIC,
+       SPECTRE_V4_POLICY_MITIGATION_ENABLED,
+       SPECTRE_V4_POLICY_MITIGATION_DISABLED,
+};
+
+static enum spectre_v4_policy __read_mostly __spectre_v4_policy;
+
+static const struct spectre_v4_param {
+       const char              *str;
+       enum spectre_v4_policy  policy;
+} spectre_v4_params[] = {
+       { "force-on",   SPECTRE_V4_POLICY_MITIGATION_ENABLED, },
+       { "force-off",  SPECTRE_V4_POLICY_MITIGATION_DISABLED, },
+       { "kernel",     SPECTRE_V4_POLICY_MITIGATION_DYNAMIC, },
+};
+static int __init parse_spectre_v4_param(char *str)
+{
+       int i;
+
+       if (!str || !str[0])
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(spectre_v4_params); i++) {
+               const struct spectre_v4_param *param = &spectre_v4_params[i];
+
+               if (strncmp(str, param->str, strlen(param->str)))
+                       continue;
+
+               __spectre_v4_policy = param->policy;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+early_param("ssbd", parse_spectre_v4_param);
+
+/*
+ * Because this was all written in a rush by people working in different silos,
+ * we've ended up with multiple command line options to control the same thing.
+ * Wrap these up in some helpers, which prefer disabling the mitigation if faced
+ * with contradictory parameters. The mitigation is always either "off",
+ * "dynamic" or "on".
+ */
+static bool spectre_v4_mitigations_off(void)
+{
+       bool ret = cpu_mitigations_off() ||
+                  __spectre_v4_policy == SPECTRE_V4_POLICY_MITIGATION_DISABLED;
+
+       if (ret)
+               pr_info_once("spectre-v4 mitigation disabled by command-line option\n");
+
+       return ret;
+}
+
+/* Do we need to toggle the mitigation state on entry to/exit from the kernel? */
+static bool spectre_v4_mitigations_dynamic(void)
+{
+       return !spectre_v4_mitigations_off() &&
+              __spectre_v4_policy == SPECTRE_V4_POLICY_MITIGATION_DYNAMIC;
+}
+
+static bool spectre_v4_mitigations_on(void)
+{
+       return !spectre_v4_mitigations_off() &&
+              __spectre_v4_policy == SPECTRE_V4_POLICY_MITIGATION_ENABLED;
+}
+
+ssize_t cpu_show_spec_store_bypass(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       switch (spectre_v4_state) {
+       case SPECTRE_UNAFFECTED:
+               return sprintf(buf, "Not affected\n");
+       case SPECTRE_MITIGATED:
+               return sprintf(buf, "Mitigation: Speculative Store Bypass disabled via prctl\n");
+       case SPECTRE_VULNERABLE:
+               fallthrough;
+       default:
+               return sprintf(buf, "Vulnerable\n");
+       }
+}
+
+enum mitigation_state arm64_get_spectre_v4_state(void)
+{
+       return spectre_v4_state;
+}
+
+static enum mitigation_state spectre_v4_get_cpu_hw_mitigation_state(void)
+{
+       static const struct midr_range spectre_v4_safe_list[] = {
+               MIDR_ALL_VERSIONS(MIDR_CORTEX_A35),
+               MIDR_ALL_VERSIONS(MIDR_CORTEX_A53),
+               MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
+               MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53),
+               MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER),
+               MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER),
+               { /* sentinel */ },
+       };
+
+       if (is_midr_in_range_list(read_cpuid_id(), spectre_v4_safe_list))
+               return SPECTRE_UNAFFECTED;
+
+       /* CPU features are detected first */
+       if (this_cpu_has_cap(ARM64_SSBS))
+               return SPECTRE_MITIGATED;
+
+       return SPECTRE_VULNERABLE;
+}
+
+static enum mitigation_state spectre_v4_get_cpu_fw_mitigation_state(void)
+{
+       int ret;
+       struct arm_smccc_res res;
+
+       arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+                            ARM_SMCCC_ARCH_WORKAROUND_2, &res);
+
+       ret = res.a0;
+       switch (ret) {
+       case SMCCC_RET_SUCCESS:
+               return SPECTRE_MITIGATED;
+       case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED:
+               fallthrough;
+       case SMCCC_RET_NOT_REQUIRED:
+               return SPECTRE_UNAFFECTED;
+       default:
+               fallthrough;
+       case SMCCC_RET_NOT_SUPPORTED:
+               return SPECTRE_VULNERABLE;
+       }
+}
+
+bool has_spectre_v4(const struct arm64_cpu_capabilities *cap, int scope)
+{
+       enum mitigation_state state;
+
+       WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
+
+       state = spectre_v4_get_cpu_hw_mitigation_state();
+       if (state == SPECTRE_VULNERABLE)
+               state = spectre_v4_get_cpu_fw_mitigation_state();
+
+       return state != SPECTRE_UNAFFECTED;
+}
+
+static int ssbs_emulation_handler(struct pt_regs *regs, u32 instr)
+{
+       if (user_mode(regs))
+               return 1;
+
+       if (instr & BIT(PSTATE_Imm_shift))
+               regs->pstate |= PSR_SSBS_BIT;
+       else
+               regs->pstate &= ~PSR_SSBS_BIT;
+
+       arm64_skip_faulting_instruction(regs, 4);
+       return 0;
+}
+
+static struct undef_hook ssbs_emulation_hook = {
+       .instr_mask     = ~(1U << PSTATE_Imm_shift),
+       .instr_val      = 0xd500401f | PSTATE_SSBS,
+       .fn             = ssbs_emulation_handler,
+};
+
+static enum mitigation_state spectre_v4_enable_hw_mitigation(void)
+{
+       static bool undef_hook_registered = false;
+       static DEFINE_RAW_SPINLOCK(hook_lock);
+       enum mitigation_state state;
+
+       /*
+        * If the system is mitigated but this CPU doesn't have SSBS, then
+        * we must be on the safelist and there's nothing more to do.
+        */
+       state = spectre_v4_get_cpu_hw_mitigation_state();
+       if (state != SPECTRE_MITIGATED || !this_cpu_has_cap(ARM64_SSBS))
+               return state;
+
+       raw_spin_lock(&hook_lock);
+       if (!undef_hook_registered) {
+               register_undef_hook(&ssbs_emulation_hook);
+               undef_hook_registered = true;
+       }
+       raw_spin_unlock(&hook_lock);
+
+       if (spectre_v4_mitigations_off()) {
+               sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_DSSBS);
+               asm volatile(SET_PSTATE_SSBS(1));
+               return SPECTRE_VULNERABLE;
+       }
+
+       /* SCTLR_EL1.DSSBS was initialised to 0 during boot */
+       asm volatile(SET_PSTATE_SSBS(0));
+       return SPECTRE_MITIGATED;
+}
+
+/*
+ * Patch a branch over the Spectre-v4 mitigation code with a NOP so that
+ * we fallthrough and check whether firmware needs to be called on this CPU.
+ */
+void __init spectre_v4_patch_fw_mitigation_enable(struct alt_instr *alt,
+                                                 __le32 *origptr,
+                                                 __le32 *updptr, int nr_inst)
+{
+       BUG_ON(nr_inst != 1); /* Branch -> NOP */
+
+       if (spectre_v4_mitigations_off())
+               return;
+
+       if (cpus_have_final_cap(ARM64_SSBS))
+               return;
+
+       if (spectre_v4_mitigations_dynamic())
+               *updptr = cpu_to_le32(aarch64_insn_gen_nop());
+}
+
+/*
+ * Patch a NOP in the Spectre-v4 mitigation code with an SMC/HVC instruction
+ * to call into firmware to adjust the mitigation state.
+ */
+void __init spectre_v4_patch_fw_mitigation_conduit(struct alt_instr *alt,
+                                                  __le32 *origptr,
+                                                  __le32 *updptr, int nr_inst)
+{
+       u32 insn;
+
+       BUG_ON(nr_inst != 1); /* NOP -> HVC/SMC */
+
+       switch (arm_smccc_1_1_get_conduit()) {
+       case SMCCC_CONDUIT_HVC:
+               insn = aarch64_insn_get_hvc_value();
+               break;
+       case SMCCC_CONDUIT_SMC:
+               insn = aarch64_insn_get_smc_value();
+               break;
+       default:
+               return;
+       }
+
+       *updptr = cpu_to_le32(insn);
+}
+
+static enum mitigation_state spectre_v4_enable_fw_mitigation(void)
+{
+       enum mitigation_state state;
+
+       state = spectre_v4_get_cpu_fw_mitigation_state();
+       if (state != SPECTRE_MITIGATED)
+               return state;
+
+       if (spectre_v4_mitigations_off()) {
+               arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_WORKAROUND_2, false, NULL);
+               return SPECTRE_VULNERABLE;
+       }
+
+       arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_WORKAROUND_2, true, NULL);
+
+       if (spectre_v4_mitigations_dynamic())
+               __this_cpu_write(arm64_ssbd_callback_required, 1);
+
+       return SPECTRE_MITIGATED;
+}
+
+void spectre_v4_enable_mitigation(const struct arm64_cpu_capabilities *__unused)
+{
+       enum mitigation_state state;
+
+       WARN_ON(preemptible());
+
+       state = spectre_v4_enable_hw_mitigation();
+       if (state == SPECTRE_VULNERABLE)
+               state = spectre_v4_enable_fw_mitigation();
+
+       update_mitigation_state(&spectre_v4_state, state);
+}
+
+static void __update_pstate_ssbs(struct pt_regs *regs, bool state)
+{
+       u64 bit = compat_user_mode(regs) ? PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
+
+       if (state)
+               regs->pstate |= bit;
+       else
+               regs->pstate &= ~bit;
+}
+
+void spectre_v4_enable_task_mitigation(struct task_struct *tsk)
+{
+       struct pt_regs *regs = task_pt_regs(tsk);
+       bool ssbs = false, kthread = tsk->flags & PF_KTHREAD;
+
+       if (spectre_v4_mitigations_off())
+               ssbs = true;
+       else if (spectre_v4_mitigations_dynamic() && !kthread)
+               ssbs = !test_tsk_thread_flag(tsk, TIF_SSBD);
+
+       __update_pstate_ssbs(regs, ssbs);
+}
+
+/*
+ * The Spectre-v4 mitigation can be controlled via a prctl() from userspace.
+ * This is interesting because the "speculation disabled" behaviour can be
+ * configured so that it is preserved across exec(), which means that the
+ * prctl() may be necessary even when PSTATE.SSBS can be toggled directly
+ * from userspace.
+ */
+static void ssbd_prctl_enable_mitigation(struct task_struct *task)
+{
+       task_clear_spec_ssb_noexec(task);
+       task_set_spec_ssb_disable(task);
+       set_tsk_thread_flag(task, TIF_SSBD);
+}
+
+static void ssbd_prctl_disable_mitigation(struct task_struct *task)
+{
+       task_clear_spec_ssb_noexec(task);
+       task_clear_spec_ssb_disable(task);
+       clear_tsk_thread_flag(task, TIF_SSBD);
+}
+
+static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
+{
+       switch (ctrl) {
+       case PR_SPEC_ENABLE:
+               /* Enable speculation: disable mitigation */
+               /*
+                * Force disabled speculation prevents it from being
+                * re-enabled.
+                */
+               if (task_spec_ssb_force_disable(task))
+                       return -EPERM;
+
+               /*
+                * If the mitigation is forced on, then speculation is forced
+                * off and we again prevent it from being re-enabled.
+                */
+               if (spectre_v4_mitigations_on())
+                       return -EPERM;
+
+               ssbd_prctl_disable_mitigation(task);
+               break;
+       case PR_SPEC_FORCE_DISABLE:
+               /* Force disable speculation: force enable mitigation */
+               /*
+                * If the mitigation is forced off, then speculation is forced
+                * on and we prevent it from being disabled.
+                */
+               if (spectre_v4_mitigations_off())
+                       return -EPERM;
+
+               task_set_spec_ssb_force_disable(task);
+               fallthrough;
+       case PR_SPEC_DISABLE:
+               /* Disable speculation: enable mitigation */
+               /* Same as PR_SPEC_FORCE_DISABLE */
+               if (spectre_v4_mitigations_off())
+                       return -EPERM;
+
+               ssbd_prctl_enable_mitigation(task);
+               break;
+       case PR_SPEC_DISABLE_NOEXEC:
+               /* Disable speculation until execve(): enable mitigation */
+               /*
+                * If the mitigation state is forced one way or the other, then
+                * we must fail now before we try to toggle it on execve().
+                */
+               if (task_spec_ssb_force_disable(task) ||
+                   spectre_v4_mitigations_off() ||
+                   spectre_v4_mitigations_on()) {
+                       return -EPERM;
+               }
+
+               ssbd_prctl_enable_mitigation(task);
+               task_set_spec_ssb_noexec(task);
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       spectre_v4_enable_task_mitigation(task);
+       return 0;
+}
+
+int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
+                            unsigned long ctrl)
+{
+       switch (which) {
+       case PR_SPEC_STORE_BYPASS:
+               return ssbd_prctl_set(task, ctrl);
+       default:
+               return -ENODEV;
+       }
+}
+
+static int ssbd_prctl_get(struct task_struct *task)
+{
+       switch (spectre_v4_state) {
+       case SPECTRE_UNAFFECTED:
+               return PR_SPEC_NOT_AFFECTED;
+       case SPECTRE_MITIGATED:
+               if (spectre_v4_mitigations_on())
+                       return PR_SPEC_NOT_AFFECTED;
+
+               if (spectre_v4_mitigations_dynamic())
+                       break;
+
+               /* Mitigations are disabled, so we're vulnerable. */
+               fallthrough;
+       case SPECTRE_VULNERABLE:
+               fallthrough;
+       default:
+               return PR_SPEC_ENABLE;
+       }
+
+       /* Check the mitigation state for this task */
+       if (task_spec_ssb_force_disable(task))
+               return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
+
+       if (task_spec_ssb_noexec(task))
+               return PR_SPEC_PRCTL | PR_SPEC_DISABLE_NOEXEC;
+
+       if (task_spec_ssb_disable(task))
+               return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
+
+       return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
+}
+
+int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
+{
+       switch (which) {
+       case PR_SPEC_STORE_BYPASS:
+               return ssbd_prctl_get(task);
+       default:
+               return -ENODEV;
+       }
+}
index d8ebfd8..f49b349 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/cpufeature.h>
 #include <asm/debug-monitors.h>
 #include <asm/fpsimd.h>
+#include <asm/mte.h>
 #include <asm/pointer_auth.h>
 #include <asm/stacktrace.h>
 #include <asm/syscall.h>
@@ -1032,6 +1033,35 @@ static int pac_generic_keys_set(struct task_struct *target,
 #endif /* CONFIG_CHECKPOINT_RESTORE */
 #endif /* CONFIG_ARM64_PTR_AUTH */
 
+#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
+static int tagged_addr_ctrl_get(struct task_struct *target,
+                               const struct user_regset *regset,
+                               struct membuf to)
+{
+       long ctrl = get_tagged_addr_ctrl(target);
+
+       if (IS_ERR_VALUE(ctrl))
+               return ctrl;
+
+       return membuf_write(&to, &ctrl, sizeof(ctrl));
+}
+
+static int tagged_addr_ctrl_set(struct task_struct *target, const struct
+                               user_regset *regset, unsigned int pos,
+                               unsigned int count, const void *kbuf, const
+                               void __user *ubuf)
+{
+       int ret;
+       long ctrl;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, 0, -1);
+       if (ret)
+               return ret;
+
+       return set_tagged_addr_ctrl(target, ctrl);
+}
+#endif
+
 enum aarch64_regset {
        REGSET_GPR,
        REGSET_FPR,
@@ -1051,6 +1081,9 @@ enum aarch64_regset {
        REGSET_PACG_KEYS,
 #endif
 #endif
+#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
+       REGSET_TAGGED_ADDR_CTRL,
+#endif
 };
 
 static const struct user_regset aarch64_regsets[] = {
@@ -1148,6 +1181,16 @@ static const struct user_regset aarch64_regsets[] = {
        },
 #endif
 #endif
+#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
+       [REGSET_TAGGED_ADDR_CTRL] = {
+               .core_note_type = NT_ARM_TAGGED_ADDR_CTRL,
+               .n = 1,
+               .size = sizeof(long),
+               .align = sizeof(long),
+               .regset_get = tagged_addr_ctrl_get,
+               .set = tagged_addr_ctrl_set,
+       },
+#endif
 };
 
 static const struct user_regset_view user_aarch64_view = {
@@ -1691,6 +1734,12 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 long arch_ptrace(struct task_struct *child, long request,
                 unsigned long addr, unsigned long data)
 {
+       switch (request) {
+       case PTRACE_PEEKMTETAGS:
+       case PTRACE_POKEMTETAGS:
+               return mte_ptrace_copy_tags(child, request, addr, data);
+       }
+
        return ptrace_request(child, request, addr, data);
 }
 
@@ -1793,7 +1842,7 @@ void syscall_trace_exit(struct pt_regs *regs)
  * We also reserve IL for the kernel; SS is handled dynamically.
  */
 #define SPSR_EL1_AARCH64_RES0_BITS \
-       (GENMASK_ULL(63, 32) | GENMASK_ULL(27, 25) | GENMASK_ULL(23, 22) | \
+       (GENMASK_ULL(63, 32) | GENMASK_ULL(27, 26) | GENMASK_ULL(23, 22) | \
         GENMASK_ULL(20, 13) | GENMASK_ULL(5, 5))
 #define SPSR_EL1_AARCH32_RES0_BITS \
        (GENMASK_ULL(63, 32) | GENMASK_ULL(22, 22) | GENMASK_ULL(20, 20))
index 542d6ed..84eec95 100644 (file)
@@ -36,18 +36,6 @@ SYM_CODE_START(arm64_relocate_new_kernel)
        mov     x14, xzr                        /* x14 = entry ptr */
        mov     x13, xzr                        /* x13 = copy dest */
 
-       /* Clear the sctlr_el2 flags. */
-       mrs     x0, CurrentEL
-       cmp     x0, #CurrentEL_EL2
-       b.ne    1f
-       mrs     x0, sctlr_el2
-       mov_q   x1, SCTLR_ELx_FLAGS
-       bic     x0, x0, x1
-       pre_disable_mmu_workaround
-       msr     sctlr_el2, x0
-       isb
-1:
-
        /* Check if the new image needs relocation. */
        tbnz    x16, IND_DONE_BIT, .Ldone
 
index a5e8b3b..a6d1875 100644 (file)
@@ -18,16 +18,16 @@ struct return_address_data {
        void *addr;
 };
 
-static int save_return_addr(struct stackframe *frame, void *d)
+static bool save_return_addr(void *d, unsigned long pc)
 {
        struct return_address_data *data = d;
 
        if (!data->level) {
-               data->addr = (void *)frame->pc;
-               return 1;
+               data->addr = (void *)pc;
+               return false;
        } else {
                --data->level;
-               return 0;
+               return true;
        }
 }
 NOKPROBE_SYMBOL(save_return_addr);
index 77c4c9b..53acbec 100644 (file)
@@ -280,7 +280,6 @@ u64 cpu_logical_map(int cpu)
 {
        return __cpu_logical_map[cpu];
 }
-EXPORT_SYMBOL_GPL(cpu_logical_map);
 
 void __init __no_sanitize_address setup_arch(char **cmdline_p)
 {
index 3b4f31f..bdcaaf0 100644 (file)
@@ -244,7 +244,8 @@ static int preserve_sve_context(struct sve_context __user *ctx)
        if (vq) {
                /*
                 * This assumes that the SVE state has already been saved to
-                * the task struct by calling preserve_fpsimd_context().
+                * the task struct by calling the function
+                * fpsimd_signal_preserve_current_state().
                 */
                err |= __copy_to_user((char __user *)ctx + SVE_SIG_REGS_OFFSET,
                                      current->thread.sve_state,
@@ -748,6 +749,9 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
                regs->pstate |= PSR_BTYPE_C;
        }
 
+       /* TCO (Tag Check Override) always cleared for signal handlers */
+       regs->pstate &= ~PSR_TCO_BIT;
+
        if (ka->sa.sa_flags & SA_RESTORER)
                sigtramp = ka->sa.sa_restorer;
        else
@@ -932,6 +936,12 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
                        if (thread_flags & _TIF_UPROBE)
                                uprobe_notify_resume(regs);
 
+                       if (thread_flags & _TIF_MTE_ASYNC_FAULT) {
+                               clear_thread_flag(TIF_MTE_ASYNC_FAULT);
+                               send_sig_fault(SIGSEGV, SEGV_MTEAERR,
+                                              (void __user *)NULL, current);
+                       }
+
                        if (thread_flags & _TIF_SIGPENDING)
                                do_signal(regs);
 
index 1f93809..d624479 100644 (file)
@@ -9,7 +9,6 @@
 #include <asm/assembler.h>
 
        .macro SMCCC instr
-       .cfi_startproc
        \instr  #0
        ldr     x4, [sp]
        stp     x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
@@ -21,7 +20,6 @@
        b.ne    1f
        str     x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
 1:     ret
-       .cfi_endproc
        .endm
 
 /*
index 03957a1..82e75fc 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/completion.h>
 #include <linux/of.h>
 #include <linux/irq_work.h>
+#include <linux/kernel_stat.h>
 #include <linux/kexec.h>
 #include <linux/kvm_host.h>
 
@@ -72,10 +73,18 @@ enum ipi_msg_type {
        IPI_CPU_CRASH_STOP,
        IPI_TIMER,
        IPI_IRQ_WORK,
-       IPI_WAKEUP
+       IPI_WAKEUP,
+       NR_IPI
 };
 
+static int ipi_irq_base __read_mostly;
+static int nr_ipi __read_mostly = NR_IPI;
+static struct irq_desc *ipi_desc[NR_IPI] __read_mostly;
+
+static void ipi_setup(int cpu);
+
 #ifdef CONFIG_HOTPLUG_CPU
+static void ipi_teardown(int cpu);
 static int op_cpu_kill(unsigned int cpu);
 #else
 static inline int op_cpu_kill(unsigned int cpu)
@@ -151,7 +160,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
                        break;
                }
                pr_crit("CPU%u: may not have shut down cleanly\n", cpu);
-               /* Fall through */
+               fallthrough;
        case CPU_STUCK_IN_KERNEL:
                pr_crit("CPU%u: is stuck in kernel\n", cpu);
                if (status & CPU_STUCK_REASON_52_BIT_VA)
@@ -237,6 +246,8 @@ asmlinkage notrace void secondary_start_kernel(void)
         */
        notify_cpu_starting(cpu);
 
+       ipi_setup(cpu);
+
        store_cpu_topology(cpu);
        numa_add_cpu(cpu);
 
@@ -302,6 +313,7 @@ int __cpu_disable(void)
         * and we must not schedule until we're ready to give up the cpu.
         */
        set_cpu_online(cpu, false);
+       ipi_teardown(cpu);
 
        /*
         * OK - migrate IRQs away from this CPU
@@ -772,13 +784,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        }
 }
 
-void (*__smp_cross_call)(const struct cpumask *, unsigned int);
-
-void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
-{
-       __smp_cross_call = fn;
-}
-
 static const char *ipi_types[NR_IPI] __tracepoint_string = {
 #define S(x,s) [x] = s
        S(IPI_RESCHEDULE, "Rescheduling interrupts"),
@@ -790,35 +795,25 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
        S(IPI_WAKEUP, "CPU wake-up interrupts"),
 };
 
-static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
-{
-       trace_ipi_raise(target, ipi_types[ipinr]);
-       __smp_cross_call(target, ipinr);
-}
+static void smp_cross_call(const struct cpumask *target, unsigned int ipinr);
 
-void show_ipi_list(struct seq_file *p, int prec)
+unsigned long irq_err_count;
+
+int arch_show_interrupts(struct seq_file *p, int prec)
 {
        unsigned int cpu, i;
 
        for (i = 0; i < NR_IPI; i++) {
+               unsigned int irq = irq_desc_get_irq(ipi_desc[i]);
                seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i,
                           prec >= 4 ? " " : "");
                for_each_online_cpu(cpu)
-                       seq_printf(p, "%10u ",
-                                  __get_irq_stat(cpu, ipi_irqs[i]));
+                       seq_printf(p, "%10u ", kstat_irqs_cpu(irq, cpu));
                seq_printf(p, "      %s\n", ipi_types[i]);
        }
-}
-
-u64 smp_irq_stat_cpu(unsigned int cpu)
-{
-       u64 sum = 0;
-       int i;
 
-       for (i = 0; i < NR_IPI; i++)
-               sum += __get_irq_stat(cpu, ipi_irqs[i]);
-
-       return sum;
+       seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
+       return 0;
 }
 
 void arch_send_call_function_ipi_mask(const struct cpumask *mask)
@@ -841,8 +836,7 @@ void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
 #ifdef CONFIG_IRQ_WORK
 void arch_irq_work_raise(void)
 {
-       if (__smp_cross_call)
-               smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
+       smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
 }
 #endif
 
@@ -890,15 +884,12 @@ static void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs)
 /*
  * Main handler for inter-processor interrupts
  */
-void handle_IPI(int ipinr, struct pt_regs *regs)
+static void do_handle_IPI(int ipinr)
 {
        unsigned int cpu = smp_processor_id();
-       struct pt_regs *old_regs = set_irq_regs(regs);
 
-       if ((unsigned)ipinr < NR_IPI) {
+       if ((unsigned)ipinr < NR_IPI)
                trace_ipi_entry_rcuidle(ipi_types[ipinr]);
-               __inc_irq_stat(cpu, ipi_irqs[ipinr]);
-       }
 
        switch (ipinr) {
        case IPI_RESCHEDULE:
@@ -906,21 +897,16 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
                break;
 
        case IPI_CALL_FUNC:
-               irq_enter();
                generic_smp_call_function_interrupt();
-               irq_exit();
                break;
 
        case IPI_CPU_STOP:
-               irq_enter();
                local_cpu_stop();
-               irq_exit();
                break;
 
        case IPI_CPU_CRASH_STOP:
                if (IS_ENABLED(CONFIG_KEXEC_CORE)) {
-                       irq_enter();
-                       ipi_cpu_crash_stop(cpu, regs);
+                       ipi_cpu_crash_stop(cpu, get_irq_regs());
 
                        unreachable();
                }
@@ -928,17 +914,13 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 
 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
        case IPI_TIMER:
-               irq_enter();
                tick_receive_broadcast();
-               irq_exit();
                break;
 #endif
 
 #ifdef CONFIG_IRQ_WORK
        case IPI_IRQ_WORK:
-               irq_enter();
                irq_work_run();
-               irq_exit();
                break;
 #endif
 
@@ -957,7 +939,66 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 
        if ((unsigned)ipinr < NR_IPI)
                trace_ipi_exit_rcuidle(ipi_types[ipinr]);
-       set_irq_regs(old_regs);
+}
+
+static irqreturn_t ipi_handler(int irq, void *data)
+{
+       do_handle_IPI(irq - ipi_irq_base);
+       return IRQ_HANDLED;
+}
+
+static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
+{
+       trace_ipi_raise(target, ipi_types[ipinr]);
+       __ipi_send_mask(ipi_desc[ipinr], target);
+}
+
+static void ipi_setup(int cpu)
+{
+       int i;
+
+       if (WARN_ON_ONCE(!ipi_irq_base))
+               return;
+
+       for (i = 0; i < nr_ipi; i++)
+               enable_percpu_irq(ipi_irq_base + i, 0);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void ipi_teardown(int cpu)
+{
+       int i;
+
+       if (WARN_ON_ONCE(!ipi_irq_base))
+               return;
+
+       for (i = 0; i < nr_ipi; i++)
+               disable_percpu_irq(ipi_irq_base + i);
+}
+#endif
+
+void __init set_smp_ipi_range(int ipi_base, int n)
+{
+       int i;
+
+       WARN_ON(n < NR_IPI);
+       nr_ipi = min(n, NR_IPI);
+
+       for (i = 0; i < nr_ipi; i++) {
+               int err;
+
+               err = request_percpu_irq(ipi_base + i, ipi_handler,
+                                        "IPI", &cpu_number);
+               WARN_ON(err);
+
+               ipi_desc[i] = irq_to_desc(ipi_base + i);
+               irq_set_status_flags(ipi_base + i, IRQ_HIDDEN);
+       }
+
+       ipi_irq_base = ipi_base;
+
+       /* Setup the boot CPU immediately */
+       ipi_setup(smp_processor_id());
 }
 
 void smp_send_reschedule(int cpu)
index c8a3fee..5892e79 100644 (file)
@@ -83,9 +83,9 @@ static int smp_spin_table_cpu_prepare(unsigned int cpu)
 
        /*
         * We write the release address as LE regardless of the native
-        * endianess of the kernel. Therefore, any boot-loaders that
+        * endianness of the kernel. Therefore, any boot-loaders that
         * read this address need to convert this address to the
-        * boot-loader's endianess before jumping. This is mandated by
+        * boot-loader's endianness before jumping. This is mandated by
         * the boot protocol.
         */
        writeq_relaxed(__pa_symbol(secondary_holding_pen), release_addr);
diff --git a/arch/arm64/kernel/ssbd.c b/arch/arm64/kernel/ssbd.c
deleted file mode 100644 (file)
index b26955f..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2018 ARM Ltd, All Rights Reserved.
- */
-
-#include <linux/compat.h>
-#include <linux/errno.h>
-#include <linux/prctl.h>
-#include <linux/sched.h>
-#include <linux/sched/task_stack.h>
-#include <linux/thread_info.h>
-
-#include <asm/cpufeature.h>
-
-static void ssbd_ssbs_enable(struct task_struct *task)
-{
-       u64 val = is_compat_thread(task_thread_info(task)) ?
-                 PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
-
-       task_pt_regs(task)->pstate |= val;
-}
-
-static void ssbd_ssbs_disable(struct task_struct *task)
-{
-       u64 val = is_compat_thread(task_thread_info(task)) ?
-                 PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
-
-       task_pt_regs(task)->pstate &= ~val;
-}
-
-/*
- * prctl interface for SSBD
- */
-static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
-{
-       int state = arm64_get_ssbd_state();
-
-       /* Unsupported */
-       if (state == ARM64_SSBD_UNKNOWN)
-               return -ENODEV;
-
-       /* Treat the unaffected/mitigated state separately */
-       if (state == ARM64_SSBD_MITIGATED) {
-               switch (ctrl) {
-               case PR_SPEC_ENABLE:
-                       return -EPERM;
-               case PR_SPEC_DISABLE:
-               case PR_SPEC_FORCE_DISABLE:
-                       return 0;
-               }
-       }
-
-       /*
-        * Things are a bit backward here: the arm64 internal API
-        * *enables the mitigation* when the userspace API *disables
-        * speculation*. So much fun.
-        */
-       switch (ctrl) {
-       case PR_SPEC_ENABLE:
-               /* If speculation is force disabled, enable is not allowed */
-               if (state == ARM64_SSBD_FORCE_ENABLE ||
-                   task_spec_ssb_force_disable(task))
-                       return -EPERM;
-               task_clear_spec_ssb_disable(task);
-               clear_tsk_thread_flag(task, TIF_SSBD);
-               ssbd_ssbs_enable(task);
-               break;
-       case PR_SPEC_DISABLE:
-               if (state == ARM64_SSBD_FORCE_DISABLE)
-                       return -EPERM;
-               task_set_spec_ssb_disable(task);
-               set_tsk_thread_flag(task, TIF_SSBD);
-               ssbd_ssbs_disable(task);
-               break;
-       case PR_SPEC_FORCE_DISABLE:
-               if (state == ARM64_SSBD_FORCE_DISABLE)
-                       return -EPERM;
-               task_set_spec_ssb_disable(task);
-               task_set_spec_ssb_force_disable(task);
-               set_tsk_thread_flag(task, TIF_SSBD);
-               ssbd_ssbs_disable(task);
-               break;
-       default:
-               return -ERANGE;
-       }
-
-       return 0;
-}
-
-int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
-                            unsigned long ctrl)
-{
-       switch (which) {
-       case PR_SPEC_STORE_BYPASS:
-               return ssbd_prctl_set(task, ctrl);
-       default:
-               return -ENODEV;
-       }
-}
-
-static int ssbd_prctl_get(struct task_struct *task)
-{
-       switch (arm64_get_ssbd_state()) {
-       case ARM64_SSBD_UNKNOWN:
-               return -ENODEV;
-       case ARM64_SSBD_FORCE_ENABLE:
-               return PR_SPEC_DISABLE;
-       case ARM64_SSBD_KERNEL:
-               if (task_spec_ssb_force_disable(task))
-                       return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
-               if (task_spec_ssb_disable(task))
-                       return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
-               return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
-       case ARM64_SSBD_FORCE_DISABLE:
-               return PR_SPEC_ENABLE;
-       default:
-               return PR_SPEC_NOT_AFFECTED;
-       }
-}
-
-int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
-{
-       switch (which) {
-       case PR_SPEC_STORE_BYPASS:
-               return ssbd_prctl_get(task);
-       default:
-               return -ENODEV;
-       }
-}
index 2dd8e3b..fa56af1 100644 (file)
@@ -118,12 +118,12 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
 NOKPROBE_SYMBOL(unwind_frame);
 
 void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
-                    int (*fn)(struct stackframe *, void *), void *data)
+                            bool (*fn)(void *, unsigned long), void *data)
 {
        while (1) {
                int ret;
 
-               if (fn(frame, data))
+               if (!fn(data, frame->pc))
                        break;
                ret = unwind_frame(tsk, frame);
                if (ret < 0)
@@ -132,84 +132,89 @@ void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
 }
 NOKPROBE_SYMBOL(walk_stackframe);
 
-#ifdef CONFIG_STACKTRACE
-struct stack_trace_data {
-       struct stack_trace *trace;
-       unsigned int no_sched_functions;
-       unsigned int skip;
-};
-
-static int save_trace(struct stackframe *frame, void *d)
+static void dump_backtrace_entry(unsigned long where, const char *loglvl)
 {
-       struct stack_trace_data *data = d;
-       struct stack_trace *trace = data->trace;
-       unsigned long addr = frame->pc;
-
-       if (data->no_sched_functions && in_sched_functions(addr))
-               return 0;
-       if (data->skip) {
-               data->skip--;
-               return 0;
-       }
-
-       trace->entries[trace->nr_entries++] = addr;
-
-       return trace->nr_entries >= trace->max_entries;
+       printk("%s %pS\n", loglvl, (void *)where);
 }
 
-void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
+void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
+                   const char *loglvl)
 {
-       struct stack_trace_data data;
        struct stackframe frame;
+       int skip = 0;
 
-       data.trace = trace;
-       data.skip = trace->skip;
-       data.no_sched_functions = 0;
+       pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 
-       start_backtrace(&frame, regs->regs[29], regs->pc);
-       walk_stackframe(current, &frame, save_trace, &data);
-}
-EXPORT_SYMBOL_GPL(save_stack_trace_regs);
+       if (regs) {
+               if (user_mode(regs))
+                       return;
+               skip = 1;
+       }
 
-static noinline void __save_stack_trace(struct task_struct *tsk,
-       struct stack_trace *trace, unsigned int nosched)
-{
-       struct stack_trace_data data;
-       struct stackframe frame;
+       if (!tsk)
+               tsk = current;
 
        if (!try_get_task_stack(tsk))
                return;
 
-       data.trace = trace;
-       data.skip = trace->skip;
-       data.no_sched_functions = nosched;
-
-       if (tsk != current) {
-               start_backtrace(&frame, thread_saved_fp(tsk),
-                               thread_saved_pc(tsk));
-       } else {
-               /* We don't want this function nor the caller */
-               data.skip += 2;
+       if (tsk == current) {
                start_backtrace(&frame,
                                (unsigned long)__builtin_frame_address(0),
-                               (unsigned long)__save_stack_trace);
+                               (unsigned long)dump_backtrace);
+       } else {
+               /*
+                * task blocked in __switch_to
+                */
+               start_backtrace(&frame,
+                               thread_saved_fp(tsk),
+                               thread_saved_pc(tsk));
        }
 
-       walk_stackframe(tsk, &frame, save_trace, &data);
+       printk("%sCall trace:\n", loglvl);
+       do {
+               /* skip until specified stack frame */
+               if (!skip) {
+                       dump_backtrace_entry(frame.pc, loglvl);
+               } else if (frame.fp == regs->regs[29]) {
+                       skip = 0;
+                       /*
+                        * Mostly, this is the case where this function is
+                        * called in panic/abort. As exception handler's
+                        * stack frame does not contain the corresponding pc
+                        * at which an exception has taken place, use regs->pc
+                        * instead.
+                        */
+                       dump_backtrace_entry(regs->pc, loglvl);
+               }
+       } while (!unwind_frame(tsk, &frame));
 
        put_task_stack(tsk);
 }
 
-void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
 {
-       __save_stack_trace(tsk, trace, 1);
+       dump_backtrace(NULL, tsk, loglvl);
+       barrier();
 }
-EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
 
-void save_stack_trace(struct stack_trace *trace)
+#ifdef CONFIG_STACKTRACE
+
+void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
+                    struct task_struct *task, struct pt_regs *regs)
 {
-       __save_stack_trace(current, trace, 0);
+       struct stackframe frame;
+
+       if (regs)
+               start_backtrace(&frame, regs->regs[29], regs->pc);
+       else if (task == current)
+               start_backtrace(&frame,
+                               (unsigned long)__builtin_frame_address(0),
+                               (unsigned long)arch_stack_walk);
+       else
+               start_backtrace(&frame, thread_saved_fp(task),
+                               thread_saved_pc(task));
+
+       walk_stackframe(task, &frame, consume_entry, cookie);
 }
 
-EXPORT_SYMBOL_GPL(save_stack_trace);
 #endif
index c1dee90..96cd347 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/daifflags.h>
 #include <asm/debug-monitors.h>
 #include <asm/exec.h>
+#include <asm/mte.h>
 #include <asm/memory.h>
 #include <asm/mmu_context.h>
 #include <asm/smp_plat.h>
@@ -72,8 +73,10 @@ void notrace __cpu_suspend_exit(void)
         * have turned the mitigation on. If the user has forcefully
         * disabled it, make sure their wishes are obeyed.
         */
-       if (arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE)
-               arm64_set_ssbd_mitigation(false);
+       spectre_v4_enable_mitigation(NULL);
+
+       /* Restore additional MTE-specific configuration */
+       mte_suspend_exit();
 }
 
 /*
index 5f0c048..e4c0dad 100644 (file)
@@ -123,6 +123,16 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
        local_daif_restore(DAIF_PROCCTX);
        user_exit();
 
+       if (system_supports_mte() && (flags & _TIF_MTE_ASYNC_FAULT)) {
+               /*
+                * Process the asynchronous tag check fault before the actual
+                * syscall. do_notify_resume() will send a signal to userspace
+                * before the syscall is restarted.
+                */
+               regs->regs[0] = -ERESTARTNOINTR;
+               return;
+       }
+
        if (has_syscall_work(flags)) {
                /*
                 * The de-facto standard way to skip a system call using ptrace
index 0801a0f..ff1dd1d 100644 (file)
@@ -36,21 +36,23 @@ void store_cpu_topology(unsigned int cpuid)
        if (mpidr & MPIDR_UP_BITMASK)
                return;
 
-       /* Create cpu topology mapping based on MPIDR. */
-       if (mpidr & MPIDR_MT_BITMASK) {
-               /* Multiprocessor system : Multi-threads per core */
-               cpuid_topo->thread_id  = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-               cpuid_topo->core_id    = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-               cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 2) |
-                                        MPIDR_AFFINITY_LEVEL(mpidr, 3) << 8;
-       } else {
-               /* Multiprocessor system : Single-thread per core */
-               cpuid_topo->thread_id  = -1;
-               cpuid_topo->core_id    = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-               cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 1) |
-                                        MPIDR_AFFINITY_LEVEL(mpidr, 2) << 8 |
-                                        MPIDR_AFFINITY_LEVEL(mpidr, 3) << 16;
-       }
+       /*
+        * This would be the place to create cpu topology based on MPIDR.
+        *
+        * However, it cannot be trusted to depict the actual topology; some
+        * pieces of the architecture enforce an artificial cap on Aff0 values
+        * (e.g. GICv3's ICC_SGI1R_EL1 limits it to 15), leading to an
+        * artificial cycling of Aff1, Aff2 and Aff3 values. IOW, these end up
+        * having absolutely no relationship to the actual underlying system
+        * topology, and cannot be reasonably used as core / package ID.
+        *
+        * If the MT bit is set, Aff0 *could* be used to define a thread ID, but
+        * we still wouldn't be able to obtain a sane core ID. This means we
+        * need to entirely ignore MPIDR for any topology deduction.
+        */
+       cpuid_topo->thread_id  = -1;
+       cpuid_topo->core_id    = cpuid;
+       cpuid_topo->package_id = cpu_to_node(cpuid);
 
        pr_debug("CPU%u: cluster %d core %d thread %d mpidr %#016llx\n",
                 cpuid, cpuid_topo->package_id, cpuid_topo->core_id,
index 13ebd5c..8af4e0e 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/daifflags.h>
 #include <asm/debug-monitors.h>
 #include <asm/esr.h>
+#include <asm/extable.h>
 #include <asm/insn.h>
 #include <asm/kprobes.h>
 #include <asm/traps.h>
@@ -53,11 +54,6 @@ static const char *handler[]= {
 
 int show_unhandled_signals = 0;
 
-static void dump_backtrace_entry(unsigned long where, const char *loglvl)
-{
-       printk("%s %pS\n", loglvl, (void *)where);
-}
-
 static void dump_kernel_instr(const char *lvl, struct pt_regs *regs)
 {
        unsigned long addr = instruction_pointer(regs);
@@ -83,66 +79,6 @@ static void dump_kernel_instr(const char *lvl, struct pt_regs *regs)
        printk("%sCode: %s\n", lvl, str);
 }
 
-void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
-                   const char *loglvl)
-{
-       struct stackframe frame;
-       int skip = 0;
-
-       pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
-
-       if (regs) {
-               if (user_mode(regs))
-                       return;
-               skip = 1;
-       }
-
-       if (!tsk)
-               tsk = current;
-
-       if (!try_get_task_stack(tsk))
-               return;
-
-       if (tsk == current) {
-               start_backtrace(&frame,
-                               (unsigned long)__builtin_frame_address(0),
-                               (unsigned long)dump_backtrace);
-       } else {
-               /*
-                * task blocked in __switch_to
-                */
-               start_backtrace(&frame,
-                               thread_saved_fp(tsk),
-                               thread_saved_pc(tsk));
-       }
-
-       printk("%sCall trace:\n", loglvl);
-       do {
-               /* skip until specified stack frame */
-               if (!skip) {
-                       dump_backtrace_entry(frame.pc, loglvl);
-               } else if (frame.fp == regs->regs[29]) {
-                       skip = 0;
-                       /*
-                        * Mostly, this is the case where this function is
-                        * called in panic/abort. As exception handler's
-                        * stack frame does not contain the corresponding pc
-                        * at which an exception has taken place, use regs->pc
-                        * instead.
-                        */
-                       dump_backtrace_entry(regs->pc, loglvl);
-               }
-       } while (!unwind_frame(tsk, &frame));
-
-       put_task_stack(tsk);
-}
-
-void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
-{
-       dump_backtrace(NULL, tsk, loglvl);
-       barrier();
-}
-
 #ifdef CONFIG_PREEMPT
 #define S_PREEMPT " PREEMPT"
 #elif defined(CONFIG_PREEMPT_RT)
@@ -200,9 +136,9 @@ void die(const char *str, struct pt_regs *regs, int err)
        oops_exit();
 
        if (in_interrupt())
-               panic("Fatal exception in interrupt");
+               panic("%s: Fatal exception in interrupt", str);
        if (panic_on_oops)
-               panic("Fatal exception");
+               panic("%s: Fatal exception", str);
 
        raw_spin_unlock_irqrestore(&die_lock, flags);
 
@@ -412,7 +348,7 @@ exit:
        return fn ? fn(regs, instr) : 1;
 }
 
-void force_signal_inject(int signal, int code, unsigned long address)
+void force_signal_inject(int signal, int code, unsigned long address, unsigned int err)
 {
        const char *desc;
        struct pt_regs *regs = current_pt_regs();
@@ -438,7 +374,7 @@ void force_signal_inject(int signal, int code, unsigned long address)
                signal = SIGKILL;
        }
 
-       arm64_notify_die(desc, regs, signal, code, (void __user *)address, 0);
+       arm64_notify_die(desc, regs, signal, code, (void __user *)address, err);
 }
 
 /*
@@ -455,7 +391,7 @@ void arm64_notify_segfault(unsigned long addr)
                code = SEGV_ACCERR;
        mmap_read_unlock(current->mm);
 
-       force_signal_inject(SIGSEGV, code, addr);
+       force_signal_inject(SIGSEGV, code, addr, 0);
 }
 
 void do_undefinstr(struct pt_regs *regs)
@@ -468,17 +404,28 @@ void do_undefinstr(struct pt_regs *regs)
                return;
 
        BUG_ON(!user_mode(regs));
-       force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc);
+       force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);
 }
 NOKPROBE_SYMBOL(do_undefinstr);
 
 void do_bti(struct pt_regs *regs)
 {
        BUG_ON(!user_mode(regs));
-       force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc);
+       force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);
 }
 NOKPROBE_SYMBOL(do_bti);
 
+void do_ptrauth_fault(struct pt_regs *regs, unsigned int esr)
+{
+       /*
+        * Unexpected FPAC exception or pointer authentication failure in
+        * the kernel: kill the task before it does any more harm.
+        */
+       BUG_ON(!user_mode(regs));
+       force_signal_inject(SIGILL, ILL_ILLOPN, regs->pc, esr);
+}
+NOKPROBE_SYMBOL(do_ptrauth_fault);
+
 #define __user_cache_maint(insn, address, res)                 \
        if (address >= user_addr_max()) {                       \
                res = -EFAULT;                                  \
@@ -528,7 +475,7 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
                __user_cache_maint("ic ivau", address, ret);
                break;
        default:
-               force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc);
+               force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);
                return;
        }
 
@@ -581,7 +528,7 @@ static void mrs_handler(unsigned int esr, struct pt_regs *regs)
        sysreg = esr_sys64_to_sysreg(esr);
 
        if (do_emulate_mrs(regs, sysreg, rt) != 0)
-               force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc);
+               force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);
 }
 
 static void wfi_handler(unsigned int esr, struct pt_regs *regs)
@@ -775,6 +722,7 @@ static const char *esr_class_str[] = {
        [ESR_ELx_EC_SYS64]              = "MSR/MRS (AArch64)",
        [ESR_ELx_EC_SVE]                = "SVE",
        [ESR_ELx_EC_ERET]               = "ERET/ERETAA/ERETAB",
+       [ESR_ELx_EC_FPAC]               = "FPAC",
        [ESR_ELx_EC_IMP_DEF]            = "EL3 IMP DEF",
        [ESR_ELx_EC_IABT_LOW]           = "IABT (lower EL)",
        [ESR_ELx_EC_IABT_CUR]           = "IABT (current EL)",
@@ -935,26 +883,6 @@ asmlinkage void enter_from_user_mode(void)
 }
 NOKPROBE_SYMBOL(enter_from_user_mode);
 
-void __pte_error(const char *file, int line, unsigned long val)
-{
-       pr_err("%s:%d: bad pte %016lx.\n", file, line, val);
-}
-
-void __pmd_error(const char *file, int line, unsigned long val)
-{
-       pr_err("%s:%d: bad pmd %016lx.\n", file, line, val);
-}
-
-void __pud_error(const char *file, int line, unsigned long val)
-{
-       pr_err("%s:%d: bad pud %016lx.\n", file, line, val);
-}
-
-void __pgd_error(const char *file, int line, unsigned long val)
-{
-       pr_err("%s:%d: bad pgd %016lx.\n", file, line, val);
-}
-
 /* GENERIC_BUG traps */
 
 int is_valid_bugaddr(unsigned long addr)
@@ -994,6 +922,21 @@ static struct break_hook bug_break_hook = {
        .imm = BUG_BRK_IMM,
 };
 
+static int reserved_fault_handler(struct pt_regs *regs, unsigned int esr)
+{
+       pr_err("%s generated an invalid instruction at %pS!\n",
+               in_bpf_jit(regs) ? "BPF JIT" : "Kernel text patching",
+               (void *)instruction_pointer(regs));
+
+       /* We cannot handle this */
+       return DBG_HOOK_ERROR;
+}
+
+static struct break_hook fault_break_hook = {
+       .fn = reserved_fault_handler,
+       .imm = FAULT_BRK_IMM,
+};
+
 #ifdef CONFIG_KASAN_SW_TAGS
 
 #define KASAN_ESR_RECOVER      0x20
@@ -1059,6 +1002,7 @@ int __init early_brk64(unsigned long addr, unsigned int esr,
 void __init trap_init(void)
 {
        register_kernel_break_hook(&bug_break_hook);
+       register_kernel_break_hook(&fault_break_hook);
 #ifdef CONFIG_KASAN_SW_TAGS
        register_kernel_break_hook(&kasan_break_hook);
 #endif
index d4202a3..debb899 100644 (file)
 #include <asm/vdso.h>
 
 extern char vdso_start[], vdso_end[];
-#ifdef CONFIG_COMPAT_VDSO
 extern char vdso32_start[], vdso32_end[];
-#endif /* CONFIG_COMPAT_VDSO */
 
 enum vdso_abi {
        VDSO_ABI_AA64,
-#ifdef CONFIG_COMPAT_VDSO
        VDSO_ABI_AA32,
-#endif /* CONFIG_COMPAT_VDSO */
 };
 
 enum vvar_pages {
@@ -284,21 +280,17 @@ up_fail:
 /*
  * Create and map the vectors page for AArch32 tasks.
  */
-#ifdef CONFIG_COMPAT_VDSO
 static int aarch32_vdso_mremap(const struct vm_special_mapping *sm,
                struct vm_area_struct *new_vma)
 {
        return __vdso_remap(VDSO_ABI_AA32, sm, new_vma);
 }
-#endif /* CONFIG_COMPAT_VDSO */
 
 enum aarch32_map {
        AA32_MAP_VECTORS, /* kuser helpers */
-#ifdef CONFIG_COMPAT_VDSO
+       AA32_MAP_SIGPAGE,
        AA32_MAP_VVAR,
        AA32_MAP_VDSO,
-#endif
-       AA32_MAP_SIGPAGE
 };
 
 static struct page *aarch32_vectors_page __ro_after_init;
@@ -309,7 +301,10 @@ static struct vm_special_mapping aarch32_vdso_maps[] = {
                .name   = "[vectors]", /* ABI */
                .pages  = &aarch32_vectors_page,
        },
-#ifdef CONFIG_COMPAT_VDSO
+       [AA32_MAP_SIGPAGE] = {
+               .name   = "[sigpage]", /* ABI */
+               .pages  = &aarch32_sig_page,
+       },
        [AA32_MAP_VVAR] = {
                .name = "[vvar]",
                .fault = vvar_fault,
@@ -319,11 +314,6 @@ static struct vm_special_mapping aarch32_vdso_maps[] = {
                .name = "[vdso]",
                .mremap = aarch32_vdso_mremap,
        },
-#endif /* CONFIG_COMPAT_VDSO */
-       [AA32_MAP_SIGPAGE] = {
-               .name   = "[sigpage]", /* ABI */
-               .pages  = &aarch32_sig_page,
-       },
 };
 
 static int aarch32_alloc_kuser_vdso_page(void)
@@ -362,25 +352,25 @@ static int aarch32_alloc_sigpage(void)
        return 0;
 }
 
-#ifdef CONFIG_COMPAT_VDSO
 static int __aarch32_alloc_vdso_pages(void)
 {
+
+       if (!IS_ENABLED(CONFIG_COMPAT_VDSO))
+               return 0;
+
        vdso_info[VDSO_ABI_AA32].dm = &aarch32_vdso_maps[AA32_MAP_VVAR];
        vdso_info[VDSO_ABI_AA32].cm = &aarch32_vdso_maps[AA32_MAP_VDSO];
 
        return __vdso_init(VDSO_ABI_AA32);
 }
-#endif /* CONFIG_COMPAT_VDSO */
 
 static int __init aarch32_alloc_vdso_pages(void)
 {
        int ret;
 
-#ifdef CONFIG_COMPAT_VDSO
        ret = __aarch32_alloc_vdso_pages();
        if (ret)
                return ret;
-#endif
 
        ret = aarch32_alloc_sigpage();
        if (ret)
@@ -449,14 +439,12 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        if (ret)
                goto out;
 
-#ifdef CONFIG_COMPAT_VDSO
-       ret = __setup_additional_pages(VDSO_ABI_AA32,
-                                      mm,
-                                      bprm,
-                                      uses_interp);
-       if (ret)
-               goto out;
-#endif /* CONFIG_COMPAT_VDSO */
+       if (IS_ENABLED(CONFIG_COMPAT_VDSO)) {
+               ret = __setup_additional_pages(VDSO_ABI_AA32, mm, bprm,
+                                              uses_interp);
+               if (ret)
+                       goto out;
+       }
 
        ret = aarch32_sigreturn_setup(mm);
 out:
@@ -497,8 +485,7 @@ static int __init vdso_init(void)
 }
 arch_initcall(vdso_init);
 
-int arch_setup_additional_pages(struct linux_binprm *bprm,
-                               int uses_interp)
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
        struct mm_struct *mm = current->mm;
        int ret;
@@ -506,11 +493,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
        if (mmap_write_lock_killable(mm))
                return -EINTR;
 
-       ret = __setup_additional_pages(VDSO_ABI_AA64,
-                                      mm,
-                                      bprm,
-                                      uses_interp);
-
+       ret = __setup_additional_pages(VDSO_ABI_AA64, mm, bprm, uses_interp);
        mmap_write_unlock(mm);
 
        return ret;
index ec8e894..5ca957e 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #define RO_EXCEPTION_TABLE_ALIGN       8
+#define RUNTIME_DISCARD_EXIT
 
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/cache.h>
@@ -20,6 +21,13 @@ ENTRY(_text)
 
 jiffies = jiffies_64;
 
+
+#define HYPERVISOR_EXTABLE                                     \
+       . = ALIGN(SZ_8);                                        \
+       __start___kvm_ex_table = .;                             \
+       *(__kvm_ex_table)                                       \
+       __stop___kvm_ex_table = .;
+
 #define HYPERVISOR_TEXT                                        \
        /*                                              \
         * Align to 4 KB so that                        \
@@ -35,6 +43,7 @@ jiffies = jiffies_64;
        __hyp_idmap_text_end = .;                       \
        __hyp_text_start = .;                           \
        *(.hyp.text)                                    \
+       HYPERVISOR_EXTABLE                              \
        __hyp_text_end = .;
 
 #define IDMAP_TEXT                                     \
@@ -88,16 +97,13 @@ SECTIONS
         * matching the same input section name.  There is no documented
         * order of matching.
         */
+       DISCARDS
        /DISCARD/ : {
-               EXIT_CALL
-               *(.discard)
-               *(.discard.*)
                *(.interp .dynamic)
                *(.dynsym .dynstr .hash .gnu.hash)
-               *(.eh_frame)
        }
 
-       . = KIMAGE_VADDR + TEXT_OFFSET;
+       . = KIMAGE_VADDR;
 
        .head.text : {
                _text = .;
@@ -123,6 +129,14 @@ SECTIONS
                *(.got)                 /* Global offset table          */
        }
 
+       /*
+        * Make sure that the .got.plt is either completely empty or it
+        * contains only the lazy dispatch entries.
+        */
+       .got.plt : { *(.got.plt) }
+       ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18,
+              "Unexpected GOT/PLT entries detected!")
+
        . = ALIGN(SEGMENT_ALIGN);
        _etext = .;                     /* End of text section */
 
@@ -241,8 +255,22 @@ SECTIONS
        _end = .;
 
        STABS_DEBUG
+       DWARF_DEBUG
+       ELF_DETAILS
 
        HEAD_SYMBOLS
+
+       /*
+        * Sections that should stay zero sized, which is safer to
+        * explicitly check instead of blindly discarding.
+        */
+       .plt : {
+               *(.plt) *(.plt.*) *(.iplt) *(.igot)
+       }
+       ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!")
+
+       .data.rel.ro : { *(.data.rel.ro) }
+       ASSERT(SIZEOF(.data.rel.ro) == 0, "Unexpected RELRO detected!")
 }
 
 #include "image-vars.h"
@@ -266,4 +294,4 @@ ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) == PAGE_SIZE,
 /*
  * If padding is applied before .head.text, virt<->phys conversions will fail.
  */
-ASSERT(_text == (KIMAGE_VADDR + TEXT_OFFSET), "HEAD is misaligned")
+ASSERT(_text == KIMAGE_VADDR, "HEAD is misaligned")
index 318c8f2..043756d 100644 (file)
@@ -57,9 +57,6 @@ config KVM_ARM_PMU
          Adds support for a virtual Performance Monitoring Unit (PMU) in
          virtual machines.
 
-config KVM_INDIRECT_VECTORS
-       def_bool HARDEN_BRANCH_PREDICTOR || RANDOMIZE_BASE
-
 endif # KVM
 
 endif # VIRTUALIZATION
index 46dc3d7..acf9a99 100644 (file)
@@ -206,6 +206,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                 */
                r = 1;
                break;
+       case KVM_CAP_STEAL_TIME:
+               r = kvm_arm_pvtime_supported();
+               break;
        default:
                r = kvm_arch_vm_ioctl_check_extension(kvm, ext);
                break;
@@ -1256,6 +1259,40 @@ long kvm_arch_vm_ioctl(struct file *filp,
        }
 }
 
+static int kvm_map_vectors(void)
+{
+       /*
+        * SV2  = ARM64_SPECTRE_V2
+        * HEL2 = ARM64_HARDEN_EL2_VECTORS
+        *
+        * !SV2 + !HEL2 -> use direct vectors
+        *  SV2 + !HEL2 -> use hardened vectors in place
+        * !SV2 +  HEL2 -> allocate one vector slot and use exec mapping
+        *  SV2 +  HEL2 -> use hardened vectors and use exec mapping
+        */
+       if (cpus_have_const_cap(ARM64_SPECTRE_V2)) {
+               __kvm_bp_vect_base = kvm_ksym_ref(__bp_harden_hyp_vecs);
+               __kvm_bp_vect_base = kern_hyp_va(__kvm_bp_vect_base);
+       }
+
+       if (cpus_have_const_cap(ARM64_HARDEN_EL2_VECTORS)) {
+               phys_addr_t vect_pa = __pa_symbol(__bp_harden_hyp_vecs);
+               unsigned long size = __BP_HARDEN_HYP_VECS_SZ;
+
+               /*
+                * Always allocate a spare vector slot, as we don't
+                * know yet which CPUs have a BP hardening slot that
+                * we can reuse.
+                */
+               __kvm_harden_el2_vector_slot = atomic_inc_return(&arm64_el2_vector_last_slot);
+               BUG_ON(__kvm_harden_el2_vector_slot >= BP_HARDEN_EL2_SLOTS);
+               return create_hyp_exec_mappings(vect_pa, size,
+                                               &__kvm_bp_vect_base);
+       }
+
+       return 0;
+}
+
 static void cpu_init_hyp_mode(void)
 {
        phys_addr_t pgd_ptr;
@@ -1292,7 +1329,7 @@ static void cpu_init_hyp_mode(void)
         * at EL2.
         */
        if (this_cpu_has_cap(ARM64_SSBS) &&
-           arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE) {
+           arm64_get_spectre_v4_state() == SPECTRE_VULNERABLE) {
                kvm_call_hyp_nvhe(__kvm_enable_ssbs);
        }
 }
@@ -1549,10 +1586,6 @@ static int init_hyp_mode(void)
                }
        }
 
-       err = hyp_map_aux_data();
-       if (err)
-               kvm_err("Cannot map host auxiliary data: %d\n", err);
-
        return 0;
 
 out_err:
index fe6c7d7..5d690d6 100644 (file)
@@ -128,7 +128,7 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
        switch (ESR_ELx_EC(esr)) {
        case ESR_ELx_EC_WATCHPT_LOW:
                run->debug.arch.far = vcpu->arch.fault.far_el2;
-               /* fall through */
+               fallthrough;
        case ESR_ELx_EC_SOFTSTP_LOW:
        case ESR_ELx_EC_BREAKPT_LOW:
        case ESR_ELx_EC_BKPT32:
index f54f0e8..d898f0d 100644 (file)
@@ -10,5 +10,4 @@ subdir-ccflags-y := -I$(incdir)                               \
                    -DDISABLE_BRANCH_PROFILING          \
                    $(DISABLE_STACKLEAK_PLUGIN)
 
-obj-$(CONFIG_KVM) += vhe/ nvhe/
-obj-$(CONFIG_KVM_INDIRECT_VECTORS) += smccc_wa.o
+obj-$(CONFIG_KVM) += vhe/ nvhe/ smccc_wa.o
index ee32a77..76e7eaf 100644 (file)
@@ -196,20 +196,23 @@ alternative_endif
        // This is our single instruction exception window. A pending
        // SError is guaranteed to occur at the earliest when we unmask
        // it, and at the latest just after the ISB.
-       .global abort_guest_exit_start
 abort_guest_exit_start:
 
        isb
 
-       .global abort_guest_exit_end
 abort_guest_exit_end:
 
        msr     daifset, #4     // Mask aborts
+       ret
+
+       _kvm_extable    abort_guest_exit_start, 9997f
+       _kvm_extable    abort_guest_exit_end, 9997f
+9997:
+       msr     daifset, #4     // Mask aborts
+       mov     x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
 
-       // If the exception took place, restore the EL1 exception
-       // context so that we can report some information.
-       // Merge the exception code with the SError pending bit.
-       tbz     x0, #ARM_EXIT_WITH_SERROR_BIT, 1f
+       // restore the EL1 exception context so that we can report some
+       // information. Merge the exception code with the SError pending bit.
        msr     elr_el2, x2
        msr     esr_el2, x3
        msr     spsr_el2, x4
index 689fccb..7ea277b 100644 (file)
 #include <asm/kvm_mmu.h>
 #include <asm/mmu.h>
 
+.macro save_caller_saved_regs_vect
+       /* x0 and x1 were saved in the vector entry */
+       stp     x2, x3,   [sp, #-16]!
+       stp     x4, x5,   [sp, #-16]!
+       stp     x6, x7,   [sp, #-16]!
+       stp     x8, x9,   [sp, #-16]!
+       stp     x10, x11, [sp, #-16]!
+       stp     x12, x13, [sp, #-16]!
+       stp     x14, x15, [sp, #-16]!
+       stp     x16, x17, [sp, #-16]!
+.endm
+
+.macro restore_caller_saved_regs_vect
+       ldp     x16, x17, [sp], #16
+       ldp     x14, x15, [sp], #16
+       ldp     x12, x13, [sp], #16
+       ldp     x10, x11, [sp], #16
+       ldp     x8, x9,   [sp], #16
+       ldp     x6, x7,   [sp], #16
+       ldp     x4, x5,   [sp], #16
+       ldp     x2, x3,   [sp], #16
+       ldp     x0, x1,   [sp], #16
+.endm
+
        .text
 
 .macro do_el2_call
@@ -92,35 +116,6 @@ el1_hvc_guest:
                          ARM_SMCCC_ARCH_WORKAROUND_2)
        cbnz    w1, el1_trap
 
-#ifdef CONFIG_ARM64_SSBD
-alternative_cb arm64_enable_wa2_handling
-       b       wa2_end
-alternative_cb_end
-       get_vcpu_ptr    x2, x0
-       ldr     x0, [x2, #VCPU_WORKAROUND_FLAGS]
-
-       // Sanitize the argument and update the guest flags
-       ldr     x1, [sp, #8]                    // Guest's x1
-       clz     w1, w1                          // Murphy's device:
-       lsr     w1, w1, #5                      // w1 = !!w1 without using
-       eor     w1, w1, #1                      // the flags...
-       bfi     x0, x1, #VCPU_WORKAROUND_2_FLAG_SHIFT, #1
-       str     x0, [x2, #VCPU_WORKAROUND_FLAGS]
-
-       /* Check that we actually need to perform the call */
-       hyp_ldr_this_cpu x0, arm64_ssbd_callback_required, x2
-       cbz     x0, wa2_end
-
-       mov     w0, #ARM_SMCCC_ARCH_WORKAROUND_2
-       smc     #0
-
-       /* Don't leak data from the SMC call */
-       mov     x3, xzr
-wa2_end:
-       mov     x2, xzr
-       mov     x1, xzr
-#endif
-
 wa_epilogue:
        mov     x0, xzr
        add     sp, sp, #16
@@ -143,13 +138,19 @@ el1_error:
        b       __guest_exit
 
 el2_sync:
-       /* Check for illegal exception return, otherwise panic */
+       /* Check for illegal exception return */
        mrs     x0, spsr_el2
+       tbnz    x0, #20, 1f
 
-       /* if this was something else, then panic! */
-       tst     x0, #PSR_IL_BIT
-       b.eq    __hyp_panic
+       save_caller_saved_regs_vect
+       stp     x29, x30, [sp, #-16]!
+       bl      kvm_unexpected_el2_exception
+       ldp     x29, x30, [sp], #16
+       restore_caller_saved_regs_vect
+
+       eret
 
+1:
        /* Let's attempt a recovery from the illegal exception return */
        get_vcpu_ptr    x1, x0
        mov     x0, #ARM_EXCEPTION_IL
@@ -157,27 +158,14 @@ el2_sync:
 
 
 el2_error:
-       ldp     x0, x1, [sp], #16
+       save_caller_saved_regs_vect
+       stp     x29, x30, [sp, #-16]!
+
+       bl      kvm_unexpected_el2_exception
+
+       ldp     x29, x30, [sp], #16
+       restore_caller_saved_regs_vect
 
-       /*
-        * Only two possibilities:
-        * 1) Either we come from the exit path, having just unmasked
-        *    PSTATE.A: change the return code to an EL2 fault, and
-        *    carry on, as we're already in a sane state to handle it.
-        * 2) Or we come from anywhere else, and that's a bug: we panic.
-        *
-        * For (1), x0 contains the original return code and x1 doesn't
-        * contain anything meaningful at that stage. We can reuse them
-        * as temp registers.
-        * For (2), who cares?
-        */
-       mrs     x0, elr_el2
-       adr     x1, abort_guest_exit_start
-       cmp     x0, x1
-       adr     x1, abort_guest_exit_end
-       ccmp    x0, x1, #4, ne
-       b.ne    __hyp_panic
-       mov     x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
        eret
        sb
 
@@ -271,7 +259,6 @@ SYM_CODE_START(__kvm_hyp_vector)
        valid_vect      el1_error               // Error 32-bit EL1
 SYM_CODE_END(__kvm_hyp_vector)
 
-#ifdef CONFIG_KVM_INDIRECT_VECTORS
 .macro hyp_ventry
        .align 7
 1:     esb
@@ -321,4 +308,3 @@ SYM_CODE_START(__bp_harden_hyp_vecs)
 1:     .org __bp_harden_hyp_vecs + __BP_HARDEN_HYP_VECS_SZ
        .org 1b
 SYM_CODE_END(__bp_harden_hyp_vecs)
-#endif
index 0297dc6..5e28ea6 100644 (file)
 #define save_debug(ptr,reg,nr)                                         \
        switch (nr) {                                                   \
        case 15:        ptr[15] = read_debug(reg, 15);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 14:        ptr[14] = read_debug(reg, 14);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 13:        ptr[13] = read_debug(reg, 13);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 12:        ptr[12] = read_debug(reg, 12);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 11:        ptr[11] = read_debug(reg, 11);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 10:        ptr[10] = read_debug(reg, 10);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 9:         ptr[9] = read_debug(reg, 9);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 8:         ptr[8] = read_debug(reg, 8);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 7:         ptr[7] = read_debug(reg, 7);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 6:         ptr[6] = read_debug(reg, 6);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 5:         ptr[5] = read_debug(reg, 5);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 4:         ptr[4] = read_debug(reg, 4);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 3:         ptr[3] = read_debug(reg, 3);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 2:         ptr[2] = read_debug(reg, 2);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 1:         ptr[1] = read_debug(reg, 1);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        default:        ptr[0] = read_debug(reg, 0);                    \
        }
 
 #define restore_debug(ptr,reg,nr)                                      \
        switch (nr) {                                                   \
        case 15:        write_debug(ptr[15], reg, 15);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 14:        write_debug(ptr[14], reg, 14);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 13:        write_debug(ptr[13], reg, 13);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 12:        write_debug(ptr[12], reg, 12);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 11:        write_debug(ptr[11], reg, 11);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 10:        write_debug(ptr[10], reg, 10);                  \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 9:         write_debug(ptr[9], reg, 9);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 8:         write_debug(ptr[8], reg, 8);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 7:         write_debug(ptr[7], reg, 7);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 6:         write_debug(ptr[6], reg, 6);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 5:         write_debug(ptr[5], reg, 5);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 4:         write_debug(ptr[4], reg, 4);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 3:         write_debug(ptr[3], reg, 3);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 2:         write_debug(ptr[2], reg, 2);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        case 1:         write_debug(ptr[1], reg, 1);                    \
-                       /* Fall through */                              \
+                       fallthrough;                                    \
        default:        write_debug(ptr[0], reg, 0);                    \
        }
 
index 426ef65..d0f07e8 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/barrier.h>
 #include <asm/cpufeature.h>
+#include <asm/extable.h>
 #include <asm/kprobes.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
@@ -29,6 +30,9 @@
 
 extern const char __hyp_panic_string[];
 
+extern struct exception_table_entry __start___kvm_ex_table;
+extern struct exception_table_entry __stop___kvm_ex_table;
+
 /* Check whether the FP regs were dirtied while in the host-side run loop: */
 static inline bool update_fp_enabled(struct kvm_vcpu *vcpu)
 {
@@ -142,10 +146,10 @@ static inline bool __translate_far_to_hpfar(u64 far, u64 *hpfar)
         * saved the guest context yet, and we may return early...
         */
        par = read_sysreg(par_el1);
-       asm volatile("at s1e1r, %0" : : "r" (far));
-       isb();
-
-       tmp = read_sysreg(par_el1);
+       if (!__kvm_at("s1e1r", far))
+               tmp = read_sysreg(par_el1);
+       else
+               tmp = SYS_PAR_EL1_F; /* back to the guest */
        write_sysreg(par, par_el1);
 
        if (unlikely(tmp & SYS_PAR_EL1_F))
@@ -445,7 +449,7 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
                        kvm_vcpu_trap_get_fault_type(vcpu) == FSC_FAULT &&
                        kvm_vcpu_dabt_isvalid(vcpu) &&
                        !kvm_vcpu_abt_issea(vcpu) &&
-                       !kvm_vcpu_dabt_iss1tw(vcpu);
+                       !kvm_vcpu_abt_iss1tw(vcpu);
 
                if (valid) {
                        int ret = __vgic_v2_perform_cpuif_access(vcpu);
@@ -475,37 +479,31 @@ exit:
        return false;
 }
 
-static inline bool __needs_ssbd_off(struct kvm_vcpu *vcpu)
+static inline void __kvm_unexpected_el2_exception(void)
 {
-       if (!cpus_have_final_cap(ARM64_SSBD))
-               return false;
-
-       return !(vcpu->arch.workaround_flags & VCPU_WORKAROUND_2_FLAG);
-}
+       unsigned long addr, fixup;
+       struct kvm_cpu_context *host_ctxt;
+       struct exception_table_entry *entry, *end;
+       unsigned long elr_el2 = read_sysreg(elr_el2);
+
+       entry = hyp_symbol_addr(__start___kvm_ex_table);
+       end = hyp_symbol_addr(__stop___kvm_ex_table);
+       host_ctxt = &__hyp_this_cpu_ptr(kvm_host_data)->host_ctxt;
+
+       while (entry < end) {
+               addr = (unsigned long)&entry->insn + entry->insn;
+               fixup = (unsigned long)&entry->fixup + entry->fixup;
+
+               if (addr != elr_el2) {
+                       entry++;
+                       continue;
+               }
 
-static inline void __set_guest_arch_workaround_state(struct kvm_vcpu *vcpu)
-{
-#ifdef CONFIG_ARM64_SSBD
-       /*
-        * The host runs with the workaround always present. If the
-        * guest wants it disabled, so be it...
-        */
-       if (__needs_ssbd_off(vcpu) &&
-           __hyp_this_cpu_read(arm64_ssbd_callback_required))
-               arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, 0, NULL);
-#endif
-}
+               write_sysreg(fixup, elr_el2);
+               return;
+       }
 
-static inline void __set_host_arch_workaround_state(struct kvm_vcpu *vcpu)
-{
-#ifdef CONFIG_ARM64_SSBD
-       /*
-        * If the guest has disabled the workaround, bring it back on.
-        */
-       if (__needs_ssbd_off(vcpu) &&
-           __hyp_this_cpu_read(arm64_ssbd_callback_required))
-               arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, 1, NULL);
-#endif
+       hyp_panic(host_ctxt);
 }
 
 #endif /* __ARM64_KVM_HYP_SWITCH_H__ */
index 341be2f..8d3dd4f 100644 (file)
@@ -202,8 +202,6 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 
        __debug_switch_to_guest(vcpu);
 
-       __set_guest_arch_workaround_state(vcpu);
-
        do {
                /* Jump in the fire! */
                exit_code = __guest_enter(vcpu, host_ctxt);
@@ -211,8 +209,6 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
                /* And we're baaack! */
        } while (fixup_guest_exit(vcpu, &exit_code));
 
-       __set_host_arch_workaround_state(vcpu);
-
        __sysreg_save_state_nvhe(guest_ctxt);
        __sysreg32_save_state(vcpu);
        __timer_disable_traps(vcpu);
@@ -270,3 +266,8 @@ void __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
                       read_sysreg(hpfar_el2), par, vcpu);
        unreachable();
 }
+
+asmlinkage void kvm_unexpected_el2_exception(void)
+{
+       return __kvm_unexpected_el2_exception();
+}
index 69eae60..b15d65a 100644 (file)
@@ -31,7 +31,14 @@ static void __tlb_switch_to_guest(struct kvm_s2_mmu *mmu,
                isb();
        }
 
+       /*
+        * __load_guest_stage2() includes an ISB only when the AT
+        * workaround is applied. Take care of the opposite condition,
+        * ensuring that we always have an ISB, but not two ISBs back
+        * to back.
+        */
        __load_guest_stage2(mmu);
+       asm(ALTERNATIVE("isb", "nop", ARM64_WORKAROUND_SPECULATIVE_AT));
 }
 
 static void __tlb_switch_to_host(struct tlb_inv_context *cxt)
index 5a00735..452f4ca 100644 (file)
@@ -340,10 +340,10 @@ void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if)
        case 7:
                cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
                cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
-               /* Fall through */
+               fallthrough;
        case 6:
                cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
-               /* Fall through */
+               fallthrough;
        default:
                cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
        }
@@ -352,10 +352,10 @@ void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if)
        case 7:
                cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
                cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
-               /* Fall through */
+               fallthrough;
        case 6:
                cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
-               /* Fall through */
+               fallthrough;
        default:
                cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
        }
@@ -373,10 +373,10 @@ void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if)
        case 7:
                __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
                __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
-               /* Fall through */
+               fallthrough;
        case 6:
                __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
-               /* Fall through */
+               fallthrough;
        default:
                __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
        }
@@ -385,10 +385,10 @@ void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if)
        case 7:
                __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
                __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
-               /* Fall through */
+               fallthrough;
        case 6:
                __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
-               /* Fall through */
+               fallthrough;
        default:
                __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
        }
index c52d714..ecf67e6 100644 (file)
@@ -131,8 +131,6 @@ static int __kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
        sysreg_restore_guest_state_vhe(guest_ctxt);
        __debug_switch_to_guest(vcpu);
 
-       __set_guest_arch_workaround_state(vcpu);
-
        do {
                /* Jump in the fire! */
                exit_code = __guest_enter(vcpu, host_ctxt);
@@ -140,8 +138,6 @@ static int __kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
                /* And we're baaack! */
        } while (fixup_guest_exit(vcpu, &exit_code));
 
-       __set_host_arch_workaround_state(vcpu);
-
        sysreg_save_guest_state_vhe(guest_ctxt);
 
        __deactivate_traps(vcpu);
@@ -217,3 +213,8 @@ void __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
        __hyp_call_panic(spsr, elr, par, host_ctxt);
        unreachable();
 }
+
+asmlinkage void kvm_unexpected_el2_exception(void)
+{
+       return __kvm_unexpected_el2_exception();
+}
index 550dfa3..9824025 100644 (file)
@@ -24,27 +24,36 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
                feature = smccc_get_arg1(vcpu);
                switch (feature) {
                case ARM_SMCCC_ARCH_WORKAROUND_1:
-                       switch (kvm_arm_harden_branch_predictor()) {
-                       case KVM_BP_HARDEN_UNKNOWN:
+                       switch (arm64_get_spectre_v2_state()) {
+                       case SPECTRE_VULNERABLE:
                                break;
-                       case KVM_BP_HARDEN_WA_NEEDED:
+                       case SPECTRE_MITIGATED:
                                val = SMCCC_RET_SUCCESS;
                                break;
-                       case KVM_BP_HARDEN_NOT_REQUIRED:
+                       case SPECTRE_UNAFFECTED:
                                val = SMCCC_RET_NOT_REQUIRED;
                                break;
                        }
                        break;
                case ARM_SMCCC_ARCH_WORKAROUND_2:
-                       switch (kvm_arm_have_ssbd()) {
-                       case KVM_SSBD_FORCE_DISABLE:
-                       case KVM_SSBD_UNKNOWN:
+                       switch (arm64_get_spectre_v4_state()) {
+                       case SPECTRE_VULNERABLE:
                                break;
-                       case KVM_SSBD_KERNEL:
-                               val = SMCCC_RET_SUCCESS;
-                               break;
-                       case KVM_SSBD_FORCE_ENABLE:
-                       case KVM_SSBD_MITIGATED:
+                       case SPECTRE_MITIGATED:
+                               /*
+                                * SSBS everywhere: Indicate no firmware
+                                * support, as the SSBS support will be
+                                * indicated to the guest and the default is
+                                * safe.
+                                *
+                                * Otherwise, expose a permanent mitigation
+                                * to the guest, and hide SSBS so that the
+                                * guest stays protected.
+                                */
+                               if (cpus_have_final_cap(ARM64_SSBS))
+                                       break;
+                               fallthrough;
+                       case SPECTRE_UNAFFECTED:
                                val = SMCCC_RET_NOT_REQUIRED;
                                break;
                        }
index ba00bcc..3d26b47 100644 (file)
@@ -1849,7 +1849,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
        struct kvm_s2_mmu *mmu = vcpu->arch.hw_mmu;
 
        write_fault = kvm_is_write_fault(vcpu);
-       exec_fault = kvm_vcpu_trap_is_iabt(vcpu);
+       exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
        VM_BUG_ON(write_fault && exec_fault);
 
        if (fault_status == FSC_PERM && !write_fault && !exec_fault) {
@@ -1877,6 +1877,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
            !fault_supports_stage2_huge_mapping(memslot, hva, vma_pagesize)) {
                force_pte = true;
                vma_pagesize = PAGE_SIZE;
+               vma_shift = PAGE_SHIFT;
        }
 
        /*
@@ -1970,7 +1971,12 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                (fault_status == FSC_PERM &&
                 stage2_is_exec(mmu, fault_ipa, vma_pagesize));
 
-       if (vma_pagesize == PUD_SIZE) {
+       /*
+        * If PUD_SIZE == PMD_SIZE, there is no real PUD level, and
+        * all we have is a 2-level page table. Trying to map a PUD in
+        * this case would be fatally wrong.
+        */
+       if (PUD_SIZE != PMD_SIZE && vma_pagesize == PUD_SIZE) {
                pud_t new_pud = kvm_pfn_pud(pfn, mem_type);
 
                new_pud = kvm_pud_mkhuge(new_pud);
@@ -2125,7 +2131,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
                        goto out;
                }
 
-               if (kvm_vcpu_dabt_iss1tw(vcpu)) {
+               if (kvm_vcpu_abt_iss1tw(vcpu)) {
                        kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
                        ret = 1;
                        goto out_unlock;
index f0d0312..81916e3 100644 (file)
@@ -269,6 +269,7 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
 
        for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++)
                kvm_pmu_release_perf_event(&pmu->pmc[i]);
+       irq_work_sync(&vcpu->arch.pmu.overflow_work);
 }
 
 u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
@@ -434,6 +435,22 @@ void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu)
 }
 
 /**
+ * When perf interrupt is an NMI, we cannot safely notify the vcpu corresponding
+ * to the event.
+ * This is why we need a callback to do it once outside of the NMI context.
+ */
+static void kvm_pmu_perf_overflow_notify_vcpu(struct irq_work *work)
+{
+       struct kvm_vcpu *vcpu;
+       struct kvm_pmu *pmu;
+
+       pmu = container_of(work, struct kvm_pmu, overflow_work);
+       vcpu = kvm_pmc_to_vcpu(pmu->pmc);
+
+       kvm_vcpu_kick(vcpu);
+}
+
+/**
  * When the perf event overflows, set the overflow status and inform the vcpu.
  */
 static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
@@ -465,7 +482,11 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
 
        if (kvm_pmu_overflow_status(vcpu)) {
                kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
-               kvm_vcpu_kick(vcpu);
+
+               if (!in_nmi())
+                       kvm_vcpu_kick(vcpu);
+               else
+                       irq_work_queue(&vcpu->arch.pmu.overflow_work);
        }
 
        cpu_pmu->pmu.start(perf_event, PERF_EF_RELOAD);
@@ -764,6 +785,9 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
                        return ret;
        }
 
+       init_irq_work(&vcpu->arch.pmu.overflow_work,
+                     kvm_pmu_perf_overflow_notify_vcpu);
+
        vcpu->arch.pmu.created = true;
        return 0;
 }
index 83415e9..db4056e 100644 (file)
@@ -425,27 +425,30 @@ static int get_kernel_wa_level(u64 regid)
 {
        switch (regid) {
        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-               switch (kvm_arm_harden_branch_predictor()) {
-               case KVM_BP_HARDEN_UNKNOWN:
+               switch (arm64_get_spectre_v2_state()) {
+               case SPECTRE_VULNERABLE:
                        return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
-               case KVM_BP_HARDEN_WA_NEEDED:
+               case SPECTRE_MITIGATED:
                        return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL;
-               case KVM_BP_HARDEN_NOT_REQUIRED:
+               case SPECTRE_UNAFFECTED:
                        return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED;
                }
                return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL;
        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
-               switch (kvm_arm_have_ssbd()) {
-               case KVM_SSBD_FORCE_DISABLE:
-                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
-               case KVM_SSBD_KERNEL:
-                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL;
-               case KVM_SSBD_FORCE_ENABLE:
-               case KVM_SSBD_MITIGATED:
+               switch (arm64_get_spectre_v4_state()) {
+               case SPECTRE_MITIGATED:
+                       /*
+                        * As for the hypercall discovery, we pretend we
+                        * don't have any FW mitigation if SSBS is there at
+                        * all times.
+                        */
+                       if (cpus_have_final_cap(ARM64_SSBS))
+                               return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
+                       fallthrough;
+               case SPECTRE_UNAFFECTED:
                        return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
-               case KVM_SSBD_UNKNOWN:
-               default:
-                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN;
+               case SPECTRE_VULNERABLE:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
                }
        }
 
@@ -462,14 +465,8 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
                val = kvm_psci_version(vcpu, vcpu->kvm);
                break;
        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
-               val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
-               break;
        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
                val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
-
-               if (val == KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL &&
-                   kvm_arm_get_vcpu_workaround_2_flag(vcpu))
-                       val |= KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED;
                break;
        default:
                return -ENOENT;
@@ -527,34 +524,35 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
                            KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED))
                        return -EINVAL;
 
-               wa_level = val & KVM_REG_FEATURE_LEVEL_MASK;
-
-               if (get_kernel_wa_level(reg->id) < wa_level)
-                       return -EINVAL;
-
                /* The enabled bit must not be set unless the level is AVAIL. */
-               if (wa_level != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL &&
-                   wa_level != val)
+               if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) &&
+                   (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL)
                        return -EINVAL;
 
-               /* Are we finished or do we need to check the enable bit ? */
-               if (kvm_arm_have_ssbd() != KVM_SSBD_KERNEL)
-                       return 0;
-
                /*
-                * If this kernel supports the workaround to be switched on
-                * or off, make sure it matches the requested setting.
+                * Map all the possible incoming states to the only two we
+                * really want to deal with.
                 */
-               switch (wa_level) {
-               case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
-                       kvm_arm_set_vcpu_workaround_2_flag(vcpu,
-                           val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED);
+               switch (val & KVM_REG_FEATURE_LEVEL_MASK) {
+               case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL:
+               case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN:
+                       wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
                        break;
+               case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL:
                case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED:
-                       kvm_arm_set_vcpu_workaround_2_flag(vcpu, true);
+                       wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
                        break;
+               default:
+                       return -EINVAL;
                }
 
+               /*
+                * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the
+                * other way around.
+                */
+               if (get_kernel_wa_level(reg->id) < wa_level)
+                       return -EINVAL;
+
                return 0;
        default:
                return -ENOENT;
index f7b52ce..920ac43 100644 (file)
 void kvm_update_stolen_time(struct kvm_vcpu *vcpu)
 {
        struct kvm *kvm = vcpu->kvm;
-       u64 steal;
-       __le64 steal_le;
-       u64 offset;
-       int idx;
        u64 base = vcpu->arch.steal.base;
+       u64 last_steal = vcpu->arch.steal.last_steal;
+       u64 offset = offsetof(struct pvclock_vcpu_stolen_time, stolen_time);
+       u64 steal = 0;
+       int idx;
 
        if (base == GPA_INVALID)
                return;
 
-       /* Let's do the local bookkeeping */
-       steal = vcpu->arch.steal.steal;
-       steal += current->sched_info.run_delay - vcpu->arch.steal.last_steal;
-       vcpu->arch.steal.last_steal = current->sched_info.run_delay;
-       vcpu->arch.steal.steal = steal;
-
-       steal_le = cpu_to_le64(steal);
        idx = srcu_read_lock(&kvm->srcu);
-       offset = offsetof(struct pvclock_vcpu_stolen_time, stolen_time);
-       kvm_put_guest(kvm, base + offset, steal_le, u64);
+       if (!kvm_get_guest(kvm, base + offset, steal)) {
+               steal = le64_to_cpu(steal);
+               vcpu->arch.steal.last_steal = READ_ONCE(current->sched_info.run_delay);
+               steal += vcpu->arch.steal.last_steal - last_steal;
+               kvm_put_guest(kvm, base + offset, cpu_to_le64(steal));
+       }
        srcu_read_unlock(&kvm->srcu, idx);
 }
 
@@ -43,7 +40,8 @@ long kvm_hypercall_pv_features(struct kvm_vcpu *vcpu)
        switch (feature) {
        case ARM_SMCCC_HV_PV_TIME_FEATURES:
        case ARM_SMCCC_HV_PV_TIME_ST:
-               val = SMCCC_RET_SUCCESS;
+               if (vcpu->arch.steal.base != GPA_INVALID)
+                       val = SMCCC_RET_SUCCESS;
                break;
        }
 
@@ -64,7 +62,6 @@ gpa_t kvm_init_stolen_time(struct kvm_vcpu *vcpu)
         * Start counting stolen time from the time the guest requests
         * the feature enabled.
         */
-       vcpu->arch.steal.steal = 0;
        vcpu->arch.steal.last_steal = current->sched_info.run_delay;
 
        idx = srcu_read_lock(&kvm->srcu);
@@ -74,7 +71,7 @@ gpa_t kvm_init_stolen_time(struct kvm_vcpu *vcpu)
        return base;
 }
 
-static bool kvm_arm_pvtime_supported(void)
+bool kvm_arm_pvtime_supported(void)
 {
        return !!sched_info_on();
 }
index ee33875..f6e8b4a 100644 (file)
@@ -319,10 +319,6 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
                vcpu->arch.reset_state.reset = false;
        }
 
-       /* Default workaround setup is enabled (if supported) */
-       if (kvm_arm_have_ssbd() == KVM_SSBD_KERNEL)
-               vcpu->arch.workaround_flags |= VCPU_WORKAROUND_2_FLAG;
-
        /* Reset timer */
        ret = kvm_timer_vcpu_reset(vcpu);
 out:
index 077293b..9ca2706 100644 (file)
@@ -1131,6 +1131,11 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
                if (!vcpu_has_sve(vcpu))
                        val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
                val &= ~(0xfUL << ID_AA64PFR0_AMU_SHIFT);
+               if (!(val & (0xfUL << ID_AA64PFR0_CSV2_SHIFT)) &&
+                   arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED)
+                       val |= (1UL << ID_AA64PFR0_CSV2_SHIFT);
+       } else if (id == SYS_ID_AA64PFR1_EL1) {
+               val &= ~(0xfUL << ID_AA64PFR1_MTE_SHIFT);
        } else if (id == SYS_ID_AA64ISAR1_EL1 && !vcpu_has_ptrauth(vcpu)) {
                val &= ~((0xfUL << ID_AA64ISAR1_APA_SHIFT) |
                         (0xfUL << ID_AA64ISAR1_API_SHIFT) |
@@ -1382,6 +1387,13 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        return true;
 }
 
+static bool access_mte_regs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+                           const struct sys_reg_desc *r)
+{
+       kvm_inject_undefined(vcpu);
+       return false;
+}
+
 /* sys_reg_desc initialiser for known cpufeature ID registers */
 #define ID_SANITISED(name) {                   \
        SYS_DESC(SYS_##name),                   \
@@ -1547,6 +1559,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
        { SYS_DESC(SYS_ACTLR_EL1), access_actlr, reset_actlr, ACTLR_EL1 },
        { SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
+
+       { SYS_DESC(SYS_RGSR_EL1), access_mte_regs },
+       { SYS_DESC(SYS_GCR_EL1), access_mte_regs },
+
        { SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
        { SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
        { SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
@@ -1571,6 +1587,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_ERXMISC0_EL1), trap_raz_wi },
        { SYS_DESC(SYS_ERXMISC1_EL1), trap_raz_wi },
 
+       { SYS_DESC(SYS_TFSR_EL1), access_mte_regs },
+       { SYS_DESC(SYS_TFSRE0_EL1), access_mte_regs },
+
        { SYS_DESC(SYS_FAR_EL1), access_vm_reg, reset_unknown, FAR_EL1 },
        { SYS_DESC(SYS_PAR_EL1), NULL, reset_unknown, PAR_EL1 },
 
index 4691053..ff04443 100644 (file)
@@ -23,7 +23,7 @@ TRACE_EVENT(kvm_entry,
                __entry->vcpu_pc                = vcpu_pc;
        ),
 
-       TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
+       TP_printk("PC: 0x%016lx", __entry->vcpu_pc)
 );
 
 TRACE_EVENT(kvm_exit,
@@ -42,7 +42,7 @@ TRACE_EVENT(kvm_exit,
                __entry->vcpu_pc                = vcpu_pc;
        ),
 
-       TP_printk("%s: HSR_EC: 0x%04x (%s), PC: 0x%08lx",
+       TP_printk("%s: HSR_EC: 0x%04x (%s), PC: 0x%016lx",
                  __print_symbolic(__entry->ret, kvm_arm_exception_type),
                  __entry->esr_ec,
                  __print_symbolic(__entry->esr_ec, kvm_arm_exception_class),
@@ -69,7 +69,7 @@ TRACE_EVENT(kvm_guest_fault,
                __entry->ipa                    = ipa;
        ),
 
-       TP_printk("ipa %#llx, hsr %#08lx, hxfar %#08lx, pc %#08lx",
+       TP_printk("ipa %#llx, hsr %#08lx, hxfar %#08lx, pc %#016lx",
                  __entry->ipa, __entry->hsr,
                  __entry->hxfar, __entry->vcpu_pc)
 );
@@ -131,7 +131,7 @@ TRACE_EVENT(kvm_mmio_emulate,
                __entry->cpsr                   = cpsr;
        ),
 
-       TP_printk("Emulate MMIO at: 0x%08lx (instr: %08lx, cpsr: %08lx)",
+       TP_printk("Emulate MMIO at: 0x%016lx (instr: %08lx, cpsr: %08lx)",
                  __entry->vcpu_pc, __entry->instr, __entry->cpsr)
 );
 
@@ -149,7 +149,7 @@ TRACE_EVENT(kvm_unmap_hva_range,
                __entry->end            = end;
        ),
 
-       TP_printk("mmu notifier unmap range: %#08lx -- %#08lx",
+       TP_printk("mmu notifier unmap range: %#016lx -- %#016lx",
                  __entry->start, __entry->end)
 );
 
@@ -165,7 +165,7 @@ TRACE_EVENT(kvm_set_spte_hva,
                __entry->hva            = hva;
        ),
 
-       TP_printk("mmu notifier set pte hva: %#08lx", __entry->hva)
+       TP_printk("mmu notifier set pte hva: %#016lx", __entry->hva)
 );
 
 TRACE_EVENT(kvm_age_hva,
@@ -182,7 +182,7 @@ TRACE_EVENT(kvm_age_hva,
                __entry->end            = end;
        ),
 
-       TP_printk("mmu notifier age hva: %#08lx -- %#08lx",
+       TP_printk("mmu notifier age hva: %#016lx -- %#016lx",
                  __entry->start, __entry->end)
 );
 
@@ -198,7 +198,7 @@ TRACE_EVENT(kvm_test_age_hva,
                __entry->hva            = hva;
        ),
 
-       TP_printk("mmu notifier test age hva: %#08lx", __entry->hva)
+       TP_printk("mmu notifier test age hva: %#016lx", __entry->hva)
 );
 
 TRACE_EVENT(kvm_set_way_flush,
index 2c56d1e..8d78acc 100644 (file)
@@ -22,7 +22,7 @@ TRACE_EVENT(kvm_wfx_arm64,
                __entry->is_wfe  = is_wfe;
        ),
 
-       TP_printk("guest executed wf%c at: 0x%08lx",
+       TP_printk("guest executed wf%c at: 0x%016lx",
                  __entry->is_wfe ? 'e' : 'i', __entry->vcpu_pc)
 );
 
@@ -42,7 +42,7 @@ TRACE_EVENT(kvm_hvc_arm64,
                __entry->imm = imm;
        ),
 
-       TP_printk("HVC at 0x%08lx (r0: 0x%08lx, imm: 0x%lx)",
+       TP_printk("HVC at 0x%016lx (r0: 0x%016lx, imm: 0x%lx)",
                  __entry->vcpu_pc, __entry->r0, __entry->imm)
 );
 
@@ -135,7 +135,7 @@ TRACE_EVENT(trap_reg,
                __entry->write_value = write_value;
        ),
 
-       TP_printk("%s %s reg %d (0x%08llx)", __entry->fn,  __entry->is_write?"write to":"read from", __entry->reg, __entry->write_value)
+       TP_printk("%s %s reg %d (0x%016llx)", __entry->fn,  __entry->is_write?"write to":"read from", __entry->reg, __entry->write_value)
 );
 
 TRACE_EVENT(kvm_handle_sys_reg,
index 5c786b9..52d6f24 100644 (file)
@@ -1001,8 +1001,8 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg, bool allow_group1)
                raw_spin_lock_irqsave(&irq->irq_lock, flags);
 
                /*
-                * An access targetting Group0 SGIs can only generate
-                * those, while an access targetting Group1 SGIs can
+                * An access targeting Group0 SGIs can only generate
+                * those, while an access targeting Group1 SGIs can
                 * generate interrupts of either group.
                 */
                if (!irq->group || allow_group1) {
index 2fc2534..d31e116 100644 (file)
@@ -16,3 +16,5 @@ lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o
 obj-$(CONFIG_CRC32) += crc32.o
 
 obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
+
+obj-$(CONFIG_ARM64_MTE) += mte.o
diff --git a/arch/arm64/lib/mte.S b/arch/arm64/lib/mte.S
new file mode 100644 (file)
index 0000000..03ca6d8
--- /dev/null
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 ARM Ltd.
+ */
+#include <linux/linkage.h>
+
+#include <asm/alternative.h>
+#include <asm/assembler.h>
+#include <asm/mte.h>
+#include <asm/page.h>
+#include <asm/sysreg.h>
+
+       .arch   armv8.5-a+memtag
+
+/*
+ * multitag_transfer_size - set \reg to the block size that is accessed by the
+ * LDGM/STGM instructions.
+ */
+       .macro  multitag_transfer_size, reg, tmp
+       mrs_s   \reg, SYS_GMID_EL1
+       ubfx    \reg, \reg, #SYS_GMID_EL1_BS_SHIFT, #SYS_GMID_EL1_BS_SIZE
+       mov     \tmp, #4
+       lsl     \reg, \tmp, \reg
+       .endm
+
+/*
+ * Clear the tags in a page
+ *   x0 - address of the page to be cleared
+ */
+SYM_FUNC_START(mte_clear_page_tags)
+       multitag_transfer_size x1, x2
+1:     stgm    xzr, [x0]
+       add     x0, x0, x1
+       tst     x0, #(PAGE_SIZE - 1)
+       b.ne    1b
+       ret
+SYM_FUNC_END(mte_clear_page_tags)
+
+/*
+ * Copy the tags from the source page to the destination one
+ *   x0 - address of the destination page
+ *   x1 - address of the source page
+ */
+SYM_FUNC_START(mte_copy_page_tags)
+       mov     x2, x0
+       mov     x3, x1
+       multitag_transfer_size x5, x6
+1:     ldgm    x4, [x3]
+       stgm    x4, [x2]
+       add     x2, x2, x5
+       add     x3, x3, x5
+       tst     x2, #(PAGE_SIZE - 1)
+       b.ne    1b
+       ret
+SYM_FUNC_END(mte_copy_page_tags)
+
+/*
+ * Read tags from a user buffer (one tag per byte) and set the corresponding
+ * tags at the given kernel address. Used by PTRACE_POKEMTETAGS.
+ *   x0 - kernel address (to)
+ *   x1 - user buffer (from)
+ *   x2 - number of tags/bytes (n)
+ * Returns:
+ *   x0 - number of tags read/set
+ */
+SYM_FUNC_START(mte_copy_tags_from_user)
+       mov     x3, x1
+       cbz     x2, 2f
+1:
+       uao_user_alternative 2f, ldrb, ldtrb, w4, x1, 0
+       lsl     x4, x4, #MTE_TAG_SHIFT
+       stg     x4, [x0], #MTE_GRANULE_SIZE
+       add     x1, x1, #1
+       subs    x2, x2, #1
+       b.ne    1b
+
+       // exception handling and function return
+2:     sub     x0, x1, x3              // update the number of tags set
+       ret
+SYM_FUNC_END(mte_copy_tags_from_user)
+
+/*
+ * Get the tags from a kernel address range and write the tag values to the
+ * given user buffer (one tag per byte). Used by PTRACE_PEEKMTETAGS.
+ *   x0 - user buffer (to)
+ *   x1 - kernel address (from)
+ *   x2 - number of tags/bytes (n)
+ * Returns:
+ *   x0 - number of tags read/set
+ */
+SYM_FUNC_START(mte_copy_tags_to_user)
+       mov     x3, x0
+       cbz     x2, 2f
+1:
+       ldg     x4, [x1]
+       ubfx    x4, x4, #MTE_TAG_SHIFT, #MTE_TAG_SIZE
+       uao_user_alternative 2f, strb, sttrb, w4, x0, 0
+       add     x0, x0, #1
+       add     x1, x1, #MTE_GRANULE_SIZE
+       subs    x2, x2, #1
+       b.ne    1b
+
+       // exception handling and function return
+2:     sub     x0, x0, x3              // update the number of tags copied
+       ret
+SYM_FUNC_END(mte_copy_tags_to_user)
+
+/*
+ * Save the tags in a page
+ *   x0 - page address
+ *   x1 - tag storage
+ */
+SYM_FUNC_START(mte_save_page_tags)
+       multitag_transfer_size x7, x5
+1:
+       mov     x2, #0
+2:
+       ldgm    x5, [x0]
+       orr     x2, x2, x5
+       add     x0, x0, x7
+       tst     x0, #0xFF               // 16 tag values fit in a register,
+       b.ne    2b                      // which is 16*16=256 bytes
+
+       str     x2, [x1], #8
+
+       tst     x0, #(PAGE_SIZE - 1)
+       b.ne    1b
+
+       ret
+SYM_FUNC_END(mte_save_page_tags)
+
+/*
+ * Restore the tags in a page
+ *   x0 - page address
+ *   x1 - tag storage
+ */
+SYM_FUNC_START(mte_restore_page_tags)
+       multitag_transfer_size x7, x5
+1:
+       ldr     x2, [x1], #8
+2:
+       stgm    x2, [x0]
+       add     x0, x0, x7
+       tst     x0, #0xFF
+       b.ne    2b
+
+       tst     x0, #(PAGE_SIZE - 1)
+       b.ne    1b
+
+       ret
+SYM_FUNC_END(mte_restore_page_tags)
index d91030f..5ead3c3 100644 (file)
@@ -4,10 +4,11 @@ obj-y                         := dma-mapping.o extable.o fault.o init.o \
                                   ioremap.o mmap.o pgd.o mmu.o \
                                   context.o proc.o pageattr.o
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
-obj-$(CONFIG_PTDUMP_CORE)      += dump.o
+obj-$(CONFIG_PTDUMP_CORE)      += ptdump.o
 obj-$(CONFIG_PTDUMP_DEBUGFS)   += ptdump_debugfs.o
 obj-$(CONFIG_NUMA)             += numa.o
 obj-$(CONFIG_DEBUG_VIRTUAL)    += physaddr.o
+obj-$(CONFIG_ARM64_MTE)                += mteswap.o
 KASAN_SANITIZE_physaddr.o      += n
 
 obj-$(CONFIG_KASAN)            += kasan_init.o
index a206655..001737a 100644 (file)
@@ -27,6 +27,10 @@ static DEFINE_PER_CPU(atomic64_t, active_asids);
 static DEFINE_PER_CPU(u64, reserved_asids);
 static cpumask_t tlb_flush_pending;
 
+static unsigned long max_pinned_asids;
+static unsigned long nr_pinned_asids;
+static unsigned long *pinned_asid_map;
+
 #define ASID_MASK              (~GENMASK(asid_bits - 1, 0))
 #define ASID_FIRST_VERSION     (1UL << asid_bits)
 
@@ -45,7 +49,7 @@ static u32 get_cpu_asid_bits(void)
        default:
                pr_warn("CPU%d: Unknown ASID size (%d); assuming 8-bit\n",
                                        smp_processor_id(),  fld);
-               /* Fallthrough */
+               fallthrough;
        case 0:
                asid = 8;
                break;
@@ -72,7 +76,7 @@ void verify_cpu_asid_bits(void)
        }
 }
 
-static void set_kpti_asid_bits(void)
+static void set_kpti_asid_bits(unsigned long *map)
 {
        unsigned int len = BITS_TO_LONGS(NUM_USER_ASIDS) * sizeof(unsigned long);
        /*
@@ -81,13 +85,15 @@ static void set_kpti_asid_bits(void)
         * is set, then the ASID will map only userspace. Thus
         * mark even as reserved for kernel.
         */
-       memset(asid_map, 0xaa, len);
+       memset(map, 0xaa, len);
 }
 
 static void set_reserved_asid_bits(void)
 {
-       if (arm64_kernel_unmapped_at_el0())
-               set_kpti_asid_bits();
+       if (pinned_asid_map)
+               bitmap_copy(asid_map, pinned_asid_map, NUM_USER_ASIDS);
+       else if (arm64_kernel_unmapped_at_el0())
+               set_kpti_asid_bits(asid_map);
        else
                bitmap_clear(asid_map, 0, NUM_USER_ASIDS);
 }
@@ -166,6 +172,14 @@ static u64 new_context(struct mm_struct *mm)
                        return newasid;
 
                /*
+                * If it is pinned, we can keep using it. Note that reserved
+                * takes priority, because even if it is also pinned, we need to
+                * update the generation into the reserved_asids.
+                */
+               if (refcount_read(&mm->context.pinned))
+                       return newasid;
+
+               /*
                 * We had a valid ASID in a previous life, so try to re-use
                 * it if possible.
                 */
@@ -256,6 +270,71 @@ switch_mm_fastpath:
                cpu_switch_mm(mm->pgd, mm);
 }
 
+unsigned long arm64_mm_context_get(struct mm_struct *mm)
+{
+       unsigned long flags;
+       u64 asid;
+
+       if (!pinned_asid_map)
+               return 0;
+
+       raw_spin_lock_irqsave(&cpu_asid_lock, flags);
+
+       asid = atomic64_read(&mm->context.id);
+
+       if (refcount_inc_not_zero(&mm->context.pinned))
+               goto out_unlock;
+
+       if (nr_pinned_asids >= max_pinned_asids) {
+               asid = 0;
+               goto out_unlock;
+       }
+
+       if (!asid_gen_match(asid)) {
+               /*
+                * We went through one or more rollover since that ASID was
+                * used. Ensure that it is still valid, or generate a new one.
+                */
+               asid = new_context(mm);
+               atomic64_set(&mm->context.id, asid);
+       }
+
+       nr_pinned_asids++;
+       __set_bit(asid2idx(asid), pinned_asid_map);
+       refcount_set(&mm->context.pinned, 1);
+
+out_unlock:
+       raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
+
+       asid &= ~ASID_MASK;
+
+       /* Set the equivalent of USER_ASID_BIT */
+       if (asid && arm64_kernel_unmapped_at_el0())
+               asid |= 1;
+
+       return asid;
+}
+EXPORT_SYMBOL_GPL(arm64_mm_context_get);
+
+void arm64_mm_context_put(struct mm_struct *mm)
+{
+       unsigned long flags;
+       u64 asid = atomic64_read(&mm->context.id);
+
+       if (!pinned_asid_map)
+               return;
+
+       raw_spin_lock_irqsave(&cpu_asid_lock, flags);
+
+       if (refcount_dec_and_test(&mm->context.pinned)) {
+               __clear_bit(asid2idx(asid), pinned_asid_map);
+               nr_pinned_asids--;
+       }
+
+       raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
+}
+EXPORT_SYMBOL_GPL(arm64_mm_context_put);
+
 /* Errata workaround post TTBRx_EL1 update. */
 asmlinkage void post_ttbr_update_workaround(void)
 {
@@ -296,8 +375,11 @@ static int asids_update_limit(void)
 {
        unsigned long num_available_asids = NUM_USER_ASIDS;
 
-       if (arm64_kernel_unmapped_at_el0())
+       if (arm64_kernel_unmapped_at_el0()) {
                num_available_asids /= 2;
+               if (pinned_asid_map)
+                       set_kpti_asid_bits(pinned_asid_map);
+       }
        /*
         * Expect allocation after rollover to fail if we don't have at least
         * one more ASID than CPUs. ASID #0 is reserved for init_mm.
@@ -305,6 +387,13 @@ static int asids_update_limit(void)
        WARN_ON(num_available_asids - 1 <= num_possible_cpus());
        pr_info("ASID allocator initialised with %lu entries\n",
                num_available_asids);
+
+       /*
+        * There must always be an ASID available after rollover. Ensure that,
+        * even if all CPUs have a reserved ASID and the maximum number of ASIDs
+        * are pinned, there still is at least one empty slot in the ASID map.
+        */
+       max_pinned_asids = num_available_asids - num_possible_cpus() - 2;
        return 0;
 }
 arch_initcall(asids_update_limit);
@@ -319,13 +408,17 @@ static int asids_init(void)
                panic("Failed to allocate bitmap for %lu ASIDs\n",
                      NUM_USER_ASIDS);
 
+       pinned_asid_map = kcalloc(BITS_TO_LONGS(NUM_USER_ASIDS),
+                                 sizeof(*pinned_asid_map), GFP_KERNEL);
+       nr_pinned_asids = 0;
+
        /*
         * We cannot call set_reserved_asid_bits() here because CPU
         * caps are not finalized yet, so it is safer to assume KPTI
         * and reserve kernel ASID's from beginning.
         */
        if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0))
-               set_kpti_asid_bits();
+               set_kpti_asid_bits(asid_map);
        return 0;
 }
 early_initcall(asids_init);
index 2ee7b73..70a71f3 100644 (file)
@@ -6,21 +6,32 @@
  * Copyright (C) 2012 ARM Ltd.
  */
 
+#include <linux/bitops.h>
 #include <linux/mm.h>
 
 #include <asm/page.h>
 #include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
+#include <asm/mte.h>
 
-void __cpu_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
+void copy_highpage(struct page *to, struct page *from)
 {
-       struct page *page = virt_to_page(kto);
+       struct page *kto = page_address(to);
+       struct page *kfrom = page_address(from);
+
        copy_page(kto, kfrom);
-       flush_dcache_page(page);
+
+       if (system_supports_mte() && test_bit(PG_mte_tagged, &from->flags)) {
+               set_bit(PG_mte_tagged, &to->flags);
+               mte_copy_page_tags(kto, kfrom);
+       }
 }
-EXPORT_SYMBOL_GPL(__cpu_copy_user_page);
+EXPORT_SYMBOL(copy_highpage);
 
-void __cpu_clear_user_page(void *kaddr, unsigned long vaddr)
+void copy_user_highpage(struct page *to, struct page *from,
+                       unsigned long vaddr, struct vm_area_struct *vma)
 {
-       clear_page(kaddr);
+       copy_highpage(to, from);
+       flush_dcache_page(to);
 }
-EXPORT_SYMBOL_GPL(__cpu_clear_user_page);
+EXPORT_SYMBOL_GPL(copy_user_highpage);
index eee1732..aa00601 100644 (file)
@@ -14,9 +14,7 @@ int fixup_exception(struct pt_regs *regs)
        if (!fixup)
                return 0;
 
-       if (IS_ENABLED(CONFIG_BPF_JIT) &&
-           regs->pc >= BPF_JIT_REGION_START &&
-           regs->pc < BPF_JIT_REGION_END)
+       if (in_bpf_jit(regs))
                return arm64_bpf_fixup_exception(fixup, regs);
 
        regs->pc = (unsigned long)&fixup->fixup + fixup->fixup;
index f07333e..94c99c1 100644 (file)
@@ -218,7 +218,9 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
                pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval, pteval);
        } while (pteval != old_pteval);
 
-       flush_tlb_fix_spurious_fault(vma, address);
+       /* Invalidate a stale read-only entry */
+       if (dirty)
+               flush_tlb_page(vma, address);
        return 1;
 }
 
@@ -641,6 +643,13 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
        return 0;
 }
 
+static int do_tag_check_fault(unsigned long addr, unsigned int esr,
+                             struct pt_regs *regs)
+{
+       do_bad_area(addr, esr, regs);
+       return 0;
+}
+
 static const struct fault_info fault_info[] = {
        { do_bad,               SIGKILL, SI_KERNEL,     "ttbr address size fault"       },
        { do_bad,               SIGKILL, SI_KERNEL,     "level 1 address size fault"    },
@@ -659,7 +668,7 @@ static const struct fault_info fault_info[] = {
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 permission fault"      },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 permission fault"      },
        { do_sea,               SIGBUS,  BUS_OBJERR,    "synchronous external abort"    },
-       { do_bad,               SIGKILL, SI_KERNEL,     "unknown 17"                    },
+       { do_tag_check_fault,   SIGSEGV, SEGV_MTESERR,  "synchronous tag check fault"   },
        { do_bad,               SIGKILL, SI_KERNEL,     "unknown 18"                    },
        { do_bad,               SIGKILL, SI_KERNEL,     "unknown 19"                    },
        { do_sea,               SIGKILL, SI_KERNEL,     "level 0 (translation table walk)"      },
index 75df62f..087a844 100644 (file)
@@ -43,7 +43,7 @@
 u64 idmap_t0sz = TCR_T0SZ(VA_BITS);
 u64 idmap_ptrs_per_pgd = PTRS_PER_PGD;
 
-u64 __section(".mmuoff.data.write") vabits_actual;
+u64 __section(.mmuoff.data.write) vabits_actual;
 EXPORT_SYMBOL(vabits_actual);
 
 u64 kimage_voffset __ro_after_init;
@@ -122,7 +122,7 @@ static bool pgattr_change_is_safe(u64 old, u64 new)
         * The following mapping attributes may be updated in live
         * kernel mappings without the need for break-before-make.
         */
-       static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG;
+       pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG;
 
        /* creating or taking down mappings is always safe */
        if (old == 0 || new == 0)
@@ -136,6 +136,17 @@ static bool pgattr_change_is_safe(u64 old, u64 new)
        if (old & ~new & PTE_NG)
                return false;
 
+       /*
+        * Changing the memory type between Normal and Normal-Tagged is safe
+        * since Tagged is considered a permission attribute from the
+        * mismatched attribute aliases perspective.
+        */
+       if (((old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
+            (old & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED)) &&
+           ((new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL) ||
+            (new & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED)))
+               mask |= PTE_ATTRINDX_MASK;
+
        return ((old ^ new) & ~mask) == 0;
 }
 
@@ -491,7 +502,12 @@ static void __init map_mem(pgd_t *pgdp)
                if (memblock_is_nomap(reg))
                        continue;
 
-               __map_memblock(pgdp, start, end, PAGE_KERNEL, flags);
+               /*
+                * The linear map must allow allocation tags reading/writing
+                * if MTE is present. Otherwise, it has the same attributes as
+                * PAGE_KERNEL.
+                */
+               __map_memblock(pgdp, start, end, PAGE_KERNEL_TAGGED, flags);
        }
 
        /*
diff --git a/arch/arm64/mm/mteswap.c b/arch/arm64/mm/mteswap.c
new file mode 100644 (file)
index 0000000..c52c184
--- /dev/null
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/pagemap.h>
+#include <linux/xarray.h>
+#include <linux/slab.h>
+#include <linux/swap.h>
+#include <linux/swapops.h>
+#include <asm/mte.h>
+
+static DEFINE_XARRAY(mte_pages);
+
+void *mte_allocate_tag_storage(void)
+{
+       /* tags granule is 16 bytes, 2 tags stored per byte */
+       return kmalloc(PAGE_SIZE / 16 / 2, GFP_KERNEL);
+}
+
+void mte_free_tag_storage(char *storage)
+{
+       kfree(storage);
+}
+
+int mte_save_tags(struct page *page)
+{
+       void *tag_storage, *ret;
+
+       if (!test_bit(PG_mte_tagged, &page->flags))
+               return 0;
+
+       tag_storage = mte_allocate_tag_storage();
+       if (!tag_storage)
+               return -ENOMEM;
+
+       mte_save_page_tags(page_address(page), tag_storage);
+
+       /* page_private contains the swap entry.val set in do_swap_page */
+       ret = xa_store(&mte_pages, page_private(page), tag_storage, GFP_KERNEL);
+       if (WARN(xa_is_err(ret), "Failed to store MTE tags")) {
+               mte_free_tag_storage(tag_storage);
+               return xa_err(ret);
+       } else if (ret) {
+               /* Entry is being replaced, free the old entry */
+               mte_free_tag_storage(ret);
+       }
+
+       return 0;
+}
+
+bool mte_restore_tags(swp_entry_t entry, struct page *page)
+{
+       void *tags = xa_load(&mte_pages, entry.val);
+
+       if (!tags)
+               return false;
+
+       mte_restore_page_tags(page_address(page), tags);
+
+       return true;
+}
+
+void mte_invalidate_tags(int type, pgoff_t offset)
+{
+       swp_entry_t entry = swp_entry(type, offset);
+       void *tags = xa_erase(&mte_pages, entry.val);
+
+       mte_free_tag_storage(tags);
+}
+
+void mte_invalidate_tags_area(int type)
+{
+       swp_entry_t entry = swp_entry(type, 0);
+       swp_entry_t last_entry = swp_entry(type + 1, 0);
+       void *tags;
+
+       XA_STATE(xa_state, &mte_pages, entry.val);
+
+       xa_lock(&mte_pages);
+       xas_for_each(&xa_state, tags, last_entry.val - 1) {
+               __xa_erase(&mte_pages, xa_state.xa_index);
+               mte_free_tag_storage(tags);
+       }
+       xa_unlock(&mte_pages);
+}
index 73f8b49..676deb2 100644 (file)
@@ -46,7 +46,11 @@ EXPORT_SYMBOL(node_to_cpumask_map);
  */
 const struct cpumask *cpumask_of_node(int node)
 {
-       if (WARN_ON(node >= nr_node_ids))
+
+       if (node == NUMA_NO_NODE)
+               return cpu_all_mask;
+
+       if (WARN_ON(node < 0 || node >= nr_node_ids))
                return cpu_none_mask;
 
        if (WARN_ON(node_to_cpumask_map[node] == NULL))
@@ -448,7 +452,7 @@ static int __init dummy_numa_init(void)
  * arm64_numa_init() - Initialize NUMA
  *
  * Try each configured NUMA initialization method until one succeeds. The
- * last fallback is dummy single node config encomapssing whole memory.
+ * last fallback is dummy single node config encompassing whole memory.
  */
 void __init arm64_numa_init(void)
 {
index 23f648c..1b94f5b 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/sched.h>
 #include <linux/vmalloc.h>
 
+#include <asm/cacheflush.h>
 #include <asm/set_memory.h>
 #include <asm/tlbflush.h>
 
index 796e47a..23c326a 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/cpufeature.h>
 #include <asm/alternative.h>
 #include <asm/smp.h>
+#include <asm/sysreg.h>
 
 #ifdef CONFIG_ARM64_64K_PAGES
 #define TCR_TG_FLAGS   TCR_TG0_64K | TCR_TG1_64K
 #define TCR_KASAN_FLAGS 0
 #endif
 
-/* Default MAIR_EL1 */
+/*
+ * Default MAIR_EL1. MT_NORMAL_TAGGED is initially mapped as Normal memory and
+ * changed during __cpu_setup to Normal Tagged if the system supports MTE.
+ */
 #define MAIR_EL1_SET                                                   \
        (MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRnE, MT_DEVICE_nGnRnE) |      \
         MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRE, MT_DEVICE_nGnRE) |        \
         MAIR_ATTRIDX(MAIR_ATTR_DEVICE_GRE, MT_DEVICE_GRE) |            \
         MAIR_ATTRIDX(MAIR_ATTR_NORMAL_NC, MT_NORMAL_NC) |              \
         MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL) |                    \
-        MAIR_ATTRIDX(MAIR_ATTR_NORMAL_WT, MT_NORMAL_WT))
+        MAIR_ATTRIDX(MAIR_ATTR_NORMAL_WT, MT_NORMAL_WT) |              \
+        MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL_TAGGED))
 
 #ifdef CONFIG_CPU_PM
 /**
@@ -421,6 +426,29 @@ SYM_FUNC_START(__cpu_setup)
         * Memory region attributes
         */
        mov_q   x5, MAIR_EL1_SET
+#ifdef CONFIG_ARM64_MTE
+       /*
+        * Update MAIR_EL1, GCR_EL1 and TFSR*_EL1 if MTE is supported
+        * (ID_AA64PFR1_EL1[11:8] > 1).
+        */
+       mrs     x10, ID_AA64PFR1_EL1
+       ubfx    x10, x10, #ID_AA64PFR1_MTE_SHIFT, #4
+       cmp     x10, #ID_AA64PFR1_MTE
+       b.lt    1f
+
+       /* Normal Tagged memory type at the corresponding MAIR index */
+       mov     x10, #MAIR_ATTR_NORMAL_TAGGED
+       bfi     x5, x10, #(8 *  MT_NORMAL_TAGGED), #8
+
+       /* initialize GCR_EL1: all non-zero tags excluded by default */
+       mov     x10, #(SYS_GCR_EL1_RRND | SYS_GCR_EL1_EXCL_MASK)
+       msr_s   SYS_GCR_EL1, x10
+
+       /* clear any pending tag check faults in TFSR*_EL1 */
+       msr_s   SYS_TFSR_EL1, xzr
+       msr_s   SYS_TFSRE0_EL1, xzr
+1:
+#endif
        msr     mair_el1, x5
        /*
         * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for
similarity index 97%
rename from arch/arm64/mm/dump.c
rename to arch/arm64/mm/ptdump.c
index 0b8da1c..807dc63 100644 (file)
@@ -41,6 +41,8 @@ static struct addr_marker address_markers[] = {
        { 0 /* KASAN_SHADOW_START */,   "Kasan shadow start" },
        { KASAN_SHADOW_END,             "Kasan shadow end" },
 #endif
+       { BPF_JIT_REGION_START,         "BPF start" },
+       { BPF_JIT_REGION_END,           "BPF end" },
        { MODULES_VADDR,                "Modules start" },
        { MODULES_END,                  "Modules end" },
        { VMALLOC_START,                "vmalloc() area" },
@@ -169,6 +171,10 @@ static const struct prot_bits pte_bits[] = {
                .mask   = PTE_ATTRINDX_MASK,
                .val    = PTE_ATTRINDX(MT_NORMAL),
                .set    = "MEM/NORMAL",
+       }, {
+               .mask   = PTE_ATTRINDX_MASK,
+               .val    = PTE_ATTRINDX(MT_NORMAL_TAGGED),
+               .set    = "MEM/NORMAL-TAGGED",
        }
 };
 
index f8912e4..ef9f1d5 100644 (file)
@@ -143,14 +143,17 @@ static inline void emit_addr_mov_i64(const int reg, const u64 val,
        }
 }
 
-static inline int bpf2a64_offset(int bpf_to, int bpf_from,
+static inline int bpf2a64_offset(int bpf_insn, int off,
                                 const struct jit_ctx *ctx)
 {
-       int to = ctx->offset[bpf_to];
-       /* -1 to account for the Branch instruction */
-       int from = ctx->offset[bpf_from] - 1;
-
-       return to - from;
+       /* BPF JMP offset is relative to the next instruction */
+       bpf_insn++;
+       /*
+        * Whereas arm64 branch instructions encode the offset
+        * from the branch itself, so we must subtract 1 from the
+        * instruction offset.
+        */
+       return ctx->offset[bpf_insn + off] - (ctx->offset[bpf_insn] - 1);
 }
 
 static void jit_fill_hole(void *area, unsigned int size)
@@ -642,7 +645,7 @@ emit_bswap_uxt:
 
        /* JUMP off */
        case BPF_JMP | BPF_JA:
-               jmp_offset = bpf2a64_offset(i + off, i, ctx);
+               jmp_offset = bpf2a64_offset(i, off, ctx);
                check_imm26(jmp_offset);
                emit(A64_B(jmp_offset), ctx);
                break;
@@ -669,7 +672,7 @@ emit_bswap_uxt:
        case BPF_JMP32 | BPF_JSLE | BPF_X:
                emit(A64_CMP(is64, dst, src), ctx);
 emit_cond_jmp:
-               jmp_offset = bpf2a64_offset(i + off, i, ctx);
+               jmp_offset = bpf2a64_offset(i, off, ctx);
                check_imm19(jmp_offset);
                switch (BPF_OP(code)) {
                case BPF_JEQ:
@@ -908,10 +911,21 @@ static int build_body(struct jit_ctx *ctx, bool extra_pass)
        const struct bpf_prog *prog = ctx->prog;
        int i;
 
+       /*
+        * - offset[0] offset of the end of prologue,
+        *   start of the 1st instruction.
+        * - offset[1] - offset of the end of 1st instruction,
+        *   start of the 2nd instruction
+        * [....]
+        * - offset[3] - offset of the end of 3rd instruction,
+        *   start of 4th instruction
+        */
        for (i = 0; i < prog->len; i++) {
                const struct bpf_insn *insn = &prog->insnsi[i];
                int ret;
 
+               if (ctx->image == NULL)
+                       ctx->offset[i] = ctx->idx;
                ret = build_insn(insn, ctx, extra_pass);
                if (ret > 0) {
                        i++;
@@ -919,11 +933,16 @@ static int build_body(struct jit_ctx *ctx, bool extra_pass)
                                ctx->offset[i] = ctx->idx;
                        continue;
                }
-               if (ctx->image == NULL)
-                       ctx->offset[i] = ctx->idx;
                if (ret)
                        return ret;
        }
+       /*
+        * offset is allocated with prog->len + 1 so fill in
+        * the last element with the offset after the last
+        * instruction (end of program)
+        */
+       if (ctx->image == NULL)
+               ctx->offset[i] = ctx->idx;
 
        return 0;
 }
@@ -1002,7 +1021,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
        memset(&ctx, 0, sizeof(ctx));
        ctx.prog = prog;
 
-       ctx.offset = kcalloc(prog->len, sizeof(int), GFP_KERNEL);
+       ctx.offset = kcalloc(prog->len + 1, sizeof(int), GFP_KERNEL);
        if (ctx.offset == NULL) {
                prog = orig_prog;
                goto out_off;
@@ -1089,7 +1108,7 @@ skip_init_ctx:
        prog->jited_len = prog_size;
 
        if (!prog->is_func || extra_pass) {
-               bpf_prog_fill_jited_linfo(prog, ctx.offset);
+               bpf_prog_fill_jited_linfo(prog, ctx.offset + 1);
 out_off:
                kfree(ctx.offset);
                kfree(jit_data);
index 36770b8..934918d 100644 (file)
@@ -26,6 +26,9 @@ csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
 }
 #define csum_tcpudp_nofold csum_tcpudp_nofold
 
+#define _HAVE_ARCH_CSUM_AND_COPY
+extern __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
+
 #include <asm-generic/checksum.h>
 
 #endif /* _ASM_C6X_CHECKSUM_H */
index e456652..d05c78e 100644 (file)
@@ -220,7 +220,7 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
                        regs->a4 = -EINTR;
                        break;
                }
-       /* fallthrough */
+               fallthrough;
        case -ERESTARTNOINTR:
 do_restart:
                regs->a4 = regs->orig_a4;
@@ -252,7 +252,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs,
                                break;
                        }
 
-                       /* fallthrough */
+                       fallthrough;
                case -ERESTARTNOINTR:
                        regs->a4 = regs->orig_a4;
                        regs->pc -= 4;
index 9c07127..5714886 100644 (file)
@@ -24,7 +24,6 @@
 ENTRY(csum_partial_copy_nocheck)
        MVC     .S2     ILC,B30
 
-       MV      .D1X    B6,A31          ; given csum
        ZERO    .D1     A9              ; csum (a side)
 ||     ZERO    .D2     B9              ; csum (b side)
 ||     SHRU    .S2X    A6,2,B5         ; len / 4
@@ -144,8 +143,7 @@ L91:        SHRU    .S2X    A9,16,B4
        SHRU    .S1     A9,16,A0
    [A0]        BNOP    .S1     L91,5
 
-L10:   ADD     .D1     A31,A9,A9
-       MV      .D1     A9,A4
+L10:   MV      .D1     A9,A4
 
        BNOP    .S2     B3,4
        MVC     .S2     B30,ILC
index f0f733b..589f090 100644 (file)
@@ -404,87 +404,14 @@ int __init arch_populate_kprobe_blacklist(void)
 
 void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address =
-               (unsigned long)&kretprobe_trampoline;
-       kprobe_opcode_t *correct_ret_addr = NULL;
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because multiple functions in the call path have
-        * return probes installed on them, and/or more than one
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always pushed into the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the (chronologically) first instance's ret_addr
-        *       will be the real return address, and all the rest will
-        *       point to kretprobe_trampoline.
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
-       correct_ret_addr = ri->ret_addr;
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               if (ri->rp && ri->rp->handler) {
-                       __this_cpu_write(current_kprobe, &ri->rp->kp);
-                       get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
-                       ri->ret_addr = correct_ret_addr;
-                       ri->rp->handler(ri, regs);
-                       __this_cpu_write(current_kprobe, NULL);
-               }
-
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
-       return (void *)orig_ret_address;
+       return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
 }
 
 void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                      struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *)regs->lr;
+       ri->fp = NULL;
        regs->lr = (unsigned long) &kretprobe_trampoline;
 }
 
index 9452d65..970895d 100644 (file)
@@ -194,7 +194,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
                                regs->a0 = -EINTR;
                                break;
                        }
-                       /* fallthrough */
+                       fallthrough;
                case -ERESTARTNOINTR:
                        regs->a0 = regs->orig_a0;
                        regs->pc -= TRAP0_SIZE;
index f05b413..f03033e 100644 (file)
@@ -109,6 +109,7 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        DISCARDS
 }
index 38d3354..69e6894 100644 (file)
@@ -227,7 +227,7 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka)
                        regs->er0 = -EINTR;
                        break;
                }
-               /* fallthrough */
+               fallthrough;
        case -ERESTARTNOINTR:
 do_restart:
                regs->er0 = regs->orig_er0;
index a5c42f4..4bc6ad9 100644 (file)
 unsigned int do_csum(const void *voidptr, int len);
 
 /*
- * the same as csum_partial, but copies from src while it
- * checksums
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-#define csum_partial_copy_nocheck csum_partial_copy_nocheck
-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                       int len, __wsum sum);
-
-/*
  * computes the checksum of the TCP/UDP pseudo-header
  * returns a 16-bit checksum, already complemented
  */
index cf99fb7..cb3bf19 100644 (file)
@@ -120,7 +120,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
                }
                case R_HEXAGON_HI16:
                        value = (value>>16) & 0xffff;
-                       /* fallthrough */
+                       fallthrough;
                case R_HEXAGON_LO16:
                        *location &= ~0x00c03fff;
                        *location |= value & 0x3fff;
index d48864c..94cc7ff 100644 (file)
@@ -155,7 +155,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
                                regs->r00 = -EINTR;
                                break;
                        }
-                       /* Fall through */
+                       fallthrough;
                case -ERESTARTNOINTR:
                        regs->r06 = regs->syscall_nr;
                        pt_set_elr(regs, pt_elr(regs) - 4);
index 0ca2471..35b18e5 100644 (file)
@@ -67,5 +67,6 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
 }
index c4a6b72..ba50822 100644 (file)
@@ -176,14 +176,3 @@ unsigned int do_csum(const void *voidptr, int len)
 
        return 0xFFFF & sum0;
 }
-
-/*
- * copy from ds while checksumming, otherwise like csum_partial
- */
-__wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
-{
-       memcpy(dst, src, len);
-       return csum_partial(dst, len, sum);
-}
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
index 5b4ec80..996c410 100644 (file)
@@ -56,6 +56,7 @@ config IA64
        select NEED_DMA_MAP_STATE
        select NEED_SG_DMA_LENGTH
        select NUMA if !FLATMEM
+       select PCI_MSI_ARCH_FALLBACKS if PCI_MSI
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
@@ -362,15 +363,6 @@ config ARCH_PROC_KCORE_TEXT
 config IA64_MCA_RECOVERY
        tristate "MCA recovery from errors other than TLB."
 
-config PERFMON
-       bool "Performance monitor support"
-       depends on BROKEN
-       help
-         Selects whether support for the IA-64 performance monitor hardware
-         is included in the kernel.  This makes some kernel data-structures a
-         little bigger and slows down execution a bit, but it is generally
-         a good idea to turn this on.  If you're unsure, say Y.
-
 config IA64_PALINFO
        tristate "/proc/pal support"
        help
index f3ba813..cfed5ed 100644 (file)
@@ -11,7 +11,6 @@ CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_PREEMPT=y
 # CONFIG_VIRTUAL_MEM_MAP is not set
-CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
 CONFIG_EFI_VARS=y
 CONFIG_BINFMT_MISC=m
@@ -27,10 +26,9 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=m
-CONFIG_IDE=m
-CONFIG_BLK_DEV_IDECD=m
-CONFIG_BLK_DEV_GENERIC=m
-CONFIG_BLK_DEV_PIIX=m
+CONFIG_ATA=m
+CONFIG_ATA_GENERIC=m
+CONFIG_ATA_PIIX=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_CONSTANTS=y
index cb267a0..ca0d596 100644 (file)
@@ -18,7 +18,6 @@ CONFIG_IA64_CYCLONE=y
 CONFIG_SMP=y
 CONFIG_HOTPLUG_CPU=y
 CONFIG_IA64_MCA_RECOVERY=y
-CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
 CONFIG_KEXEC=y
 CONFIG_CRASH_DUMP=y
@@ -45,11 +44,10 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_SGI_XP=m
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_CMD64X=y
-CONFIG_BLK_DEV_PIIX=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_CMD64X=y
+CONFIG_ATA_PIIX=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=m
index 7e25f2f..281eb9c 100644 (file)
@@ -17,7 +17,6 @@ CONFIG_NR_CPUS=512
 CONFIG_HOTPLUG_CPU=y
 CONFIG_SPARSEMEM_MANUAL=y
 CONFIG_IA64_MCA_RECOVERY=y
-CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
 CONFIG_EFI_VARS=y
 CONFIG_BINFMT_MISC=m
@@ -36,12 +35,11 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
-CONFIG_IDE=y
+CONFIG_ATA=y
 CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_CMD64X=y
-CONFIG_BLK_DEV_PIIX=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_CMD64X=y
+CONFIG_ATA_PIIX=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
index 3f486d5..b4f9819 100644 (file)
@@ -21,7 +21,6 @@ CONFIG_HOTPLUG_CPU=y
 CONFIG_PERMIT_BSP_REMOVE=y
 CONFIG_FORCE_CPEI_RETARGET=y
 CONFIG_IA64_MCA_RECOVERY=y
-CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
 CONFIG_KEXEC=y
 CONFIG_EFI_VARS=y
@@ -41,11 +40,10 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_CMD64X=y
-CONFIG_BLK_DEV_PIIX=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_CMD64X=y
+CONFIG_ATA_PIIX=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
index 261e98e..629cb9c 100644 (file)
@@ -10,7 +10,6 @@ CONFIG_NR_CPUS=16
 CONFIG_HOTPLUG_CPU=y
 CONFIG_FLATMEM_MANUAL=y
 CONFIG_IA64_MCA_RECOVERY=y
-CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
 CONFIG_CRASH_DUMP=y
 CONFIG_EFI_VARS=y
@@ -26,10 +25,9 @@ CONFIG_IP_MULTICAST=y
 CONFIG_NETFILTER=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_CMD64X=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_CMD64X=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
index b66ba90..87927eb 100644 (file)
@@ -74,8 +74,6 @@ static inline void arch_acpi_set_pdc_bits(u32 *buf)
        buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP;
 }
 
-#define acpi_unlazy_tlb(x)
-
 #ifdef CONFIG_ACPI_NUMA
 extern cpumask_t early_cpu_possible_map;
 #define for_each_possible_early_cpu(cpu)  \
index 2a1c646..f302621 100644 (file)
@@ -37,9 +37,6 @@ extern __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
  */
 extern __wsum csum_partial(const void *buff, int len, __wsum sum);
 
-extern __wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                              int len, __wsum sum);
-
 /*
  * This routine is used for miscellaneous IP-like checksums, mainly in
  * icmp.c
index 95a2ec3..2d8bcdc 100644 (file)
@@ -280,15 +280,6 @@ struct thread_struct {
        __u64 map_base;                 /* base address for get_unmapped_area() */
        __u64 rbs_bot;                  /* the base address for the RBS */
        int last_fph_cpu;               /* CPU that may hold the contents of f32-f127 */
-
-#ifdef CONFIG_PERFMON
-       void *pfm_context;                   /* pointer to detailed PMU context */
-       unsigned long pfm_needs_checking;    /* when >0, pending perfmon work on kernel exit */
-# define INIT_THREAD_PM                .pfm_context =          NULL,     \
-                               .pfm_needs_checking =   0UL,
-#else
-# define INIT_THREAD_PM
-#endif
        unsigned long dbr[IA64_NUM_DBG_REGS];
        unsigned long ibr[IA64_NUM_DBG_REGS];
        struct ia64_fpreg fph[96];      /* saved/loaded on demand */
@@ -301,7 +292,6 @@ struct thread_struct {
        .map_base =     DEFAULT_MAP_BASE,                       \
        .rbs_bot =      STACK_TOP - DEFAULT_USER_STACK_SIZE,    \
        .last_fph_cpu =  -1,                                    \
-       INIT_THREAD_PM                                          \
        .dbr =          {0, },                                  \
        .ibr =          {0, },                                  \
        .fph =          {{{{0}}}, }                             \
index 9011e90..a5a4e09 100644 (file)
@@ -31,16 +31,8 @@ extern struct task_struct *ia64_switch_to (void *next_task);
 extern void ia64_save_extra (struct task_struct *task);
 extern void ia64_load_extra (struct task_struct *task);
 
-#ifdef CONFIG_PERFMON
-  DECLARE_PER_CPU(unsigned long, pfm_syst_info);
-# define PERFMON_IS_SYSWIDE() (__this_cpu_read(pfm_syst_info) & 0x1)
-#else
-# define PERFMON_IS_SYSWIDE() (0)
-#endif
-
 #define IA64_HAS_EXTRA_STATE(t)                                                        \
-       ((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)       \
-        || PERFMON_IS_SYSWIDE())
+       ((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID))
 
 #define __switch_to(prev,next,last) do {                                                        \
        if (IA64_HAS_EXTRA_STATE(prev))                                                          \
index 1a8df66..81901c5 100644 (file)
@@ -10,7 +10,7 @@ endif
 extra-y        := head.o vmlinux.lds
 
 obj-y := entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o     \
-        irq_lsapic.o ivt.o pal.o patch.o process.o perfmon.o ptrace.o sal.o            \
+        irq_lsapic.o ivt.o pal.o patch.o process.o ptrace.o sal.o              \
         salinfo.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
         unwind.o mca.o mca_asm.o topology.o dma-mapping.o iosapic.o acpi.o \
         acpi-ext.o
@@ -21,7 +21,6 @@ obj-$(CONFIG_IA64_PALINFO)    += palinfo.o
 obj-$(CONFIG_MODULES)          += module.o
 obj-$(CONFIG_SMP)              += smp.o smpboot.o
 obj-$(CONFIG_NUMA)             += numa.o
-obj-$(CONFIG_PERFMON)          += perfmon_default_smpl.o
 obj-$(CONFIG_IA64_CYCLONE)     += cyclone.o
 obj-$(CONFIG_IA64_MCA_RECOVERY)        += mca_recovery.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
index bec762a..fec70d6 100644 (file)
@@ -163,7 +163,7 @@ kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data)
                case DIE_INIT_MONARCH_LEAVE:
                        if (!kdump_freeze_monarch)
                                break;
-                       /* fall through */
+                       fallthrough;
                case DIE_INIT_SLAVE_LEAVE:
                case DIE_INIT_MONARCH_ENTER:
                case DIE_MCA_RENDZVOUS_LEAVE:
index b49fe6f..f8150ee 100644 (file)
@@ -3,7 +3,7 @@
  * Architecture-specific kernel symbols
  */
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
+#if defined(CONFIG_VIRTUAL_MEM_MAP) || defined(CONFIG_DISCONTIGMEM)
 #include <linux/compiler.h>
 #include <linux/export.h>
 #include <linux/memblock.h>
index 6fff934..46e33c5 100644 (file)
 #include <asm/hw_irq.h>
 #include <asm/tlbflush.h>
 
-#ifdef CONFIG_PERFMON
-# include <asm/perfmon.h>
-#endif
-
 #define IRQ_DEBUG      0
 
 #define IRQ_VECTOR_UNASSIGNED  (0)
@@ -627,9 +623,6 @@ init_IRQ (void)
                                    "irq_move");
        }
 #endif
-#ifdef CONFIG_PERFMON
-       pfm_init_percpu();
-#endif
 }
 
 void
index 7a7df94..fc1ff8a 100644 (file)
@@ -396,83 +396,9 @@ static void kretprobe_trampoline(void)
 {
 }
 
-/*
- * At this point the target function has been tricked into
- * returning into our trampoline.  Lookup the associated instance
- * and then:
- *    - call the handler function
- *    - cleanup by marking the instance as unused
- *    - long jump back to the original return address
- */
 int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address =
-               ((struct fnptr *)kretprobe_trampoline)->ip;
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because an multiple functions in the call path
-        * have a return probe installed on them, and/or more than one return
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       regs->cr_iip = orig_ret_address;
-
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               if (ri->rp && ri->rp->handler)
-                       ri->rp->handler(ri, regs);
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
+       regs->cr_iip = __kretprobe_trampoline_handler(regs, kretprobe_trampoline, NULL);
        /*
         * By returning a non-zero value, we are telling
         * kprobe_handler() that we don't want the post_handler
@@ -485,6 +411,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                      struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *)regs->b0;
+       ri->fp = NULL;
 
        /* Replace the return addr with trampoline addr */
        regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
index 1a42ba8..00a496c 100644 (file)
@@ -654,7 +654,7 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend,
                                }
                        } else if (!is_internal(mod, val))
                                val = get_plt(mod, location, val, &ok);
-                       /* FALL THROUGH */
+                       fallthrough;
                      default:
                        val -= bundle(location);
                        break;
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
deleted file mode 100644 (file)
index 971f166..0000000
+++ /dev/null
@@ -1,6703 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * This file implements the perfmon-2 subsystem which is used
- * to program the IA-64 Performance Monitoring Unit (PMU).
- *
- * The initial version of perfmon.c was written by
- * Ganesh Venkitachalam, IBM Corp.
- *
- * Then it was modified for perfmon-1.x by Stephane Eranian and
- * David Mosberger, Hewlett Packard Co.
- *
- * Version Perfmon-2.x is a rewrite of perfmon-1.x
- * by Stephane Eranian, Hewlett Packard Co.
- *
- * Copyright (C) 1999-2005  Hewlett Packard Co
- *               Stephane Eranian <eranian@hpl.hp.com>
- *               David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * More information about perfmon available at:
- *     http://www.hpl.hp.com/research/linux/perfmon
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/sched/task.h>
-#include <linux/sched/task_stack.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/sysctl.h>
-#include <linux/list.h>
-#include <linux/file.h>
-#include <linux/poll.h>
-#include <linux/vfs.h>
-#include <linux/smp.h>
-#include <linux/pagemap.h>
-#include <linux/mount.h>
-#include <linux/pseudo_fs.h>
-#include <linux/bitops.h>
-#include <linux/capability.h>
-#include <linux/rcupdate.h>
-#include <linux/completion.h>
-#include <linux/tracehook.h>
-#include <linux/slab.h>
-#include <linux/cpu.h>
-
-#include <asm/errno.h>
-#include <asm/intrinsics.h>
-#include <asm/page.h>
-#include <asm/perfmon.h>
-#include <asm/processor.h>
-#include <asm/signal.h>
-#include <linux/uaccess.h>
-#include <asm/delay.h>
-
-#include "irq.h"
-
-#ifdef CONFIG_PERFMON
-/*
- * perfmon context state
- */
-#define PFM_CTX_UNLOADED       1       /* context is not loaded onto any task */
-#define PFM_CTX_LOADED         2       /* context is loaded onto a task */
-#define PFM_CTX_MASKED         3       /* context is loaded but monitoring is masked due to overflow */
-#define PFM_CTX_ZOMBIE         4       /* owner of the context is closing it */
-
-#define PFM_INVALID_ACTIVATION (~0UL)
-
-#define PFM_NUM_PMC_REGS       64      /* PMC save area for ctxsw */
-#define PFM_NUM_PMD_REGS       64      /* PMD save area for ctxsw */
-
-/*
- * depth of message queue
- */
-#define PFM_MAX_MSGS           32
-#define PFM_CTXQ_EMPTY(g)      ((g)->ctx_msgq_head == (g)->ctx_msgq_tail)
-
-/*
- * type of a PMU register (bitmask).
- * bitmask structure:
- *     bit0   : register implemented
- *     bit1   : end marker
- *     bit2-3 : reserved
- *     bit4   : pmc has pmc.pm
- *     bit5   : pmc controls a counter (has pmc.oi), pmd is used as counter
- *     bit6-7 : register type
- *     bit8-31: reserved
- */
-#define PFM_REG_NOTIMPL                0x0 /* not implemented at all */
-#define PFM_REG_IMPL           0x1 /* register implemented */
-#define PFM_REG_END            0x2 /* end marker */
-#define PFM_REG_MONITOR                (0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */
-#define PFM_REG_COUNTING       (0x2<<4|PFM_REG_MONITOR) /* a monitor + pmc.oi+ PMD used as a counter */
-#define PFM_REG_CONTROL                (0x4<<4|PFM_REG_IMPL) /* PMU control register */
-#define        PFM_REG_CONFIG          (0x8<<4|PFM_REG_IMPL) /* configuration register */
-#define PFM_REG_BUFFER         (0xc<<4|PFM_REG_IMPL) /* PMD used as buffer */
-
-#define PMC_IS_LAST(i) (pmu_conf->pmc_desc[i].type & PFM_REG_END)
-#define PMD_IS_LAST(i) (pmu_conf->pmd_desc[i].type & PFM_REG_END)
-
-#define PMC_OVFL_NOTIFY(ctx, i)        ((ctx)->ctx_pmds[i].flags &  PFM_REGFL_OVFL_NOTIFY)
-
-/* i assumed unsigned */
-#define PMC_IS_IMPL(i)   (i< PMU_MAX_PMCS && (pmu_conf->pmc_desc[i].type & PFM_REG_IMPL))
-#define PMD_IS_IMPL(i)   (i< PMU_MAX_PMDS && (pmu_conf->pmd_desc[i].type & PFM_REG_IMPL))
-
-/* XXX: these assume that register i is implemented */
-#define PMD_IS_COUNTING(i) ((pmu_conf->pmd_desc[i].type & PFM_REG_COUNTING) == PFM_REG_COUNTING)
-#define PMC_IS_COUNTING(i) ((pmu_conf->pmc_desc[i].type & PFM_REG_COUNTING) == PFM_REG_COUNTING)
-#define PMC_IS_MONITOR(i)  ((pmu_conf->pmc_desc[i].type & PFM_REG_MONITOR)  == PFM_REG_MONITOR)
-#define PMC_IS_CONTROL(i)  ((pmu_conf->pmc_desc[i].type & PFM_REG_CONTROL)  == PFM_REG_CONTROL)
-
-#define PMC_DFL_VAL(i)     pmu_conf->pmc_desc[i].default_value
-#define PMC_RSVD_MASK(i)   pmu_conf->pmc_desc[i].reserved_mask
-#define PMD_PMD_DEP(i)    pmu_conf->pmd_desc[i].dep_pmd[0]
-#define PMC_PMD_DEP(i)    pmu_conf->pmc_desc[i].dep_pmd[0]
-
-#define PFM_NUM_IBRS     IA64_NUM_DBG_REGS
-#define PFM_NUM_DBRS     IA64_NUM_DBG_REGS
-
-#define CTX_OVFL_NOBLOCK(c)    ((c)->ctx_fl_block == 0)
-#define CTX_HAS_SMPL(c)                ((c)->ctx_fl_is_sampling)
-#define PFM_CTX_TASK(h)                (h)->ctx_task
-
-#define PMU_PMC_OI             5 /* position of pmc.oi bit */
-
-/* XXX: does not support more than 64 PMDs */
-#define CTX_USED_PMD(ctx, mask) (ctx)->ctx_used_pmds[0] |= (mask)
-#define CTX_IS_USED_PMD(ctx, c) (((ctx)->ctx_used_pmds[0] & (1UL << (c))) != 0UL)
-
-#define CTX_USED_MONITOR(ctx, mask) (ctx)->ctx_used_monitors[0] |= (mask)
-
-#define CTX_USED_IBR(ctx,n)    (ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64)
-#define CTX_USED_DBR(ctx,n)    (ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64)
-#define CTX_USES_DBREGS(ctx)   (((pfm_context_t *)(ctx))->ctx_fl_using_dbreg==1)
-#define PFM_CODE_RR    0       /* requesting code range restriction */
-#define PFM_DATA_RR    1       /* requestion data range restriction */
-
-#define PFM_CPUINFO_CLEAR(v)   pfm_get_cpu_var(pfm_syst_info) &= ~(v)
-#define PFM_CPUINFO_SET(v)     pfm_get_cpu_var(pfm_syst_info) |= (v)
-#define PFM_CPUINFO_GET()      pfm_get_cpu_var(pfm_syst_info)
-
-#define RDEP(x)        (1UL<<(x))
-
-/*
- * context protection macros
- * in SMP:
- *     - we need to protect against CPU concurrency (spin_lock)
- *     - we need to protect against PMU overflow interrupts (local_irq_disable)
- * in UP:
- *     - we need to protect against PMU overflow interrupts (local_irq_disable)
- *
- * spin_lock_irqsave()/spin_unlock_irqrestore():
- *     in SMP: local_irq_disable + spin_lock
- *     in UP : local_irq_disable
- *
- * spin_lock()/spin_lock():
- *     in UP : removed automatically
- *     in SMP: protect against context accesses from other CPU. interrupts
- *             are not masked. This is useful for the PMU interrupt handler
- *             because we know we will not get PMU concurrency in that code.
- */
-#define PROTECT_CTX(c, f) \
-       do {  \
-               DPRINT(("spinlock_irq_save ctx %p by [%d]\n", c, task_pid_nr(current))); \
-               spin_lock_irqsave(&(c)->ctx_lock, f); \
-               DPRINT(("spinlocked ctx %p  by [%d]\n", c, task_pid_nr(current))); \
-       } while(0)
-
-#define UNPROTECT_CTX(c, f) \
-       do { \
-               DPRINT(("spinlock_irq_restore ctx %p by [%d]\n", c, task_pid_nr(current))); \
-               spin_unlock_irqrestore(&(c)->ctx_lock, f); \
-       } while(0)
-
-#define PROTECT_CTX_NOPRINT(c, f) \
-       do {  \
-               spin_lock_irqsave(&(c)->ctx_lock, f); \
-       } while(0)
-
-
-#define UNPROTECT_CTX_NOPRINT(c, f) \
-       do { \
-               spin_unlock_irqrestore(&(c)->ctx_lock, f); \
-       } while(0)
-
-
-#define PROTECT_CTX_NOIRQ(c) \
-       do {  \
-               spin_lock(&(c)->ctx_lock); \
-       } while(0)
-
-#define UNPROTECT_CTX_NOIRQ(c) \
-       do { \
-               spin_unlock(&(c)->ctx_lock); \
-       } while(0)
-
-
-#ifdef CONFIG_SMP
-
-#define GET_ACTIVATION()       pfm_get_cpu_var(pmu_activation_number)
-#define INC_ACTIVATION()       pfm_get_cpu_var(pmu_activation_number)++
-#define SET_ACTIVATION(c)      (c)->ctx_last_activation = GET_ACTIVATION()
-
-#else /* !CONFIG_SMP */
-#define SET_ACTIVATION(t)      do {} while(0)
-#define GET_ACTIVATION(t)      do {} while(0)
-#define INC_ACTIVATION(t)      do {} while(0)
-#endif /* CONFIG_SMP */
-
-#define SET_PMU_OWNER(t, c)    do { pfm_get_cpu_var(pmu_owner) = (t); pfm_get_cpu_var(pmu_ctx) = (c); } while(0)
-#define GET_PMU_OWNER()                pfm_get_cpu_var(pmu_owner)
-#define GET_PMU_CTX()          pfm_get_cpu_var(pmu_ctx)
-
-#define LOCK_PFS(g)            spin_lock_irqsave(&pfm_sessions.pfs_lock, g)
-#define UNLOCK_PFS(g)          spin_unlock_irqrestore(&pfm_sessions.pfs_lock, g)
-
-#define PFM_REG_RETFLAG_SET(flags, val)        do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0)
-
-/*
- * cmp0 must be the value of pmc0
- */
-#define PMC0_HAS_OVFL(cmp0)  (cmp0 & ~0x1UL)
-
-#define PFMFS_MAGIC 0xa0b4d889
-
-/*
- * debugging
- */
-#define PFM_DEBUGGING 1
-#ifdef PFM_DEBUGGING
-#define DPRINT(a) \
-       do { \
-               if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d [%d] ", __func__, __LINE__, smp_processor_id(), task_pid_nr(current)); printk a; } \
-       } while (0)
-
-#define DPRINT_ovfl(a) \
-       do { \
-               if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d [%d] ", __func__, __LINE__, smp_processor_id(), task_pid_nr(current)); printk a; } \
-       } while (0)
-#endif
-
-/*
- * 64-bit software counter structure
- *
- * the next_reset_type is applied to the next call to pfm_reset_regs()
- */
-typedef struct {
-       unsigned long   val;            /* virtual 64bit counter value */
-       unsigned long   lval;           /* last reset value */
-       unsigned long   long_reset;     /* reset value on sampling overflow */
-       unsigned long   short_reset;    /* reset value on overflow */
-       unsigned long   reset_pmds[4];  /* which other pmds to reset when this counter overflows */
-       unsigned long   smpl_pmds[4];   /* which pmds are accessed when counter overflow */
-       unsigned long   seed;           /* seed for random-number generator */
-       unsigned long   mask;           /* mask for random-number generator */
-       unsigned int    flags;          /* notify/do not notify */
-       unsigned long   eventid;        /* overflow event identifier */
-} pfm_counter_t;
-
-/*
- * context flags
- */
-typedef struct {
-       unsigned int block:1;           /* when 1, task will blocked on user notifications */
-       unsigned int system:1;          /* do system wide monitoring */
-       unsigned int using_dbreg:1;     /* using range restrictions (debug registers) */
-       unsigned int is_sampling:1;     /* true if using a custom format */
-       unsigned int excl_idle:1;       /* exclude idle task in system wide session */
-       unsigned int going_zombie:1;    /* context is zombie (MASKED+blocking) */
-       unsigned int trap_reason:2;     /* reason for going into pfm_handle_work() */
-       unsigned int no_msg:1;          /* no message sent on overflow */
-       unsigned int can_restart:1;     /* allowed to issue a PFM_RESTART */
-       unsigned int reserved:22;
-} pfm_context_flags_t;
-
-#define PFM_TRAP_REASON_NONE           0x0     /* default value */
-#define PFM_TRAP_REASON_BLOCK          0x1     /* we need to block on overflow */
-#define PFM_TRAP_REASON_RESET          0x2     /* we need to reset PMDs */
-
-
-/*
- * perfmon context: encapsulates all the state of a monitoring session
- */
-
-typedef struct pfm_context {
-       spinlock_t              ctx_lock;               /* context protection */
-
-       pfm_context_flags_t     ctx_flags;              /* bitmask of flags  (block reason incl.) */
-       unsigned int            ctx_state;              /* state: active/inactive (no bitfield) */
-
-       struct task_struct      *ctx_task;              /* task to which context is attached */
-
-       unsigned long           ctx_ovfl_regs[4];       /* which registers overflowed (notification) */
-
-       struct completion       ctx_restart_done;       /* use for blocking notification mode */
-
-       unsigned long           ctx_used_pmds[4];       /* bitmask of PMD used            */
-       unsigned long           ctx_all_pmds[4];        /* bitmask of all accessible PMDs */
-       unsigned long           ctx_reload_pmds[4];     /* bitmask of force reload PMD on ctxsw in */
-
-       unsigned long           ctx_all_pmcs[4];        /* bitmask of all accessible PMCs */
-       unsigned long           ctx_reload_pmcs[4];     /* bitmask of force reload PMC on ctxsw in */
-       unsigned long           ctx_used_monitors[4];   /* bitmask of monitor PMC being used */
-
-       unsigned long           ctx_pmcs[PFM_NUM_PMC_REGS];     /*  saved copies of PMC values */
-
-       unsigned int            ctx_used_ibrs[1];               /* bitmask of used IBR (speedup ctxsw in) */
-       unsigned int            ctx_used_dbrs[1];               /* bitmask of used DBR (speedup ctxsw in) */
-       unsigned long           ctx_dbrs[IA64_NUM_DBG_REGS];    /* DBR values (cache) when not loaded */
-       unsigned long           ctx_ibrs[IA64_NUM_DBG_REGS];    /* IBR values (cache) when not loaded */
-
-       pfm_counter_t           ctx_pmds[PFM_NUM_PMD_REGS]; /* software state for PMDS */
-
-       unsigned long           th_pmcs[PFM_NUM_PMC_REGS];      /* PMC thread save state */
-       unsigned long           th_pmds[PFM_NUM_PMD_REGS];      /* PMD thread save state */
-
-       unsigned long           ctx_saved_psr_up;       /* only contains psr.up value */
-
-       unsigned long           ctx_last_activation;    /* context last activation number for last_cpu */
-       unsigned int            ctx_last_cpu;           /* CPU id of current or last CPU used (SMP only) */
-       unsigned int            ctx_cpu;                /* cpu to which perfmon is applied (system wide) */
-
-       int                     ctx_fd;                 /* file descriptor used my this context */
-       pfm_ovfl_arg_t          ctx_ovfl_arg;           /* argument to custom buffer format handler */
-
-       pfm_buffer_fmt_t        *ctx_buf_fmt;           /* buffer format callbacks */
-       void                    *ctx_smpl_hdr;          /* points to sampling buffer header kernel vaddr */
-       unsigned long           ctx_smpl_size;          /* size of sampling buffer */
-       void                    *ctx_smpl_vaddr;        /* user level virtual address of smpl buffer */
-
-       wait_queue_head_t       ctx_msgq_wait;
-       pfm_msg_t               ctx_msgq[PFM_MAX_MSGS];
-       int                     ctx_msgq_head;
-       int                     ctx_msgq_tail;
-       struct fasync_struct    *ctx_async_queue;
-
-       wait_queue_head_t       ctx_zombieq;            /* termination cleanup wait queue */
-} pfm_context_t;
-
-/*
- * magic number used to verify that structure is really
- * a perfmon context
- */
-#define PFM_IS_FILE(f)         ((f)->f_op == &pfm_file_ops)
-
-#define PFM_GET_CTX(t)         ((pfm_context_t *)(t)->thread.pfm_context)
-
-#ifdef CONFIG_SMP
-#define SET_LAST_CPU(ctx, v)   (ctx)->ctx_last_cpu = (v)
-#define GET_LAST_CPU(ctx)      (ctx)->ctx_last_cpu
-#else
-#define SET_LAST_CPU(ctx, v)   do {} while(0)
-#define GET_LAST_CPU(ctx)      do {} while(0)
-#endif
-
-
-#define ctx_fl_block           ctx_flags.block
-#define ctx_fl_system          ctx_flags.system
-#define ctx_fl_using_dbreg     ctx_flags.using_dbreg
-#define ctx_fl_is_sampling     ctx_flags.is_sampling
-#define ctx_fl_excl_idle       ctx_flags.excl_idle
-#define ctx_fl_going_zombie    ctx_flags.going_zombie
-#define ctx_fl_trap_reason     ctx_flags.trap_reason
-#define ctx_fl_no_msg          ctx_flags.no_msg
-#define ctx_fl_can_restart     ctx_flags.can_restart
-
-#define PFM_SET_WORK_PENDING(t, v)     do { (t)->thread.pfm_needs_checking = v; } while(0);
-#define PFM_GET_WORK_PENDING(t)                (t)->thread.pfm_needs_checking
-
-/*
- * global information about all sessions
- * mostly used to synchronize between system wide and per-process
- */
-typedef struct {
-       spinlock_t              pfs_lock;                  /* lock the structure */
-
-       unsigned int            pfs_task_sessions;         /* number of per task sessions */
-       unsigned int            pfs_sys_sessions;          /* number of per system wide sessions */
-       unsigned int            pfs_sys_use_dbregs;        /* incremented when a system wide session uses debug regs */
-       unsigned int            pfs_ptrace_use_dbregs;     /* incremented when a process uses debug regs */
-       struct task_struct      *pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */
-} pfm_session_t;
-
-/*
- * information about a PMC or PMD.
- * dep_pmd[]: a bitmask of dependent PMD registers
- * dep_pmc[]: a bitmask of dependent PMC registers
- */
-typedef int (*pfm_reg_check_t)(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
-typedef struct {
-       unsigned int            type;
-       int                     pm_pos;
-       unsigned long           default_value;  /* power-on default value */
-       unsigned long           reserved_mask;  /* bitmask of reserved bits */
-       pfm_reg_check_t         read_check;
-       pfm_reg_check_t         write_check;
-       unsigned long           dep_pmd[4];
-       unsigned long           dep_pmc[4];
-} pfm_reg_desc_t;
-
-/* assume cnum is a valid monitor */
-#define PMC_PM(cnum, val)      (((val) >> (pmu_conf->pmc_desc[cnum].pm_pos)) & 0x1)
-
-/*
- * This structure is initialized at boot time and contains
- * a description of the PMU main characteristics.
- *
- * If the probe function is defined, detection is based
- * on its return value: 
- *     - 0 means recognized PMU
- *     - anything else means not supported
- * When the probe function is not defined, then the pmu_family field
- * is used and it must match the host CPU family such that:
- *     - cpu->family & config->pmu_family != 0
- */
-typedef struct {
-       unsigned long  ovfl_val;        /* overflow value for counters */
-
-       pfm_reg_desc_t *pmc_desc;       /* detailed PMC register dependencies descriptions */
-       pfm_reg_desc_t *pmd_desc;       /* detailed PMD register dependencies descriptions */
-
-       unsigned int   num_pmcs;        /* number of PMCS: computed at init time */
-       unsigned int   num_pmds;        /* number of PMDS: computed at init time */
-       unsigned long  impl_pmcs[4];    /* bitmask of implemented PMCS */
-       unsigned long  impl_pmds[4];    /* bitmask of implemented PMDS */
-
-       char          *pmu_name;        /* PMU family name */
-       unsigned int  pmu_family;       /* cpuid family pattern used to identify pmu */
-       unsigned int  flags;            /* pmu specific flags */
-       unsigned int  num_ibrs;         /* number of IBRS: computed at init time */
-       unsigned int  num_dbrs;         /* number of DBRS: computed at init time */
-       unsigned int  num_counters;     /* PMC/PMD counting pairs : computed at init time */
-       int           (*probe)(void);   /* customized probe routine */
-       unsigned int  use_rr_dbregs:1;  /* set if debug registers used for range restriction */
-} pmu_config_t;
-/*
- * PMU specific flags
- */
-#define PFM_PMU_IRQ_RESEND     1       /* PMU needs explicit IRQ resend */
-
-/*
- * debug register related type definitions
- */
-typedef struct {
-       unsigned long ibr_mask:56;
-       unsigned long ibr_plm:4;
-       unsigned long ibr_ig:3;
-       unsigned long ibr_x:1;
-} ibr_mask_reg_t;
-
-typedef struct {
-       unsigned long dbr_mask:56;
-       unsigned long dbr_plm:4;
-       unsigned long dbr_ig:2;
-       unsigned long dbr_w:1;
-       unsigned long dbr_r:1;
-} dbr_mask_reg_t;
-
-typedef union {
-       unsigned long  val;
-       ibr_mask_reg_t ibr;
-       dbr_mask_reg_t dbr;
-} dbreg_t;
-
-
-/*
- * perfmon command descriptions
- */
-typedef struct {
-       int             (*cmd_func)(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs);
-       char            *cmd_name;
-       int             cmd_flags;
-       unsigned int    cmd_narg;
-       size_t          cmd_argsize;
-       int             (*cmd_getsize)(void *arg, size_t *sz);
-} pfm_cmd_desc_t;
-
-#define PFM_CMD_FD             0x01    /* command requires a file descriptor */
-#define PFM_CMD_ARG_READ       0x02    /* command must read argument(s) */
-#define PFM_CMD_ARG_RW         0x04    /* command must read/write argument(s) */
-#define PFM_CMD_STOP           0x08    /* command does not work on zombie context */
-
-
-#define PFM_CMD_NAME(cmd)      pfm_cmd_tab[(cmd)].cmd_name
-#define PFM_CMD_READ_ARG(cmd)  (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_ARG_READ)
-#define PFM_CMD_RW_ARG(cmd)    (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_ARG_RW)
-#define PFM_CMD_USE_FD(cmd)    (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_FD)
-#define PFM_CMD_STOPPED(cmd)   (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_STOP)
-
-#define PFM_CMD_ARG_MANY       -1 /* cannot be zero */
-
-typedef struct {
-       unsigned long pfm_spurious_ovfl_intr_count;     /* keep track of spurious ovfl interrupts */
-       unsigned long pfm_replay_ovfl_intr_count;       /* keep track of replayed ovfl interrupts */
-       unsigned long pfm_ovfl_intr_count;              /* keep track of ovfl interrupts */
-       unsigned long pfm_ovfl_intr_cycles;             /* cycles spent processing ovfl interrupts */
-       unsigned long pfm_ovfl_intr_cycles_min;         /* min cycles spent processing ovfl interrupts */
-       unsigned long pfm_ovfl_intr_cycles_max;         /* max cycles spent processing ovfl interrupts */
-       unsigned long pfm_smpl_handler_calls;
-       unsigned long pfm_smpl_handler_cycles;
-       char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
-} pfm_stats_t;
-
-/*
- * perfmon internal variables
- */
-static pfm_stats_t             pfm_stats[NR_CPUS];
-static pfm_session_t           pfm_sessions;   /* global sessions information */
-
-static DEFINE_SPINLOCK(pfm_alt_install_check);
-static pfm_intr_handler_desc_t  *pfm_alt_intr_handler;
-
-static struct proc_dir_entry   *perfmon_dir;
-static pfm_uuid_t              pfm_null_uuid = {0,};
-
-static spinlock_t              pfm_buffer_fmt_lock;
-static LIST_HEAD(pfm_buffer_fmt_list);
-
-static pmu_config_t            *pmu_conf;
-
-/* sysctl() controls */
-pfm_sysctl_t pfm_sysctl;
-EXPORT_SYMBOL(pfm_sysctl);
-
-static struct ctl_table pfm_ctl_table[] = {
-       {
-               .procname       = "debug",
-               .data           = &pfm_sysctl.debug,
-               .maxlen         = sizeof(int),
-               .mode           = 0666,
-               .proc_handler   = proc_dointvec,
-       },
-       {
-               .procname       = "debug_ovfl",
-               .data           = &pfm_sysctl.debug_ovfl,
-               .maxlen         = sizeof(int),
-               .mode           = 0666,
-               .proc_handler   = proc_dointvec,
-       },
-       {
-               .procname       = "fastctxsw",
-               .data           = &pfm_sysctl.fastctxsw,
-               .maxlen         = sizeof(int),
-               .mode           = 0600,
-               .proc_handler   = proc_dointvec,
-       },
-       {
-               .procname       = "expert_mode",
-               .data           = &pfm_sysctl.expert_mode,
-               .maxlen         = sizeof(int),
-               .mode           = 0600,
-               .proc_handler   = proc_dointvec,
-       },
-       {}
-};
-static struct ctl_table pfm_sysctl_dir[] = {
-       {
-               .procname       = "perfmon",
-               .mode           = 0555,
-               .child          = pfm_ctl_table,
-       },
-       {}
-};
-static struct ctl_table pfm_sysctl_root[] = {
-       {
-               .procname       = "kernel",
-               .mode           = 0555,
-               .child          = pfm_sysctl_dir,
-       },
-       {}
-};
-static struct ctl_table_header *pfm_sysctl_header;
-
-static int pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs);
-
-#define pfm_get_cpu_var(v)             __ia64_per_cpu_var(v)
-#define pfm_get_cpu_data(a,b)          per_cpu(a, b)
-
-static inline void
-pfm_put_task(struct task_struct *task)
-{
-       if (task != current) put_task_struct(task);
-}
-
-static inline unsigned long
-pfm_protect_ctx_ctxsw(pfm_context_t *x)
-{
-       spin_lock(&(x)->ctx_lock);
-       return 0UL;
-}
-
-static inline void
-pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f)
-{
-       spin_unlock(&(x)->ctx_lock);
-}
-
-/* forward declaration */
-static const struct dentry_operations pfmfs_dentry_operations;
-
-static int pfmfs_init_fs_context(struct fs_context *fc)
-{
-       struct pseudo_fs_context *ctx = init_pseudo(fc, PFMFS_MAGIC);
-       if (!ctx)
-               return -ENOMEM;
-       ctx->dops = &pfmfs_dentry_operations;
-       return 0;
-}
-
-static struct file_system_type pfm_fs_type = {
-       .name                   = "pfmfs",
-       .init_fs_context        = pfmfs_init_fs_context,
-       .kill_sb                = kill_anon_super,
-};
-MODULE_ALIAS_FS("pfmfs");
-
-DEFINE_PER_CPU(unsigned long, pfm_syst_info);
-DEFINE_PER_CPU(struct task_struct *, pmu_owner);
-DEFINE_PER_CPU(pfm_context_t  *, pmu_ctx);
-DEFINE_PER_CPU(unsigned long, pmu_activation_number);
-EXPORT_PER_CPU_SYMBOL_GPL(pfm_syst_info);
-
-
-/* forward declaration */
-static const struct file_operations pfm_file_ops;
-
-/*
- * forward declarations
- */
-#ifndef CONFIG_SMP
-static void pfm_lazy_save_regs (struct task_struct *ta);
-#endif
-
-void dump_pmu_state(const char *);
-static int pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs);
-
-#include "perfmon_itanium.h"
-#include "perfmon_mckinley.h"
-#include "perfmon_montecito.h"
-#include "perfmon_generic.h"
-
-static pmu_config_t *pmu_confs[]={
-       &pmu_conf_mont,
-       &pmu_conf_mck,
-       &pmu_conf_ita,
-       &pmu_conf_gen, /* must be last */
-       NULL
-};
-
-
-static int pfm_end_notify_user(pfm_context_t *ctx);
-
-static inline void
-pfm_clear_psr_pp(void)
-{
-       ia64_rsm(IA64_PSR_PP);
-       ia64_srlz_i();
-}
-
-static inline void
-pfm_set_psr_pp(void)
-{
-       ia64_ssm(IA64_PSR_PP);
-       ia64_srlz_i();
-}
-
-static inline void
-pfm_clear_psr_up(void)
-{
-       ia64_rsm(IA64_PSR_UP);
-       ia64_srlz_i();
-}
-
-static inline void
-pfm_set_psr_up(void)
-{
-       ia64_ssm(IA64_PSR_UP);
-       ia64_srlz_i();
-}
-
-static inline unsigned long
-pfm_get_psr(void)
-{
-       unsigned long tmp;
-       tmp = ia64_getreg(_IA64_REG_PSR);
-       ia64_srlz_i();
-       return tmp;
-}
-
-static inline void
-pfm_set_psr_l(unsigned long val)
-{
-       ia64_setreg(_IA64_REG_PSR_L, val);
-       ia64_srlz_i();
-}
-
-static inline void
-pfm_freeze_pmu(void)
-{
-       ia64_set_pmc(0,1UL);
-       ia64_srlz_d();
-}
-
-static inline void
-pfm_unfreeze_pmu(void)
-{
-       ia64_set_pmc(0,0UL);
-       ia64_srlz_d();
-}
-
-static inline void
-pfm_restore_ibrs(unsigned long *ibrs, unsigned int nibrs)
-{
-       int i;
-
-       for (i=0; i < nibrs; i++) {
-               ia64_set_ibr(i, ibrs[i]);
-               ia64_dv_serialize_instruction();
-       }
-       ia64_srlz_i();
-}
-
-static inline void
-pfm_restore_dbrs(unsigned long *dbrs, unsigned int ndbrs)
-{
-       int i;
-
-       for (i=0; i < ndbrs; i++) {
-               ia64_set_dbr(i, dbrs[i]);
-               ia64_dv_serialize_data();
-       }
-       ia64_srlz_d();
-}
-
-/*
- * PMD[i] must be a counter. no check is made
- */
-static inline unsigned long
-pfm_read_soft_counter(pfm_context_t *ctx, int i)
-{
-       return ctx->ctx_pmds[i].val + (ia64_get_pmd(i) & pmu_conf->ovfl_val);
-}
-
-/*
- * PMD[i] must be a counter. no check is made
- */
-static inline void
-pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val)
-{
-       unsigned long ovfl_val = pmu_conf->ovfl_val;
-
-       ctx->ctx_pmds[i].val = val  & ~ovfl_val;
-       /*
-        * writing to unimplemented part is ignore, so we do not need to
-        * mask off top part
-        */
-       ia64_set_pmd(i, val & ovfl_val);
-}
-
-static pfm_msg_t *
-pfm_get_new_msg(pfm_context_t *ctx)
-{
-       int idx, next;
-
-       next = (ctx->ctx_msgq_tail+1) % PFM_MAX_MSGS;
-
-       DPRINT(("ctx_fd=%p head=%d tail=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail));
-       if (next == ctx->ctx_msgq_head) return NULL;
-
-       idx =   ctx->ctx_msgq_tail;
-       ctx->ctx_msgq_tail = next;
-
-       DPRINT(("ctx=%p head=%d tail=%d msg=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail, idx));
-
-       return ctx->ctx_msgq+idx;
-}
-
-static pfm_msg_t *
-pfm_get_next_msg(pfm_context_t *ctx)
-{
-       pfm_msg_t *msg;
-
-       DPRINT(("ctx=%p head=%d tail=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail));
-
-       if (PFM_CTXQ_EMPTY(ctx)) return NULL;
-
-       /*
-        * get oldest message
-        */
-       msg = ctx->ctx_msgq+ctx->ctx_msgq_head;
-
-       /*
-        * and move forward
-        */
-       ctx->ctx_msgq_head = (ctx->ctx_msgq_head+1) % PFM_MAX_MSGS;
-
-       DPRINT(("ctx=%p head=%d tail=%d type=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail, msg->pfm_gen_msg.msg_type));
-
-       return msg;
-}
-
-static void
-pfm_reset_msgq(pfm_context_t *ctx)
-{
-       ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0;
-       DPRINT(("ctx=%p msgq reset\n", ctx));
-}
-
-static pfm_context_t *
-pfm_context_alloc(int ctx_flags)
-{
-       pfm_context_t *ctx;
-
-       /* 
-        * allocate context descriptor 
-        * must be able to free with interrupts disabled
-        */
-       ctx = kzalloc(sizeof(pfm_context_t), GFP_KERNEL);
-       if (ctx) {
-               DPRINT(("alloc ctx @%p\n", ctx));
-
-               /*
-                * init context protection lock
-                */
-               spin_lock_init(&ctx->ctx_lock);
-
-               /*
-                * context is unloaded
-                */
-               ctx->ctx_state = PFM_CTX_UNLOADED;
-
-               /*
-                * initialization of context's flags
-                */
-               ctx->ctx_fl_block       = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
-               ctx->ctx_fl_system      = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
-               ctx->ctx_fl_no_msg      = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0;
-               /*
-                * will move to set properties
-                * ctx->ctx_fl_excl_idle   = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
-                */
-
-               /*
-                * init restart semaphore to locked
-                */
-               init_completion(&ctx->ctx_restart_done);
-
-               /*
-                * activation is used in SMP only
-                */
-               ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
-               SET_LAST_CPU(ctx, -1);
-
-               /*
-                * initialize notification message queue
-                */
-               ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0;
-               init_waitqueue_head(&ctx->ctx_msgq_wait);
-               init_waitqueue_head(&ctx->ctx_zombieq);
-
-       }
-       return ctx;
-}
-
-static void
-pfm_context_free(pfm_context_t *ctx)
-{
-       if (ctx) {
-               DPRINT(("free ctx @%p\n", ctx));
-               kfree(ctx);
-       }
-}
-
-static void
-pfm_mask_monitoring(struct task_struct *task)
-{
-       pfm_context_t *ctx = PFM_GET_CTX(task);
-       unsigned long mask, val, ovfl_mask;
-       int i;
-
-       DPRINT_ovfl(("masking monitoring for [%d]\n", task_pid_nr(task)));
-
-       ovfl_mask = pmu_conf->ovfl_val;
-       /*
-        * monitoring can only be masked as a result of a valid
-        * counter overflow. In UP, it means that the PMU still
-        * has an owner. Note that the owner can be different
-        * from the current task. However the PMU state belongs
-        * to the owner.
-        * In SMP, a valid overflow only happens when task is
-        * current. Therefore if we come here, we know that
-        * the PMU state belongs to the current task, therefore
-        * we can access the live registers.
-        *
-        * So in both cases, the live register contains the owner's
-        * state. We can ONLY touch the PMU registers and NOT the PSR.
-        *
-        * As a consequence to this call, the ctx->th_pmds[] array
-        * contains stale information which must be ignored
-        * when context is reloaded AND monitoring is active (see
-        * pfm_restart).
-        */
-       mask = ctx->ctx_used_pmds[0];
-       for (i = 0; mask; i++, mask>>=1) {
-               /* skip non used pmds */
-               if ((mask & 0x1) == 0) continue;
-               val = ia64_get_pmd(i);
-
-               if (PMD_IS_COUNTING(i)) {
-                       /*
-                        * we rebuild the full 64 bit value of the counter
-                        */
-                       ctx->ctx_pmds[i].val += (val & ovfl_mask);
-               } else {
-                       ctx->ctx_pmds[i].val = val;
-               }
-               DPRINT_ovfl(("pmd[%d]=0x%lx hw_pmd=0x%lx\n",
-                       i,
-                       ctx->ctx_pmds[i].val,
-                       val & ovfl_mask));
-       }
-       /*
-        * mask monitoring by setting the privilege level to 0
-        * we cannot use psr.pp/psr.up for this, it is controlled by
-        * the user
-        *
-        * if task is current, modify actual registers, otherwise modify
-        * thread save state, i.e., what will be restored in pfm_load_regs()
-        */
-       mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER;
-       for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) {
-               if ((mask & 0x1) == 0UL) continue;
-               ia64_set_pmc(i, ctx->th_pmcs[i] & ~0xfUL);
-               ctx->th_pmcs[i] &= ~0xfUL;
-               DPRINT_ovfl(("pmc[%d]=0x%lx\n", i, ctx->th_pmcs[i]));
-       }
-       /*
-        * make all of this visible
-        */
-       ia64_srlz_d();
-}
-
-/*
- * must always be done with task == current
- *
- * context must be in MASKED state when calling
- */
-static void
-pfm_restore_monitoring(struct task_struct *task)
-{
-       pfm_context_t *ctx = PFM_GET_CTX(task);
-       unsigned long mask, ovfl_mask;
-       unsigned long psr, val;
-       int i, is_system;
-
-       is_system = ctx->ctx_fl_system;
-       ovfl_mask = pmu_conf->ovfl_val;
-
-       if (task != current) {
-               printk(KERN_ERR "perfmon.%d: invalid task[%d] current[%d]\n", __LINE__, task_pid_nr(task), task_pid_nr(current));
-               return;
-       }
-       if (ctx->ctx_state != PFM_CTX_MASKED) {
-               printk(KERN_ERR "perfmon.%d: task[%d] current[%d] invalid state=%d\n", __LINE__,
-                       task_pid_nr(task), task_pid_nr(current), ctx->ctx_state);
-               return;
-       }
-       psr = pfm_get_psr();
-       /*
-        * monitoring is masked via the PMC.
-        * As we restore their value, we do not want each counter to
-        * restart right away. We stop monitoring using the PSR,
-        * restore the PMC (and PMD) and then re-establish the psr
-        * as it was. Note that there can be no pending overflow at
-        * this point, because monitoring was MASKED.
-        *
-        * system-wide session are pinned and self-monitoring
-        */
-       if (is_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) {
-               /* disable dcr pp */
-               ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) & ~IA64_DCR_PP);
-               pfm_clear_psr_pp();
-       } else {
-               pfm_clear_psr_up();
-       }
-       /*
-        * first, we restore the PMD
-        */
-       mask = ctx->ctx_used_pmds[0];
-       for (i = 0; mask; i++, mask>>=1) {
-               /* skip non used pmds */
-               if ((mask & 0x1) == 0) continue;
-
-               if (PMD_IS_COUNTING(i)) {
-                       /*
-                        * we split the 64bit value according to
-                        * counter width
-                        */
-                       val = ctx->ctx_pmds[i].val & ovfl_mask;
-                       ctx->ctx_pmds[i].val &= ~ovfl_mask;
-               } else {
-                       val = ctx->ctx_pmds[i].val;
-               }
-               ia64_set_pmd(i, val);
-
-               DPRINT(("pmd[%d]=0x%lx hw_pmd=0x%lx\n",
-                       i,
-                       ctx->ctx_pmds[i].val,
-                       val));
-       }
-       /*
-        * restore the PMCs
-        */
-       mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER;
-       for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) {
-               if ((mask & 0x1) == 0UL) continue;
-               ctx->th_pmcs[i] = ctx->ctx_pmcs[i];
-               ia64_set_pmc(i, ctx->th_pmcs[i]);
-               DPRINT(("[%d] pmc[%d]=0x%lx\n",
-                                       task_pid_nr(task), i, ctx->th_pmcs[i]));
-       }
-       ia64_srlz_d();
-
-       /*
-        * must restore DBR/IBR because could be modified while masked
-        * XXX: need to optimize 
-        */
-       if (ctx->ctx_fl_using_dbreg) {
-               pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs);
-               pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs);
-       }
-
-       /*
-        * now restore PSR
-        */
-       if (is_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) {
-               /* enable dcr pp */
-               ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) | IA64_DCR_PP);
-               ia64_srlz_i();
-       }
-       pfm_set_psr_l(psr);
-}
-
-static inline void
-pfm_save_pmds(unsigned long *pmds, unsigned long mask)
-{
-       int i;
-
-       ia64_srlz_d();
-
-       for (i=0; mask; i++, mask>>=1) {
-               if (mask & 0x1) pmds[i] = ia64_get_pmd(i);
-       }
-}
-
-/*
- * reload from thread state (used for ctxw only)
- */
-static inline void
-pfm_restore_pmds(unsigned long *pmds, unsigned long mask)
-{
-       int i;
-       unsigned long val, ovfl_val = pmu_conf->ovfl_val;
-
-       for (i=0; mask; i++, mask>>=1) {
-               if ((mask & 0x1) == 0) continue;
-               val = PMD_IS_COUNTING(i) ? pmds[i] & ovfl_val : pmds[i];
-               ia64_set_pmd(i, val);
-       }
-       ia64_srlz_d();
-}
-
-/*
- * propagate PMD from context to thread-state
- */
-static inline void
-pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx)
-{
-       unsigned long ovfl_val = pmu_conf->ovfl_val;
-       unsigned long mask = ctx->ctx_all_pmds[0];
-       unsigned long val;
-       int i;
-
-       DPRINT(("mask=0x%lx\n", mask));
-
-       for (i=0; mask; i++, mask>>=1) {
-
-               val = ctx->ctx_pmds[i].val;
-
-               /*
-                * We break up the 64 bit value into 2 pieces
-                * the lower bits go to the machine state in the
-                * thread (will be reloaded on ctxsw in).
-                * The upper part stays in the soft-counter.
-                */
-               if (PMD_IS_COUNTING(i)) {
-                       ctx->ctx_pmds[i].val = val & ~ovfl_val;
-                        val &= ovfl_val;
-               }
-               ctx->th_pmds[i] = val;
-
-               DPRINT(("pmd[%d]=0x%lx soft_val=0x%lx\n",
-                       i,
-                       ctx->th_pmds[i],
-                       ctx->ctx_pmds[i].val));
-       }
-}
-
-/*
- * propagate PMC from context to thread-state
- */
-static inline void
-pfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx)
-{
-       unsigned long mask = ctx->ctx_all_pmcs[0];
-       int i;
-
-       DPRINT(("mask=0x%lx\n", mask));
-
-       for (i=0; mask; i++, mask>>=1) {
-               /* masking 0 with ovfl_val yields 0 */
-               ctx->th_pmcs[i] = ctx->ctx_pmcs[i];
-               DPRINT(("pmc[%d]=0x%lx\n", i, ctx->th_pmcs[i]));
-       }
-}
-
-
-
-static inline void
-pfm_restore_pmcs(unsigned long *pmcs, unsigned long mask)
-{
-       int i;
-
-       for (i=0; mask; i++, mask>>=1) {
-               if ((mask & 0x1) == 0) continue;
-               ia64_set_pmc(i, pmcs[i]);
-       }
-       ia64_srlz_d();
-}
-
-static inline int
-pfm_uuid_cmp(pfm_uuid_t a, pfm_uuid_t b)
-{
-       return memcmp(a, b, sizeof(pfm_uuid_t));
-}
-
-static inline int
-pfm_buf_fmt_exit(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, struct pt_regs *regs)
-{
-       int ret = 0;
-       if (fmt->fmt_exit) ret = (*fmt->fmt_exit)(task, buf, regs);
-       return ret;
-}
-
-static inline int
-pfm_buf_fmt_getsize(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size)
-{
-       int ret = 0;
-       if (fmt->fmt_getsize) ret = (*fmt->fmt_getsize)(task, flags, cpu, arg, size);
-       return ret;
-}
-
-
-static inline int
-pfm_buf_fmt_validate(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags,
-                    int cpu, void *arg)
-{
-       int ret = 0;
-       if (fmt->fmt_validate) ret = (*fmt->fmt_validate)(task, flags, cpu, arg);
-       return ret;
-}
-
-static inline int
-pfm_buf_fmt_init(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, unsigned int flags,
-                    int cpu, void *arg)
-{
-       int ret = 0;
-       if (fmt->fmt_init) ret = (*fmt->fmt_init)(task, buf, flags, cpu, arg);
-       return ret;
-}
-
-static inline int
-pfm_buf_fmt_restart(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs)
-{
-       int ret = 0;
-       if (fmt->fmt_restart) ret = (*fmt->fmt_restart)(task, ctrl, buf, regs);
-       return ret;
-}
-
-static inline int
-pfm_buf_fmt_restart_active(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs)
-{
-       int ret = 0;
-       if (fmt->fmt_restart_active) ret = (*fmt->fmt_restart_active)(task, ctrl, buf, regs);
-       return ret;
-}
-
-static pfm_buffer_fmt_t *
-__pfm_find_buffer_fmt(pfm_uuid_t uuid)
-{
-       struct list_head * pos;
-       pfm_buffer_fmt_t * entry;
-
-       list_for_each(pos, &pfm_buffer_fmt_list) {
-               entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list);
-               if (pfm_uuid_cmp(uuid, entry->fmt_uuid) == 0)
-                       return entry;
-       }
-       return NULL;
-}
-/*
- * find a buffer format based on its uuid
- */
-static pfm_buffer_fmt_t *
-pfm_find_buffer_fmt(pfm_uuid_t uuid)
-{
-       pfm_buffer_fmt_t * fmt;
-       spin_lock(&pfm_buffer_fmt_lock);
-       fmt = __pfm_find_buffer_fmt(uuid);
-       spin_unlock(&pfm_buffer_fmt_lock);
-       return fmt;
-}
-int
-pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt)
-{
-       int ret = 0;
-
-       /* some sanity checks */
-       if (fmt == NULL || fmt->fmt_name == NULL) return -EINVAL;
-
-       /* we need at least a handler */
-       if (fmt->fmt_handler == NULL) return -EINVAL;
-
-       /*
-        * XXX: need check validity of fmt_arg_size
-        */
-
-       spin_lock(&pfm_buffer_fmt_lock);
-
-       if (__pfm_find_buffer_fmt(fmt->fmt_uuid)) {
-               printk(KERN_ERR "perfmon: duplicate sampling format: %s\n", fmt->fmt_name);
-               ret = -EBUSY;
-               goto out;
-       } 
-       list_add(&fmt->fmt_list, &pfm_buffer_fmt_list);
-       printk(KERN_INFO "perfmon: added sampling format %s\n", fmt->fmt_name);
-
-out:
-       spin_unlock(&pfm_buffer_fmt_lock);
-       return ret;
-}
-EXPORT_SYMBOL(pfm_register_buffer_fmt);
-
-int
-pfm_unregister_buffer_fmt(pfm_uuid_t uuid)
-{
-       pfm_buffer_fmt_t *fmt;
-       int ret = 0;
-
-       spin_lock(&pfm_buffer_fmt_lock);
-
-       fmt = __pfm_find_buffer_fmt(uuid);
-       if (!fmt) {
-               printk(KERN_ERR "perfmon: cannot unregister format, not found\n");
-               ret = -EINVAL;
-               goto out;
-       }
-       list_del_init(&fmt->fmt_list);
-       printk(KERN_INFO "perfmon: removed sampling format: %s\n", fmt->fmt_name);
-
-out:
-       spin_unlock(&pfm_buffer_fmt_lock);
-       return ret;
-
-}
-EXPORT_SYMBOL(pfm_unregister_buffer_fmt);
-
-static int
-pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu)
-{
-       unsigned long flags;
-       /*
-        * validity checks on cpu_mask have been done upstream
-        */
-       LOCK_PFS(flags);
-
-       DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n",
-               pfm_sessions.pfs_sys_sessions,
-               pfm_sessions.pfs_task_sessions,
-               pfm_sessions.pfs_sys_use_dbregs,
-               is_syswide,
-               cpu));
-
-       if (is_syswide) {
-               /*
-                * cannot mix system wide and per-task sessions
-                */
-               if (pfm_sessions.pfs_task_sessions > 0UL) {
-                       DPRINT(("system wide not possible, %u conflicting task_sessions\n",
-                               pfm_sessions.pfs_task_sessions));
-                       goto abort;
-               }
-
-               if (pfm_sessions.pfs_sys_session[cpu]) goto error_conflict;
-
-               DPRINT(("reserving system wide session on CPU%u currently on CPU%u\n", cpu, smp_processor_id()));
-
-               pfm_sessions.pfs_sys_session[cpu] = task;
-
-               pfm_sessions.pfs_sys_sessions++ ;
-
-       } else {
-               if (pfm_sessions.pfs_sys_sessions) goto abort;
-               pfm_sessions.pfs_task_sessions++;
-       }
-
-       DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n",
-               pfm_sessions.pfs_sys_sessions,
-               pfm_sessions.pfs_task_sessions,
-               pfm_sessions.pfs_sys_use_dbregs,
-               is_syswide,
-               cpu));
-
-       /*
-        * Force idle() into poll mode
-        */
-       cpu_idle_poll_ctrl(true);
-
-       UNLOCK_PFS(flags);
-
-       return 0;
-
-error_conflict:
-       DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n",
-               task_pid_nr(pfm_sessions.pfs_sys_session[cpu]),
-               cpu));
-abort:
-       UNLOCK_PFS(flags);
-
-       return -EBUSY;
-
-}
-
-static int
-pfm_unreserve_session(pfm_context_t *ctx, int is_syswide, unsigned int cpu)
-{
-       unsigned long flags;
-       /*
-        * validity checks on cpu_mask have been done upstream
-        */
-       LOCK_PFS(flags);
-
-       DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n",
-               pfm_sessions.pfs_sys_sessions,
-               pfm_sessions.pfs_task_sessions,
-               pfm_sessions.pfs_sys_use_dbregs,
-               is_syswide,
-               cpu));
-
-
-       if (is_syswide) {
-               pfm_sessions.pfs_sys_session[cpu] = NULL;
-               /*
-                * would not work with perfmon+more than one bit in cpu_mask
-                */
-               if (ctx && ctx->ctx_fl_using_dbreg) {
-                       if (pfm_sessions.pfs_sys_use_dbregs == 0) {
-                               printk(KERN_ERR "perfmon: invalid release for ctx %p sys_use_dbregs=0\n", ctx);
-                       } else {
-                               pfm_sessions.pfs_sys_use_dbregs--;
-                       }
-               }
-               pfm_sessions.pfs_sys_sessions--;
-       } else {
-               pfm_sessions.pfs_task_sessions--;
-       }
-       DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n",
-               pfm_sessions.pfs_sys_sessions,
-               pfm_sessions.pfs_task_sessions,
-               pfm_sessions.pfs_sys_use_dbregs,
-               is_syswide,
-               cpu));
-
-       /* Undo forced polling. Last session reenables pal_halt */
-       cpu_idle_poll_ctrl(false);
-
-       UNLOCK_PFS(flags);
-
-       return 0;
-}
-
-/*
- * removes virtual mapping of the sampling buffer.
- * IMPORTANT: cannot be called with interrupts disable, e.g. inside
- * a PROTECT_CTX() section.
- */
-static int
-pfm_remove_smpl_mapping(void *vaddr, unsigned long size)
-{
-       struct task_struct *task = current;
-       int r;
-
-       /* sanity checks */
-       if (task->mm == NULL || size == 0UL || vaddr == NULL) {
-               printk(KERN_ERR "perfmon: pfm_remove_smpl_mapping [%d] invalid context mm=%p\n", task_pid_nr(task), task->mm);
-               return -EINVAL;
-       }
-
-       DPRINT(("smpl_vaddr=%p size=%lu\n", vaddr, size));
-
-       /*
-        * does the actual unmapping
-        */
-       r = vm_munmap((unsigned long)vaddr, size);
-
-       if (r !=0) {
-               printk(KERN_ERR "perfmon: [%d] unable to unmap sampling buffer @%p size=%lu\n", task_pid_nr(task), vaddr, size);
-       }
-
-       DPRINT(("do_unmap(%p, %lu)=%d\n", vaddr, size, r));
-
-       return 0;
-}
-
-/*
- * free actual physical storage used by sampling buffer
- */
-#if 0
-static int
-pfm_free_smpl_buffer(pfm_context_t *ctx)
-{
-       pfm_buffer_fmt_t *fmt;
-
-       if (ctx->ctx_smpl_hdr == NULL) goto invalid_free;
-
-       /*
-        * we won't use the buffer format anymore
-        */
-       fmt = ctx->ctx_buf_fmt;
-
-       DPRINT(("sampling buffer @%p size %lu vaddr=%p\n",
-               ctx->ctx_smpl_hdr,
-               ctx->ctx_smpl_size,
-               ctx->ctx_smpl_vaddr));
-
-       pfm_buf_fmt_exit(fmt, current, NULL, NULL);
-
-       /*
-        * free the buffer
-        */
-       vfree(ctx->ctx_smpl_hdr);
-
-       ctx->ctx_smpl_hdr  = NULL;
-       ctx->ctx_smpl_size = 0UL;
-
-       return 0;
-
-invalid_free:
-       printk(KERN_ERR "perfmon: pfm_free_smpl_buffer [%d] no buffer\n", task_pid_nr(current));
-       return -EINVAL;
-}
-#endif
-
-static inline void
-pfm_exit_smpl_buffer(pfm_buffer_fmt_t *fmt)
-{
-       if (fmt == NULL) return;
-
-       pfm_buf_fmt_exit(fmt, current, NULL, NULL);
-
-}
-
-/*
- * pfmfs should _never_ be mounted by userland - too much of security hassle,
- * no real gain from having the whole whorehouse mounted. So we don't need
- * any operations on the root directory. However, we need a non-trivial
- * d_name - pfm: will go nicely and kill the special-casing in procfs.
- */
-static struct vfsmount *pfmfs_mnt __read_mostly;
-
-static int __init
-init_pfm_fs(void)
-{
-       int err = register_filesystem(&pfm_fs_type);
-       if (!err) {
-               pfmfs_mnt = kern_mount(&pfm_fs_type);
-               err = PTR_ERR(pfmfs_mnt);
-               if (IS_ERR(pfmfs_mnt))
-                       unregister_filesystem(&pfm_fs_type);
-               else
-                       err = 0;
-       }
-       return err;
-}
-
-static ssize_t
-pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
-{
-       pfm_context_t *ctx;
-       pfm_msg_t *msg;
-       ssize_t ret;
-       unsigned long flags;
-       DECLARE_WAITQUEUE(wait, current);
-       if (PFM_IS_FILE(filp) == 0) {
-               printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", task_pid_nr(current));
-               return -EINVAL;
-       }
-
-       ctx = filp->private_data;
-       if (ctx == NULL) {
-               printk(KERN_ERR "perfmon: pfm_read: NULL ctx [%d]\n", task_pid_nr(current));
-               return -EINVAL;
-       }
-
-       /*
-        * check even when there is no message
-        */
-       if (size < sizeof(pfm_msg_t)) {
-               DPRINT(("message is too small ctx=%p (>=%ld)\n", ctx, sizeof(pfm_msg_t)));
-               return -EINVAL;
-       }
-
-       PROTECT_CTX(ctx, flags);
-
-       /*
-        * put ourselves on the wait queue
-        */
-       add_wait_queue(&ctx->ctx_msgq_wait, &wait);
-
-
-       for(;;) {
-               /*
-                * check wait queue
-                */
-
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               DPRINT(("head=%d tail=%d\n", ctx->ctx_msgq_head, ctx->ctx_msgq_tail));
-
-               ret = 0;
-               if(PFM_CTXQ_EMPTY(ctx) == 0) break;
-
-               UNPROTECT_CTX(ctx, flags);
-
-               /*
-                * check non-blocking read
-                */
-               ret = -EAGAIN;
-               if(filp->f_flags & O_NONBLOCK) break;
-
-               /*
-                * check pending signals
-                */
-               if(signal_pending(current)) {
-                       ret = -EINTR;
-                       break;
-               }
-               /*
-                * no message, so wait
-                */
-               schedule();
-
-               PROTECT_CTX(ctx, flags);
-       }
-       DPRINT(("[%d] back to running ret=%ld\n", task_pid_nr(current), ret));
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&ctx->ctx_msgq_wait, &wait);
-
-       if (ret < 0) goto abort;
-
-       ret = -EINVAL;
-       msg = pfm_get_next_msg(ctx);
-       if (msg == NULL) {
-               printk(KERN_ERR "perfmon: pfm_read no msg for ctx=%p [%d]\n", ctx, task_pid_nr(current));
-               goto abort_locked;
-       }
-
-       DPRINT(("fd=%d type=%d\n", msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type));
-
-       ret = -EFAULT;
-       if(copy_to_user(buf, msg, sizeof(pfm_msg_t)) == 0) ret = sizeof(pfm_msg_t);
-
-abort_locked:
-       UNPROTECT_CTX(ctx, flags);
-abort:
-       return ret;
-}
-
-static ssize_t
-pfm_write(struct file *file, const char __user *ubuf,
-                         size_t size, loff_t *ppos)
-{
-       DPRINT(("pfm_write called\n"));
-       return -EINVAL;
-}
-
-static __poll_t
-pfm_poll(struct file *filp, poll_table * wait)
-{
-       pfm_context_t *ctx;
-       unsigned long flags;
-       __poll_t mask = 0;
-
-       if (PFM_IS_FILE(filp) == 0) {
-               printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", task_pid_nr(current));
-               return 0;
-       }
-
-       ctx = filp->private_data;
-       if (ctx == NULL) {
-               printk(KERN_ERR "perfmon: pfm_poll: NULL ctx [%d]\n", task_pid_nr(current));
-               return 0;
-       }
-
-
-       DPRINT(("pfm_poll ctx_fd=%d before poll_wait\n", ctx->ctx_fd));
-
-       poll_wait(filp, &ctx->ctx_msgq_wait, wait);
-
-       PROTECT_CTX(ctx, flags);
-
-       if (PFM_CTXQ_EMPTY(ctx) == 0)
-               mask =  EPOLLIN | EPOLLRDNORM;
-
-       UNPROTECT_CTX(ctx, flags);
-
-       DPRINT(("pfm_poll ctx_fd=%d mask=0x%x\n", ctx->ctx_fd, mask));
-
-       return mask;
-}
-
-static long
-pfm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       DPRINT(("pfm_ioctl called\n"));
-       return -EINVAL;
-}
-
-/*
- * interrupt cannot be masked when coming here
- */
-static inline int
-pfm_do_fasync(int fd, struct file *filp, pfm_context_t *ctx, int on)
-{
-       int ret;
-
-       ret = fasync_helper (fd, filp, on, &ctx->ctx_async_queue);
-
-       DPRINT(("pfm_fasync called by [%d] on ctx_fd=%d on=%d async_queue=%p ret=%d\n",
-               task_pid_nr(current),
-               fd,
-               on,
-               ctx->ctx_async_queue, ret));
-
-       return ret;
-}
-
-static int
-pfm_fasync(int fd, struct file *filp, int on)
-{
-       pfm_context_t *ctx;
-       int ret;
-
-       if (PFM_IS_FILE(filp) == 0) {
-               printk(KERN_ERR "perfmon: pfm_fasync bad magic [%d]\n", task_pid_nr(current));
-               return -EBADF;
-       }
-
-       ctx = filp->private_data;
-       if (ctx == NULL) {
-               printk(KERN_ERR "perfmon: pfm_fasync NULL ctx [%d]\n", task_pid_nr(current));
-               return -EBADF;
-       }
-       /*
-        * we cannot mask interrupts during this call because this may
-        * may go to sleep if memory is not readily avalaible.
-        *
-        * We are protected from the conetxt disappearing by the get_fd()/put_fd()
-        * done in caller. Serialization of this function is ensured by caller.
-        */
-       ret = pfm_do_fasync(fd, filp, ctx, on);
-
-
-       DPRINT(("pfm_fasync called on ctx_fd=%d on=%d async_queue=%p ret=%d\n",
-               fd,
-               on,
-               ctx->ctx_async_queue, ret));
-
-       return ret;
-}
-
-#ifdef CONFIG_SMP
-/*
- * this function is exclusively called from pfm_close().
- * The context is not protected at that time, nor are interrupts
- * on the remote CPU. That's necessary to avoid deadlocks.
- */
-static void
-pfm_syswide_force_stop(void *info)
-{
-       pfm_context_t   *ctx = (pfm_context_t *)info;
-       struct pt_regs *regs = task_pt_regs(current);
-       struct task_struct *owner;
-       unsigned long flags;
-       int ret;
-
-       if (ctx->ctx_cpu != smp_processor_id()) {
-               printk(KERN_ERR "perfmon: pfm_syswide_force_stop for CPU%d  but on CPU%d\n",
-                       ctx->ctx_cpu,
-                       smp_processor_id());
-               return;
-       }
-       owner = GET_PMU_OWNER();
-       if (owner != ctx->ctx_task) {
-               printk(KERN_ERR "perfmon: pfm_syswide_force_stop CPU%d unexpected owner [%d] instead of [%d]\n",
-                       smp_processor_id(),
-                       task_pid_nr(owner), task_pid_nr(ctx->ctx_task));
-               return;
-       }
-       if (GET_PMU_CTX() != ctx) {
-               printk(KERN_ERR "perfmon: pfm_syswide_force_stop CPU%d unexpected ctx %p instead of %p\n",
-                       smp_processor_id(),
-                       GET_PMU_CTX(), ctx);
-               return;
-       }
-
-       DPRINT(("on CPU%d forcing system wide stop for [%d]\n", smp_processor_id(), task_pid_nr(ctx->ctx_task)));
-       /*
-        * the context is already protected in pfm_close(), we simply
-        * need to mask interrupts to avoid a PMU interrupt race on
-        * this CPU
-        */
-       local_irq_save(flags);
-
-       ret = pfm_context_unload(ctx, NULL, 0, regs);
-       if (ret) {
-               DPRINT(("context_unload returned %d\n", ret));
-       }
-
-       /*
-        * unmask interrupts, PMU interrupts are now spurious here
-        */
-       local_irq_restore(flags);
-}
-
-static void
-pfm_syswide_cleanup_other_cpu(pfm_context_t *ctx)
-{
-       int ret;
-
-       DPRINT(("calling CPU%d for cleanup\n", ctx->ctx_cpu));
-       ret = smp_call_function_single(ctx->ctx_cpu, pfm_syswide_force_stop, ctx, 1);
-       DPRINT(("called CPU%d for cleanup ret=%d\n", ctx->ctx_cpu, ret));
-}
-#endif /* CONFIG_SMP */
-
-/*
- * called for each close(). Partially free resources.
- * When caller is self-monitoring, the context is unloaded.
- */
-static int
-pfm_flush(struct file *filp, fl_owner_t id)
-{
-       pfm_context_t *ctx;
-       struct task_struct *task;
-       struct pt_regs *regs;
-       unsigned long flags;
-       unsigned long smpl_buf_size = 0UL;
-       void *smpl_buf_vaddr = NULL;
-       int state, is_system;
-
-       if (PFM_IS_FILE(filp) == 0) {
-               DPRINT(("bad magic for\n"));
-               return -EBADF;
-       }
-
-       ctx = filp->private_data;
-       if (ctx == NULL) {
-               printk(KERN_ERR "perfmon: pfm_flush: NULL ctx [%d]\n", task_pid_nr(current));
-               return -EBADF;
-       }
-
-       /*
-        * remove our file from the async queue, if we use this mode.
-        * This can be done without the context being protected. We come
-        * here when the context has become unreachable by other tasks.
-        *
-        * We may still have active monitoring at this point and we may
-        * end up in pfm_overflow_handler(). However, fasync_helper()
-        * operates with interrupts disabled and it cleans up the
-        * queue. If the PMU handler is called prior to entering
-        * fasync_helper() then it will send a signal. If it is
-        * invoked after, it will find an empty queue and no
-        * signal will be sent. In both case, we are safe
-        */
-       PROTECT_CTX(ctx, flags);
-
-       state     = ctx->ctx_state;
-       is_system = ctx->ctx_fl_system;
-
-       task = PFM_CTX_TASK(ctx);
-       regs = task_pt_regs(task);
-
-       DPRINT(("ctx_state=%d is_current=%d\n",
-               state,
-               task == current ? 1 : 0));
-
-       /*
-        * if state == UNLOADED, then task is NULL
-        */
-
-       /*
-        * we must stop and unload because we are losing access to the context.
-        */
-       if (task == current) {
-#ifdef CONFIG_SMP
-               /*
-                * the task IS the owner but it migrated to another CPU: that's bad
-                * but we must handle this cleanly. Unfortunately, the kernel does
-                * not provide a mechanism to block migration (while the context is loaded).
-                *
-                * We need to release the resource on the ORIGINAL cpu.
-                */
-               if (is_system && ctx->ctx_cpu != smp_processor_id()) {
-
-                       DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu));
-                       /*
-                        * keep context protected but unmask interrupt for IPI
-                        */
-                       local_irq_restore(flags);
-
-                       pfm_syswide_cleanup_other_cpu(ctx);
-
-                       /*
-                        * restore interrupt masking
-                        */
-                       local_irq_save(flags);
-
-                       /*
-                        * context is unloaded at this point
-                        */
-               } else
-#endif /* CONFIG_SMP */
-               {
-
-                       DPRINT(("forcing unload\n"));
-                       /*
-                       * stop and unload, returning with state UNLOADED
-                       * and session unreserved.
-                       */
-                       pfm_context_unload(ctx, NULL, 0, regs);
-
-                       DPRINT(("ctx_state=%d\n", ctx->ctx_state));
-               }
-       }
-
-       /*
-        * remove virtual mapping, if any, for the calling task.
-        * cannot reset ctx field until last user is calling close().
-        *
-        * ctx_smpl_vaddr must never be cleared because it is needed
-        * by every task with access to the context
-        *
-        * When called from do_exit(), the mm context is gone already, therefore
-        * mm is NULL, i.e., the VMA is already gone  and we do not have to
-        * do anything here
-        */
-       if (ctx->ctx_smpl_vaddr && current->mm) {
-               smpl_buf_vaddr = ctx->ctx_smpl_vaddr;
-               smpl_buf_size  = ctx->ctx_smpl_size;
-       }
-
-       UNPROTECT_CTX(ctx, flags);
-
-       /*
-        * if there was a mapping, then we systematically remove it
-        * at this point. Cannot be done inside critical section
-        * because some VM function reenables interrupts.
-        *
-        */
-       if (smpl_buf_vaddr) pfm_remove_smpl_mapping(smpl_buf_vaddr, smpl_buf_size);
-
-       return 0;
-}
-/*
- * called either on explicit close() or from exit_files(). 
- * Only the LAST user of the file gets to this point, i.e., it is
- * called only ONCE.
- *
- * IMPORTANT: we get called ONLY when the refcnt on the file gets to zero 
- * (fput()),i.e, last task to access the file. Nobody else can access the 
- * file at this point.
- *
- * When called from exit_files(), the VMA has been freed because exit_mm()
- * is executed before exit_files().
- *
- * When called from exit_files(), the current task is not yet ZOMBIE but we
- * flush the PMU state to the context. 
- */
-static int
-pfm_close(struct inode *inode, struct file *filp)
-{
-       pfm_context_t *ctx;
-       struct task_struct *task;
-       struct pt_regs *regs;
-       DECLARE_WAITQUEUE(wait, current);
-       unsigned long flags;
-       unsigned long smpl_buf_size = 0UL;
-       void *smpl_buf_addr = NULL;
-       int free_possible = 1;
-       int state, is_system;
-
-       DPRINT(("pfm_close called private=%p\n", filp->private_data));
-
-       if (PFM_IS_FILE(filp) == 0) {
-               DPRINT(("bad magic\n"));
-               return -EBADF;
-       }
-       
-       ctx = filp->private_data;
-       if (ctx == NULL) {
-               printk(KERN_ERR "perfmon: pfm_close: NULL ctx [%d]\n", task_pid_nr(current));
-               return -EBADF;
-       }
-
-       PROTECT_CTX(ctx, flags);
-
-       state     = ctx->ctx_state;
-       is_system = ctx->ctx_fl_system;
-
-       task = PFM_CTX_TASK(ctx);
-       regs = task_pt_regs(task);
-
-       DPRINT(("ctx_state=%d is_current=%d\n", 
-               state,
-               task == current ? 1 : 0));
-
-       /*
-        * if task == current, then pfm_flush() unloaded the context
-        */
-       if (state == PFM_CTX_UNLOADED) goto doit;
-
-       /*
-        * context is loaded/masked and task != current, we need to
-        * either force an unload or go zombie
-        */
-
-       /*
-        * The task is currently blocked or will block after an overflow.
-        * we must force it to wakeup to get out of the
-        * MASKED state and transition to the unloaded state by itself.
-        *
-        * This situation is only possible for per-task mode
-        */
-       if (state == PFM_CTX_MASKED && CTX_OVFL_NOBLOCK(ctx) == 0) {
-
-               /*
-                * set a "partial" zombie state to be checked
-                * upon return from down() in pfm_handle_work().
-                *
-                * We cannot use the ZOMBIE state, because it is checked
-                * by pfm_load_regs() which is called upon wakeup from down().
-                * In such case, it would free the context and then we would
-                * return to pfm_handle_work() which would access the
-                * stale context. Instead, we set a flag invisible to pfm_load_regs()
-                * but visible to pfm_handle_work().
-                *
-                * For some window of time, we have a zombie context with
-                * ctx_state = MASKED  and not ZOMBIE
-                */
-               ctx->ctx_fl_going_zombie = 1;
-
-               /*
-                * force task to wake up from MASKED state
-                */
-               complete(&ctx->ctx_restart_done);
-
-               DPRINT(("waking up ctx_state=%d\n", state));
-
-               /*
-                * put ourself to sleep waiting for the other
-                * task to report completion
-                *
-                * the context is protected by mutex, therefore there
-                * is no risk of being notified of completion before
-                * begin actually on the waitq.
-                */
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&ctx->ctx_zombieq, &wait);
-
-               UNPROTECT_CTX(ctx, flags);
-
-               /*
-                * XXX: check for signals :
-                *      - ok for explicit close
-                *      - not ok when coming from exit_files()
-                */
-               schedule();
-
-
-               PROTECT_CTX(ctx, flags);
-
-
-               remove_wait_queue(&ctx->ctx_zombieq, &wait);
-               set_current_state(TASK_RUNNING);
-
-               /*
-                * context is unloaded at this point
-                */
-               DPRINT(("after zombie wakeup ctx_state=%d for\n", state));
-       }
-       else if (task != current) {
-#ifdef CONFIG_SMP
-               /*
-                * switch context to zombie state
-                */
-               ctx->ctx_state = PFM_CTX_ZOMBIE;
-
-               DPRINT(("zombie ctx for [%d]\n", task_pid_nr(task)));
-               /*
-                * cannot free the context on the spot. deferred until
-                * the task notices the ZOMBIE state
-                */
-               free_possible = 0;
-#else
-               pfm_context_unload(ctx, NULL, 0, regs);
-#endif
-       }
-
-doit:
-       /* reload state, may have changed during  opening of critical section */
-       state = ctx->ctx_state;
-
-       /*
-        * the context is still attached to a task (possibly current)
-        * we cannot destroy it right now
-        */
-
-       /*
-        * we must free the sampling buffer right here because
-        * we cannot rely on it being cleaned up later by the
-        * monitored task. It is not possible to free vmalloc'ed
-        * memory in pfm_load_regs(). Instead, we remove the buffer
-        * now. should there be subsequent PMU overflow originally
-        * meant for sampling, the will be converted to spurious
-        * and that's fine because the monitoring tools is gone anyway.
-        */
-       if (ctx->ctx_smpl_hdr) {
-               smpl_buf_addr = ctx->ctx_smpl_hdr;
-               smpl_buf_size = ctx->ctx_smpl_size;
-               /* no more sampling */
-               ctx->ctx_smpl_hdr = NULL;
-               ctx->ctx_fl_is_sampling = 0;
-       }
-
-       DPRINT(("ctx_state=%d free_possible=%d addr=%p size=%lu\n",
-               state,
-               free_possible,
-               smpl_buf_addr,
-               smpl_buf_size));
-
-       if (smpl_buf_addr) pfm_exit_smpl_buffer(ctx->ctx_buf_fmt);
-
-       /*
-        * UNLOADED that the session has already been unreserved.
-        */
-       if (state == PFM_CTX_ZOMBIE) {
-               pfm_unreserve_session(ctx, ctx->ctx_fl_system , ctx->ctx_cpu);
-       }
-
-       /*
-        * disconnect file descriptor from context must be done
-        * before we unlock.
-        */
-       filp->private_data = NULL;
-
-       /*
-        * if we free on the spot, the context is now completely unreachable
-        * from the callers side. The monitored task side is also cut, so we
-        * can freely cut.
-        *
-        * If we have a deferred free, only the caller side is disconnected.
-        */
-       UNPROTECT_CTX(ctx, flags);
-
-       /*
-        * All memory free operations (especially for vmalloc'ed memory)
-        * MUST be done with interrupts ENABLED.
-        */
-       vfree(smpl_buf_addr);
-
-       /*
-        * return the memory used by the context
-        */
-       if (free_possible) pfm_context_free(ctx);
-
-       return 0;
-}
-
-static const struct file_operations pfm_file_ops = {
-       .llseek         = no_llseek,
-       .read           = pfm_read,
-       .write          = pfm_write,
-       .poll           = pfm_poll,
-       .unlocked_ioctl = pfm_ioctl,
-       .fasync         = pfm_fasync,
-       .release        = pfm_close,
-       .flush          = pfm_flush
-};
-
-static char *pfmfs_dname(struct dentry *dentry, char *buffer, int buflen)
-{
-       return dynamic_dname(dentry, buffer, buflen, "pfm:[%lu]",
-                            d_inode(dentry)->i_ino);
-}
-
-static const struct dentry_operations pfmfs_dentry_operations = {
-       .d_delete = always_delete_dentry,
-       .d_dname = pfmfs_dname,
-};
-
-
-static struct file *
-pfm_alloc_file(pfm_context_t *ctx)
-{
-       struct file *file;
-       struct inode *inode;
-       struct path path;
-       struct qstr this = { .name = "" };
-
-       /*
-        * allocate a new inode
-        */
-       inode = new_inode(pfmfs_mnt->mnt_sb);
-       if (!inode)
-               return ERR_PTR(-ENOMEM);
-
-       DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode));
-
-       inode->i_mode = S_IFCHR|S_IRUGO;
-       inode->i_uid  = current_fsuid();
-       inode->i_gid  = current_fsgid();
-
-       /*
-        * allocate a new dcache entry
-        */
-       path.dentry = d_alloc(pfmfs_mnt->mnt_root, &this);
-       if (!path.dentry) {
-               iput(inode);
-               return ERR_PTR(-ENOMEM);
-       }
-       path.mnt = mntget(pfmfs_mnt);
-
-       d_add(path.dentry, inode);
-
-       file = alloc_file(&path, FMODE_READ, &pfm_file_ops);
-       if (IS_ERR(file)) {
-               path_put(&path);
-               return file;
-       }
-
-       file->f_flags = O_RDONLY;
-       file->private_data = ctx;
-
-       return file;
-}
-
-static int
-pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long addr, unsigned long size)
-{
-       DPRINT(("CPU%d buf=0x%lx addr=0x%lx size=%ld\n", smp_processor_id(), buf, addr, size));
-
-       while (size > 0) {
-               unsigned long pfn = ia64_tpa(buf) >> PAGE_SHIFT;
-
-
-               if (remap_pfn_range(vma, addr, pfn, PAGE_SIZE, PAGE_READONLY))
-                       return -ENOMEM;
-
-               addr  += PAGE_SIZE;
-               buf   += PAGE_SIZE;
-               size  -= PAGE_SIZE;
-       }
-       return 0;
-}
-
-/*
- * allocate a sampling buffer and remaps it into the user address space of the task
- */
-static int
-pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t *ctx, unsigned long rsize, void **user_vaddr)
-{
-       struct mm_struct *mm = task->mm;
-       struct vm_area_struct *vma = NULL;
-       unsigned long size;
-       void *smpl_buf;
-
-
-       /*
-        * the fixed header + requested size and align to page boundary
-        */
-       size = PAGE_ALIGN(rsize);
-
-       DPRINT(("sampling buffer rsize=%lu size=%lu bytes\n", rsize, size));
-
-       /*
-        * check requested size to avoid Denial-of-service attacks
-        * XXX: may have to refine this test
-        * Check against address space limit.
-        *
-        * if ((mm->total_vm << PAGE_SHIFT) + len> task->rlim[RLIMIT_AS].rlim_cur)
-        *      return -ENOMEM;
-        */
-       if (size > task_rlimit(task, RLIMIT_MEMLOCK))
-               return -ENOMEM;
-
-       /*
-        * We do the easy to undo allocations first.
-        */
-       smpl_buf = vzalloc(size);
-       if (smpl_buf == NULL) {
-               DPRINT(("Can't allocate sampling buffer\n"));
-               return -ENOMEM;
-       }
-
-       DPRINT(("smpl_buf @%p\n", smpl_buf));
-
-       /* allocate vma */
-       vma = vm_area_alloc(mm);
-       if (!vma) {
-               DPRINT(("Cannot allocate vma\n"));
-               goto error_kmem;
-       }
-
-       /*
-        * partially initialize the vma for the sampling buffer
-        */
-       vma->vm_file         = get_file(filp);
-       vma->vm_flags        = VM_READ|VM_MAYREAD|VM_DONTEXPAND|VM_DONTDUMP;
-       vma->vm_page_prot    = PAGE_READONLY; /* XXX may need to change */
-
-       /*
-        * Now we have everything we need and we can initialize
-        * and connect all the data structures
-        */
-
-       ctx->ctx_smpl_hdr   = smpl_buf;
-       ctx->ctx_smpl_size  = size; /* aligned size */
-
-       /*
-        * Let's do the difficult operations next.
-        *
-        * now we atomically find some area in the address space and
-        * remap the buffer in it.
-        */
-       mmap_write_lock(task->mm);
-
-       /* find some free area in address space, must have mmap sem held */
-       vma->vm_start = get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS);
-       if (IS_ERR_VALUE(vma->vm_start)) {
-               DPRINT(("Cannot find unmapped area for size %ld\n", size));
-               mmap_write_unlock(task->mm);
-               goto error;
-       }
-       vma->vm_end = vma->vm_start + size;
-       vma->vm_pgoff = vma->vm_start >> PAGE_SHIFT;
-
-       DPRINT(("aligned size=%ld, hdr=%p mapped @0x%lx\n", size, ctx->ctx_smpl_hdr, vma->vm_start));
-
-       /* can only be applied to current task, need to have the mm semaphore held when called */
-       if (pfm_remap_buffer(vma, (unsigned long)smpl_buf, vma->vm_start, size)) {
-               DPRINT(("Can't remap buffer\n"));
-               mmap_write_unlock(task->mm);
-               goto error;
-       }
-
-       /*
-        * now insert the vma in the vm list for the process, must be
-        * done with mmap lock held
-        */
-       insert_vm_struct(mm, vma);
-
-       vm_stat_account(vma->vm_mm, vma->vm_flags, vma_pages(vma));
-       mmap_write_unlock(task->mm);
-
-       /*
-        * keep track of user level virtual address
-        */
-       ctx->ctx_smpl_vaddr = (void *)vma->vm_start;
-       *(unsigned long *)user_vaddr = vma->vm_start;
-
-       return 0;
-
-error:
-       vm_area_free(vma);
-error_kmem:
-       vfree(smpl_buf);
-
-       return -ENOMEM;
-}
-
-/*
- * XXX: do something better here
- */
-static int
-pfm_bad_permissions(struct task_struct *task)
-{
-       const struct cred *tcred;
-       kuid_t uid = current_uid();
-       kgid_t gid = current_gid();
-       int ret;
-
-       rcu_read_lock();
-       tcred = __task_cred(task);
-
-       /* inspired by ptrace_attach() */
-       DPRINT(("cur: uid=%d gid=%d task: euid=%d suid=%d uid=%d egid=%d sgid=%d\n",
-               from_kuid(&init_user_ns, uid),
-               from_kgid(&init_user_ns, gid),
-               from_kuid(&init_user_ns, tcred->euid),
-               from_kuid(&init_user_ns, tcred->suid),
-               from_kuid(&init_user_ns, tcred->uid),
-               from_kgid(&init_user_ns, tcred->egid),
-               from_kgid(&init_user_ns, tcred->sgid)));
-
-       ret = ((!uid_eq(uid, tcred->euid))
-              || (!uid_eq(uid, tcred->suid))
-              || (!uid_eq(uid, tcred->uid))
-              || (!gid_eq(gid, tcred->egid))
-              || (!gid_eq(gid, tcred->sgid))
-              || (!gid_eq(gid, tcred->gid))) && !capable(CAP_SYS_PTRACE);
-
-       rcu_read_unlock();
-       return ret;
-}
-
-static int
-pfarg_is_sane(struct task_struct *task, pfarg_context_t *pfx)
-{
-       int ctx_flags;
-
-       /* valid signal */
-
-       ctx_flags = pfx->ctx_flags;
-
-       if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
-
-               /*
-                * cannot block in this mode
-                */
-               if (ctx_flags & PFM_FL_NOTIFY_BLOCK) {
-                       DPRINT(("cannot use blocking mode when in system wide monitoring\n"));
-                       return -EINVAL;
-               }
-       } else {
-       }
-       /* probably more to add here */
-
-       return 0;
-}
-
-static int
-pfm_setup_buffer_fmt(struct task_struct *task, struct file *filp, pfm_context_t *ctx, unsigned int ctx_flags,
-                    unsigned int cpu, pfarg_context_t *arg)
-{
-       pfm_buffer_fmt_t *fmt = NULL;
-       unsigned long size = 0UL;
-       void *uaddr = NULL;
-       void *fmt_arg = NULL;
-       int ret = 0;
-#define PFM_CTXARG_BUF_ARG(a)  (pfm_buffer_fmt_t *)(a+1)
-
-       /* invoke and lock buffer format, if found */
-       fmt = pfm_find_buffer_fmt(arg->ctx_smpl_buf_id);
-       if (fmt == NULL) {
-               DPRINT(("[%d] cannot find buffer format\n", task_pid_nr(task)));
-               return -EINVAL;
-       }
-
-       /*
-        * buffer argument MUST be contiguous to pfarg_context_t
-        */
-       if (fmt->fmt_arg_size) fmt_arg = PFM_CTXARG_BUF_ARG(arg);
-
-       ret = pfm_buf_fmt_validate(fmt, task, ctx_flags, cpu, fmt_arg);
-
-       DPRINT(("[%d] after validate(0x%x,%d,%p)=%d\n", task_pid_nr(task), ctx_flags, cpu, fmt_arg, ret));
-
-       if (ret) goto error;
-
-       /* link buffer format and context */
-       ctx->ctx_buf_fmt = fmt;
-       ctx->ctx_fl_is_sampling = 1; /* assume record() is defined */
-
-       /*
-        * check if buffer format wants to use perfmon buffer allocation/mapping service
-        */
-       ret = pfm_buf_fmt_getsize(fmt, task, ctx_flags, cpu, fmt_arg, &size);
-       if (ret) goto error;
-
-       if (size) {
-               /*
-                * buffer is always remapped into the caller's address space
-                */
-               ret = pfm_smpl_buffer_alloc(current, filp, ctx, size, &uaddr);
-               if (ret) goto error;
-
-               /* keep track of user address of buffer */
-               arg->ctx_smpl_vaddr = uaddr;
-       }
-       ret = pfm_buf_fmt_init(fmt, task, ctx->ctx_smpl_hdr, ctx_flags, cpu, fmt_arg);
-
-error:
-       return ret;
-}
-
-static void
-pfm_reset_pmu_state(pfm_context_t *ctx)
-{
-       int i;
-
-       /*
-        * install reset values for PMC.
-        */
-       for (i=1; PMC_IS_LAST(i) == 0; i++) {
-               if (PMC_IS_IMPL(i) == 0) continue;
-               ctx->ctx_pmcs[i] = PMC_DFL_VAL(i);
-               DPRINT(("pmc[%d]=0x%lx\n", i, ctx->ctx_pmcs[i]));
-       }
-       /*
-        * PMD registers are set to 0UL when the context in memset()
-        */
-
-       /*
-        * On context switched restore, we must restore ALL pmc and ALL pmd even
-        * when they are not actively used by the task. In UP, the incoming process
-        * may otherwise pick up left over PMC, PMD state from the previous process.
-        * As opposed to PMD, stale PMC can cause harm to the incoming
-        * process because they may change what is being measured.
-        * Therefore, we must systematically reinstall the entire
-        * PMC state. In SMP, the same thing is possible on the
-        * same CPU but also on between 2 CPUs.
-        *
-        * The problem with PMD is information leaking especially
-        * to user level when psr.sp=0
-        *
-        * There is unfortunately no easy way to avoid this problem
-        * on either UP or SMP. This definitively slows down the
-        * pfm_load_regs() function.
-        */
-
-        /*
-         * bitmask of all PMCs accessible to this context
-         *
-         * PMC0 is treated differently.
-         */
-       ctx->ctx_all_pmcs[0] = pmu_conf->impl_pmcs[0] & ~0x1;
-
-       /*
-        * bitmask of all PMDs that are accessible to this context
-        */
-       ctx->ctx_all_pmds[0] = pmu_conf->impl_pmds[0];
-
-       DPRINT(("<%d> all_pmcs=0x%lx all_pmds=0x%lx\n", ctx->ctx_fd, ctx->ctx_all_pmcs[0],ctx->ctx_all_pmds[0]));
-
-       /*
-        * useful in case of re-enable after disable
-        */
-       ctx->ctx_used_ibrs[0] = 0UL;
-       ctx->ctx_used_dbrs[0] = 0UL;
-}
-
-static int
-pfm_ctx_getsize(void *arg, size_t *sz)
-{
-       pfarg_context_t *req = (pfarg_context_t *)arg;
-       pfm_buffer_fmt_t *fmt;
-
-       *sz = 0;
-
-       if (!pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) return 0;
-
-       fmt = pfm_find_buffer_fmt(req->ctx_smpl_buf_id);
-       if (fmt == NULL) {
-               DPRINT(("cannot find buffer format\n"));
-               return -EINVAL;
-       }
-       /* get just enough to copy in user parameters */
-       *sz = fmt->fmt_arg_size;
-       DPRINT(("arg_size=%lu\n", *sz));
-
-       return 0;
-}
-
-
-
-/*
- * cannot attach if :
- *     - kernel task
- *     - task not owned by caller
- *     - task incompatible with context mode
- */
-static int
-pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task)
-{
-       /*
-        * no kernel task or task not owner by caller
-        */
-       if (task->mm == NULL) {
-               DPRINT(("task [%d] has not memory context (kernel thread)\n", task_pid_nr(task)));
-               return -EPERM;
-       }
-       if (pfm_bad_permissions(task)) {
-               DPRINT(("no permission to attach to  [%d]\n", task_pid_nr(task)));
-               return -EPERM;
-       }
-       /*
-        * cannot block in self-monitoring mode
-        */
-       if (CTX_OVFL_NOBLOCK(ctx) == 0 && task == current) {
-               DPRINT(("cannot load a blocking context on self for [%d]\n", task_pid_nr(task)));
-               return -EINVAL;
-       }
-
-       if (task->exit_state == EXIT_ZOMBIE) {
-               DPRINT(("cannot attach to  zombie task [%d]\n", task_pid_nr(task)));
-               return -EBUSY;
-       }
-
-       /*
-        * always ok for self
-        */
-       if (task == current) return 0;
-
-       if (!task_is_stopped_or_traced(task)) {
-               DPRINT(("cannot attach to non-stopped task [%d] state=%ld\n", task_pid_nr(task), task->state));
-               return -EBUSY;
-       }
-       /*
-        * make sure the task is off any CPU
-        */
-       wait_task_inactive(task, 0);
-
-       /* more to come... */
-
-       return 0;
-}
-
-static int
-pfm_get_task(pfm_context_t *ctx, pid_t pid, struct task_struct **task)
-{
-       struct task_struct *p = current;
-       int ret;
-
-       /* XXX: need to add more checks here */
-       if (pid < 2) return -EPERM;
-
-       if (pid != task_pid_vnr(current)) {
-               /* make sure task cannot go away while we operate on it */
-               p = find_get_task_by_vpid(pid);
-               if (!p)
-                       return -ESRCH;
-       }
-
-       ret = pfm_task_incompatible(ctx, p);
-       if (ret == 0) {
-               *task = p;
-       } else if (p != current) {
-               pfm_put_task(p);
-       }
-       return ret;
-}
-
-
-
-static int
-pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       pfarg_context_t *req = (pfarg_context_t *)arg;
-       struct file *filp;
-       struct path path;
-       int ctx_flags;
-       int fd;
-       int ret;
-
-       /* let's check the arguments first */
-       ret = pfarg_is_sane(current, req);
-       if (ret < 0)
-               return ret;
-
-       ctx_flags = req->ctx_flags;
-
-       ret = -ENOMEM;
-
-       fd = get_unused_fd_flags(0);
-       if (fd < 0)
-               return fd;
-
-       ctx = pfm_context_alloc(ctx_flags);
-       if (!ctx)
-               goto error;
-
-       filp = pfm_alloc_file(ctx);
-       if (IS_ERR(filp)) {
-               ret = PTR_ERR(filp);
-               goto error_file;
-       }
-
-       req->ctx_fd = ctx->ctx_fd = fd;
-
-       /*
-        * does the user want to sample?
-        */
-       if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) {
-               ret = pfm_setup_buffer_fmt(current, filp, ctx, ctx_flags, 0, req);
-               if (ret)
-                       goto buffer_error;
-       }
-
-       DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d\n",
-               ctx,
-               ctx_flags,
-               ctx->ctx_fl_system,
-               ctx->ctx_fl_block,
-               ctx->ctx_fl_excl_idle,
-               ctx->ctx_fl_no_msg,
-               ctx->ctx_fd));
-
-       /*
-        * initialize soft PMU state
-        */
-       pfm_reset_pmu_state(ctx);
-
-       fd_install(fd, filp);
-
-       return 0;
-
-buffer_error:
-       path = filp->f_path;
-       put_filp(filp);
-       path_put(&path);
-
-       if (ctx->ctx_buf_fmt) {
-               pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs);
-       }
-error_file:
-       pfm_context_free(ctx);
-
-error:
-       put_unused_fd(fd);
-       return ret;
-}
-
-static inline unsigned long
-pfm_new_counter_value (pfm_counter_t *reg, int is_long_reset)
-{
-       unsigned long val = is_long_reset ? reg->long_reset : reg->short_reset;
-       unsigned long new_seed, old_seed = reg->seed, mask = reg->mask;
-       extern unsigned long carta_random32 (unsigned long seed);
-
-       if (reg->flags & PFM_REGFL_RANDOM) {
-               new_seed = carta_random32(old_seed);
-               val -= (old_seed & mask);       /* counter values are negative numbers! */
-               if ((mask >> 32) != 0)
-                       /* construct a full 64-bit random value: */
-                       new_seed |= carta_random32(old_seed >> 32) << 32;
-               reg->seed = new_seed;
-       }
-       reg->lval = val;
-       return val;
-}
-
-static void
-pfm_reset_regs_masked(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset)
-{
-       unsigned long mask = ovfl_regs[0];
-       unsigned long reset_others = 0UL;
-       unsigned long val;
-       int i;
-
-       /*
-        * now restore reset value on sampling overflowed counters
-        */
-       mask >>= PMU_FIRST_COUNTER;
-       for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) {
-
-               if ((mask & 0x1UL) == 0UL) continue;
-
-               ctx->ctx_pmds[i].val = val = pfm_new_counter_value(ctx->ctx_pmds+ i, is_long_reset);
-               reset_others        |= ctx->ctx_pmds[i].reset_pmds[0];
-
-               DPRINT_ovfl((" %s reset ctx_pmds[%d]=%lx\n", is_long_reset ? "long" : "short", i, val));
-       }
-
-       /*
-        * Now take care of resetting the other registers
-        */
-       for(i = 0; reset_others; i++, reset_others >>= 1) {
-
-               if ((reset_others & 0x1) == 0) continue;
-
-               ctx->ctx_pmds[i].val = val = pfm_new_counter_value(ctx->ctx_pmds + i, is_long_reset);
-
-               DPRINT_ovfl(("%s reset_others pmd[%d]=%lx\n",
-                         is_long_reset ? "long" : "short", i, val));
-       }
-}
-
-static void
-pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset)
-{
-       unsigned long mask = ovfl_regs[0];
-       unsigned long reset_others = 0UL;
-       unsigned long val;
-       int i;
-
-       DPRINT_ovfl(("ovfl_regs=0x%lx is_long_reset=%d\n", ovfl_regs[0], is_long_reset));
-
-       if (ctx->ctx_state == PFM_CTX_MASKED) {
-               pfm_reset_regs_masked(ctx, ovfl_regs, is_long_reset);
-               return;
-       }
-
-       /*
-        * now restore reset value on sampling overflowed counters
-        */
-       mask >>= PMU_FIRST_COUNTER;
-       for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) {
-
-               if ((mask & 0x1UL) == 0UL) continue;
-
-               val           = pfm_new_counter_value(ctx->ctx_pmds+ i, is_long_reset);
-               reset_others |= ctx->ctx_pmds[i].reset_pmds[0];
-
-               DPRINT_ovfl((" %s reset ctx_pmds[%d]=%lx\n", is_long_reset ? "long" : "short", i, val));
-
-               pfm_write_soft_counter(ctx, i, val);
-       }
-
-       /*
-        * Now take care of resetting the other registers
-        */
-       for(i = 0; reset_others; i++, reset_others >>= 1) {
-
-               if ((reset_others & 0x1) == 0) continue;
-
-               val = pfm_new_counter_value(ctx->ctx_pmds + i, is_long_reset);
-
-               if (PMD_IS_COUNTING(i)) {
-                       pfm_write_soft_counter(ctx, i, val);
-               } else {
-                       ia64_set_pmd(i, val);
-               }
-               DPRINT_ovfl(("%s reset_others pmd[%d]=%lx\n",
-                         is_long_reset ? "long" : "short", i, val));
-       }
-       ia64_srlz_d();
-}
-
-static int
-pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       struct task_struct *task;
-       pfarg_reg_t *req = (pfarg_reg_t *)arg;
-       unsigned long value, pmc_pm;
-       unsigned long smpl_pmds, reset_pmds, impl_pmds;
-       unsigned int cnum, reg_flags, flags, pmc_type;
-       int i, can_access_pmu = 0, is_loaded, is_system, expert_mode;
-       int is_monitor, is_counting, state;
-       int ret = -EINVAL;
-       pfm_reg_check_t wr_func;
-#define PFM_CHECK_PMC_PM(x, y, z) ((x)->ctx_fl_system ^ PMC_PM(y, z))
-
-       state     = ctx->ctx_state;
-       is_loaded = state == PFM_CTX_LOADED ? 1 : 0;
-       is_system = ctx->ctx_fl_system;
-       task      = ctx->ctx_task;
-       impl_pmds = pmu_conf->impl_pmds[0];
-
-       if (state == PFM_CTX_ZOMBIE) return -EINVAL;
-
-       if (is_loaded) {
-               /*
-                * In system wide and when the context is loaded, access can only happen
-                * when the caller is running on the CPU being monitored by the session.
-                * It does not have to be the owner (ctx_task) of the context per se.
-                */
-               if (is_system && ctx->ctx_cpu != smp_processor_id()) {
-                       DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu));
-                       return -EBUSY;
-               }
-               can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0;
-       }
-       expert_mode = pfm_sysctl.expert_mode; 
-
-       for (i = 0; i < count; i++, req++) {
-
-               cnum       = req->reg_num;
-               reg_flags  = req->reg_flags;
-               value      = req->reg_value;
-               smpl_pmds  = req->reg_smpl_pmds[0];
-               reset_pmds = req->reg_reset_pmds[0];
-               flags      = 0;
-
-
-               if (cnum >= PMU_MAX_PMCS) {
-                       DPRINT(("pmc%u is invalid\n", cnum));
-                       goto error;
-               }
-
-               pmc_type   = pmu_conf->pmc_desc[cnum].type;
-               pmc_pm     = (value >> pmu_conf->pmc_desc[cnum].pm_pos) & 0x1;
-               is_counting = (pmc_type & PFM_REG_COUNTING) == PFM_REG_COUNTING ? 1 : 0;
-               is_monitor  = (pmc_type & PFM_REG_MONITOR) == PFM_REG_MONITOR ? 1 : 0;
-
-               /*
-                * we reject all non implemented PMC as well
-                * as attempts to modify PMC[0-3] which are used
-                * as status registers by the PMU
-                */
-               if ((pmc_type & PFM_REG_IMPL) == 0 || (pmc_type & PFM_REG_CONTROL) == PFM_REG_CONTROL) {
-                       DPRINT(("pmc%u is unimplemented or no-access pmc_type=%x\n", cnum, pmc_type));
-                       goto error;
-               }
-               wr_func = pmu_conf->pmc_desc[cnum].write_check;
-               /*
-                * If the PMC is a monitor, then if the value is not the default:
-                *      - system-wide session: PMCx.pm=1 (privileged monitor)
-                *      - per-task           : PMCx.pm=0 (user monitor)
-                */
-               if (is_monitor && value != PMC_DFL_VAL(cnum) && is_system ^ pmc_pm) {
-                       DPRINT(("pmc%u pmc_pm=%lu is_system=%d\n",
-                               cnum,
-                               pmc_pm,
-                               is_system));
-                       goto error;
-               }
-
-               if (is_counting) {
-                       /*
-                        * enforce generation of overflow interrupt. Necessary on all
-                        * CPUs.
-                        */
-                       value |= 1 << PMU_PMC_OI;
-
-                       if (reg_flags & PFM_REGFL_OVFL_NOTIFY) {
-                               flags |= PFM_REGFL_OVFL_NOTIFY;
-                       }
-
-                       if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM;
-
-                       /* verify validity of smpl_pmds */
-                       if ((smpl_pmds & impl_pmds) != smpl_pmds) {
-                               DPRINT(("invalid smpl_pmds 0x%lx for pmc%u\n", smpl_pmds, cnum));
-                               goto error;
-                       }
-
-                       /* verify validity of reset_pmds */
-                       if ((reset_pmds & impl_pmds) != reset_pmds) {
-                               DPRINT(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum));
-                               goto error;
-                       }
-               } else {
-                       if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) {
-                               DPRINT(("cannot set ovfl_notify or random on pmc%u\n", cnum));
-                               goto error;
-                       }
-                       /* eventid on non-counting monitors are ignored */
-               }
-
-               /*
-                * execute write checker, if any
-                */
-               if (likely(expert_mode == 0 && wr_func)) {
-                       ret = (*wr_func)(task, ctx, cnum, &value, regs);
-                       if (ret) goto error;
-                       ret = -EINVAL;
-               }
-
-               /*
-                * no error on this register
-                */
-               PFM_REG_RETFLAG_SET(req->reg_flags, 0);
-
-               /*
-                * Now we commit the changes to the software state
-                */
-
-               /*
-                * update overflow information
-                */
-               if (is_counting) {
-                       /*
-                        * full flag update each time a register is programmed
-                        */
-                       ctx->ctx_pmds[cnum].flags = flags;
-
-                       ctx->ctx_pmds[cnum].reset_pmds[0] = reset_pmds;
-                       ctx->ctx_pmds[cnum].smpl_pmds[0]  = smpl_pmds;
-                       ctx->ctx_pmds[cnum].eventid       = req->reg_smpl_eventid;
-
-                       /*
-                        * Mark all PMDS to be accessed as used.
-                        *
-                        * We do not keep track of PMC because we have to
-                        * systematically restore ALL of them.
-                        *
-                        * We do not update the used_monitors mask, because
-                        * if we have not programmed them, then will be in
-                        * a quiescent state, therefore we will not need to
-                        * mask/restore then when context is MASKED.
-                        */
-                       CTX_USED_PMD(ctx, reset_pmds);
-                       CTX_USED_PMD(ctx, smpl_pmds);
-                       /*
-                        * make sure we do not try to reset on
-                        * restart because we have established new values
-                        */
-                       if (state == PFM_CTX_MASKED) ctx->ctx_ovfl_regs[0] &= ~1UL << cnum;
-               }
-               /*
-                * Needed in case the user does not initialize the equivalent
-                * PMD. Clearing is done indirectly via pfm_reset_pmu_state() so there is no
-                * possible leak here.
-                */
-               CTX_USED_PMD(ctx, pmu_conf->pmc_desc[cnum].dep_pmd[0]);
-
-               /*
-                * keep track of the monitor PMC that we are using.
-                * we save the value of the pmc in ctx_pmcs[] and if
-                * the monitoring is not stopped for the context we also
-                * place it in the saved state area so that it will be
-                * picked up later by the context switch code.
-                *
-                * The value in ctx_pmcs[] can only be changed in pfm_write_pmcs().
-                *
-                * The value in th_pmcs[] may be modified on overflow, i.e.,  when
-                * monitoring needs to be stopped.
-                */
-               if (is_monitor) CTX_USED_MONITOR(ctx, 1UL << cnum);
-
-               /*
-                * update context state
-                */
-               ctx->ctx_pmcs[cnum] = value;
-
-               if (is_loaded) {
-                       /*
-                        * write thread state
-                        */
-                       if (is_system == 0) ctx->th_pmcs[cnum] = value;
-
-                       /*
-                        * write hardware register if we can
-                        */
-                       if (can_access_pmu) {
-                               ia64_set_pmc(cnum, value);
-                       }
-#ifdef CONFIG_SMP
-                       else {
-                               /*
-                                * per-task SMP only here
-                                *
-                                * we are guaranteed that the task is not running on the other CPU,
-                                * we indicate that this PMD will need to be reloaded if the task
-                                * is rescheduled on the CPU it ran last on.
-                                */
-                               ctx->ctx_reload_pmcs[0] |= 1UL << cnum;
-                       }
-#endif
-               }
-
-               DPRINT(("pmc[%u]=0x%lx ld=%d apmu=%d flags=0x%x all_pmcs=0x%lx used_pmds=0x%lx eventid=%ld smpl_pmds=0x%lx reset_pmds=0x%lx reloads_pmcs=0x%lx used_monitors=0x%lx ovfl_regs=0x%lx\n",
-                         cnum,
-                         value,
-                         is_loaded,
-                         can_access_pmu,
-                         flags,
-                         ctx->ctx_all_pmcs[0],
-                         ctx->ctx_used_pmds[0],
-                         ctx->ctx_pmds[cnum].eventid,
-                         smpl_pmds,
-                         reset_pmds,
-                         ctx->ctx_reload_pmcs[0],
-                         ctx->ctx_used_monitors[0],
-                         ctx->ctx_ovfl_regs[0]));
-       }
-
-       /*
-        * make sure the changes are visible
-        */
-       if (can_access_pmu) ia64_srlz_d();
-
-       return 0;
-error:
-       PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL);
-       return ret;
-}
-
-static int
-pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       struct task_struct *task;
-       pfarg_reg_t *req = (pfarg_reg_t *)arg;
-       unsigned long value, hw_value, ovfl_mask;
-       unsigned int cnum;
-       int i, can_access_pmu = 0, state;
-       int is_counting, is_loaded, is_system, expert_mode;
-       int ret = -EINVAL;
-       pfm_reg_check_t wr_func;
-
-
-       state     = ctx->ctx_state;
-       is_loaded = state == PFM_CTX_LOADED ? 1 : 0;
-       is_system = ctx->ctx_fl_system;
-       ovfl_mask = pmu_conf->ovfl_val;
-       task      = ctx->ctx_task;
-
-       if (unlikely(state == PFM_CTX_ZOMBIE)) return -EINVAL;
-
-       /*
-        * on both UP and SMP, we can only write to the PMC when the task is
-        * the owner of the local PMU.
-        */
-       if (likely(is_loaded)) {
-               /*
-                * In system wide and when the context is loaded, access can only happen
-                * when the caller is running on the CPU being monitored by the session.
-                * It does not have to be the owner (ctx_task) of the context per se.
-                */
-               if (unlikely(is_system && ctx->ctx_cpu != smp_processor_id())) {
-                       DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu));
-                       return -EBUSY;
-               }
-               can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0;
-       }
-       expert_mode = pfm_sysctl.expert_mode; 
-
-       for (i = 0; i < count; i++, req++) {
-
-               cnum  = req->reg_num;
-               value = req->reg_value;
-
-               if (!PMD_IS_IMPL(cnum)) {
-                       DPRINT(("pmd[%u] is unimplemented or invalid\n", cnum));
-                       goto abort_mission;
-               }
-               is_counting = PMD_IS_COUNTING(cnum);
-               wr_func     = pmu_conf->pmd_desc[cnum].write_check;
-
-               /*
-                * execute write checker, if any
-                */
-               if (unlikely(expert_mode == 0 && wr_func)) {
-                       unsigned long v = value;
-
-                       ret = (*wr_func)(task, ctx, cnum, &v, regs);
-                       if (ret) goto abort_mission;
-
-                       value = v;
-                       ret   = -EINVAL;
-               }
-
-               /*
-                * no error on this register
-                */
-               PFM_REG_RETFLAG_SET(req->reg_flags, 0);
-
-               /*
-                * now commit changes to software state
-                */
-               hw_value = value;
-
-               /*
-                * update virtualized (64bits) counter
-                */
-               if (is_counting) {
-                       /*
-                        * write context state
-                        */
-                       ctx->ctx_pmds[cnum].lval = value;
-
-                       /*
-                        * when context is load we use the split value
-                        */
-                       if (is_loaded) {
-                               hw_value = value &  ovfl_mask;
-                               value    = value & ~ovfl_mask;
-                       }
-               }
-               /*
-                * update reset values (not just for counters)
-                */
-               ctx->ctx_pmds[cnum].long_reset  = req->reg_long_reset;
-               ctx->ctx_pmds[cnum].short_reset = req->reg_short_reset;
-
-               /*
-                * update randomization parameters (not just for counters)
-                */
-               ctx->ctx_pmds[cnum].seed = req->reg_random_seed;
-               ctx->ctx_pmds[cnum].mask = req->reg_random_mask;
-
-               /*
-                * update context value
-                */
-               ctx->ctx_pmds[cnum].val  = value;
-
-               /*
-                * Keep track of what we use
-                *
-                * We do not keep track of PMC because we have to
-                * systematically restore ALL of them.
-                */
-               CTX_USED_PMD(ctx, PMD_PMD_DEP(cnum));
-
-               /*
-                * mark this PMD register used as well
-                */
-               CTX_USED_PMD(ctx, RDEP(cnum));
-
-               /*
-                * make sure we do not try to reset on
-                * restart because we have established new values
-                */
-               if (is_counting && state == PFM_CTX_MASKED) {
-                       ctx->ctx_ovfl_regs[0] &= ~1UL << cnum;
-               }
-
-               if (is_loaded) {
-                       /*
-                        * write thread state
-                        */
-                       if (is_system == 0) ctx->th_pmds[cnum] = hw_value;
-
-                       /*
-                        * write hardware register if we can
-                        */
-                       if (can_access_pmu) {
-                               ia64_set_pmd(cnum, hw_value);
-                       } else {
-#ifdef CONFIG_SMP
-                               /*
-                                * we are guaranteed that the task is not running on the other CPU,
-                                * we indicate that this PMD will need to be reloaded if the task
-                                * is rescheduled on the CPU it ran last on.
-                                */
-                               ctx->ctx_reload_pmds[0] |= 1UL << cnum;
-#endif
-                       }
-               }
-
-               DPRINT(("pmd[%u]=0x%lx ld=%d apmu=%d, hw_value=0x%lx ctx_pmd=0x%lx  short_reset=0x%lx "
-                         "long_reset=0x%lx notify=%c seed=0x%lx mask=0x%lx used_pmds=0x%lx reset_pmds=0x%lx reload_pmds=0x%lx all_pmds=0x%lx ovfl_regs=0x%lx\n",
-                       cnum,
-                       value,
-                       is_loaded,
-                       can_access_pmu,
-                       hw_value,
-                       ctx->ctx_pmds[cnum].val,
-                       ctx->ctx_pmds[cnum].short_reset,
-                       ctx->ctx_pmds[cnum].long_reset,
-                       PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N',
-                       ctx->ctx_pmds[cnum].seed,
-                       ctx->ctx_pmds[cnum].mask,
-                       ctx->ctx_used_pmds[0],
-                       ctx->ctx_pmds[cnum].reset_pmds[0],
-                       ctx->ctx_reload_pmds[0],
-                       ctx->ctx_all_pmds[0],
-                       ctx->ctx_ovfl_regs[0]));
-       }
-
-       /*
-        * make changes visible
-        */
-       if (can_access_pmu) ia64_srlz_d();
-
-       return 0;
-
-abort_mission:
-       /*
-        * for now, we have only one possibility for error
-        */
-       PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL);
-       return ret;
-}
-
-/*
- * By the way of PROTECT_CONTEXT(), interrupts are masked while we are in this function.
- * Therefore we know, we do not have to worry about the PMU overflow interrupt. If an
- * interrupt is delivered during the call, it will be kept pending until we leave, making
- * it appears as if it had been generated at the UNPROTECT_CONTEXT(). At least we are
- * guaranteed to return consistent data to the user, it may simply be old. It is not
- * trivial to treat the overflow while inside the call because you may end up in
- * some module sampling buffer code causing deadlocks.
- */
-static int
-pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       struct task_struct *task;
-       unsigned long val = 0UL, lval, ovfl_mask, sval;
-       pfarg_reg_t *req = (pfarg_reg_t *)arg;
-       unsigned int cnum, reg_flags = 0;
-       int i, can_access_pmu = 0, state;
-       int is_loaded, is_system, is_counting, expert_mode;
-       int ret = -EINVAL;
-       pfm_reg_check_t rd_func;
-
-       /*
-        * access is possible when loaded only for
-        * self-monitoring tasks or in UP mode
-        */
-
-       state     = ctx->ctx_state;
-       is_loaded = state == PFM_CTX_LOADED ? 1 : 0;
-       is_system = ctx->ctx_fl_system;
-       ovfl_mask = pmu_conf->ovfl_val;
-       task      = ctx->ctx_task;
-
-       if (state == PFM_CTX_ZOMBIE) return -EINVAL;
-
-       if (likely(is_loaded)) {
-               /*
-                * In system wide and when the context is loaded, access can only happen
-                * when the caller is running on the CPU being monitored by the session.
-                * It does not have to be the owner (ctx_task) of the context per se.
-                */
-               if (unlikely(is_system && ctx->ctx_cpu != smp_processor_id())) {
-                       DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu));
-                       return -EBUSY;
-               }
-               /*
-                * this can be true when not self-monitoring only in UP
-                */
-               can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0;
-
-               if (can_access_pmu) ia64_srlz_d();
-       }
-       expert_mode = pfm_sysctl.expert_mode; 
-
-       DPRINT(("ld=%d apmu=%d ctx_state=%d\n",
-               is_loaded,
-               can_access_pmu,
-               state));
-
-       /*
-        * on both UP and SMP, we can only read the PMD from the hardware register when
-        * the task is the owner of the local PMU.
-        */
-
-       for (i = 0; i < count; i++, req++) {
-
-               cnum        = req->reg_num;
-               reg_flags   = req->reg_flags;
-
-               if (unlikely(!PMD_IS_IMPL(cnum))) goto error;
-               /*
-                * we can only read the register that we use. That includes
-                * the one we explicitly initialize AND the one we want included
-                * in the sampling buffer (smpl_regs).
-                *
-                * Having this restriction allows optimization in the ctxsw routine
-                * without compromising security (leaks)
-                */
-               if (unlikely(!CTX_IS_USED_PMD(ctx, cnum))) goto error;
-
-               sval        = ctx->ctx_pmds[cnum].val;
-               lval        = ctx->ctx_pmds[cnum].lval;
-               is_counting = PMD_IS_COUNTING(cnum);
-
-               /*
-                * If the task is not the current one, then we check if the
-                * PMU state is still in the local live register due to lazy ctxsw.
-                * If true, then we read directly from the registers.
-                */
-               if (can_access_pmu){
-                       val = ia64_get_pmd(cnum);
-               } else {
-                       /*
-                        * context has been saved
-                        * if context is zombie, then task does not exist anymore.
-                        * In this case, we use the full value saved in the context (pfm_flush_regs()).
-                        */
-                       val = is_loaded ? ctx->th_pmds[cnum] : 0UL;
-               }
-               rd_func = pmu_conf->pmd_desc[cnum].read_check;
-
-               if (is_counting) {
-                       /*
-                        * XXX: need to check for overflow when loaded
-                        */
-                       val &= ovfl_mask;
-                       val += sval;
-               }
-
-               /*
-                * execute read checker, if any
-                */
-               if (unlikely(expert_mode == 0 && rd_func)) {
-                       unsigned long v = val;
-                       ret = (*rd_func)(ctx->ctx_task, ctx, cnum, &v, regs);
-                       if (ret) goto error;
-                       val = v;
-                       ret = -EINVAL;
-               }
-
-               PFM_REG_RETFLAG_SET(reg_flags, 0);
-
-               DPRINT(("pmd[%u]=0x%lx\n", cnum, val));
-
-               /*
-                * update register return value, abort all if problem during copy.
-                * we only modify the reg_flags field. no check mode is fine because
-                * access has been verified upfront in sys_perfmonctl().
-                */
-               req->reg_value            = val;
-               req->reg_flags            = reg_flags;
-               req->reg_last_reset_val   = lval;
-       }
-
-       return 0;
-
-error:
-       PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL);
-       return ret;
-}
-
-int
-pfm_mod_write_pmcs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs)
-{
-       pfm_context_t *ctx;
-
-       if (req == NULL) return -EINVAL;
-
-       ctx = GET_PMU_CTX();
-
-       if (ctx == NULL) return -EINVAL;
-
-       /*
-        * for now limit to current task, which is enough when calling
-        * from overflow handler
-        */
-       if (task != current && ctx->ctx_fl_system == 0) return -EBUSY;
-
-       return pfm_write_pmcs(ctx, req, nreq, regs);
-}
-EXPORT_SYMBOL(pfm_mod_write_pmcs);
-
-int
-pfm_mod_read_pmds(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs)
-{
-       pfm_context_t *ctx;
-
-       if (req == NULL) return -EINVAL;
-
-       ctx = GET_PMU_CTX();
-
-       if (ctx == NULL) return -EINVAL;
-
-       /*
-        * for now limit to current task, which is enough when calling
-        * from overflow handler
-        */
-       if (task != current && ctx->ctx_fl_system == 0) return -EBUSY;
-
-       return pfm_read_pmds(ctx, req, nreq, regs);
-}
-EXPORT_SYMBOL(pfm_mod_read_pmds);
-
-/*
- * Only call this function when a process it trying to
- * write the debug registers (reading is always allowed)
- */
-int
-pfm_use_debug_registers(struct task_struct *task)
-{
-       pfm_context_t *ctx = task->thread.pfm_context;
-       unsigned long flags;
-       int ret = 0;
-
-       if (pmu_conf->use_rr_dbregs == 0) return 0;
-
-       DPRINT(("called for [%d]\n", task_pid_nr(task)));
-
-       /*
-        * do it only once
-        */
-       if (task->thread.flags & IA64_THREAD_DBG_VALID) return 0;
-
-       /*
-        * Even on SMP, we do not need to use an atomic here because
-        * the only way in is via ptrace() and this is possible only when the
-        * process is stopped. Even in the case where the ctxsw out is not totally
-        * completed by the time we come here, there is no way the 'stopped' process
-        * could be in the middle of fiddling with the pfm_write_ibr_dbr() routine.
-        * So this is always safe.
-        */
-       if (ctx && ctx->ctx_fl_using_dbreg == 1) return -1;
-
-       LOCK_PFS(flags);
-
-       /*
-        * We cannot allow setting breakpoints when system wide monitoring
-        * sessions are using the debug registers.
-        */
-       if (pfm_sessions.pfs_sys_use_dbregs> 0)
-               ret = -1;
-       else
-               pfm_sessions.pfs_ptrace_use_dbregs++;
-
-       DPRINT(("ptrace_use_dbregs=%u  sys_use_dbregs=%u by [%d] ret = %d\n",
-                 pfm_sessions.pfs_ptrace_use_dbregs,
-                 pfm_sessions.pfs_sys_use_dbregs,
-                 task_pid_nr(task), ret));
-
-       UNLOCK_PFS(flags);
-
-       return ret;
-}
-
-/*
- * This function is called for every task that exits with the
- * IA64_THREAD_DBG_VALID set. This indicates a task which was
- * able to use the debug registers for debugging purposes via
- * ptrace(). Therefore we know it was not using them for
- * performance monitoring, so we only decrement the number
- * of "ptraced" debug register users to keep the count up to date
- */
-int
-pfm_release_debug_registers(struct task_struct *task)
-{
-       unsigned long flags;
-       int ret;
-
-       if (pmu_conf->use_rr_dbregs == 0) return 0;
-
-       LOCK_PFS(flags);
-       if (pfm_sessions.pfs_ptrace_use_dbregs == 0) {
-               printk(KERN_ERR "perfmon: invalid release for [%d] ptrace_use_dbregs=0\n", task_pid_nr(task));
-               ret = -1;
-       }  else {
-               pfm_sessions.pfs_ptrace_use_dbregs--;
-               ret = 0;
-       }
-       UNLOCK_PFS(flags);
-
-       return ret;
-}
-
-static int
-pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       struct task_struct *task;
-       pfm_buffer_fmt_t *fmt;
-       pfm_ovfl_ctrl_t rst_ctrl;
-       int state, is_system;
-       int ret = 0;
-
-       state     = ctx->ctx_state;
-       fmt       = ctx->ctx_buf_fmt;
-       is_system = ctx->ctx_fl_system;
-       task      = PFM_CTX_TASK(ctx);
-
-       switch(state) {
-               case PFM_CTX_MASKED:
-                       break;
-               case PFM_CTX_LOADED: 
-                       if (CTX_HAS_SMPL(ctx) && fmt->fmt_restart_active) break;
-                       /* fall through */
-               case PFM_CTX_UNLOADED:
-               case PFM_CTX_ZOMBIE:
-                       DPRINT(("invalid state=%d\n", state));
-                       return -EBUSY;
-               default:
-                       DPRINT(("state=%d, cannot operate (no active_restart handler)\n", state));
-                       return -EINVAL;
-       }
-
-       /*
-        * In system wide and when the context is loaded, access can only happen
-        * when the caller is running on the CPU being monitored by the session.
-        * It does not have to be the owner (ctx_task) of the context per se.
-        */
-       if (is_system && ctx->ctx_cpu != smp_processor_id()) {
-               DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu));
-               return -EBUSY;
-       }
-
-       /* sanity check */
-       if (unlikely(task == NULL)) {
-               printk(KERN_ERR "perfmon: [%d] pfm_restart no task\n", task_pid_nr(current));
-               return -EINVAL;
-       }
-
-       if (task == current || is_system) {
-
-               fmt = ctx->ctx_buf_fmt;
-
-               DPRINT(("restarting self %d ovfl=0x%lx\n",
-                       task_pid_nr(task),
-                       ctx->ctx_ovfl_regs[0]));
-
-               if (CTX_HAS_SMPL(ctx)) {
-
-                       prefetch(ctx->ctx_smpl_hdr);
-
-                       rst_ctrl.bits.mask_monitoring = 0;
-                       rst_ctrl.bits.reset_ovfl_pmds = 0;
-
-                       if (state == PFM_CTX_LOADED)
-                               ret = pfm_buf_fmt_restart_active(fmt, task, &rst_ctrl, ctx->ctx_smpl_hdr, regs);
-                       else
-                               ret = pfm_buf_fmt_restart(fmt, task, &rst_ctrl, ctx->ctx_smpl_hdr, regs);
-               } else {
-                       rst_ctrl.bits.mask_monitoring = 0;
-                       rst_ctrl.bits.reset_ovfl_pmds = 1;
-               }
-
-               if (ret == 0) {
-                       if (rst_ctrl.bits.reset_ovfl_pmds)
-                               pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET);
-
-                       if (rst_ctrl.bits.mask_monitoring == 0) {
-                               DPRINT(("resuming monitoring for [%d]\n", task_pid_nr(task)));
-
-                               if (state == PFM_CTX_MASKED) pfm_restore_monitoring(task);
-                       } else {
-                               DPRINT(("keeping monitoring stopped for [%d]\n", task_pid_nr(task)));
-
-                               // cannot use pfm_stop_monitoring(task, regs);
-                       }
-               }
-               /*
-                * clear overflowed PMD mask to remove any stale information
-                */
-               ctx->ctx_ovfl_regs[0] = 0UL;
-
-               /*
-                * back to LOADED state
-                */
-               ctx->ctx_state = PFM_CTX_LOADED;
-
-               /*
-                * XXX: not really useful for self monitoring
-                */
-               ctx->ctx_fl_can_restart = 0;
-
-               return 0;
-       }
-
-       /* 
-        * restart another task
-        */
-
-       /*
-        * When PFM_CTX_MASKED, we cannot issue a restart before the previous 
-        * one is seen by the task.
-        */
-       if (state == PFM_CTX_MASKED) {
-               if (ctx->ctx_fl_can_restart == 0) return -EINVAL;
-               /*
-                * will prevent subsequent restart before this one is
-                * seen by other task
-                */
-               ctx->ctx_fl_can_restart = 0;
-       }
-
-       /*
-        * if blocking, then post the semaphore is PFM_CTX_MASKED, i.e.
-        * the task is blocked or on its way to block. That's the normal
-        * restart path. If the monitoring is not masked, then the task
-        * can be actively monitoring and we cannot directly intervene.
-        * Therefore we use the trap mechanism to catch the task and
-        * force it to reset the buffer/reset PMDs.
-        *
-        * if non-blocking, then we ensure that the task will go into
-        * pfm_handle_work() before returning to user mode.
-        *
-        * We cannot explicitly reset another task, it MUST always
-        * be done by the task itself. This works for system wide because
-        * the tool that is controlling the session is logically doing 
-        * "self-monitoring".
-        */
-       if (CTX_OVFL_NOBLOCK(ctx) == 0 && state == PFM_CTX_MASKED) {
-               DPRINT(("unblocking [%d]\n", task_pid_nr(task)));
-               complete(&ctx->ctx_restart_done);
-       } else {
-               DPRINT(("[%d] armed exit trap\n", task_pid_nr(task)));
-
-               ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET;
-
-               PFM_SET_WORK_PENDING(task, 1);
-
-               set_notify_resume(task);
-
-               /*
-                * XXX: send reschedule if task runs on another CPU
-                */
-       }
-       return 0;
-}
-
-static int
-pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       unsigned int m = *(unsigned int *)arg;
-
-       pfm_sysctl.debug = m == 0 ? 0 : 1;
-
-       printk(KERN_INFO "perfmon debugging %s (timing reset)\n", pfm_sysctl.debug ? "on" : "off");
-
-       if (m == 0) {
-               memset(pfm_stats, 0, sizeof(pfm_stats));
-               for(m=0; m < NR_CPUS; m++) pfm_stats[m].pfm_ovfl_intr_cycles_min = ~0UL;
-       }
-       return 0;
-}
-
-/*
- * arg can be NULL and count can be zero for this function
- */
-static int
-pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       struct thread_struct *thread = NULL;
-       struct task_struct *task;
-       pfarg_dbreg_t *req = (pfarg_dbreg_t *)arg;
-       unsigned long flags;
-       dbreg_t dbreg;
-       unsigned int rnum;
-       int first_time;
-       int ret = 0, state;
-       int i, can_access_pmu = 0;
-       int is_system, is_loaded;
-
-       if (pmu_conf->use_rr_dbregs == 0) return -EINVAL;
-
-       state     = ctx->ctx_state;
-       is_loaded = state == PFM_CTX_LOADED ? 1 : 0;
-       is_system = ctx->ctx_fl_system;
-       task      = ctx->ctx_task;
-
-       if (state == PFM_CTX_ZOMBIE) return -EINVAL;
-
-       /*
-        * on both UP and SMP, we can only write to the PMC when the task is
-        * the owner of the local PMU.
-        */
-       if (is_loaded) {
-               thread = &task->thread;
-               /*
-                * In system wide and when the context is loaded, access can only happen
-                * when the caller is running on the CPU being monitored by the session.
-                * It does not have to be the owner (ctx_task) of the context per se.
-                */
-               if (unlikely(is_system && ctx->ctx_cpu != smp_processor_id())) {
-                       DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu));
-                       return -EBUSY;
-               }
-               can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0;
-       }
-
-       /*
-        * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w
-        * ensuring that no real breakpoint can be installed via this call.
-        *
-        * IMPORTANT: regs can be NULL in this function
-        */
-
-       first_time = ctx->ctx_fl_using_dbreg == 0;
-
-       /*
-        * don't bother if we are loaded and task is being debugged
-        */
-       if (is_loaded && (thread->flags & IA64_THREAD_DBG_VALID) != 0) {
-               DPRINT(("debug registers already in use for [%d]\n", task_pid_nr(task)));
-               return -EBUSY;
-       }
-
-       /*
-        * check for debug registers in system wide mode
-        *
-        * If though a check is done in pfm_context_load(),
-        * we must repeat it here, in case the registers are
-        * written after the context is loaded
-        */
-       if (is_loaded) {
-               LOCK_PFS(flags);
-
-               if (first_time && is_system) {
-                       if (pfm_sessions.pfs_ptrace_use_dbregs)
-                               ret = -EBUSY;
-                       else
-                               pfm_sessions.pfs_sys_use_dbregs++;
-               }
-               UNLOCK_PFS(flags);
-       }
-
-       if (ret != 0) return ret;
-
-       /*
-        * mark ourself as user of the debug registers for
-        * perfmon purposes.
-        */
-       ctx->ctx_fl_using_dbreg = 1;
-
-       /*
-        * clear hardware registers to make sure we don't
-        * pick up stale state.
-        *
-        * for a system wide session, we do not use
-        * thread.dbr, thread.ibr because this process
-        * never leaves the current CPU and the state
-        * is shared by all processes running on it
-        */
-       if (first_time && can_access_pmu) {
-               DPRINT(("[%d] clearing ibrs, dbrs\n", task_pid_nr(task)));
-               for (i=0; i < pmu_conf->num_ibrs; i++) {
-                       ia64_set_ibr(i, 0UL);
-                       ia64_dv_serialize_instruction();
-               }
-               ia64_srlz_i();
-               for (i=0; i < pmu_conf->num_dbrs; i++) {
-                       ia64_set_dbr(i, 0UL);
-                       ia64_dv_serialize_data();
-               }
-               ia64_srlz_d();
-       }
-
-       /*
-        * Now install the values into the registers
-        */
-       for (i = 0; i < count; i++, req++) {
-
-               rnum      = req->dbreg_num;
-               dbreg.val = req->dbreg_value;
-
-               ret = -EINVAL;
-
-               if ((mode == PFM_CODE_RR && rnum >= PFM_NUM_IBRS) || ((mode == PFM_DATA_RR) && rnum >= PFM_NUM_DBRS)) {
-                       DPRINT(("invalid register %u val=0x%lx mode=%d i=%d count=%d\n",
-                                 rnum, dbreg.val, mode, i, count));
-
-                       goto abort_mission;
-               }
-
-               /*
-                * make sure we do not install enabled breakpoint
-                */
-               if (rnum & 0x1) {
-                       if (mode == PFM_CODE_RR)
-                               dbreg.ibr.ibr_x = 0;
-                       else
-                               dbreg.dbr.dbr_r = dbreg.dbr.dbr_w = 0;
-               }
-
-               PFM_REG_RETFLAG_SET(req->dbreg_flags, 0);
-
-               /*
-                * Debug registers, just like PMC, can only be modified
-                * by a kernel call. Moreover, perfmon() access to those
-                * registers are centralized in this routine. The hardware
-                * does not modify the value of these registers, therefore,
-                * if we save them as they are written, we can avoid having
-                * to save them on context switch out. This is made possible
-                * by the fact that when perfmon uses debug registers, ptrace()
-                * won't be able to modify them concurrently.
-                */
-               if (mode == PFM_CODE_RR) {
-                       CTX_USED_IBR(ctx, rnum);
-
-                       if (can_access_pmu) {
-                               ia64_set_ibr(rnum, dbreg.val);
-                               ia64_dv_serialize_instruction();
-                       }
-
-                       ctx->ctx_ibrs[rnum] = dbreg.val;
-
-                       DPRINT(("write ibr%u=0x%lx used_ibrs=0x%x ld=%d apmu=%d\n",
-                               rnum, dbreg.val, ctx->ctx_used_ibrs[0], is_loaded, can_access_pmu));
-               } else {
-                       CTX_USED_DBR(ctx, rnum);
-
-                       if (can_access_pmu) {
-                               ia64_set_dbr(rnum, dbreg.val);
-                               ia64_dv_serialize_data();
-                       }
-                       ctx->ctx_dbrs[rnum] = dbreg.val;
-
-                       DPRINT(("write dbr%u=0x%lx used_dbrs=0x%x ld=%d apmu=%d\n",
-                               rnum, dbreg.val, ctx->ctx_used_dbrs[0], is_loaded, can_access_pmu));
-               }
-       }
-
-       return 0;
-
-abort_mission:
-       /*
-        * in case it was our first attempt, we undo the global modifications
-        */
-       if (first_time) {
-               LOCK_PFS(flags);
-               if (ctx->ctx_fl_system) {
-                       pfm_sessions.pfs_sys_use_dbregs--;
-               }
-               UNLOCK_PFS(flags);
-               ctx->ctx_fl_using_dbreg = 0;
-       }
-       /*
-        * install error return flag
-        */
-       PFM_REG_RETFLAG_SET(req->dbreg_flags, PFM_REG_RETFL_EINVAL);
-
-       return ret;
-}
-
-static int
-pfm_write_ibrs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       return pfm_write_ibr_dbr(PFM_CODE_RR, ctx, arg, count, regs);
-}
-
-static int
-pfm_write_dbrs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       return pfm_write_ibr_dbr(PFM_DATA_RR, ctx, arg, count, regs);
-}
-
-int
-pfm_mod_write_ibrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs)
-{
-       pfm_context_t *ctx;
-
-       if (req == NULL) return -EINVAL;
-
-       ctx = GET_PMU_CTX();
-
-       if (ctx == NULL) return -EINVAL;
-
-       /*
-        * for now limit to current task, which is enough when calling
-        * from overflow handler
-        */
-       if (task != current && ctx->ctx_fl_system == 0) return -EBUSY;
-
-       return pfm_write_ibrs(ctx, req, nreq, regs);
-}
-EXPORT_SYMBOL(pfm_mod_write_ibrs);
-
-int
-pfm_mod_write_dbrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs)
-{
-       pfm_context_t *ctx;
-
-       if (req == NULL) return -EINVAL;
-
-       ctx = GET_PMU_CTX();
-
-       if (ctx == NULL) return -EINVAL;
-
-       /*
-        * for now limit to current task, which is enough when calling
-        * from overflow handler
-        */
-       if (task != current && ctx->ctx_fl_system == 0) return -EBUSY;
-
-       return pfm_write_dbrs(ctx, req, nreq, regs);
-}
-EXPORT_SYMBOL(pfm_mod_write_dbrs);
-
-
-static int
-pfm_get_features(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       pfarg_features_t *req = (pfarg_features_t *)arg;
-
-       req->ft_version = PFM_VERSION;
-       return 0;
-}
-
-static int
-pfm_stop(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       struct pt_regs *tregs;
-       struct task_struct *task = PFM_CTX_TASK(ctx);
-       int state, is_system;
-
-       state     = ctx->ctx_state;
-       is_system = ctx->ctx_fl_system;
-
-       /*
-        * context must be attached to issue the stop command (includes LOADED,MASKED,ZOMBIE)
-        */
-       if (state == PFM_CTX_UNLOADED) return -EINVAL;
-
-       /*
-        * In system wide and when the context is loaded, access can only happen
-        * when the caller is running on the CPU being monitored by the session.
-        * It does not have to be the owner (ctx_task) of the context per se.
-        */
-       if (is_system && ctx->ctx_cpu != smp_processor_id()) {
-               DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu));
-               return -EBUSY;
-       }
-       DPRINT(("task [%d] ctx_state=%d is_system=%d\n",
-               task_pid_nr(PFM_CTX_TASK(ctx)),
-               state,
-               is_system));
-       /*
-        * in system mode, we need to update the PMU directly
-        * and the user level state of the caller, which may not
-        * necessarily be the creator of the context.
-        */
-       if (is_system) {
-               /*
-                * Update local PMU first
-                *
-                * disable dcr pp
-                */
-               ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) & ~IA64_DCR_PP);
-               ia64_srlz_i();
-
-               /*
-                * update local cpuinfo
-                */
-               PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP);
-
-               /*
-                * stop monitoring, does srlz.i
-                */
-               pfm_clear_psr_pp();
-
-               /*
-                * stop monitoring in the caller
-                */
-               ia64_psr(regs)->pp = 0;
-
-               return 0;
-       }
-       /*
-        * per-task mode
-        */
-
-       if (task == current) {
-               /* stop monitoring  at kernel level */
-               pfm_clear_psr_up();
-
-               /*
-                * stop monitoring at the user level
-                */
-               ia64_psr(regs)->up = 0;
-       } else {
-               tregs = task_pt_regs(task);
-
-               /*
-                * stop monitoring at the user level
-                */
-               ia64_psr(tregs)->up = 0;
-
-               /*
-                * monitoring disabled in kernel at next reschedule
-                */
-               ctx->ctx_saved_psr_up = 0;
-               DPRINT(("task=[%d]\n", task_pid_nr(task)));
-       }
-       return 0;
-}
-
-
-static int
-pfm_start(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       struct pt_regs *tregs;
-       int state, is_system;
-
-       state     = ctx->ctx_state;
-       is_system = ctx->ctx_fl_system;
-
-       if (state != PFM_CTX_LOADED) return -EINVAL;
-
-       /*
-        * In system wide and when the context is loaded, access can only happen
-        * when the caller is running on the CPU being monitored by the session.
-        * It does not have to be the owner (ctx_task) of the context per se.
-        */
-       if (is_system && ctx->ctx_cpu != smp_processor_id()) {
-               DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu));
-               return -EBUSY;
-       }
-
-       /*
-        * in system mode, we need to update the PMU directly
-        * and the user level state of the caller, which may not
-        * necessarily be the creator of the context.
-        */
-       if (is_system) {
-
-               /*
-                * set user level psr.pp for the caller
-                */
-               ia64_psr(regs)->pp = 1;
-
-               /*
-                * now update the local PMU and cpuinfo
-                */
-               PFM_CPUINFO_SET(PFM_CPUINFO_DCR_PP);
-
-               /*
-                * start monitoring at kernel level
-                */
-               pfm_set_psr_pp();
-
-               /* enable dcr pp */
-               ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) | IA64_DCR_PP);
-               ia64_srlz_i();
-
-               return 0;
-       }
-
-       /*
-        * per-process mode
-        */
-
-       if (ctx->ctx_task == current) {
-
-               /* start monitoring at kernel level */
-               pfm_set_psr_up();
-
-               /*
-                * activate monitoring at user level
-                */
-               ia64_psr(regs)->up = 1;
-
-       } else {
-               tregs = task_pt_regs(ctx->ctx_task);
-
-               /*
-                * start monitoring at the kernel level the next
-                * time the task is scheduled
-                */
-               ctx->ctx_saved_psr_up = IA64_PSR_UP;
-
-               /*
-                * activate monitoring at user level
-                */
-               ia64_psr(tregs)->up = 1;
-       }
-       return 0;
-}
-
-static int
-pfm_get_pmc_reset(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       pfarg_reg_t *req = (pfarg_reg_t *)arg;
-       unsigned int cnum;
-       int i;
-       int ret = -EINVAL;
-
-       for (i = 0; i < count; i++, req++) {
-
-               cnum = req->reg_num;
-
-               if (!PMC_IS_IMPL(cnum)) goto abort_mission;
-
-               req->reg_value = PMC_DFL_VAL(cnum);
-
-               PFM_REG_RETFLAG_SET(req->reg_flags, 0);
-
-               DPRINT(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, req->reg_value));
-       }
-       return 0;
-
-abort_mission:
-       PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL);
-       return ret;
-}
-
-static int
-pfm_check_task_exist(pfm_context_t *ctx)
-{
-       struct task_struct *g, *t;
-       int ret = -ESRCH;
-
-       read_lock(&tasklist_lock);
-
-       do_each_thread (g, t) {
-               if (t->thread.pfm_context == ctx) {
-                       ret = 0;
-                       goto out;
-               }
-       } while_each_thread (g, t);
-out:
-       read_unlock(&tasklist_lock);
-
-       DPRINT(("pfm_check_task_exist: ret=%d ctx=%p\n", ret, ctx));
-
-       return ret;
-}
-
-static int
-pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       struct task_struct *task;
-       struct thread_struct *thread;
-       struct pfm_context_t *old;
-       unsigned long flags;
-#ifndef CONFIG_SMP
-       struct task_struct *owner_task = NULL;
-#endif
-       pfarg_load_t *req = (pfarg_load_t *)arg;
-       unsigned long *pmcs_source, *pmds_source;
-       int the_cpu;
-       int ret = 0;
-       int state, is_system, set_dbregs = 0;
-
-       state     = ctx->ctx_state;
-       is_system = ctx->ctx_fl_system;
-       /*
-        * can only load from unloaded or terminated state
-        */
-       if (state != PFM_CTX_UNLOADED) {
-               DPRINT(("cannot load to [%d], invalid ctx_state=%d\n",
-                       req->load_pid,
-                       ctx->ctx_state));
-               return -EBUSY;
-       }
-
-       DPRINT(("load_pid [%d] using_dbreg=%d\n", req->load_pid, ctx->ctx_fl_using_dbreg));
-
-       if (CTX_OVFL_NOBLOCK(ctx) == 0 && req->load_pid == current->pid) {
-               DPRINT(("cannot use blocking mode on self\n"));
-               return -EINVAL;
-       }
-
-       ret = pfm_get_task(ctx, req->load_pid, &task);
-       if (ret) {
-               DPRINT(("load_pid [%d] get_task=%d\n", req->load_pid, ret));
-               return ret;
-       }
-
-       ret = -EINVAL;
-
-       /*
-        * system wide is self monitoring only
-        */
-       if (is_system && task != current) {
-               DPRINT(("system wide is self monitoring only load_pid=%d\n",
-                       req->load_pid));
-               goto error;
-       }
-
-       thread = &task->thread;
-
-       ret = 0;
-       /*
-        * cannot load a context which is using range restrictions,
-        * into a task that is being debugged.
-        */
-       if (ctx->ctx_fl_using_dbreg) {
-               if (thread->flags & IA64_THREAD_DBG_VALID) {
-                       ret = -EBUSY;
-                       DPRINT(("load_pid [%d] task is debugged, cannot load range restrictions\n", req->load_pid));
-                       goto error;
-               }
-               LOCK_PFS(flags);
-
-               if (is_system) {
-                       if (pfm_sessions.pfs_ptrace_use_dbregs) {
-                               DPRINT(("cannot load [%d] dbregs in use\n",
-                                                       task_pid_nr(task)));
-                               ret = -EBUSY;
-                       } else {
-                               pfm_sessions.pfs_sys_use_dbregs++;
-                               DPRINT(("load [%d] increased sys_use_dbreg=%u\n", task_pid_nr(task), pfm_sessions.pfs_sys_use_dbregs));
-                               set_dbregs = 1;
-                       }
-               }
-
-               UNLOCK_PFS(flags);
-
-               if (ret) goto error;
-       }
-
-       /*
-        * SMP system-wide monitoring implies self-monitoring.
-        *
-        * The programming model expects the task to
-        * be pinned on a CPU throughout the session.
-        * Here we take note of the current CPU at the
-        * time the context is loaded. No call from
-        * another CPU will be allowed.
-        *
-        * The pinning via shed_setaffinity()
-        * must be done by the calling task prior
-        * to this call.
-        *
-        * systemwide: keep track of CPU this session is supposed to run on
-        */
-       the_cpu = ctx->ctx_cpu = smp_processor_id();
-
-       ret = -EBUSY;
-       /*
-        * now reserve the session
-        */
-       ret = pfm_reserve_session(current, is_system, the_cpu);
-       if (ret) goto error;
-
-       /*
-        * task is necessarily stopped at this point.
-        *
-        * If the previous context was zombie, then it got removed in
-        * pfm_save_regs(). Therefore we should not see it here.
-        * If we see a context, then this is an active context
-        *
-        * XXX: needs to be atomic
-        */
-       DPRINT(("before cmpxchg() old_ctx=%p new_ctx=%p\n",
-               thread->pfm_context, ctx));
-
-       ret = -EBUSY;
-       old = ia64_cmpxchg(acq, &thread->pfm_context, NULL, ctx, sizeof(pfm_context_t *));
-       if (old != NULL) {
-               DPRINT(("load_pid [%d] already has a context\n", req->load_pid));
-               goto error_unres;
-       }
-
-       pfm_reset_msgq(ctx);
-
-       ctx->ctx_state = PFM_CTX_LOADED;
-
-       /*
-        * link context to task
-        */
-       ctx->ctx_task = task;
-
-       if (is_system) {
-               /*
-                * we load as stopped
-                */
-               PFM_CPUINFO_SET(PFM_CPUINFO_SYST_WIDE);
-               PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP);
-
-               if (ctx->ctx_fl_excl_idle) PFM_CPUINFO_SET(PFM_CPUINFO_EXCL_IDLE);
-       } else {
-               thread->flags |= IA64_THREAD_PM_VALID;
-       }
-
-       /*
-        * propagate into thread-state
-        */
-       pfm_copy_pmds(task, ctx);
-       pfm_copy_pmcs(task, ctx);
-
-       pmcs_source = ctx->th_pmcs;
-       pmds_source = ctx->th_pmds;
-
-       /*
-        * always the case for system-wide
-        */
-       if (task == current) {
-
-               if (is_system == 0) {
-
-                       /* allow user level control */
-                       ia64_psr(regs)->sp = 0;
-                       DPRINT(("clearing psr.sp for [%d]\n", task_pid_nr(task)));
-
-                       SET_LAST_CPU(ctx, smp_processor_id());
-                       INC_ACTIVATION();
-                       SET_ACTIVATION(ctx);
-#ifndef CONFIG_SMP
-                       /*
-                        * push the other task out, if any
-                        */
-                       owner_task = GET_PMU_OWNER();
-                       if (owner_task) pfm_lazy_save_regs(owner_task);
-#endif
-               }
-               /*
-                * load all PMD from ctx to PMU (as opposed to thread state)
-                * restore all PMC from ctx to PMU
-                */
-               pfm_restore_pmds(pmds_source, ctx->ctx_all_pmds[0]);
-               pfm_restore_pmcs(pmcs_source, ctx->ctx_all_pmcs[0]);
-
-               ctx->ctx_reload_pmcs[0] = 0UL;
-               ctx->ctx_reload_pmds[0] = 0UL;
-
-               /*
-                * guaranteed safe by earlier check against DBG_VALID
-                */
-               if (ctx->ctx_fl_using_dbreg) {
-                       pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs);
-                       pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs);
-               }
-               /*
-                * set new ownership
-                */
-               SET_PMU_OWNER(task, ctx);
-
-               DPRINT(("context loaded on PMU for [%d]\n", task_pid_nr(task)));
-       } else {
-               /*
-                * when not current, task MUST be stopped, so this is safe
-                */
-               regs = task_pt_regs(task);
-
-               /* force a full reload */
-               ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
-               SET_LAST_CPU(ctx, -1);
-
-               /* initial saved psr (stopped) */
-               ctx->ctx_saved_psr_up = 0UL;
-               ia64_psr(regs)->up = ia64_psr(regs)->pp = 0;
-       }
-
-       ret = 0;
-
-error_unres:
-       if (ret) pfm_unreserve_session(ctx, ctx->ctx_fl_system, the_cpu);
-error:
-       /*
-        * we must undo the dbregs setting (for system-wide)
-        */
-       if (ret && set_dbregs) {
-               LOCK_PFS(flags);
-               pfm_sessions.pfs_sys_use_dbregs--;
-               UNLOCK_PFS(flags);
-       }
-       /*
-        * release task, there is now a link with the context
-        */
-       if (is_system == 0 && task != current) {
-               pfm_put_task(task);
-
-               if (ret == 0) {
-                       ret = pfm_check_task_exist(ctx);
-                       if (ret) {
-                               ctx->ctx_state = PFM_CTX_UNLOADED;
-                               ctx->ctx_task  = NULL;
-                       }
-               }
-       }
-       return ret;
-}
-
-/*
- * in this function, we do not need to increase the use count
- * for the task via get_task_struct(), because we hold the
- * context lock. If the task were to disappear while having
- * a context attached, it would go through pfm_exit_thread()
- * which also grabs the context lock  and would therefore be blocked
- * until we are here.
- */
-static void pfm_flush_pmds(struct task_struct *, pfm_context_t *ctx);
-
-static int
-pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
-{
-       struct task_struct *task = PFM_CTX_TASK(ctx);
-       struct pt_regs *tregs;
-       int prev_state, is_system;
-       int ret;
-
-       DPRINT(("ctx_state=%d task [%d]\n", ctx->ctx_state, task ? task_pid_nr(task) : -1));
-
-       prev_state = ctx->ctx_state;
-       is_system  = ctx->ctx_fl_system;
-
-       /*
-        * unload only when necessary
-        */
-       if (prev_state == PFM_CTX_UNLOADED) {
-               DPRINT(("ctx_state=%d, nothing to do\n", prev_state));
-               return 0;
-       }
-
-       /*
-        * clear psr and dcr bits
-        */
-       ret = pfm_stop(ctx, NULL, 0, regs);
-       if (ret) return ret;
-
-       ctx->ctx_state = PFM_CTX_UNLOADED;
-
-       /*
-        * in system mode, we need to update the PMU directly
-        * and the user level state of the caller, which may not
-        * necessarily be the creator of the context.
-        */
-       if (is_system) {
-
-               /*
-                * Update cpuinfo
-                *
-                * local PMU is taken care of in pfm_stop()
-                */
-               PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE);
-               PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE);
-
-               /*
-                * save PMDs in context
-                * release ownership
-                */
-               pfm_flush_pmds(current, ctx);
-
-               /*
-                * at this point we are done with the PMU
-                * so we can unreserve the resource.
-                */
-               if (prev_state != PFM_CTX_ZOMBIE) 
-                       pfm_unreserve_session(ctx, 1 , ctx->ctx_cpu);
-
-               /*
-                * disconnect context from task
-                */
-               task->thread.pfm_context = NULL;
-               /*
-                * disconnect task from context
-                */
-               ctx->ctx_task = NULL;
-
-               /*
-                * There is nothing more to cleanup here.
-                */
-               return 0;
-       }
-
-       /*
-        * per-task mode
-        */
-       tregs = task == current ? regs : task_pt_regs(task);
-
-       if (task == current) {
-               /*
-                * cancel user level control
-                */
-               ia64_psr(regs)->sp = 1;
-
-               DPRINT(("setting psr.sp for [%d]\n", task_pid_nr(task)));
-       }
-       /*
-        * save PMDs to context
-        * release ownership
-        */
-       pfm_flush_pmds(task, ctx);
-
-       /*
-        * at this point we are done with the PMU
-        * so we can unreserve the resource.
-        *
-        * when state was ZOMBIE, we have already unreserved.
-        */
-       if (prev_state != PFM_CTX_ZOMBIE) 
-               pfm_unreserve_session(ctx, 0 , ctx->ctx_cpu);
-
-       /*
-        * reset activation counter and psr
-        */
-       ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
-       SET_LAST_CPU(ctx, -1);
-
-       /*
-        * PMU state will not be restored
-        */
-       task->thread.flags &= ~IA64_THREAD_PM_VALID;
-
-       /*
-        * break links between context and task
-        */
-       task->thread.pfm_context  = NULL;
-       ctx->ctx_task             = NULL;
-
-       PFM_SET_WORK_PENDING(task, 0);
-
-       ctx->ctx_fl_trap_reason  = PFM_TRAP_REASON_NONE;
-       ctx->ctx_fl_can_restart  = 0;
-       ctx->ctx_fl_going_zombie = 0;
-
-       DPRINT(("disconnected [%d] from context\n", task_pid_nr(task)));
-
-       return 0;
-}
-
-
-/*
- * called only from exit_thread()
- * we come here only if the task has a context attached (loaded or masked)
- */
-void
-pfm_exit_thread(struct task_struct *task)
-{
-       pfm_context_t *ctx;
-       unsigned long flags;
-       struct pt_regs *regs = task_pt_regs(task);
-       int ret, state;
-       int free_ok = 0;
-
-       ctx = PFM_GET_CTX(task);
-
-       PROTECT_CTX(ctx, flags);
-
-       DPRINT(("state=%d task [%d]\n", ctx->ctx_state, task_pid_nr(task)));
-
-       state = ctx->ctx_state;
-       switch(state) {
-               case PFM_CTX_UNLOADED:
-                       /*
-                        * only comes to this function if pfm_context is not NULL, i.e., cannot
-                        * be in unloaded state
-                        */
-                       printk(KERN_ERR "perfmon: pfm_exit_thread [%d] ctx unloaded\n", task_pid_nr(task));
-                       break;
-               case PFM_CTX_LOADED:
-               case PFM_CTX_MASKED:
-                       ret = pfm_context_unload(ctx, NULL, 0, regs);
-                       if (ret) {
-                               printk(KERN_ERR "perfmon: pfm_exit_thread [%d] state=%d unload failed %d\n", task_pid_nr(task), state, ret);
-                       }
-                       DPRINT(("ctx unloaded for current state was %d\n", state));
-
-                       pfm_end_notify_user(ctx);
-                       break;
-               case PFM_CTX_ZOMBIE:
-                       ret = pfm_context_unload(ctx, NULL, 0, regs);
-                       if (ret) {
-                               printk(KERN_ERR "perfmon: pfm_exit_thread [%d] state=%d unload failed %d\n", task_pid_nr(task), state, ret);
-                       }
-                       free_ok = 1;
-                       break;
-               default:
-                       printk(KERN_ERR "perfmon: pfm_exit_thread [%d] unexpected state=%d\n", task_pid_nr(task), state);
-                       break;
-       }
-       UNPROTECT_CTX(ctx, flags);
-
-       { u64 psr = pfm_get_psr();
-         BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP));
-         BUG_ON(GET_PMU_OWNER());
-         BUG_ON(ia64_psr(regs)->up);
-         BUG_ON(ia64_psr(regs)->pp);
-       }
-
-       /*
-        * All memory free operations (especially for vmalloc'ed memory)
-        * MUST be done with interrupts ENABLED.
-        */
-       if (free_ok) pfm_context_free(ctx);
-}
-
-/*
- * functions MUST be listed in the increasing order of their index (see permfon.h)
- */
-#define PFM_CMD(name, flags, arg_count, arg_type, getsz) { name, #name, flags, arg_count, sizeof(arg_type), getsz }
-#define PFM_CMD_S(name, flags) { name, #name, flags, 0, 0, NULL }
-#define PFM_CMD_PCLRWS (PFM_CMD_FD|PFM_CMD_ARG_RW|PFM_CMD_STOP)
-#define PFM_CMD_PCLRW  (PFM_CMD_FD|PFM_CMD_ARG_RW)
-#define PFM_CMD_NONE   { NULL, "no-cmd", 0, 0, 0, NULL}
-
-static pfm_cmd_desc_t pfm_cmd_tab[]={
-/* 0  */PFM_CMD_NONE,
-/* 1  */PFM_CMD(pfm_write_pmcs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL),
-/* 2  */PFM_CMD(pfm_write_pmds, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL),
-/* 3  */PFM_CMD(pfm_read_pmds, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL),
-/* 4  */PFM_CMD_S(pfm_stop, PFM_CMD_PCLRWS),
-/* 5  */PFM_CMD_S(pfm_start, PFM_CMD_PCLRWS),
-/* 6  */PFM_CMD_NONE,
-/* 7  */PFM_CMD_NONE,
-/* 8  */PFM_CMD(pfm_context_create, PFM_CMD_ARG_RW, 1, pfarg_context_t, pfm_ctx_getsize),
-/* 9  */PFM_CMD_NONE,
-/* 10 */PFM_CMD_S(pfm_restart, PFM_CMD_PCLRW),
-/* 11 */PFM_CMD_NONE,
-/* 12 */PFM_CMD(pfm_get_features, PFM_CMD_ARG_RW, 1, pfarg_features_t, NULL),
-/* 13 */PFM_CMD(pfm_debug, 0, 1, unsigned int, NULL),
-/* 14 */PFM_CMD_NONE,
-/* 15 */PFM_CMD(pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL),
-/* 16 */PFM_CMD(pfm_context_load, PFM_CMD_PCLRWS, 1, pfarg_load_t, NULL),
-/* 17 */PFM_CMD_S(pfm_context_unload, PFM_CMD_PCLRWS),
-/* 18 */PFM_CMD_NONE,
-/* 19 */PFM_CMD_NONE,
-/* 20 */PFM_CMD_NONE,
-/* 21 */PFM_CMD_NONE,
-/* 22 */PFM_CMD_NONE,
-/* 23 */PFM_CMD_NONE,
-/* 24 */PFM_CMD_NONE,
-/* 25 */PFM_CMD_NONE,
-/* 26 */PFM_CMD_NONE,
-/* 27 */PFM_CMD_NONE,
-/* 28 */PFM_CMD_NONE,
-/* 29 */PFM_CMD_NONE,
-/* 30 */PFM_CMD_NONE,
-/* 31 */PFM_CMD_NONE,
-/* 32 */PFM_CMD(pfm_write_ibrs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_dbreg_t, NULL),
-/* 33 */PFM_CMD(pfm_write_dbrs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_dbreg_t, NULL)
-};
-#define PFM_CMD_COUNT  (sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t))
-
-static int
-pfm_check_task_state(pfm_context_t *ctx, int cmd, unsigned long flags)
-{
-       struct task_struct *task;
-       int state, old_state;
-
-recheck:
-       state = ctx->ctx_state;
-       task  = ctx->ctx_task;
-
-       if (task == NULL) {
-               DPRINT(("context %d no task, state=%d\n", ctx->ctx_fd, state));
-               return 0;
-       }
-
-       DPRINT(("context %d state=%d [%d] task_state=%ld must_stop=%d\n",
-               ctx->ctx_fd,
-               state,
-               task_pid_nr(task),
-               task->state, PFM_CMD_STOPPED(cmd)));
-
-       /*
-        * self-monitoring always ok.
-        *
-        * for system-wide the caller can either be the creator of the
-        * context (to one to which the context is attached to) OR
-        * a task running on the same CPU as the session.
-        */
-       if (task == current || ctx->ctx_fl_system) return 0;
-
-       /*
-        * we are monitoring another thread
-        */
-       switch(state) {
-               case PFM_CTX_UNLOADED:
-                       /*
-                        * if context is UNLOADED we are safe to go
-                        */
-                       return 0;
-               case PFM_CTX_ZOMBIE:
-                       /*
-                        * no command can operate on a zombie context
-                        */
-                       DPRINT(("cmd %d state zombie cannot operate on context\n", cmd));
-                       return -EINVAL;
-               case PFM_CTX_MASKED:
-                       /*
-                        * PMU state has been saved to software even though
-                        * the thread may still be running.
-                        */
-                       if (cmd != PFM_UNLOAD_CONTEXT) return 0;
-       }
-
-       /*
-        * context is LOADED or MASKED. Some commands may need to have 
-        * the task stopped.
-        *
-        * We could lift this restriction for UP but it would mean that
-        * the user has no guarantee the task would not run between
-        * two successive calls to perfmonctl(). That's probably OK.
-        * If this user wants to ensure the task does not run, then
-        * the task must be stopped.
-        */
-       if (PFM_CMD_STOPPED(cmd)) {
-               if (!task_is_stopped_or_traced(task)) {
-                       DPRINT(("[%d] task not in stopped state\n", task_pid_nr(task)));
-                       return -EBUSY;
-               }
-               /*
-                * task is now stopped, wait for ctxsw out
-                *
-                * This is an interesting point in the code.
-                * We need to unprotect the context because
-                * the pfm_save_regs() routines needs to grab
-                * the same lock. There are danger in doing
-                * this because it leaves a window open for
-                * another task to get access to the context
-                * and possibly change its state. The one thing
-                * that is not possible is for the context to disappear
-                * because we are protected by the VFS layer, i.e.,
-                * get_fd()/put_fd().
-                */
-               old_state = state;
-
-               UNPROTECT_CTX(ctx, flags);
-
-               wait_task_inactive(task, 0);
-
-               PROTECT_CTX(ctx, flags);
-
-               /*
-                * we must recheck to verify if state has changed
-                */
-               if (ctx->ctx_state != old_state) {
-                       DPRINT(("old_state=%d new_state=%d\n", old_state, ctx->ctx_state));
-                       goto recheck;
-               }
-       }
-       return 0;
-}
-
-/*
- * system-call entry point (must return long)
- */
-asmlinkage long
-sys_perfmonctl (int fd, int cmd, void __user *arg, int count)
-{
-       struct fd f = {NULL, 0};
-       pfm_context_t *ctx = NULL;
-       unsigned long flags = 0UL;
-       void *args_k = NULL;
-       long ret; /* will expand int return types */
-       size_t base_sz, sz, xtra_sz = 0;
-       int narg, completed_args = 0, call_made = 0, cmd_flags;
-       int (*func)(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs);
-       int (*getsize)(void *arg, size_t *sz);
-#define PFM_MAX_ARGSIZE        4096
-
-       /*
-        * reject any call if perfmon was disabled at initialization
-        */
-       if (unlikely(pmu_conf == NULL)) return -ENOSYS;
-
-       if (unlikely(cmd < 0 || cmd >= PFM_CMD_COUNT)) {
-               DPRINT(("invalid cmd=%d\n", cmd));
-               return -EINVAL;
-       }
-
-       func      = pfm_cmd_tab[cmd].cmd_func;
-       narg      = pfm_cmd_tab[cmd].cmd_narg;
-       base_sz   = pfm_cmd_tab[cmd].cmd_argsize;
-       getsize   = pfm_cmd_tab[cmd].cmd_getsize;
-       cmd_flags = pfm_cmd_tab[cmd].cmd_flags;
-
-       if (unlikely(func == NULL)) {
-               DPRINT(("invalid cmd=%d\n", cmd));
-               return -EINVAL;
-       }
-
-       DPRINT(("cmd=%s idx=%d narg=0x%x argsz=%lu count=%d\n",
-               PFM_CMD_NAME(cmd),
-               cmd,
-               narg,
-               base_sz,
-               count));
-
-       /*
-        * check if number of arguments matches what the command expects
-        */
-       if (unlikely((narg == PFM_CMD_ARG_MANY && count <= 0) || (narg > 0 && narg != count)))
-               return -EINVAL;
-
-restart_args:
-       sz = xtra_sz + base_sz*count;
-       /*
-        * limit abuse to min page size
-        */
-       if (unlikely(sz > PFM_MAX_ARGSIZE)) {
-               printk(KERN_ERR "perfmon: [%d] argument too big %lu\n", task_pid_nr(current), sz);
-               return -E2BIG;
-       }
-
-       /*
-        * allocate default-sized argument buffer
-        */
-       if (likely(count && args_k == NULL)) {
-               args_k = kmalloc(PFM_MAX_ARGSIZE, GFP_KERNEL);
-               if (args_k == NULL) return -ENOMEM;
-       }
-
-       ret = -EFAULT;
-
-       /*
-        * copy arguments
-        *
-        * assume sz = 0 for command without parameters
-        */
-       if (sz && copy_from_user(args_k, arg, sz)) {
-               DPRINT(("cannot copy_from_user %lu bytes @%p\n", sz, arg));
-               goto error_args;
-       }
-
-       /*
-        * check if command supports extra parameters
-        */
-       if (completed_args == 0 && getsize) {
-               /*
-                * get extra parameters size (based on main argument)
-                */
-               ret = (*getsize)(args_k, &xtra_sz);
-               if (ret) goto error_args;
-
-               completed_args = 1;
-
-               DPRINT(("restart_args sz=%lu xtra_sz=%lu\n", sz, xtra_sz));
-
-               /* retry if necessary */
-               if (likely(xtra_sz)) goto restart_args;
-       }
-
-       if (unlikely((cmd_flags & PFM_CMD_FD) == 0)) goto skip_fd;
-
-       ret = -EBADF;
-
-       f = fdget(fd);
-       if (unlikely(f.file == NULL)) {
-               DPRINT(("invalid fd %d\n", fd));
-               goto error_args;
-       }
-       if (unlikely(PFM_IS_FILE(f.file) == 0)) {
-               DPRINT(("fd %d not related to perfmon\n", fd));
-               goto error_args;
-       }
-
-       ctx = f.file->private_data;
-       if (unlikely(ctx == NULL)) {
-               DPRINT(("no context for fd %d\n", fd));
-               goto error_args;
-       }
-       prefetch(&ctx->ctx_state);
-
-       PROTECT_CTX(ctx, flags);
-
-       /*
-        * check task is stopped
-        */
-       ret = pfm_check_task_state(ctx, cmd, flags);
-       if (unlikely(ret)) goto abort_locked;
-
-skip_fd:
-       ret = (*func)(ctx, args_k, count, task_pt_regs(current));
-
-       call_made = 1;
-
-abort_locked:
-       if (likely(ctx)) {
-               DPRINT(("context unlocked\n"));
-               UNPROTECT_CTX(ctx, flags);
-       }
-
-       /* copy argument back to user, if needed */
-       if (call_made && PFM_CMD_RW_ARG(cmd) && copy_to_user(arg, args_k, base_sz*count)) ret = -EFAULT;
-
-error_args:
-       if (f.file)
-               fdput(f);
-
-       kfree(args_k);
-
-       DPRINT(("cmd=%s ret=%ld\n", PFM_CMD_NAME(cmd), ret));
-
-       return ret;
-}
-
-static void
-pfm_resume_after_ovfl(pfm_context_t *ctx, unsigned long ovfl_regs, struct pt_regs *regs)
-{
-       pfm_buffer_fmt_t *fmt = ctx->ctx_buf_fmt;
-       pfm_ovfl_ctrl_t rst_ctrl;
-       int state;
-       int ret = 0;
-
-       state = ctx->ctx_state;
-       /*
-        * Unlock sampling buffer and reset index atomically
-        * XXX: not really needed when blocking
-        */
-       if (CTX_HAS_SMPL(ctx)) {
-
-               rst_ctrl.bits.mask_monitoring = 0;
-               rst_ctrl.bits.reset_ovfl_pmds = 0;
-
-               if (state == PFM_CTX_LOADED)
-                       ret = pfm_buf_fmt_restart_active(fmt, current, &rst_ctrl, ctx->ctx_smpl_hdr, regs);
-               else
-                       ret = pfm_buf_fmt_restart(fmt, current, &rst_ctrl, ctx->ctx_smpl_hdr, regs);
-       } else {
-               rst_ctrl.bits.mask_monitoring = 0;
-               rst_ctrl.bits.reset_ovfl_pmds = 1;
-       }
-
-       if (ret == 0) {
-               if (rst_ctrl.bits.reset_ovfl_pmds) {
-                       pfm_reset_regs(ctx, &ovfl_regs, PFM_PMD_LONG_RESET);
-               }
-               if (rst_ctrl.bits.mask_monitoring == 0) {
-                       DPRINT(("resuming monitoring\n"));
-                       if (ctx->ctx_state == PFM_CTX_MASKED) pfm_restore_monitoring(current);
-               } else {
-                       DPRINT(("stopping monitoring\n"));
-                       //pfm_stop_monitoring(current, regs);
-               }
-               ctx->ctx_state = PFM_CTX_LOADED;
-       }
-}
-
-/*
- * context MUST BE LOCKED when calling
- * can only be called for current
- */
-static void
-pfm_context_force_terminate(pfm_context_t *ctx, struct pt_regs *regs)
-{
-       int ret;
-
-       DPRINT(("entering for [%d]\n", task_pid_nr(current)));
-
-       ret = pfm_context_unload(ctx, NULL, 0, regs);
-       if (ret) {
-               printk(KERN_ERR "pfm_context_force_terminate: [%d] unloaded failed with %d\n", task_pid_nr(current), ret);
-       }
-
-       /*
-        * and wakeup controlling task, indicating we are now disconnected
-        */
-       wake_up_interruptible(&ctx->ctx_zombieq);
-
-       /*
-        * given that context is still locked, the controlling
-        * task will only get access when we return from
-        * pfm_handle_work().
-        */
-}
-
-static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds);
-
- /*
-  * pfm_handle_work() can be called with interrupts enabled
-  * (TIF_NEED_RESCHED) or disabled. The down_interruptible
-  * call may sleep, therefore we must re-enable interrupts
-  * to avoid deadlocks. It is safe to do so because this function
-  * is called ONLY when returning to user level (pUStk=1), in which case
-  * there is no risk of kernel stack overflow due to deep
-  * interrupt nesting.
-  */
-void
-pfm_handle_work(void)
-{
-       pfm_context_t *ctx;
-       struct pt_regs *regs;
-       unsigned long flags, dummy_flags;
-       unsigned long ovfl_regs;
-       unsigned int reason;
-       int ret;
-
-       ctx = PFM_GET_CTX(current);
-       if (ctx == NULL) {
-               printk(KERN_ERR "perfmon: [%d] has no PFM context\n",
-                       task_pid_nr(current));
-               return;
-       }
-
-       PROTECT_CTX(ctx, flags);
-
-       PFM_SET_WORK_PENDING(current, 0);
-
-       regs = task_pt_regs(current);
-
-       /*
-        * extract reason for being here and clear
-        */
-       reason = ctx->ctx_fl_trap_reason;
-       ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE;
-       ovfl_regs = ctx->ctx_ovfl_regs[0];
-
-       DPRINT(("reason=%d state=%d\n", reason, ctx->ctx_state));
-
-       /*
-        * must be done before we check for simple-reset mode
-        */
-       if (ctx->ctx_fl_going_zombie || ctx->ctx_state == PFM_CTX_ZOMBIE)
-               goto do_zombie;
-
-       //if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking;
-       if (reason == PFM_TRAP_REASON_RESET)
-               goto skip_blocking;
-
-       /*
-        * restore interrupt mask to what it was on entry.
-        * Could be enabled/diasbled.
-        */
-       UNPROTECT_CTX(ctx, flags);
-
-       /*
-        * force interrupt enable because of down_interruptible()
-        */
-       local_irq_enable();
-
-       DPRINT(("before block sleeping\n"));
-
-       /*
-        * may go through without blocking on SMP systems
-        * if restart has been received already by the time we call down()
-        */
-       ret = wait_for_completion_interruptible(&ctx->ctx_restart_done);
-
-       DPRINT(("after block sleeping ret=%d\n", ret));
-
-       /*
-        * lock context and mask interrupts again
-        * We save flags into a dummy because we may have
-        * altered interrupts mask compared to entry in this
-        * function.
-        */
-       PROTECT_CTX(ctx, dummy_flags);
-
-       /*
-        * we need to read the ovfl_regs only after wake-up
-        * because we may have had pfm_write_pmds() in between
-        * and that can changed PMD values and therefore 
-        * ovfl_regs is reset for these new PMD values.
-        */
-       ovfl_regs = ctx->ctx_ovfl_regs[0];
-
-       if (ctx->ctx_fl_going_zombie) {
-do_zombie:
-               DPRINT(("context is zombie, bailing out\n"));
-               pfm_context_force_terminate(ctx, regs);
-               goto nothing_to_do;
-       }
-       /*
-        * in case of interruption of down() we don't restart anything
-        */
-       if (ret < 0)
-               goto nothing_to_do;
-
-skip_blocking:
-       pfm_resume_after_ovfl(ctx, ovfl_regs, regs);
-       ctx->ctx_ovfl_regs[0] = 0UL;
-
-nothing_to_do:
-       /*
-        * restore flags as they were upon entry
-        */
-       UNPROTECT_CTX(ctx, flags);
-}
-
-static int
-pfm_notify_user(pfm_context_t *ctx, pfm_msg_t *msg)
-{
-       if (ctx->ctx_state == PFM_CTX_ZOMBIE) {
-               DPRINT(("ignoring overflow notification, owner is zombie\n"));
-               return 0;
-       }
-
-       DPRINT(("waking up somebody\n"));
-
-       if (msg) wake_up_interruptible(&ctx->ctx_msgq_wait);
-
-       /*
-        * safe, we are not in intr handler, nor in ctxsw when
-        * we come here
-        */
-       kill_fasync (&ctx->ctx_async_queue, SIGIO, POLL_IN);
-
-       return 0;
-}
-
-static int
-pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds)
-{
-       pfm_msg_t *msg = NULL;
-
-       if (ctx->ctx_fl_no_msg == 0) {
-               msg = pfm_get_new_msg(ctx);
-               if (msg == NULL) {
-                       printk(KERN_ERR "perfmon: pfm_ovfl_notify_user no more notification msgs\n");
-                       return -1;
-               }
-
-               msg->pfm_ovfl_msg.msg_type         = PFM_MSG_OVFL;
-               msg->pfm_ovfl_msg.msg_ctx_fd       = ctx->ctx_fd;
-               msg->pfm_ovfl_msg.msg_active_set   = 0;
-               msg->pfm_ovfl_msg.msg_ovfl_pmds[0] = ovfl_pmds;
-               msg->pfm_ovfl_msg.msg_ovfl_pmds[1] = 0UL;
-               msg->pfm_ovfl_msg.msg_ovfl_pmds[2] = 0UL;
-               msg->pfm_ovfl_msg.msg_ovfl_pmds[3] = 0UL;
-               msg->pfm_ovfl_msg.msg_tstamp       = 0UL;
-       }
-
-       DPRINT(("ovfl msg: msg=%p no_msg=%d fd=%d ovfl_pmds=0x%lx\n",
-               msg,
-               ctx->ctx_fl_no_msg,
-               ctx->ctx_fd,
-               ovfl_pmds));
-
-       return pfm_notify_user(ctx, msg);
-}
-
-static int
-pfm_end_notify_user(pfm_context_t *ctx)
-{
-       pfm_msg_t *msg;
-
-       msg = pfm_get_new_msg(ctx);
-       if (msg == NULL) {
-               printk(KERN_ERR "perfmon: pfm_end_notify_user no more notification msgs\n");
-               return -1;
-       }
-       /* no leak */
-       memset(msg, 0, sizeof(*msg));
-
-       msg->pfm_end_msg.msg_type    = PFM_MSG_END;
-       msg->pfm_end_msg.msg_ctx_fd  = ctx->ctx_fd;
-       msg->pfm_ovfl_msg.msg_tstamp = 0UL;
-
-       DPRINT(("end msg: msg=%p no_msg=%d ctx_fd=%d\n",
-               msg,
-               ctx->ctx_fl_no_msg,
-               ctx->ctx_fd));
-
-       return pfm_notify_user(ctx, msg);
-}
-
-/*
- * main overflow processing routine.
- * it can be called from the interrupt path or explicitly during the context switch code
- */
-static void pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx,
-                               unsigned long pmc0, struct pt_regs *regs)
-{
-       pfm_ovfl_arg_t *ovfl_arg;
-       unsigned long mask;
-       unsigned long old_val, ovfl_val, new_val;
-       unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL, smpl_pmds = 0UL, reset_pmds;
-       unsigned long tstamp;
-       pfm_ovfl_ctrl_t ovfl_ctrl;
-       unsigned int i, has_smpl;
-       int must_notify = 0;
-
-       if (unlikely(ctx->ctx_state == PFM_CTX_ZOMBIE)) goto stop_monitoring;
-
-       /*
-        * sanity test. Should never happen
-        */
-       if (unlikely((pmc0 & 0x1) == 0)) goto sanity_check;
-
-       tstamp   = ia64_get_itc();
-       mask     = pmc0 >> PMU_FIRST_COUNTER;
-       ovfl_val = pmu_conf->ovfl_val;
-       has_smpl = CTX_HAS_SMPL(ctx);
-
-       DPRINT_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s "
-                    "used_pmds=0x%lx\n",
-                       pmc0,
-                       task ? task_pid_nr(task): -1,
-                       (regs ? regs->cr_iip : 0),
-                       CTX_OVFL_NOBLOCK(ctx) ? "nonblocking" : "blocking",
-                       ctx->ctx_used_pmds[0]));
-
-
-       /*
-        * first we update the virtual counters
-        * assume there was a prior ia64_srlz_d() issued
-        */
-       for (i = PMU_FIRST_COUNTER; mask ; i++, mask >>= 1) {
-
-               /* skip pmd which did not overflow */
-               if ((mask & 0x1) == 0) continue;
-
-               /*
-                * Note that the pmd is not necessarily 0 at this point as qualified events
-                * may have happened before the PMU was frozen. The residual count is not
-                * taken into consideration here but will be with any read of the pmd via
-                * pfm_read_pmds().
-                */
-               old_val              = new_val = ctx->ctx_pmds[i].val;
-               new_val             += 1 + ovfl_val;
-               ctx->ctx_pmds[i].val = new_val;
-
-               /*
-                * check for overflow condition
-                */
-               if (likely(old_val > new_val)) {
-                       ovfl_pmds |= 1UL << i;
-                       if (PMC_OVFL_NOTIFY(ctx, i)) ovfl_notify |= 1UL << i;
-               }
-
-               DPRINT_ovfl(("ctx_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx\n",
-                       i,
-                       new_val,
-                       old_val,
-                       ia64_get_pmd(i) & ovfl_val,
-                       ovfl_pmds,
-                       ovfl_notify));
-       }
-
-       /*
-        * there was no 64-bit overflow, nothing else to do
-        */
-       if (ovfl_pmds == 0UL) return;
-
-       /* 
-        * reset all control bits
-        */
-       ovfl_ctrl.val = 0;
-       reset_pmds    = 0UL;
-
-       /*
-        * if a sampling format module exists, then we "cache" the overflow by 
-        * calling the module's handler() routine.
-        */
-       if (has_smpl) {
-               unsigned long start_cycles, end_cycles;
-               unsigned long pmd_mask;
-               int j, k, ret = 0;
-               int this_cpu = smp_processor_id();
-
-               pmd_mask = ovfl_pmds >> PMU_FIRST_COUNTER;
-               ovfl_arg = &ctx->ctx_ovfl_arg;
-
-               prefetch(ctx->ctx_smpl_hdr);
-
-               for(i=PMU_FIRST_COUNTER; pmd_mask && ret == 0; i++, pmd_mask >>=1) {
-
-                       mask = 1UL << i;
-
-                       if ((pmd_mask & 0x1) == 0) continue;
-
-                       ovfl_arg->ovfl_pmd      = (unsigned char )i;
-                       ovfl_arg->ovfl_notify   = ovfl_notify & mask ? 1 : 0;
-                       ovfl_arg->active_set    = 0;
-                       ovfl_arg->ovfl_ctrl.val = 0; /* module must fill in all fields */
-                       ovfl_arg->smpl_pmds[0]  = smpl_pmds = ctx->ctx_pmds[i].smpl_pmds[0];
-
-                       ovfl_arg->pmd_value      = ctx->ctx_pmds[i].val;
-                       ovfl_arg->pmd_last_reset = ctx->ctx_pmds[i].lval;
-                       ovfl_arg->pmd_eventid    = ctx->ctx_pmds[i].eventid;
-
-                       /*
-                        * copy values of pmds of interest. Sampling format may copy them
-                        * into sampling buffer.
-                        */
-                       if (smpl_pmds) {
-                               for(j=0, k=0; smpl_pmds; j++, smpl_pmds >>=1) {
-                                       if ((smpl_pmds & 0x1) == 0) continue;
-                                       ovfl_arg->smpl_pmds_values[k++] = PMD_IS_COUNTING(j) ?  pfm_read_soft_counter(ctx, j) : ia64_get_pmd(j);
-                                       DPRINT_ovfl(("smpl_pmd[%d]=pmd%u=0x%lx\n", k-1, j, ovfl_arg->smpl_pmds_values[k-1]));
-                               }
-                       }
-
-                       pfm_stats[this_cpu].pfm_smpl_handler_calls++;
-
-                       start_cycles = ia64_get_itc();
-
-                       /*
-                        * call custom buffer format record (handler) routine
-                        */
-                       ret = (*ctx->ctx_buf_fmt->fmt_handler)(task, ctx->ctx_smpl_hdr, ovfl_arg, regs, tstamp);
-
-                       end_cycles = ia64_get_itc();
-
-                       /*
-                        * For those controls, we take the union because they have
-                        * an all or nothing behavior.
-                        */
-                       ovfl_ctrl.bits.notify_user     |= ovfl_arg->ovfl_ctrl.bits.notify_user;
-                       ovfl_ctrl.bits.block_task      |= ovfl_arg->ovfl_ctrl.bits.block_task;
-                       ovfl_ctrl.bits.mask_monitoring |= ovfl_arg->ovfl_ctrl.bits.mask_monitoring;
-                       /*
-                        * build the bitmask of pmds to reset now
-                        */
-                       if (ovfl_arg->ovfl_ctrl.bits.reset_ovfl_pmds) reset_pmds |= mask;
-
-                       pfm_stats[this_cpu].pfm_smpl_handler_cycles += end_cycles - start_cycles;
-               }
-               /*
-                * when the module cannot handle the rest of the overflows, we abort right here
-                */
-               if (ret && pmd_mask) {
-                       DPRINT(("handler aborts leftover ovfl_pmds=0x%lx\n",
-                               pmd_mask<<PMU_FIRST_COUNTER));
-               }
-               /*
-                * remove the pmds we reset now from the set of pmds to reset in pfm_restart()
-                */
-               ovfl_pmds &= ~reset_pmds;
-       } else {
-               /*
-                * when no sampling module is used, then the default
-                * is to notify on overflow if requested by user
-                */
-               ovfl_ctrl.bits.notify_user     = ovfl_notify ? 1 : 0;
-               ovfl_ctrl.bits.block_task      = ovfl_notify ? 1 : 0;
-               ovfl_ctrl.bits.mask_monitoring = ovfl_notify ? 1 : 0; /* XXX: change for saturation */
-               ovfl_ctrl.bits.reset_ovfl_pmds = ovfl_notify ? 0 : 1;
-               /*
-                * if needed, we reset all overflowed pmds
-                */
-               if (ovfl_notify == 0) reset_pmds = ovfl_pmds;
-       }
-
-       DPRINT_ovfl(("ovfl_pmds=0x%lx reset_pmds=0x%lx\n", ovfl_pmds, reset_pmds));
-
-       /*
-        * reset the requested PMD registers using the short reset values
-        */
-       if (reset_pmds) {
-               unsigned long bm = reset_pmds;
-               pfm_reset_regs(ctx, &bm, PFM_PMD_SHORT_RESET);
-       }
-
-       if (ovfl_notify && ovfl_ctrl.bits.notify_user) {
-               /*
-                * keep track of what to reset when unblocking
-                */
-               ctx->ctx_ovfl_regs[0] = ovfl_pmds;
-
-               /*
-                * check for blocking context 
-                */
-               if (CTX_OVFL_NOBLOCK(ctx) == 0 && ovfl_ctrl.bits.block_task) {
-
-                       ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_BLOCK;
-
-                       /*
-                        * set the perfmon specific checking pending work for the task
-                        */
-                       PFM_SET_WORK_PENDING(task, 1);
-
-                       /*
-                        * when coming from ctxsw, current still points to the
-                        * previous task, therefore we must work with task and not current.
-                        */
-                       set_notify_resume(task);
-               }
-               /*
-                * defer until state is changed (shorten spin window). the context is locked
-                * anyway, so the signal receiver would come spin for nothing.
-                */
-               must_notify = 1;
-       }
-
-       DPRINT_ovfl(("owner [%d] pending=%ld reason=%u ovfl_pmds=0x%lx ovfl_notify=0x%lx masked=%d\n",
-                       GET_PMU_OWNER() ? task_pid_nr(GET_PMU_OWNER()) : -1,
-                       PFM_GET_WORK_PENDING(task),
-                       ctx->ctx_fl_trap_reason,
-                       ovfl_pmds,
-                       ovfl_notify,
-                       ovfl_ctrl.bits.mask_monitoring ? 1 : 0));
-       /*
-        * in case monitoring must be stopped, we toggle the psr bits
-        */
-       if (ovfl_ctrl.bits.mask_monitoring) {
-               pfm_mask_monitoring(task);
-               ctx->ctx_state = PFM_CTX_MASKED;
-               ctx->ctx_fl_can_restart = 1;
-       }
-
-       /*
-        * send notification now
-        */
-       if (must_notify) pfm_ovfl_notify_user(ctx, ovfl_notify);
-
-       return;
-
-sanity_check:
-       printk(KERN_ERR "perfmon: CPU%d overflow handler [%d] pmc0=0x%lx\n",
-                       smp_processor_id(),
-                       task ? task_pid_nr(task) : -1,
-                       pmc0);
-       return;
-
-stop_monitoring:
-       /*
-        * in SMP, zombie context is never restored but reclaimed in pfm_load_regs().
-        * Moreover, zombies are also reclaimed in pfm_save_regs(). Therefore we can
-        * come here as zombie only if the task is the current task. In which case, we
-        * can access the PMU  hardware directly.
-        *
-        * Note that zombies do have PM_VALID set. So here we do the minimal.
-        *
-        * In case the context was zombified it could not be reclaimed at the time
-        * the monitoring program exited. At this point, the PMU reservation has been
-        * returned, the sampiing buffer has been freed. We must convert this call
-        * into a spurious interrupt. However, we must also avoid infinite overflows
-        * by stopping monitoring for this task. We can only come here for a per-task
-        * context. All we need to do is to stop monitoring using the psr bits which
-        * are always task private. By re-enabling secure montioring, we ensure that
-        * the monitored task will not be able to re-activate monitoring.
-        * The task will eventually be context switched out, at which point the context
-        * will be reclaimed (that includes releasing ownership of the PMU).
-        *
-        * So there might be a window of time where the number of per-task session is zero
-        * yet one PMU might have a owner and get at most one overflow interrupt for a zombie
-        * context. This is safe because if a per-task session comes in, it will push this one
-        * out and by the virtue on pfm_save_regs(), this one will disappear. If a system wide
-        * session is force on that CPU, given that we use task pinning, pfm_save_regs() will
-        * also push our zombie context out.
-        *
-        * Overall pretty hairy stuff....
-        */
-       DPRINT(("ctx is zombie for [%d], converted to spurious\n", task ? task_pid_nr(task): -1));
-       pfm_clear_psr_up();
-       ia64_psr(regs)->up = 0;
-       ia64_psr(regs)->sp = 1;
-       return;
-}
-
-static int
-pfm_do_interrupt_handler(void *arg, struct pt_regs *regs)
-{
-       struct task_struct *task;
-       pfm_context_t *ctx;
-       unsigned long flags;
-       u64 pmc0;
-       int this_cpu = smp_processor_id();
-       int retval = 0;
-
-       pfm_stats[this_cpu].pfm_ovfl_intr_count++;
-
-       /*
-        * srlz.d done before arriving here
-        */
-       pmc0 = ia64_get_pmc(0);
-
-       task = GET_PMU_OWNER();
-       ctx  = GET_PMU_CTX();
-
-       /*
-        * if we have some pending bits set
-        * assumes : if any PMC0.bit[63-1] is set, then PMC0.fr = 1
-        */
-       if (PMC0_HAS_OVFL(pmc0) && task) {
-               /*
-                * we assume that pmc0.fr is always set here
-                */
-
-               /* sanity check */
-               if (!ctx) goto report_spurious1;
-
-               if (ctx->ctx_fl_system == 0 && (task->thread.flags & IA64_THREAD_PM_VALID) == 0) 
-                       goto report_spurious2;
-
-               PROTECT_CTX_NOPRINT(ctx, flags);
-
-               pfm_overflow_handler(task, ctx, pmc0, regs);
-
-               UNPROTECT_CTX_NOPRINT(ctx, flags);
-
-       } else {
-               pfm_stats[this_cpu].pfm_spurious_ovfl_intr_count++;
-               retval = -1;
-       }
-       /*
-        * keep it unfrozen at all times
-        */
-       pfm_unfreeze_pmu();
-
-       return retval;
-
-report_spurious1:
-       printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d has no PFM context\n",
-               this_cpu, task_pid_nr(task));
-       pfm_unfreeze_pmu();
-       return -1;
-report_spurious2:
-       printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d, invalid flag\n", 
-               this_cpu, 
-               task_pid_nr(task));
-       pfm_unfreeze_pmu();
-       return -1;
-}
-
-static irqreturn_t
-pfm_interrupt_handler(int irq, void *arg)
-{
-       unsigned long start_cycles, total_cycles;
-       unsigned long min, max;
-       int this_cpu;
-       int ret;
-       struct pt_regs *regs = get_irq_regs();
-
-       this_cpu = get_cpu();
-       if (likely(!pfm_alt_intr_handler)) {
-               min = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min;
-               max = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max;
-
-               start_cycles = ia64_get_itc();
-
-               ret = pfm_do_interrupt_handler(arg, regs);
-
-               total_cycles = ia64_get_itc();
-
-               /*
-                * don't measure spurious interrupts
-                */
-               if (likely(ret == 0)) {
-                       total_cycles -= start_cycles;
-
-                       if (total_cycles < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = total_cycles;
-                       if (total_cycles > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = total_cycles;
-
-                       pfm_stats[this_cpu].pfm_ovfl_intr_cycles += total_cycles;
-               }
-       }
-       else {
-               (*pfm_alt_intr_handler->handler)(irq, arg, regs);
-       }
-
-       put_cpu();
-       return IRQ_HANDLED;
-}
-
-/*
- * /proc/perfmon interface, for debug only
- */
-
-#define PFM_PROC_SHOW_HEADER   ((void *)(long)nr_cpu_ids+1)
-
-static void *
-pfm_proc_start(struct seq_file *m, loff_t *pos)
-{
-       if (*pos == 0) {
-               return PFM_PROC_SHOW_HEADER;
-       }
-
-       while (*pos <= nr_cpu_ids) {
-               if (cpu_online(*pos - 1)) {
-                       return (void *)*pos;
-               }
-               ++*pos;
-       }
-       return NULL;
-}
-
-static void *
-pfm_proc_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       ++*pos;
-       return pfm_proc_start(m, pos);
-}
-
-static void
-pfm_proc_stop(struct seq_file *m, void *v)
-{
-}
-
-static void
-pfm_proc_show_header(struct seq_file *m)
-{
-       struct list_head * pos;
-       pfm_buffer_fmt_t * entry;
-       unsigned long flags;
-
-       seq_printf(m,
-               "perfmon version           : %u.%u\n"
-               "model                     : %s\n"
-               "fastctxsw                 : %s\n"
-               "expert mode               : %s\n"
-               "ovfl_mask                 : 0x%lx\n"
-               "PMU flags                 : 0x%x\n",
-               PFM_VERSION_MAJ, PFM_VERSION_MIN,
-               pmu_conf->pmu_name,
-               pfm_sysctl.fastctxsw > 0 ? "Yes": "No",
-               pfm_sysctl.expert_mode > 0 ? "Yes": "No",
-               pmu_conf->ovfl_val,
-               pmu_conf->flags);
-
-       LOCK_PFS(flags);
-
-       seq_printf(m,
-               "proc_sessions             : %u\n"
-               "sys_sessions              : %u\n"
-               "sys_use_dbregs            : %u\n"
-               "ptrace_use_dbregs         : %u\n",
-               pfm_sessions.pfs_task_sessions,
-               pfm_sessions.pfs_sys_sessions,
-               pfm_sessions.pfs_sys_use_dbregs,
-               pfm_sessions.pfs_ptrace_use_dbregs);
-
-       UNLOCK_PFS(flags);
-
-       spin_lock(&pfm_buffer_fmt_lock);
-
-       list_for_each(pos, &pfm_buffer_fmt_list) {
-               entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list);
-               seq_printf(m, "format                    : %16phD %s\n",
-                          entry->fmt_uuid, entry->fmt_name);
-       }
-       spin_unlock(&pfm_buffer_fmt_lock);
-
-}
-
-static int
-pfm_proc_show(struct seq_file *m, void *v)
-{
-       unsigned long psr;
-       unsigned int i;
-       int cpu;
-
-       if (v == PFM_PROC_SHOW_HEADER) {
-               pfm_proc_show_header(m);
-               return 0;
-       }
-
-       /* show info for CPU (v - 1) */
-
-       cpu = (long)v - 1;
-       seq_printf(m,
-               "CPU%-2d overflow intrs      : %lu\n"
-               "CPU%-2d overflow cycles     : %lu\n"
-               "CPU%-2d overflow min        : %lu\n"
-               "CPU%-2d overflow max        : %lu\n"
-               "CPU%-2d smpl handler calls  : %lu\n"
-               "CPU%-2d smpl handler cycles : %lu\n"
-               "CPU%-2d spurious intrs      : %lu\n"
-               "CPU%-2d replay   intrs      : %lu\n"
-               "CPU%-2d syst_wide           : %d\n"
-               "CPU%-2d dcr_pp              : %d\n"
-               "CPU%-2d exclude idle        : %d\n"
-               "CPU%-2d owner               : %d\n"
-               "CPU%-2d context             : %p\n"
-               "CPU%-2d activations         : %lu\n",
-               cpu, pfm_stats[cpu].pfm_ovfl_intr_count,
-               cpu, pfm_stats[cpu].pfm_ovfl_intr_cycles,
-               cpu, pfm_stats[cpu].pfm_ovfl_intr_cycles_min,
-               cpu, pfm_stats[cpu].pfm_ovfl_intr_cycles_max,
-               cpu, pfm_stats[cpu].pfm_smpl_handler_calls,
-               cpu, pfm_stats[cpu].pfm_smpl_handler_cycles,
-               cpu, pfm_stats[cpu].pfm_spurious_ovfl_intr_count,
-               cpu, pfm_stats[cpu].pfm_replay_ovfl_intr_count,
-               cpu, pfm_get_cpu_data(pfm_syst_info, cpu) & PFM_CPUINFO_SYST_WIDE ? 1 : 0,
-               cpu, pfm_get_cpu_data(pfm_syst_info, cpu) & PFM_CPUINFO_DCR_PP ? 1 : 0,
-               cpu, pfm_get_cpu_data(pfm_syst_info, cpu) & PFM_CPUINFO_EXCL_IDLE ? 1 : 0,
-               cpu, pfm_get_cpu_data(pmu_owner, cpu) ? pfm_get_cpu_data(pmu_owner, cpu)->pid: -1,
-               cpu, pfm_get_cpu_data(pmu_ctx, cpu),
-               cpu, pfm_get_cpu_data(pmu_activation_number, cpu));
-
-       if (num_online_cpus() == 1 && pfm_sysctl.debug > 0) {
-
-               psr = pfm_get_psr();
-
-               ia64_srlz_d();
-
-               seq_printf(m, 
-                       "CPU%-2d psr                 : 0x%lx\n"
-                       "CPU%-2d pmc0                : 0x%lx\n", 
-                       cpu, psr,
-                       cpu, ia64_get_pmc(0));
-
-               for (i=0; PMC_IS_LAST(i) == 0;  i++) {
-                       if (PMC_IS_COUNTING(i) == 0) continue;
-                       seq_printf(m, 
-                               "CPU%-2d pmc%u                : 0x%lx\n"
-                               "CPU%-2d pmd%u                : 0x%lx\n", 
-                               cpu, i, ia64_get_pmc(i),
-                               cpu, i, ia64_get_pmd(i));
-               }
-       }
-       return 0;
-}
-
-const struct seq_operations pfm_seq_ops = {
-       .start =        pfm_proc_start,
-       .next =         pfm_proc_next,
-       .stop =         pfm_proc_stop,
-       .show =         pfm_proc_show
-};
-
-/*
- * we come here as soon as local_cpu_data->pfm_syst_wide is set. this happens
- * during pfm_enable() hence before pfm_start(). We cannot assume monitoring
- * is active or inactive based on mode. We must rely on the value in
- * local_cpu_data->pfm_syst_info
- */
-void
-pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin)
-{
-       struct pt_regs *regs;
-       unsigned long dcr;
-       unsigned long dcr_pp;
-
-       dcr_pp = info & PFM_CPUINFO_DCR_PP ? 1 : 0;
-
-       /*
-        * pid 0 is guaranteed to be the idle task. There is one such task with pid 0
-        * on every CPU, so we can rely on the pid to identify the idle task.
-        */
-       if ((info & PFM_CPUINFO_EXCL_IDLE) == 0 || task->pid) {
-               regs = task_pt_regs(task);
-               ia64_psr(regs)->pp = is_ctxswin ? dcr_pp : 0;
-               return;
-       }
-       /*
-        * if monitoring has started
-        */
-       if (dcr_pp) {
-               dcr = ia64_getreg(_IA64_REG_CR_DCR);
-               /*
-                * context switching in?
-                */
-               if (is_ctxswin) {
-                       /* mask monitoring for the idle task */
-                       ia64_setreg(_IA64_REG_CR_DCR, dcr & ~IA64_DCR_PP);
-                       pfm_clear_psr_pp();
-                       ia64_srlz_i();
-                       return;
-               }
-               /*
-                * context switching out
-                * restore monitoring for next task
-                *
-                * Due to inlining this odd if-then-else construction generates
-                * better code.
-                */
-               ia64_setreg(_IA64_REG_CR_DCR, dcr |IA64_DCR_PP);
-               pfm_set_psr_pp();
-               ia64_srlz_i();
-       }
-}
-
-#ifdef CONFIG_SMP
-
-static void
-pfm_force_cleanup(pfm_context_t *ctx, struct pt_regs *regs)
-{
-       struct task_struct *task = ctx->ctx_task;
-
-       ia64_psr(regs)->up = 0;
-       ia64_psr(regs)->sp = 1;
-
-       if (GET_PMU_OWNER() == task) {
-               DPRINT(("cleared ownership for [%d]\n",
-                                       task_pid_nr(ctx->ctx_task)));
-               SET_PMU_OWNER(NULL, NULL);
-       }
-
-       /*
-        * disconnect the task from the context and vice-versa
-        */
-       PFM_SET_WORK_PENDING(task, 0);
-
-       task->thread.pfm_context  = NULL;
-       task->thread.flags       &= ~IA64_THREAD_PM_VALID;
-
-       DPRINT(("force cleanup for [%d]\n",  task_pid_nr(task)));
-}
-
-
-/*
- * in 2.6, interrupts are masked when we come here and the runqueue lock is held
- */
-void
-pfm_save_regs(struct task_struct *task)
-{
-       pfm_context_t *ctx;
-       unsigned long flags;
-       u64 psr;
-
-
-       ctx = PFM_GET_CTX(task);
-       if (ctx == NULL) return;
-
-       /*
-        * we always come here with interrupts ALREADY disabled by
-        * the scheduler. So we simply need to protect against concurrent
-        * access, not CPU concurrency.
-        */
-       flags = pfm_protect_ctx_ctxsw(ctx);
-
-       if (ctx->ctx_state == PFM_CTX_ZOMBIE) {
-               struct pt_regs *regs = task_pt_regs(task);
-
-               pfm_clear_psr_up();
-
-               pfm_force_cleanup(ctx, regs);
-
-               BUG_ON(ctx->ctx_smpl_hdr);
-
-               pfm_unprotect_ctx_ctxsw(ctx, flags);
-
-               pfm_context_free(ctx);
-               return;
-       }
-
-       /*
-        * save current PSR: needed because we modify it
-        */
-       ia64_srlz_d();
-       psr = pfm_get_psr();
-
-       BUG_ON(psr & (IA64_PSR_I));
-
-       /*
-        * stop monitoring:
-        * This is the last instruction which may generate an overflow
-        *
-        * We do not need to set psr.sp because, it is irrelevant in kernel.
-        * It will be restored from ipsr when going back to user level
-        */
-       pfm_clear_psr_up();
-
-       /*
-        * keep a copy of psr.up (for reload)
-        */
-       ctx->ctx_saved_psr_up = psr & IA64_PSR_UP;
-
-       /*
-        * release ownership of this PMU.
-        * PM interrupts are masked, so nothing
-        * can happen.
-        */
-       SET_PMU_OWNER(NULL, NULL);
-
-       /*
-        * we systematically save the PMD as we have no
-        * guarantee we will be schedule at that same
-        * CPU again.
-        */
-       pfm_save_pmds(ctx->th_pmds, ctx->ctx_used_pmds[0]);
-
-       /*
-        * save pmc0 ia64_srlz_d() done in pfm_save_pmds()
-        * we will need it on the restore path to check
-        * for pending overflow.
-        */
-       ctx->th_pmcs[0] = ia64_get_pmc(0);
-
-       /*
-        * unfreeze PMU if had pending overflows
-        */
-       if (ctx->th_pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
-
-       /*
-        * finally, allow context access.
-        * interrupts will still be masked after this call.
-        */
-       pfm_unprotect_ctx_ctxsw(ctx, flags);
-}
-
-#else /* !CONFIG_SMP */
-void
-pfm_save_regs(struct task_struct *task)
-{
-       pfm_context_t *ctx;
-       u64 psr;
-
-       ctx = PFM_GET_CTX(task);
-       if (ctx == NULL) return;
-
-       /*
-        * save current PSR: needed because we modify it
-        */
-       psr = pfm_get_psr();
-
-       BUG_ON(psr & (IA64_PSR_I));
-
-       /*
-        * stop monitoring:
-        * This is the last instruction which may generate an overflow
-        *
-        * We do not need to set psr.sp because, it is irrelevant in kernel.
-        * It will be restored from ipsr when going back to user level
-        */
-       pfm_clear_psr_up();
-
-       /*
-        * keep a copy of psr.up (for reload)
-        */
-       ctx->ctx_saved_psr_up = psr & IA64_PSR_UP;
-}
-
-static void
-pfm_lazy_save_regs (struct task_struct *task)
-{
-       pfm_context_t *ctx;
-       unsigned long flags;
-
-       { u64 psr  = pfm_get_psr();
-         BUG_ON(psr & IA64_PSR_UP);
-       }
-
-       ctx = PFM_GET_CTX(task);
-
-       /*
-        * we need to mask PMU overflow here to
-        * make sure that we maintain pmc0 until
-        * we save it. overflow interrupts are
-        * treated as spurious if there is no
-        * owner.
-        *
-        * XXX: I don't think this is necessary
-        */
-       PROTECT_CTX(ctx,flags);
-
-       /*
-        * release ownership of this PMU.
-        * must be done before we save the registers.
-        *
-        * after this call any PMU interrupt is treated
-        * as spurious.
-        */
-       SET_PMU_OWNER(NULL, NULL);
-
-       /*
-        * save all the pmds we use
-        */
-       pfm_save_pmds(ctx->th_pmds, ctx->ctx_used_pmds[0]);
-
-       /*
-        * save pmc0 ia64_srlz_d() done in pfm_save_pmds()
-        * it is needed to check for pended overflow
-        * on the restore path
-        */
-       ctx->th_pmcs[0] = ia64_get_pmc(0);
-
-       /*
-        * unfreeze PMU if had pending overflows
-        */
-       if (ctx->th_pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
-
-       /*
-        * now get can unmask PMU interrupts, they will
-        * be treated as purely spurious and we will not
-        * lose any information
-        */
-       UNPROTECT_CTX(ctx,flags);
-}
-#endif /* CONFIG_SMP */
-
-#ifdef CONFIG_SMP
-/*
- * in 2.6, interrupts are masked when we come here and the runqueue lock is held
- */
-void
-pfm_load_regs (struct task_struct *task)
-{
-       pfm_context_t *ctx;
-       unsigned long pmc_mask = 0UL, pmd_mask = 0UL;
-       unsigned long flags;
-       u64 psr, psr_up;
-       int need_irq_resend;
-
-       ctx = PFM_GET_CTX(task);
-       if (unlikely(ctx == NULL)) return;
-
-       BUG_ON(GET_PMU_OWNER());
-
-       /*
-        * possible on unload
-        */
-       if (unlikely((task->thread.flags & IA64_THREAD_PM_VALID) == 0)) return;
-
-       /*
-        * we always come here with interrupts ALREADY disabled by
-        * the scheduler. So we simply need to protect against concurrent
-        * access, not CPU concurrency.
-        */
-       flags = pfm_protect_ctx_ctxsw(ctx);
-       psr   = pfm_get_psr();
-
-       need_irq_resend = pmu_conf->flags & PFM_PMU_IRQ_RESEND;
-
-       BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP));
-       BUG_ON(psr & IA64_PSR_I);
-
-       if (unlikely(ctx->ctx_state == PFM_CTX_ZOMBIE)) {
-               struct pt_regs *regs = task_pt_regs(task);
-
-               BUG_ON(ctx->ctx_smpl_hdr);
-
-               pfm_force_cleanup(ctx, regs);
-
-               pfm_unprotect_ctx_ctxsw(ctx, flags);
-
-               /*
-                * this one (kmalloc'ed) is fine with interrupts disabled
-                */
-               pfm_context_free(ctx);
-
-               return;
-       }
-
-       /*
-        * we restore ALL the debug registers to avoid picking up
-        * stale state.
-        */
-       if (ctx->ctx_fl_using_dbreg) {
-               pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs);
-               pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs);
-       }
-       /*
-        * retrieve saved psr.up
-        */
-       psr_up = ctx->ctx_saved_psr_up;
-
-       /*
-        * if we were the last user of the PMU on that CPU,
-        * then nothing to do except restore psr
-        */
-       if (GET_LAST_CPU(ctx) == smp_processor_id() && ctx->ctx_last_activation == GET_ACTIVATION()) {
-
-               /*
-                * retrieve partial reload masks (due to user modifications)
-                */
-               pmc_mask = ctx->ctx_reload_pmcs[0];
-               pmd_mask = ctx->ctx_reload_pmds[0];
-
-       } else {
-               /*
-                * To avoid leaking information to the user level when psr.sp=0,
-                * we must reload ALL implemented pmds (even the ones we don't use).
-                * In the kernel we only allow PFM_READ_PMDS on registers which
-                * we initialized or requested (sampling) so there is no risk there.
-                */
-               pmd_mask = pfm_sysctl.fastctxsw ?  ctx->ctx_used_pmds[0] : ctx->ctx_all_pmds[0];
-
-               /*
-                * ALL accessible PMCs are systematically reloaded, unused registers
-                * get their default (from pfm_reset_pmu_state()) values to avoid picking
-                * up stale configuration.
-                *
-                * PMC0 is never in the mask. It is always restored separately.
-                */
-               pmc_mask = ctx->ctx_all_pmcs[0];
-       }
-       /*
-        * when context is MASKED, we will restore PMC with plm=0
-        * and PMD with stale information, but that's ok, nothing
-        * will be captured.
-        *
-        * XXX: optimize here
-        */
-       if (pmd_mask) pfm_restore_pmds(ctx->th_pmds, pmd_mask);
-       if (pmc_mask) pfm_restore_pmcs(ctx->th_pmcs, pmc_mask);
-
-       /*
-        * check for pending overflow at the time the state
-        * was saved.
-        */
-       if (unlikely(PMC0_HAS_OVFL(ctx->th_pmcs[0]))) {
-               /*
-                * reload pmc0 with the overflow information
-                * On McKinley PMU, this will trigger a PMU interrupt
-                */
-               ia64_set_pmc(0, ctx->th_pmcs[0]);
-               ia64_srlz_d();
-               ctx->th_pmcs[0] = 0UL;
-
-               /*
-                * will replay the PMU interrupt
-                */
-               if (need_irq_resend) ia64_resend_irq(IA64_PERFMON_VECTOR);
-
-               pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++;
-       }
-
-       /*
-        * we just did a reload, so we reset the partial reload fields
-        */
-       ctx->ctx_reload_pmcs[0] = 0UL;
-       ctx->ctx_reload_pmds[0] = 0UL;
-
-       SET_LAST_CPU(ctx, smp_processor_id());
-
-       /*
-        * dump activation value for this PMU
-        */
-       INC_ACTIVATION();
-       /*
-        * record current activation for this context
-        */
-       SET_ACTIVATION(ctx);
-
-       /*
-        * establish new ownership. 
-        */
-       SET_PMU_OWNER(task, ctx);
-
-       /*
-        * restore the psr.up bit. measurement
-        * is active again.
-        * no PMU interrupt can happen at this point
-        * because we still have interrupts disabled.
-        */
-       if (likely(psr_up)) pfm_set_psr_up();
-
-       /*
-        * allow concurrent access to context
-        */
-       pfm_unprotect_ctx_ctxsw(ctx, flags);
-}
-#else /*  !CONFIG_SMP */
-/*
- * reload PMU state for UP kernels
- * in 2.5 we come here with interrupts disabled
- */
-void
-pfm_load_regs (struct task_struct *task)
-{
-       pfm_context_t *ctx;
-       struct task_struct *owner;
-       unsigned long pmd_mask, pmc_mask;
-       u64 psr, psr_up;
-       int need_irq_resend;
-
-       owner = GET_PMU_OWNER();
-       ctx   = PFM_GET_CTX(task);
-       psr   = pfm_get_psr();
-
-       BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP));
-       BUG_ON(psr & IA64_PSR_I);
-
-       /*
-        * we restore ALL the debug registers to avoid picking up
-        * stale state.
-        *
-        * This must be done even when the task is still the owner
-        * as the registers may have been modified via ptrace()
-        * (not perfmon) by the previous task.
-        */
-       if (ctx->ctx_fl_using_dbreg) {
-               pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs);
-               pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs);
-       }
-
-       /*
-        * retrieved saved psr.up
-        */
-       psr_up = ctx->ctx_saved_psr_up;
-       need_irq_resend = pmu_conf->flags & PFM_PMU_IRQ_RESEND;
-
-       /*
-        * short path, our state is still there, just
-        * need to restore psr and we go
-        *
-        * we do not touch either PMC nor PMD. the psr is not touched
-        * by the overflow_handler. So we are safe w.r.t. to interrupt
-        * concurrency even without interrupt masking.
-        */
-       if (likely(owner == task)) {
-               if (likely(psr_up)) pfm_set_psr_up();
-               return;
-       }
-
-       /*
-        * someone else is still using the PMU, first push it out and
-        * then we'll be able to install our stuff !
-        *
-        * Upon return, there will be no owner for the current PMU
-        */
-       if (owner) pfm_lazy_save_regs(owner);
-
-       /*
-        * To avoid leaking information to the user level when psr.sp=0,
-        * we must reload ALL implemented pmds (even the ones we don't use).
-        * In the kernel we only allow PFM_READ_PMDS on registers which
-        * we initialized or requested (sampling) so there is no risk there.
-        */
-       pmd_mask = pfm_sysctl.fastctxsw ?  ctx->ctx_used_pmds[0] : ctx->ctx_all_pmds[0];
-
-       /*
-        * ALL accessible PMCs are systematically reloaded, unused registers
-        * get their default (from pfm_reset_pmu_state()) values to avoid picking
-        * up stale configuration.
-        *
-        * PMC0 is never in the mask. It is always restored separately
-        */
-       pmc_mask = ctx->ctx_all_pmcs[0];
-
-       pfm_restore_pmds(ctx->th_pmds, pmd_mask);
-       pfm_restore_pmcs(ctx->th_pmcs, pmc_mask);
-
-       /*
-        * check for pending overflow at the time the state
-        * was saved.
-        */
-       if (unlikely(PMC0_HAS_OVFL(ctx->th_pmcs[0]))) {
-               /*
-                * reload pmc0 with the overflow information
-                * On McKinley PMU, this will trigger a PMU interrupt
-                */
-               ia64_set_pmc(0, ctx->th_pmcs[0]);
-               ia64_srlz_d();
-
-               ctx->th_pmcs[0] = 0UL;
-
-               /*
-                * will replay the PMU interrupt
-                */
-               if (need_irq_resend) ia64_resend_irq(IA64_PERFMON_VECTOR);
-
-               pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++;
-       }
-
-       /*
-        * establish new ownership. 
-        */
-       SET_PMU_OWNER(task, ctx);
-
-       /*
-        * restore the psr.up bit. measurement
-        * is active again.
-        * no PMU interrupt can happen at this point
-        * because we still have interrupts disabled.
-        */
-       if (likely(psr_up)) pfm_set_psr_up();
-}
-#endif /* CONFIG_SMP */
-
-/*
- * this function assumes monitoring is stopped
- */
-static void
-pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
-{
-       u64 pmc0;
-       unsigned long mask2, val, pmd_val, ovfl_val;
-       int i, can_access_pmu = 0;
-       int is_self;
-
-       /*
-        * is the caller the task being monitored (or which initiated the
-        * session for system wide measurements)
-        */
-       is_self = ctx->ctx_task == task ? 1 : 0;
-
-       /*
-        * can access PMU is task is the owner of the PMU state on the current CPU
-        * or if we are running on the CPU bound to the context in system-wide mode
-        * (that is not necessarily the task the context is attached to in this mode).
-        * In system-wide we always have can_access_pmu true because a task running on an
-        * invalid processor is flagged earlier in the call stack (see pfm_stop).
-        */
-       can_access_pmu = (GET_PMU_OWNER() == task) || (ctx->ctx_fl_system && ctx->ctx_cpu == smp_processor_id());
-       if (can_access_pmu) {
-               /*
-                * Mark the PMU as not owned
-                * This will cause the interrupt handler to do nothing in case an overflow
-                * interrupt was in-flight
-                * This also guarantees that pmc0 will contain the final state
-                * It virtually gives us full control on overflow processing from that point
-                * on.
-                */
-               SET_PMU_OWNER(NULL, NULL);
-               DPRINT(("releasing ownership\n"));
-
-               /*
-                * read current overflow status:
-                *
-                * we are guaranteed to read the final stable state
-                */
-               ia64_srlz_d();
-               pmc0 = ia64_get_pmc(0); /* slow */
-
-               /*
-                * reset freeze bit, overflow status information destroyed
-                */
-               pfm_unfreeze_pmu();
-       } else {
-               pmc0 = ctx->th_pmcs[0];
-               /*
-                * clear whatever overflow status bits there were
-                */
-               ctx->th_pmcs[0] = 0;
-       }
-       ovfl_val = pmu_conf->ovfl_val;
-       /*
-        * we save all the used pmds
-        * we take care of overflows for counting PMDs
-        *
-        * XXX: sampling situation is not taken into account here
-        */
-       mask2 = ctx->ctx_used_pmds[0];
-
-       DPRINT(("is_self=%d ovfl_val=0x%lx mask2=0x%lx\n", is_self, ovfl_val, mask2));
-
-       for (i = 0; mask2; i++, mask2>>=1) {
-
-               /* skip non used pmds */
-               if ((mask2 & 0x1) == 0) continue;
-
-               /*
-                * can access PMU always true in system wide mode
-                */
-               val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : ctx->th_pmds[i];
-
-               if (PMD_IS_COUNTING(i)) {
-                       DPRINT(("[%d] pmd[%d] ctx_pmd=0x%lx hw_pmd=0x%lx\n",
-                               task_pid_nr(task),
-                               i,
-                               ctx->ctx_pmds[i].val,
-                               val & ovfl_val));
-
-                       /*
-                        * we rebuild the full 64 bit value of the counter
-                        */
-                       val = ctx->ctx_pmds[i].val + (val & ovfl_val);
-
-                       /*
-                        * now everything is in ctx_pmds[] and we need
-                        * to clear the saved context from save_regs() such that
-                        * pfm_read_pmds() gets the correct value
-                        */
-                       pmd_val = 0UL;
-
-                       /*
-                        * take care of overflow inline
-                        */
-                       if (pmc0 & (1UL << i)) {
-                               val += 1 + ovfl_val;
-                               DPRINT(("[%d] pmd[%d] overflowed\n", task_pid_nr(task), i));
-                       }
-               }
-
-               DPRINT(("[%d] ctx_pmd[%d]=0x%lx  pmd_val=0x%lx\n", task_pid_nr(task), i, val, pmd_val));
-
-               if (is_self) ctx->th_pmds[i] = pmd_val;
-
-               ctx->ctx_pmds[i].val = val;
-       }
-}
-
-static void
-pfm_alt_save_pmu_state(void *data)
-{
-       struct pt_regs *regs;
-
-       regs = task_pt_regs(current);
-
-       DPRINT(("called\n"));
-
-       /*
-        * should not be necessary but
-        * let's take not risk
-        */
-       pfm_clear_psr_up();
-       pfm_clear_psr_pp();
-       ia64_psr(regs)->pp = 0;
-
-       /*
-        * This call is required
-        * May cause a spurious interrupt on some processors
-        */
-       pfm_freeze_pmu();
-
-       ia64_srlz_d();
-}
-
-void
-pfm_alt_restore_pmu_state(void *data)
-{
-       struct pt_regs *regs;
-
-       regs = task_pt_regs(current);
-
-       DPRINT(("called\n"));
-
-       /*
-        * put PMU back in state expected
-        * by perfmon
-        */
-       pfm_clear_psr_up();
-       pfm_clear_psr_pp();
-       ia64_psr(regs)->pp = 0;
-
-       /*
-        * perfmon runs with PMU unfrozen at all times
-        */
-       pfm_unfreeze_pmu();
-
-       ia64_srlz_d();
-}
-
-int
-pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl)
-{
-       int ret, i;
-       int reserve_cpu;
-
-       /* some sanity checks */
-       if (hdl == NULL || hdl->handler == NULL) return -EINVAL;
-
-       /* do the easy test first */
-       if (pfm_alt_intr_handler) return -EBUSY;
-
-       /* one at a time in the install or remove, just fail the others */
-       if (!spin_trylock(&pfm_alt_install_check)) {
-               return -EBUSY;
-       }
-
-       /* reserve our session */
-       for_each_online_cpu(reserve_cpu) {
-               ret = pfm_reserve_session(NULL, 1, reserve_cpu);
-               if (ret) goto cleanup_reserve;
-       }
-
-       /* save the current system wide pmu states */
-       on_each_cpu(pfm_alt_save_pmu_state, NULL, 1);
-
-       /* officially change to the alternate interrupt handler */
-       pfm_alt_intr_handler = hdl;
-
-       spin_unlock(&pfm_alt_install_check);
-
-       return 0;
-
-cleanup_reserve:
-       for_each_online_cpu(i) {
-               /* don't unreserve more than we reserved */
-               if (i >= reserve_cpu) break;
-
-               pfm_unreserve_session(NULL, 1, i);
-       }
-
-       spin_unlock(&pfm_alt_install_check);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(pfm_install_alt_pmu_interrupt);
-
-int
-pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl)
-{
-       int i;
-
-       if (hdl == NULL) return -EINVAL;
-
-       /* cannot remove someone else's handler! */
-       if (pfm_alt_intr_handler != hdl) return -EINVAL;
-
-       /* one at a time in the install or remove, just fail the others */
-       if (!spin_trylock(&pfm_alt_install_check)) {
-               return -EBUSY;
-       }
-
-       pfm_alt_intr_handler = NULL;
-
-       on_each_cpu(pfm_alt_restore_pmu_state, NULL, 1);
-
-       for_each_online_cpu(i) {
-               pfm_unreserve_session(NULL, 1, i);
-       }
-
-       spin_unlock(&pfm_alt_install_check);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(pfm_remove_alt_pmu_interrupt);
-
-/*
- * perfmon initialization routine, called from the initcall() table
- */
-static int init_pfm_fs(void);
-
-static int __init
-pfm_probe_pmu(void)
-{
-       pmu_config_t **p;
-       int family;
-
-       family = local_cpu_data->family;
-       p      = pmu_confs;
-
-       while(*p) {
-               if ((*p)->probe) {
-                       if ((*p)->probe() == 0) goto found;
-               } else if ((*p)->pmu_family == family || (*p)->pmu_family == 0xff) {
-                       goto found;
-               }
-               p++;
-       }
-       return -1;
-found:
-       pmu_conf = *p;
-       return 0;
-}
-
-int __init
-pfm_init(void)
-{
-       unsigned int n, n_counters, i;
-
-       printk("perfmon: version %u.%u IRQ %u\n",
-               PFM_VERSION_MAJ,
-               PFM_VERSION_MIN,
-               IA64_PERFMON_VECTOR);
-
-       if (pfm_probe_pmu()) {
-               printk(KERN_INFO "perfmon: disabled, there is no support for processor family %d\n", 
-                               local_cpu_data->family);
-               return -ENODEV;
-       }
-
-       /*
-        * compute the number of implemented PMD/PMC from the
-        * description tables
-        */
-       n = 0;
-       for (i=0; PMC_IS_LAST(i) == 0;  i++) {
-               if (PMC_IS_IMPL(i) == 0) continue;
-               pmu_conf->impl_pmcs[i>>6] |= 1UL << (i&63);
-               n++;
-       }
-       pmu_conf->num_pmcs = n;
-
-       n = 0; n_counters = 0;
-       for (i=0; PMD_IS_LAST(i) == 0;  i++) {
-               if (PMD_IS_IMPL(i) == 0) continue;
-               pmu_conf->impl_pmds[i>>6] |= 1UL << (i&63);
-               n++;
-               if (PMD_IS_COUNTING(i)) n_counters++;
-       }
-       pmu_conf->num_pmds      = n;
-       pmu_conf->num_counters  = n_counters;
-
-       /*
-        * sanity checks on the number of debug registers
-        */
-       if (pmu_conf->use_rr_dbregs) {
-               if (pmu_conf->num_ibrs > IA64_NUM_DBG_REGS) {
-                       printk(KERN_INFO "perfmon: unsupported number of code debug registers (%u)\n", pmu_conf->num_ibrs);
-                       pmu_conf = NULL;
-                       return -1;
-               }
-               if (pmu_conf->num_dbrs > IA64_NUM_DBG_REGS) {
-                       printk(KERN_INFO "perfmon: unsupported number of data debug registers (%u)\n", pmu_conf->num_ibrs);
-                       pmu_conf = NULL;
-                       return -1;
-               }
-       }
-
-       printk("perfmon: %s PMU detected, %u PMCs, %u PMDs, %u counters (%lu bits)\n",
-              pmu_conf->pmu_name,
-              pmu_conf->num_pmcs,
-              pmu_conf->num_pmds,
-              pmu_conf->num_counters,
-              ffz(pmu_conf->ovfl_val));
-
-       /* sanity check */
-       if (pmu_conf->num_pmds >= PFM_NUM_PMD_REGS || pmu_conf->num_pmcs >= PFM_NUM_PMC_REGS) {
-               printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n");
-               pmu_conf = NULL;
-               return -1;
-       }
-
-       /*
-        * create /proc/perfmon (mostly for debugging purposes)
-        */
-       perfmon_dir = proc_create_seq("perfmon", S_IRUGO, NULL, &pfm_seq_ops);
-       if (perfmon_dir == NULL) {
-               printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n");
-               pmu_conf = NULL;
-               return -1;
-       }
-
-       /*
-        * create /proc/sys/kernel/perfmon (for debugging purposes)
-        */
-       pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root);
-
-       /*
-        * initialize all our spinlocks
-        */
-       spin_lock_init(&pfm_sessions.pfs_lock);
-       spin_lock_init(&pfm_buffer_fmt_lock);
-
-       init_pfm_fs();
-
-       for(i=0; i < NR_CPUS; i++) pfm_stats[i].pfm_ovfl_intr_cycles_min = ~0UL;
-
-       return 0;
-}
-
-__initcall(pfm_init);
-
-/*
- * this function is called before pfm_init()
- */
-void
-pfm_init_percpu (void)
-{
-       static int first_time=1;
-       /*
-        * make sure no measurement is active
-        * (may inherit programmed PMCs from EFI).
-        */
-       pfm_clear_psr_pp();
-       pfm_clear_psr_up();
-
-       /*
-        * we run with the PMU not frozen at all times
-        */
-       pfm_unfreeze_pmu();
-
-       if (first_time) {
-               register_percpu_irq(IA64_PERFMON_VECTOR, pfm_interrupt_handler,
-                                   0, "perfmon");
-               first_time=0;
-       }
-
-       ia64_setreg(_IA64_REG_CR_PMV, IA64_PERFMON_VECTOR);
-       ia64_srlz_d();
-}
-
-/*
- * used for debug purposes only
- */
-void
-dump_pmu_state(const char *from)
-{
-       struct task_struct *task;
-       struct pt_regs *regs;
-       pfm_context_t *ctx;
-       unsigned long psr, dcr, info, flags;
-       int i, this_cpu;
-
-       local_irq_save(flags);
-
-       this_cpu = smp_processor_id();
-       regs     = task_pt_regs(current);
-       info     = PFM_CPUINFO_GET();
-       dcr      = ia64_getreg(_IA64_REG_CR_DCR);
-
-       if (info == 0 && ia64_psr(regs)->pp == 0 && (dcr & IA64_DCR_PP) == 0) {
-               local_irq_restore(flags);
-               return;
-       }
-
-       printk("CPU%d from %s() current [%d] iip=0x%lx %s\n", 
-               this_cpu, 
-               from, 
-               task_pid_nr(current),
-               regs->cr_iip,
-               current->comm);
-
-       task = GET_PMU_OWNER();
-       ctx  = GET_PMU_CTX();
-
-       printk("->CPU%d owner [%d] ctx=%p\n", this_cpu, task ? task_pid_nr(task) : -1, ctx);
-
-       psr = pfm_get_psr();
-
-       printk("->CPU%d pmc0=0x%lx psr.pp=%d psr.up=%d dcr.pp=%d syst_info=0x%lx user_psr.up=%d user_psr.pp=%d\n", 
-               this_cpu,
-               ia64_get_pmc(0),
-               psr & IA64_PSR_PP ? 1 : 0,
-               psr & IA64_PSR_UP ? 1 : 0,
-               dcr & IA64_DCR_PP ? 1 : 0,
-               info,
-               ia64_psr(regs)->up,
-               ia64_psr(regs)->pp);
-
-       ia64_psr(regs)->up = 0;
-       ia64_psr(regs)->pp = 0;
-
-       for (i=1; PMC_IS_LAST(i) == 0; i++) {
-               if (PMC_IS_IMPL(i) == 0) continue;
-               printk("->CPU%d pmc[%d]=0x%lx thread_pmc[%d]=0x%lx\n", this_cpu, i, ia64_get_pmc(i), i, ctx->th_pmcs[i]);
-       }
-
-       for (i=1; PMD_IS_LAST(i) == 0; i++) {
-               if (PMD_IS_IMPL(i) == 0) continue;
-               printk("->CPU%d pmd[%d]=0x%lx thread_pmd[%d]=0x%lx\n", this_cpu, i, ia64_get_pmd(i), i, ctx->th_pmds[i]);
-       }
-
-       if (ctx) {
-               printk("->CPU%d ctx_state=%d vaddr=%p addr=%p fd=%d ctx_task=[%d] saved_psr_up=0x%lx\n",
-                               this_cpu,
-                               ctx->ctx_state,
-                               ctx->ctx_smpl_vaddr,
-                               ctx->ctx_smpl_hdr,
-                               ctx->ctx_msgq_head,
-                               ctx->ctx_msgq_tail,
-                               ctx->ctx_saved_psr_up);
-       }
-       local_irq_restore(flags);
-}
-
-/*
- * called from process.c:copy_thread(). task is new child.
- */
-void
-pfm_inherit(struct task_struct *task, struct pt_regs *regs)
-{
-       struct thread_struct *thread;
-
-       DPRINT(("perfmon: pfm_inherit clearing state for [%d]\n", task_pid_nr(task)));
-
-       thread = &task->thread;
-
-       /*
-        * cut links inherited from parent (current)
-        */
-       thread->pfm_context = NULL;
-
-       PFM_SET_WORK_PENDING(task, 0);
-
-       /*
-        * the psr bits are already set properly in copy_threads()
-        */
-}
-#else  /* !CONFIG_PERFMON */
-asmlinkage long
-sys_perfmonctl (int fd, int cmd, void *arg, int count)
-{
-       return -ENOSYS;
-}
-#endif /* CONFIG_PERFMON */
index f19cb97..e74e10f 100644 (file)
 
 #include "entry.h"
 
-#ifdef CONFIG_PERFMON
-# include <asm/perfmon.h>
-#endif
-
 #include "sigframe.h"
 
 void (*ia64_mark_idle)(int);
@@ -174,15 +170,6 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall)
                return;
        }
 
-#ifdef CONFIG_PERFMON
-       if (current->thread.pfm_needs_checking)
-               /*
-                * Note: pfm_handle_work() allow us to call it with interrupts
-                * disabled, and may enable interrupts within the function.
-                */
-               pfm_handle_work();
-#endif
-
        /* deal with pending signal delivery */
        if (test_thread_flag(TIF_SIGPENDING)) {
                local_irq_enable();     /* force interrupt enable */
@@ -264,41 +251,15 @@ void arch_cpu_idle(void)
 void
 ia64_save_extra (struct task_struct *task)
 {
-#ifdef CONFIG_PERFMON
-       unsigned long info;
-#endif
-
        if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0)
                ia64_save_debug_regs(&task->thread.dbr[0]);
-
-#ifdef CONFIG_PERFMON
-       if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
-               pfm_save_regs(task);
-
-       info = __this_cpu_read(pfm_syst_info);
-       if (info & PFM_CPUINFO_SYST_WIDE)
-               pfm_syst_wide_update_task(task, info, 0);
-#endif
 }
 
 void
 ia64_load_extra (struct task_struct *task)
 {
-#ifdef CONFIG_PERFMON
-       unsigned long info;
-#endif
-
        if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0)
                ia64_load_debug_regs(&task->thread.dbr[0]);
-
-#ifdef CONFIG_PERFMON
-       if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
-               pfm_load_regs(task);
-
-       info = __this_cpu_read(pfm_syst_info);
-       if (info & PFM_CPUINFO_SYST_WIDE)
-               pfm_syst_wide_update_task(task, info, 1);
-#endif
 }
 
 /*
@@ -432,11 +393,6 @@ copy_thread(unsigned long clone_flags, unsigned long user_stack_base,
         */
        child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
                                 & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
-
-#ifdef CONFIG_PERFMON
-       if (current->thread.pfm_context)
-               pfm_inherit(p, child_ptregs);
-#endif
        return retval;
 }
 
@@ -563,15 +519,6 @@ exit_thread (struct task_struct *tsk)
 {
 
        ia64_drop_fpu(tsk);
-#ifdef CONFIG_PERFMON
-       /* if needed, stop monitoring and flush state to perfmon context */
-       if (tsk->thread.pfm_context)
-               pfm_exit_thread(tsk);
-
-       /* free debug register resources */
-       if (tsk->thread.flags & IA64_THREAD_DBG_VALID)
-               pfm_release_debug_registers(tsk);
-#endif
 }
 
 unsigned long
index 33ca9fa..75c070a 100644 (file)
@@ -30,9 +30,6 @@
 #include <asm/rse.h>
 #include <linux/uaccess.h>
 #include <asm/unwind.h>
-#ifdef CONFIG_PERFMON
-#include <asm/perfmon.h>
-#endif
 
 #include "entry.h"
 
@@ -1951,27 +1948,6 @@ access_uarea(struct task_struct *child, unsigned long addr,
                                "address 0x%lx\n", addr);
                return -1;
        }
-#ifdef CONFIG_PERFMON
-       /*
-        * Check if debug registers are used by perfmon. This
-        * test must be done once we know that we can do the
-        * operation, i.e. the arguments are all valid, but
-        * before we start modifying the state.
-        *
-        * Perfmon needs to keep a count of how many processes
-        * are trying to modify the debug registers for system
-        * wide monitoring sessions.
-        *
-        * We also include read access here, because they may
-        * cause the PMU-installed debug register state
-        * (dbr[], ibr[]) to be reset. The two arrays are also
-        * used by perfmon, but we do not use
-        * IA64_THREAD_DBG_VALID. The registers are restored
-        * by the PMU context switch code.
-        */
-       if (pfm_use_debug_registers(child))
-               return -1;
-#endif
 
        if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) {
                child->thread.flags |= IA64_THREAD_DBG_VALID;
index d07ed65..e67b22f 100644 (file)
@@ -374,7 +374,7 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
                                        /* note: scr->pt.r10 is already -1 */
                                        break;
                                }
-                               /*FALLTHRU*/
+                               fallthrough;
                        case ERESTARTNOINTR:
                                ia64_decrement_ip(&scr->pt);
                                restart = 0; /* don't restart twice if handle_signal() fails... */
index c29c600..093040f 100644 (file)
@@ -355,10 +355,6 @@ smp_callin (void)
        extern void ia64_init_itm(void);
        extern volatile int time_keeper_id;
 
-#ifdef CONFIG_PERFMON
-       extern void pfm_init_percpu(void);
-#endif
-
        cpuid = smp_processor_id();
        phys_id = hard_smp_processor_id();
        itc_master = time_keeper_id;
@@ -389,10 +385,6 @@ smp_callin (void)
 
        ia64_mca_cmc_vector_setup();    /* Setup vector on AP */
 
-#ifdef CONFIG_PERFMON
-       pfm_init_percpu();
-#endif
-
        local_irq_enable();
 
        if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
index f52a41f..4799c96 100644 (file)
 148    common  mmap2                           sys_mmap2
 149    common  pciconfig_read                  sys_pciconfig_read
 150    common  pciconfig_write                 sys_pciconfig_write
-151    common  perfmonctl                      sys_perfmonctl
+151    common  perfmonctl                      sys_ni_syscall
 152    common  sigaltstack                     sys_sigaltstack
 153    common  rt_sigaction                    sys_rt_sigaction
 154    common  rt_sigpending                   sys_rt_sigpending
index 2d4e65b..6c1a895 100644 (file)
@@ -1431,7 +1431,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
                if (u.insn.x)
                        /* oops, really a semaphore op (cmpxchg, etc) */
                        goto failure;
-               /*FALLTHRU*/
+               fallthrough;
              case LDS_IMM_OP:
              case LDSA_IMM_OP:
              case LDFS_OP:
@@ -1459,7 +1459,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
                if (u.insn.x)
                        /* oops, really a semaphore op (cmpxchg, etc) */
                        goto failure;
-               /*FALLTHRU*/
+               fallthrough;
              case LD_IMM_OP:
              case LDA_IMM_OP:
              case LDBIAS_IMM_OP:
@@ -1475,7 +1475,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
                if (u.insn.x)
                        /* oops, really a semaphore op (cmpxchg, etc) */
                        goto failure;
-               /*FALLTHRU*/
+               fallthrough;
              case ST_IMM_OP:
              case STREL_IMM_OP:
                ret = emulate_store_int(ifa, u.insn, regs);
index 7601fe0..6bd64c3 100644 (file)
@@ -324,7 +324,7 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char
                                                        return 0;
                                                }
                                        }
-                                       /* fall through */
+                                       fallthrough;
                                      case UNW_NAT_NONE:
                                        dummy_nat = 0;
                                        nat_addr = &dummy_nat;
index d259690..9b26578 100644 (file)
@@ -218,6 +218,7 @@ SECTIONS {
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        /* Default discards */
        DISCARDS
index 82118b3..081fcba 100644 (file)
@@ -12,7 +12,6 @@ lib-y := io.o __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o           \
 
 lib-$(CONFIG_ITANIUM)  += copy_page.o copy_user.o memcpy.o
 lib-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o
-lib-$(CONFIG_PERFMON)  += carta_random.o
 
 AFLAGS___divdi3.o      =
 AFLAGS___udivdi3.o     = -DUNSIGNED
diff --git a/arch/ia64/lib/carta_random.S b/arch/ia64/lib/carta_random.S
deleted file mode 100644 (file)
index 1a4a639..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Fast, simple, yet decent quality random number generator based on
- * a paper by David G. Carta ("Two Fast Implementations of the
- * `Minimal Standard' Random Number Generator," Communications of the
- * ACM, January, 1990).
- *
- * Copyright (C) 2002 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#include <asm/asmmacro.h>
-
-#define a      r2
-#define m      r3
-#define lo     r8
-#define hi     r9
-#define t0     r16
-#define t1     r17
-#define        seed    r32
-
-GLOBAL_ENTRY(carta_random32)
-       movl    a = (16807 << 16) | 16807
-       ;;
-       pmpyshr2.u t0 = a, seed, 0
-       pmpyshr2.u t1 = a, seed, 16
-       ;;
-       unpack2.l t0 = t1, t0
-       dep     m = -1, r0, 0, 31
-       ;;
-       zxt4    lo = t0
-       shr.u   hi = t0, 32
-       ;;
-       dep     t0 = 0, hi, 15, 49      // t0 = (hi & 0x7fff)
-       ;;
-       shl     t0 = t0, 16             // t0 = (hi & 0x7fff) << 16
-       shr     t1 = hi, 15             // t1 = (hi >> 15)
-       ;;
-       add     lo = lo, t0
-       ;;
-       cmp.gtu p6, p0 = lo, m
-       ;;
-(p6)   and     lo = lo, m
-       ;;
-(p6)   add     lo = 1, lo
-       ;;
-       add     lo = lo, t1
-       ;;
-       cmp.gtu p6, p0 = lo, m
-       ;;
-(p6)   and     lo = lo, m
-       ;;
-(p6)   add     lo = 1, lo
-       br.ret.sptk.many rp
-END(carta_random32)
index 6e82e0b..917e313 100644 (file)
@@ -96,18 +96,3 @@ unsigned long do_csum_c(const unsigned char * buff, int len, unsigned int psum)
 out:
        return result;
 }
-
-/*
- * XXX Fixme
- *
- * This is very ugly but temporary. THIS NEEDS SERIOUS ENHANCEMENTS.
- * But it's very tricky to get right even in C.
- */
-__wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
-{
-       memcpy(dst, src, len);
-       return csum_partial(dst, len, sum);
-}
-
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
index 0b3fb4c..8e7b8c6 100644 (file)
@@ -538,7 +538,7 @@ virtual_memmap_init(u64 start, u64 end, void *arg)
        if (map_start < map_end)
                memmap_init_zone((unsigned long)(map_end - map_start),
                                 args->nid, args->zone, page_to_pfn(map_start),
-                                MEMMAP_EARLY, NULL);
+                                MEMINIT_EARLY, NULL);
        return 0;
 }
 
@@ -547,8 +547,8 @@ memmap_init (unsigned long size, int nid, unsigned long zone,
             unsigned long start_pfn)
 {
        if (!vmem_map) {
-               memmap_init_zone(size, nid, zone, start_pfn, MEMMAP_EARLY,
-                               NULL);
+               memmap_init_zone(size, nid, zone, start_pfn,
+                                MEMINIT_EARLY, NULL);
        } else {
                struct page *start;
                struct memmap_init_callback_data args;
index cd134d6..fc7944d 100644 (file)
@@ -8,4 +8,3 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
                timer_int.o )
 
 oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
-oprofile-$(CONFIG_PERFMON) += perfmon.o
index 31b545c..a692ba1 100644 (file)
@@ -18,21 +18,11 @@ extern void ia64_backtrace(struct pt_regs * const regs, unsigned int depth);
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-       int ret = -ENODEV;
-
-#ifdef CONFIG_PERFMON
-       /* perfmon_init() can fail, but we have no way to report it */
-       ret = perfmon_init(ops);
-#endif
        ops->backtrace = ia64_backtrace;
-
-       return ret;
+       return -ENODEV;
 }
 
 
 void oprofile_arch_exit(void)
 {
-#ifdef CONFIG_PERFMON
-       perfmon_exit();
-#endif
 }
diff --git a/arch/ia64/oprofile/perfmon.c b/arch/ia64/oprofile/perfmon.c
deleted file mode 100644 (file)
index 192d3e8..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * @file perfmon.c
- *
- * @remark Copyright 2003 OProfile authors
- * @remark Read the file COPYING
- *
- * @author John Levon <levon@movementarian.org>
- */
-
-#include <linux/kernel.h>
-#include <linux/oprofile.h>
-#include <linux/sched.h>
-#include <asm/perfmon.h>
-#include <asm/ptrace.h>
-#include <asm/errno.h>
-
-static int allow_ints;
-
-static int
-perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg,
-                struct pt_regs *regs, unsigned long stamp)
-{
-       int event = arg->pmd_eventid;
-       arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1;
-
-       /* the owner of the oprofile event buffer may have exited
-        * without perfmon being shutdown (e.g. SIGSEGV)
-        */
-       if (allow_ints)
-               oprofile_add_sample(regs, event);
-       return 0;
-}
-
-
-static int perfmon_start(void)
-{
-       allow_ints = 1;
-       return 0;
-}
-
-
-static void perfmon_stop(void)
-{
-       allow_ints = 0;
-}
-
-
-#define OPROFILE_FMT_UUID { \
-       0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c }
-
-static pfm_buffer_fmt_t oprofile_fmt = {
-       .fmt_name           = "oprofile_format",
-       .fmt_uuid           = OPROFILE_FMT_UUID,
-       .fmt_handler        = perfmon_handler,
-};
-
-
-static char *get_cpu_type(void)
-{
-       __u8 family = local_cpu_data->family;
-
-       switch (family) {
-               case 0x07:
-                       return "ia64/itanium";
-               case 0x1f:
-                       return "ia64/itanium2";
-               default:
-                       return "ia64/ia64";
-       }
-}
-
-
-/* all the ops are handled via userspace for IA64 perfmon */
-
-static int using_perfmon;
-
-int perfmon_init(struct oprofile_operations *ops)
-{
-       int ret = pfm_register_buffer_fmt(&oprofile_fmt);
-       if (ret)
-               return -ENODEV;
-
-       ops->cpu_type = get_cpu_type();
-       ops->start = perfmon_start;
-       ops->stop = perfmon_stop;
-       using_perfmon = 1;
-       printk(KERN_INFO "oprofile: using perfmon.\n");
-       return 0;
-}
-
-
-void perfmon_exit(void)
-{
-       if (!using_perfmon)
-               return;
-
-       pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid);
-}
index 6f2f38d..93bbb74 100644 (file)
@@ -6,32 +6,32 @@ config M68K
        select ARCH_HAS_BINFMT_FLAT
        select ARCH_HAS_DMA_PREP_COHERENT if HAS_DMA && MMU && !COLDFIRE
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
        select ARCH_MIGHT_HAVE_PC_PARPORT if ISA
        select ARCH_NO_PREEMPT if !COLDFIRE
+       select ARCH_WANT_IPC_PARSE_VERSION
        select BINFMT_FLAT_ARGVP_ENVP_ON_STACK
        select DMA_DIRECT_REMAP if HAS_DMA && MMU && !COLDFIRE
-       select HAVE_IDE
-       select HAVE_AOUT if MMU
-       select HAVE_ASM_MODVERSIONS
-       select HAVE_DEBUG_BUGVERBOSE
-       select GENERIC_IRQ_SHOW
        select GENERIC_ATOMIC64
-       select NO_DMA if !MMU && !COLDFIRE
-       select HAVE_UID16
-       select VIRT_TO_BUS
-       select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
        select GENERIC_CPU_DEVICES
        select GENERIC_IOMAP
+       select GENERIC_IRQ_SHOW
        select GENERIC_STRNCPY_FROM_USER if MMU
        select GENERIC_STRNLEN_USER if MMU
-       select ARCH_WANT_IPC_PARSE_VERSION
+       select HAVE_AOUT if MMU
+       select HAVE_ASM_MODVERSIONS
+       select HAVE_DEBUG_BUGVERBOSE
        select HAVE_FUTEX_CMPXCHG if MMU && FUTEX
+       select HAVE_IDE
        select HAVE_MOD_ARCH_SPECIFIC
+       select HAVE_UID16
+       select MMU_GATHER_NO_RANGE if MMU
        select MODULES_USE_ELF_REL
        select MODULES_USE_ELF_RELA
-       select OLD_SIGSUSPEND3
+       select NO_DMA if !MMU && !COLDFIRE
        select OLD_SIGACTION
-       select MMU_GATHER_NO_RANGE if MMU
+       select OLD_SIGSUSPEND3
+       select VIRT_TO_BUS
 
 config CPU_BIG_ENDIAN
        def_bool y
index 8f23b2f..bee9f24 100644 (file)
@@ -214,7 +214,7 @@ static void __init amiga_identify(void)
 
        switch (amiga_model) {
        case AMI_UNKNOWN:
-               goto Generic;
+               break;
 
        case AMI_600:
        case AMI_1200:
@@ -227,7 +227,7 @@ static void __init amiga_identify(void)
        case AMI_2000:
        case AMI_2500:
                AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */
-               goto Generic;
+               break;
 
        case AMI_3000:
        case AMI_3000T:
@@ -238,7 +238,7 @@ static void __init amiga_identify(void)
                AMIGAHW_SET(A3000_SCSI);
                AMIGAHW_SET(A3000_CLK);
                AMIGAHW_SET(ZORRO3);
-               goto Generic;
+               break;
 
        case AMI_4000T:
                AMIGAHW_SET(A4000_SCSI);
@@ -247,68 +247,12 @@ static void __init amiga_identify(void)
                AMIGAHW_SET(A4000_IDE);
                AMIGAHW_SET(A3000_CLK);
                AMIGAHW_SET(ZORRO3);
-               goto Generic;
+               break;
 
        case AMI_CDTV:
        case AMI_CD32:
                AMIGAHW_SET(CD_ROM);
                AMIGAHW_SET(A2000_CLK);             /* Is this correct? */
-               goto Generic;
-
-       Generic:
-               AMIGAHW_SET(AMI_VIDEO);
-               AMIGAHW_SET(AMI_BLITTER);
-               AMIGAHW_SET(AMI_AUDIO);
-               AMIGAHW_SET(AMI_FLOPPY);
-               AMIGAHW_SET(AMI_KEYBOARD);
-               AMIGAHW_SET(AMI_MOUSE);
-               AMIGAHW_SET(AMI_SERIAL);
-               AMIGAHW_SET(AMI_PARALLEL);
-               AMIGAHW_SET(CHIP_RAM);
-               AMIGAHW_SET(PAULA);
-
-               switch (amiga_chipset) {
-               case CS_OCS:
-               case CS_ECS:
-               case CS_AGA:
-                       switch (amiga_custom.deniseid & 0xf) {
-                       case 0x0c:
-                               AMIGAHW_SET(DENISE_HR);
-                               break;
-                       case 0x08:
-                               AMIGAHW_SET(LISA);
-                               break;
-                       }
-                       break;
-               default:
-                       AMIGAHW_SET(DENISE);
-                       break;
-               }
-               switch ((amiga_custom.vposr>>8) & 0x7f) {
-               case 0x00:
-                       AMIGAHW_SET(AGNUS_PAL);
-                       break;
-               case 0x10:
-                       AMIGAHW_SET(AGNUS_NTSC);
-                       break;
-               case 0x20:
-               case 0x21:
-                       AMIGAHW_SET(AGNUS_HR_PAL);
-                       break;
-               case 0x30:
-               case 0x31:
-                       AMIGAHW_SET(AGNUS_HR_NTSC);
-                       break;
-               case 0x22:
-               case 0x23:
-                       AMIGAHW_SET(ALICE_PAL);
-                       break;
-               case 0x32:
-               case 0x33:
-                       AMIGAHW_SET(ALICE_NTSC);
-                       break;
-               }
-               AMIGAHW_SET(ZORRO);
                break;
 
        case AMI_DRACO:
@@ -318,6 +262,60 @@ static void __init amiga_identify(void)
                panic("Unknown Amiga Model");
        }
 
+       AMIGAHW_SET(AMI_VIDEO);
+       AMIGAHW_SET(AMI_BLITTER);
+       AMIGAHW_SET(AMI_AUDIO);
+       AMIGAHW_SET(AMI_FLOPPY);
+       AMIGAHW_SET(AMI_KEYBOARD);
+       AMIGAHW_SET(AMI_MOUSE);
+       AMIGAHW_SET(AMI_SERIAL);
+       AMIGAHW_SET(AMI_PARALLEL);
+       AMIGAHW_SET(CHIP_RAM);
+       AMIGAHW_SET(PAULA);
+
+       switch (amiga_chipset) {
+       case CS_OCS:
+       case CS_ECS:
+       case CS_AGA:
+               switch (amiga_custom.deniseid & 0xf) {
+               case 0x0c:
+                       AMIGAHW_SET(DENISE_HR);
+                       break;
+               case 0x08:
+                       AMIGAHW_SET(LISA);
+                       break;
+               default:
+                       AMIGAHW_SET(DENISE);
+                       break;
+               }
+               break;
+       }
+       switch ((amiga_custom.vposr>>8) & 0x7f) {
+       case 0x00:
+               AMIGAHW_SET(AGNUS_PAL);
+               break;
+       case 0x10:
+               AMIGAHW_SET(AGNUS_NTSC);
+               break;
+       case 0x20:
+       case 0x21:
+               AMIGAHW_SET(AGNUS_HR_PAL);
+               break;
+       case 0x30:
+       case 0x31:
+               AMIGAHW_SET(AGNUS_HR_NTSC);
+               break;
+       case 0x22:
+       case 0x23:
+               AMIGAHW_SET(ALICE_PAL);
+               break;
+       case 0x32:
+       case 0x33:
+               AMIGAHW_SET(ALICE_NTSC);
+               break;
+       }
+       AMIGAHW_SET(ZORRO);
+
 #define AMIGAHW_ANNOUNCE(name, str)            \
        if (AMIGAHW_PRESENT(name))              \
                pr_cont(str)
index 3709189..5e0e682 100644 (file)
@@ -207,7 +207,7 @@ repeat:
                                        self_test_last_rcv = jiffies;
                                        break;
                                }
-                               /* FALL THROUGH */
+                               fallthrough;
 
                        default:
                                break_flag = scancode & BREAK_MASK;
index 522dcf6..3cd76bf 100644 (file)
@@ -317,6 +317,7 @@ CONFIG_DUMMY_IRQ=m
 CONFIG_IDE=y
 CONFIG_IDE_GD_ATAPI=y
 CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_PLATFORM=y
 CONFIG_BLK_DEV_MAC_IDE=y
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
index 2433409..c3d6faa 100644 (file)
@@ -346,6 +346,7 @@ CONFIG_DUMMY_IRQ=m
 CONFIG_IDE=y
 CONFIG_IDE_GD_ATAPI=y
 CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_PLATFORM=y
 CONFIG_BLK_DEV_GAYLE=y
 CONFIG_BLK_DEV_BUDDHA=y
 CONFIG_BLK_DEV_FALCON_IDE=y
index 3f2c15d..692e7b6 100644 (file)
@@ -31,14 +31,13 @@ __wsum csum_partial(const void *buff, int len, __wsum sum);
  */
 
 #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
+#define _HAVE_ARCH_CSUM_AND_COPY
 extern __wsum csum_and_copy_from_user(const void __user *src,
                                                void *dst,
-                                               int len, __wsum sum,
-                                               int *csum_err);
+                                               int len);
 
 extern __wsum csum_partial_copy_nocheck(const void *src,
-                                             void *dst, int len,
-                                             __wsum sum);
+                                             void *dst, int len);
 
 /*
  *     This is a version of ip_fast_csum() optimized for IP headers,
index 015f1ca..3689c67 100644 (file)
@@ -68,4 +68,12 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_MEMDIE             16      /* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK    18      /* restore signal mask in do_signal */
 
+#define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
+#define _TIF_DELAYED_TRACE     (1 << TIF_DELAYED_TRACE)
+#define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
+#define _TIF_MEMDIE            (1 << TIF_MEMDIE)
+#define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
+
 #endif /* _ASM_M68K_THREAD_INFO_H */
index 29de2b3..493c95d 100644 (file)
@@ -57,7 +57,7 @@
  * Of course, readability is a subjective issue, so it will never be
  * argued that that goal was accomplished.  It was merely a goal.
  * A key way to help make code more readable is to give good
- * documentation.  So, the first thing you will find is exaustive
+ * documentation.  So, the first thing you will find is exhaustive
  * write-ups on the structure of the file, and the features of the
  * functional subroutines.
  *
@@ -1304,7 +1304,7 @@ L(mmu_fixup_done):
  * mmu_engage
  *
  * This chunk of code performs the gruesome task of engaging the MMU.
- * The reason its gruesome is because when the MMU becomes engaged it
+ * The reason it's gruesome is because when the MMU becomes engaged it
  * maps logical addresses to physical addresses.  The Program Counter
  * register is then passed through the MMU before the next instruction
  * is fetched (the instruction following the engage MMU instruction).
@@ -1369,7 +1369,7 @@ L(mmu_fixup_done):
 /*
  * After this point no new memory is allocated and
  * the start of available memory is stored in availmem.
- * (The bootmem allocator requires now the physicall address.)
+ * (The bootmem allocator requires now the physical address.)
  */
 
        movel   L(memory_start),availmem
@@ -1547,7 +1547,7 @@ func_return       get_bi_record
  *     seven bits of the logical address (LA) are used as an
  *     index into the "root table."  Each entry in the root
  *     table has a bit which specifies if it's a valid pointer to a
- *     pointer table.  Each entry defines a 32KMeg range of memory.
+ *     pointer table.  Each entry defines a 32Meg range of memory.
  *     If an entry is invalid then that logical range of 32M is
  *     invalid and references to that range of memory (when the MMU
  *     is enabled) will fault.  If the entry is valid, then it does
@@ -1584,7 +1584,7 @@ func_return       get_bi_record
  *             bits 17..12 - index into the Page Table
  *             bits 11..0  - offset into a particular 4K page
  *
- *     The algorithms which follows do one thing: they abstract
+ *     The algorithms which follow do one thing: they abstract
  *     the MMU hardware.  For example, there are three kinds of
  *     cache settings that are relevant.  Either, memory is
  *     being mapped in which case it is either Kernel Code (or
@@ -2082,7 +2082,7 @@ func_return       mmu_map_tt
  *     mmu_map
  *
  *     This routine will map a range of memory using a pointer
- *     table and allocating the pages on the fly from the kernel.
+ *     table and allocate the pages on the fly from the kernel.
  *     The pointer table does not have to be already linked into
  *     the root table, this routine will do that if necessary.
  *
@@ -2528,7 +2528,7 @@ func_start        mmu_get_root_table_entry,%d0/%a1
 
        /* Find the start of free memory, get_bi_record does this for us,
         * as the bootinfo structure is located directly behind the kernel
-        * and and we simply search for the last entry.
+        * we simply search for the last entry.
         */
        get_bi_record   BI_LAST
        addw    #PAGESIZE-1,%a0
@@ -2654,7 +2654,7 @@ func_start        mmu_get_page_table_entry,%d0/%a1
        jne     2f
 
        /* If the page table entry doesn't exist, we allocate a complete new
-        * page and use it as one continues big page table which can cover
+        * page and use it as one continuous big page table which can cover
         * 4MB of memory, nearly almost all mappings have that alignment.
         */
        get_new_page
index fc034fd..a98fca9 100644 (file)
@@ -1067,7 +1067,7 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
                        regs->d0 = -EINTR;
                        break;
                }
-       /* fallthrough */
+               fallthrough;
        case -ERESTARTNOINTR:
        do_restart:
                regs->d0 = regs->orig_d0;
index 546e819..9e12614 100644 (file)
@@ -845,7 +845,6 @@ static void show_trace(unsigned long *stack, const char *loglvl)
 void show_registers(struct pt_regs *regs)
 {
        struct frame *fp = (struct frame *)regs;
-       mm_segment_t old_fs = get_fs();
        u16 c, *cp;
        unsigned long addr;
        int i;
@@ -918,10 +917,9 @@ void show_registers(struct pt_regs *regs)
        show_stack(NULL, (unsigned long *)addr, KERN_INFO);
 
        pr_info("Code:");
-       set_fs(KERNEL_DS);
        cp = (u16 *)regs->pc;
        for (i = -8; i < 16; i++) {
-               if (get_user(c, cp + i) && i >= 0) {
+               if (get_kernel_nofault(c, cp + i) && i >= 0) {
                        pr_cont(" Bad PC value.");
                        break;
                }
@@ -930,7 +928,6 @@ void show_registers(struct pt_regs *regs)
                else
                        pr_cont(" <%04x>", c);
        }
-       set_fs(old_fs);
        pr_cont("\n");
 }
 
index 31797be..7e6afea 100644 (file)
@@ -129,8 +129,7 @@ EXPORT_SYMBOL(csum_partial);
  */
 
 __wsum
-csum_and_copy_from_user(const void __user *src, void *dst,
-                           int len, __wsum sum, int *csum_err)
+csum_and_copy_from_user(const void __user *src, void *dst, int len)
 {
        /*
         * GCC doesn't like more than 10 operands for the asm
@@ -138,6 +137,7 @@ csum_and_copy_from_user(const void __user *src, void *dst,
         * code.
         */
        unsigned long tmp1, tmp2;
+       __wsum sum = ~0U;
 
        __asm__("movel %2,%4\n\t"
                "btst #1,%4\n\t"        /* Check alignment */
@@ -236,84 +236,33 @@ csum_and_copy_from_user(const void __user *src, void *dst,
                "clrl %5\n\t"
                "addxl %5,%0\n\t"       /* add X bit */
             "7:\t"
-               "clrl %5\n"             /* no error - clear return value */
-            "8:\n"
                ".section .fixup,\"ax\"\n"
                ".even\n"
-               /* If any exception occurs zero out the rest.
-                  Similarities with the code above are intentional :-) */
+               /* If any exception occurs, return 0 */
             "90:\t"
-               "clrw %3@+\n\t"
-               "movel %1,%4\n\t"
-               "lsrl #5,%1\n\t"
-               "jeq 1f\n\t"
-               "subql #1,%1\n"
-            "91:\t"
-               "clrl %3@+\n"
-            "92:\t"
-               "clrl %3@+\n"
-            "93:\t"
-               "clrl %3@+\n"
-            "94:\t"
-               "clrl %3@+\n"
-            "95:\t"
-               "clrl %3@+\n"
-            "96:\t"
-               "clrl %3@+\n"
-            "97:\t"
-               "clrl %3@+\n"
-            "98:\t"
-               "clrl %3@+\n\t"
-               "dbra %1,91b\n\t"
-               "clrw %1\n\t"
-               "subql #1,%1\n\t"
-               "jcc 91b\n"
-            "1:\t"
-               "movel %4,%1\n\t"
-               "andw #0x1c,%4\n\t"
-               "jeq 1f\n\t"
-               "lsrw #2,%4\n\t"
-               "subqw #1,%4\n"
-            "99:\t"
-               "clrl %3@+\n\t"
-               "dbra %4,99b\n\t"
-            "1:\t"
-               "andw #3,%1\n\t"
-               "jeq 9f\n"
-            "100:\t"
-               "clrw %3@+\n\t"
-               "tstw %1\n\t"
-               "jeq 9f\n"
-            "101:\t"
-               "clrb %3@+\n"
-            "9:\t"
-#define STR(X) STR1(X)
-#define STR1(X) #X
-               "moveq #-" STR(EFAULT) ",%5\n\t"
-               "jra 8b\n"
+               "clrl %0\n"
+               "jra 7b\n"
                ".previous\n"
                ".section __ex_table,\"a\"\n"
                ".long 10b,90b\n"
-               ".long 11b,91b\n"
-               ".long 12b,92b\n"
-               ".long 13b,93b\n"
-               ".long 14b,94b\n"
-               ".long 15b,95b\n"
-               ".long 16b,96b\n"
-               ".long 17b,97b\n"
-               ".long 18b,98b\n"
-               ".long 19b,99b\n"
-               ".long 20b,100b\n"
-               ".long 21b,101b\n"
+               ".long 11b,90b\n"
+               ".long 12b,90b\n"
+               ".long 13b,90b\n"
+               ".long 14b,90b\n"
+               ".long 15b,90b\n"
+               ".long 16b,90b\n"
+               ".long 17b,90b\n"
+               ".long 18b,90b\n"
+               ".long 19b,90b\n"
+               ".long 20b,90b\n"
+               ".long 21b,90b\n"
                ".previous"
                : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
                  "=&d" (tmp1), "=d" (tmp2)
                : "0" (sum), "1" (len), "2" (src), "3" (dst)
            );
 
-       *csum_err = tmp2;
-
-       return(sum);
+       return sum;
 }
 
 EXPORT_SYMBOL(csum_and_copy_from_user);
@@ -324,9 +273,10 @@ EXPORT_SYMBOL(csum_and_copy_from_user);
  */
 
 __wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
+csum_partial_copy_nocheck(const void *src, void *dst, int len)
 {
        unsigned long tmp1, tmp2;
+       __wsum sum = 0;
        __asm__("movel %2,%4\n\t"
                "btst #1,%4\n\t"        /* Check alignment */
                "jeq 2f\n\t"
index 5c9f3a2..0ac53d8 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/vt_kern.h>
 #include <linux/platform_device.h>
+#include <linux/ata_platform.h>
 #include <linux/adb.h>
 #include <linux/cuda.h>
 #include <linux/pmu.h>
@@ -940,6 +941,26 @@ static const struct resource mac_scsi_ccl_rsrc[] __initconst = {
        },
 };
 
+static const struct resource mac_ide_quadra_rsrc[] __initconst = {
+       DEFINE_RES_MEM(0x50F1A000, 0x104),
+       DEFINE_RES_IRQ(IRQ_NUBUS_F),
+};
+
+static const struct resource mac_ide_pb_rsrc[] __initconst = {
+       DEFINE_RES_MEM(0x50F1A000, 0x104),
+       DEFINE_RES_IRQ(IRQ_NUBUS_C),
+};
+
+static const struct resource mac_pata_baboon_rsrc[] __initconst = {
+       DEFINE_RES_MEM(0x50F1A000, 0x38),
+       DEFINE_RES_MEM(0x50F1A038, 0x04),
+       DEFINE_RES_IRQ(IRQ_BABOON_1),
+};
+
+static const struct pata_platform_info mac_pata_baboon_data __initconst = {
+       .ioport_shift = 2,
+};
+
 int __init mac_platform_init(void)
 {
        phys_addr_t swim_base = 0;
@@ -1018,7 +1039,7 @@ int __init mac_platform_init(void)
                 */
                platform_device_register_simple("mac_scsi", 1,
                        mac_scsi_duo_rsrc, ARRAY_SIZE(mac_scsi_duo_rsrc));
-               /* fall through */
+               fallthrough;
        case MAC_SCSI_OLD:
                /* Addresses from Developer Notes for Duo System,
                 * PowerBook 180 & 160, 140 & 170, Macintosh IIsi
@@ -1049,6 +1070,26 @@ int __init mac_platform_init(void)
        }
 
        /*
+        * IDE device
+        */
+
+       switch (macintosh_config->ide_type) {
+       case MAC_IDE_QUADRA:
+               platform_device_register_simple("mac_ide", -1,
+                       mac_ide_quadra_rsrc, ARRAY_SIZE(mac_ide_quadra_rsrc));
+               break;
+       case MAC_IDE_PB:
+               platform_device_register_simple("mac_ide", -1,
+                       mac_ide_pb_rsrc, ARRAY_SIZE(mac_ide_pb_rsrc));
+               break;
+       case MAC_IDE_BABOON:
+               platform_device_register_resndata(NULL, "pata_platform", -1,
+                       mac_pata_baboon_rsrc, ARRAY_SIZE(mac_pata_baboon_rsrc),
+                       &mac_pata_baboon_data, sizeof(mac_pata_baboon_data));
+               break;
+       }
+
+       /*
         * Ethernet device
         */
 
index 3887807..4de6229 100644 (file)
@@ -116,7 +116,7 @@ static void mac_init_asc( void )
                         *   support 16-bit stereo output, but only mono input."
                         *
                         *   Technical Information Library (TIL) article number 16405. 
-                        *   http://support.apple.com/kb/TA32601 
+                        *   https://support.apple.com/kb/TA32601
                         *
                         * --David Kilzer
                         */
index 1f0fad2..ac77d73 100644 (file)
@@ -370,7 +370,7 @@ void via_nubus_irq_startup(int irq)
                        /* Allow NuBus slots 9 through F. */
                        via2[vDirA] &= 0x80 | ~(1 << irq_idx);
                }
-               /* fall through */
+               fallthrough;
        case MAC_VIA_IICI:
                via_irq_enable(irq);
                break;
index 795f483..ef46e77 100644 (file)
@@ -118,7 +118,7 @@ good_area:
        pr_debug("do_page_fault: good_area\n");
        switch (error_code & 3) {
                default:        /* 3: write, present */
-                       /* fall through */
+                       fallthrough;
                case 2:         /* write, not present */
                        if (!(vma->vm_flags & VM_WRITE))
                                goto acc_err;
index 2b9cb4a..eac9dde 100644 (file)
@@ -42,7 +42,7 @@ void __init paging_init(void)
        unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0 };
        int i;
 
-       empty_zero_page = (void *) memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+       empty_zero_page = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
        if (!empty_zero_page)
                panic("%s: Failed to allocate %lu bytes align=0x%lx\n",
                      __func__, PAGE_SIZE, PAGE_SIZE);
index 2bb006b..3a653f0 100644 (file)
@@ -226,8 +226,8 @@ static pte_t * __init kernel_page_table(void)
 {
        pte_t *pte_table = last_pte_table;
 
-       if (((unsigned long)last_pte_table & ~PAGE_MASK) == 0) {
-               pte_table = (pte_t *)memblock_alloc_low(PAGE_SIZE, PAGE_SIZE);
+       if (PAGE_ALIGNED(last_pte_table)) {
+               pte_table = memblock_alloc_low(PAGE_SIZE, PAGE_SIZE);
                if (!pte_table) {
                        panic("%s: Failed to allocate %lu bytes align=%lx\n",
                                        __func__, PAGE_SIZE, PAGE_SIZE);
@@ -274,9 +274,8 @@ static pmd_t * __init kernel_ptr_table(void)
        }
 
        last_pmd_table += PTRS_PER_PMD;
-       if (((unsigned long)last_pmd_table & ~PAGE_MASK) == 0) {
-               last_pmd_table = (pmd_t *)memblock_alloc_low(PAGE_SIZE,
-                                                          PAGE_SIZE);
+       if (PAGE_ALIGNED(last_pmd_table)) {
+               last_pmd_table = memblock_alloc_low(PAGE_SIZE, PAGE_SIZE);
                if (!last_pmd_table)
                        panic("%s: Failed to allocate %lu bytes align=%lx\n",
                              __func__, PAGE_SIZE, PAGE_SIZE);
index 2e87a9b..63bce83 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 generated-y += syscall_table.h
 generic-y += extable.h
-generic-y += hw_irq.h
 generic-y += kvm_para.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
index 65bf5fd..4a96b59 100644 (file)
@@ -249,7 +249,7 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
                        regs->r3 = -EINTR;
                        break;
        }
-       /* fallthrough */
+               fallthrough;
        case -ERESTARTNOINTR:
 do_restart:
                /* offset of 4 bytes to re-execute trap (brki) instruction */
index 0880a00..3344d4a 100644 (file)
@@ -46,6 +46,9 @@ unsigned long memory_size;
 EXPORT_SYMBOL(memory_size);
 unsigned long lowmem_size;
 
+EXPORT_SYMBOL(min_low_pfn);
+EXPORT_SYMBOL(max_low_pfn);
+
 #ifdef CONFIG_HIGHMEM
 pte_t *kmap_pte;
 EXPORT_SYMBOL(kmap_pte);
index c95fa3a..cff1922 100644 (file)
@@ -86,6 +86,7 @@ config MIPS
        select MODULES_USE_ELF_REL if MODULES
        select MODULES_USE_ELF_RELA if MODULES && 64BIT
        select PERF_USE_VMALLOC
+       select PCI_MSI_ARCH_FALLBACKS if PCI_MSI
        select RTC_LIB
        select SYSCTL_EXCEPTION_TRACE
        select VIRT_TO_BUS
@@ -877,6 +878,7 @@ config SNI_RM
        select I8253
        select I8259
        select ISA
+       select MIPS_L1_CACHE_SHIFT_6
        select SWAP_IO_SPACE if CPU_BIG_ENDIAN
        select SYS_HAS_CPU_R4X00
        select SYS_HAS_CPU_R5000
index 82627c2..01427bd 100644 (file)
@@ -148,7 +148,7 @@ void __init plat_mem_setup(void)
 {
        struct cpuinfo_mips *c = &current_cpu_data;
 
-       if ((c->cputype == CPU_74K) || (c->cputype == CPU_1074K)) {
+       if (c->cputype == CPU_74K) {
                pr_info("Using bcma bus\n");
 #ifdef CONFIG_BCM47XX_BCMA
                bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;
index 181f7d1..5f80c28 100644 (file)
  */
 __wsum csum_partial(const void *buff, int len, __wsum sum);
 
-__wsum __csum_partial_copy_kernel(const void *src, void *dst,
-                                 int len, __wsum sum, int *err_ptr);
-
-__wsum __csum_partial_copy_from_user(const void *src, void *dst,
-                                    int len, __wsum sum, int *err_ptr);
-__wsum __csum_partial_copy_to_user(const void *src, void *dst,
-                                  int len, __wsum sum, int *err_ptr);
-/*
- * this is a new version of the above that records errors it finds in *errp,
- * but continues and zeros the rest of the buffer.
- */
-static inline
-__wsum csum_partial_copy_from_user(const void __user *src, void *dst, int len,
-                                  __wsum sum, int *err_ptr)
-{
-       might_fault();
-       if (uaccess_kernel())
-               return __csum_partial_copy_kernel((__force void *)src, dst,
-                                                 len, sum, err_ptr);
-       else
-               return __csum_partial_copy_from_user((__force void *)src, dst,
-                                                    len, sum, err_ptr);
-}
+__wsum __csum_partial_copy_from_user(const void __user *src, void *dst, int len);
+__wsum __csum_partial_copy_to_user(const void *src, void __user *dst, int len);
 
 #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
 static inline
-__wsum csum_and_copy_from_user(const void __user *src, void *dst,
-                              int len, __wsum sum, int *err_ptr)
+__wsum csum_and_copy_from_user(const void __user *src, void *dst, int len)
 {
-       if (access_ok(src, len))
-               return csum_partial_copy_from_user(src, dst, len, sum,
-                                                  err_ptr);
-       if (len)
-               *err_ptr = -EFAULT;
-
-       return sum;
+       might_fault();
+       if (!access_ok(src, len))
+               return 0;
+       return __csum_partial_copy_from_user(src, dst, len);
 }
 
 /*
@@ -77,33 +52,24 @@ __wsum csum_and_copy_from_user(const void __user *src, void *dst,
  */
 #define HAVE_CSUM_COPY_USER
 static inline
-__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
-                            __wsum sum, int *err_ptr)
+__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len)
 {
        might_fault();
-       if (access_ok(dst, len)) {
-               if (uaccess_kernel())
-                       return __csum_partial_copy_kernel(src,
-                                                         (__force void *)dst,
-                                                         len, sum, err_ptr);
-               else
-                       return __csum_partial_copy_to_user(src,
-                                                          (__force void *)dst,
-                                                          len, sum, err_ptr);
-       }
-       if (len)
-               *err_ptr = -EFAULT;
-
-       return (__force __wsum)-1; /* invalid checksum */
+       if (!access_ok(dst, len))
+               return 0;
+       return __csum_partial_copy_to_user(src, dst, len);
 }
 
 /*
  * the same as csum_partial, but copies from user space (but on MIPS
  * we have just one address space, so this is identical to the above)
  */
-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                      int len, __wsum sum);
-#define csum_partial_copy_nocheck csum_partial_copy_nocheck
+#define _HAVE_ARCH_CSUM_AND_COPY
+__wsum __csum_partial_copy_nocheck(const void *src, void *dst, int len);
+static inline __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
+{
+       return __csum_partial_copy_nocheck(src, dst, len);
+}
 
 /*
  *     Fold a partial checksum without adding pseudo headers
index 255afcd..6597571 100644 (file)
@@ -26,8 +26,6 @@ typedef s32           compat_caddr_t;
 typedef struct {
        s32     val[2];
 } compat_fsid_t;
-typedef s64            compat_s64;
-typedef u64            compat_u64;
 
 struct compat_stat {
        compat_dev_t    st_dev;
index 75a7a38..3288cef 100644 (file)
@@ -47,6 +47,7 @@ static inline int __pure __get_cpu_type(const int cpu_type)
        case CPU_34K:
        case CPU_1004K:
        case CPU_74K:
+       case CPU_1074K:
        case CPU_M14KC:
        case CPU_M14KEC:
        case CPU_INTERAPTIV:
index 47a8ffc..f5b8300 100644 (file)
@@ -137,6 +137,11 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
        return !(flags & 1);
 }
 
+static inline int arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
 #endif /* #ifndef __ASSEMBLY__ */
 
 /*
index b6e9c99..eb18122 100644 (file)
@@ -26,7 +26,6 @@
 #define cpu_has_counter                1
 #define cpu_has_dc_aliases     (PAGE_SIZE < 0x4000)
 #define cpu_has_divec          0
-#define cpu_has_ejtag          0
 #define cpu_has_inclusive_pcaches      1
 #define cpu_has_llsc           1
 #define cpu_has_mcheck         0
@@ -42,7 +41,6 @@
 #define cpu_has_veic           0
 #define cpu_has_vint           0
 #define cpu_has_vtag_icache    0
-#define cpu_has_watch          1
 #define cpu_has_wsbh           1
 #define cpu_has_ic_fills_f_dc  1
 #define cpu_hwrena_impl_bits   0xc0000000
index f5e362f..bf24809 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef __ASM_MACH_LOONGSON64_IRQ_H_
 #define __ASM_MACH_LOONGSON64_IRQ_H_
 
-#include <boot_param.h>
-
 /* cpu core interrupt numbers */
 #define NR_IRQS_LEGACY         16
 #define NR_MIPS_CPU_IRQS       8
index 3a25dbd..5eaca4f 100644 (file)
@@ -9,7 +9,6 @@
 #ifndef _ASM_MACH_LOONGSON64_MMZONE_H
 #define _ASM_MACH_LOONGSON64_MMZONE_H
 
-#include <boot_param.h>
 #define NODE_ADDRSPACE_SHIFT 44
 #define NODE0_ADDRSPACE_OFFSET 0x000000000000UL
 #define NODE1_ADDRSPACE_OFFSET 0x100000000000UL
index 7dd4a80..6f4ac85 100644 (file)
        BUILD_BUG_ON(!__builtin_constant_p(times));             \
                                                                \
        switch (times) {                                        \
-       case 32: fn(__VA_ARGS__); /* fall through */            \
-       case 31: fn(__VA_ARGS__); /* fall through */            \
-       case 30: fn(__VA_ARGS__); /* fall through */            \
-       case 29: fn(__VA_ARGS__); /* fall through */            \
-       case 28: fn(__VA_ARGS__); /* fall through */            \
-       case 27: fn(__VA_ARGS__); /* fall through */            \
-       case 26: fn(__VA_ARGS__); /* fall through */            \
-       case 25: fn(__VA_ARGS__); /* fall through */            \
-       case 24: fn(__VA_ARGS__); /* fall through */            \
-       case 23: fn(__VA_ARGS__); /* fall through */            \
-       case 22: fn(__VA_ARGS__); /* fall through */            \
-       case 21: fn(__VA_ARGS__); /* fall through */            \
-       case 20: fn(__VA_ARGS__); /* fall through */            \
-       case 19: fn(__VA_ARGS__); /* fall through */            \
-       case 18: fn(__VA_ARGS__); /* fall through */            \
-       case 17: fn(__VA_ARGS__); /* fall through */            \
-       case 16: fn(__VA_ARGS__); /* fall through */            \
-       case 15: fn(__VA_ARGS__); /* fall through */            \
-       case 14: fn(__VA_ARGS__); /* fall through */            \
-       case 13: fn(__VA_ARGS__); /* fall through */            \
-       case 12: fn(__VA_ARGS__); /* fall through */            \
-       case 11: fn(__VA_ARGS__); /* fall through */            \
-       case 10: fn(__VA_ARGS__); /* fall through */            \
-       case 9: fn(__VA_ARGS__); /* fall through */             \
-       case 8: fn(__VA_ARGS__); /* fall through */             \
-       case 7: fn(__VA_ARGS__); /* fall through */             \
-       case 6: fn(__VA_ARGS__); /* fall through */             \
-       case 5: fn(__VA_ARGS__); /* fall through */             \
-       case 4: fn(__VA_ARGS__); /* fall through */             \
-       case 3: fn(__VA_ARGS__); /* fall through */             \
-       case 2: fn(__VA_ARGS__); /* fall through */             \
-       case 1: fn(__VA_ARGS__); /* fall through */             \
+       case 32: fn(__VA_ARGS__); fallthrough;                  \
+       case 31: fn(__VA_ARGS__); fallthrough;                  \
+       case 30: fn(__VA_ARGS__); fallthrough;                  \
+       case 29: fn(__VA_ARGS__); fallthrough;                  \
+       case 28: fn(__VA_ARGS__); fallthrough;                  \
+       case 27: fn(__VA_ARGS__); fallthrough;                  \
+       case 26: fn(__VA_ARGS__); fallthrough;                  \
+       case 25: fn(__VA_ARGS__); fallthrough;                  \
+       case 24: fn(__VA_ARGS__); fallthrough;                  \
+       case 23: fn(__VA_ARGS__); fallthrough;                  \
+       case 22: fn(__VA_ARGS__); fallthrough;                  \
+       case 21: fn(__VA_ARGS__); fallthrough;                  \
+       case 20: fn(__VA_ARGS__); fallthrough;                  \
+       case 19: fn(__VA_ARGS__); fallthrough;                  \
+       case 18: fn(__VA_ARGS__); fallthrough;                  \
+       case 17: fn(__VA_ARGS__); fallthrough;                  \
+       case 16: fn(__VA_ARGS__); fallthrough;                  \
+       case 15: fn(__VA_ARGS__); fallthrough;                  \
+       case 14: fn(__VA_ARGS__); fallthrough;                  \
+       case 13: fn(__VA_ARGS__); fallthrough;                  \
+       case 12: fn(__VA_ARGS__); fallthrough;                  \
+       case 11: fn(__VA_ARGS__); fallthrough;                  \
+       case 10: fn(__VA_ARGS__); fallthrough;                  \
+       case 9: fn(__VA_ARGS__); fallthrough;                   \
+       case 8: fn(__VA_ARGS__); fallthrough;                   \
+       case 7: fn(__VA_ARGS__); fallthrough;                   \
+       case 6: fn(__VA_ARGS__); fallthrough;                   \
+       case 5: fn(__VA_ARGS__); fallthrough;                   \
+       case 4: fn(__VA_ARGS__); fallthrough;                   \
+       case 3: fn(__VA_ARGS__); fallthrough;                   \
+       case 2: fn(__VA_ARGS__); fallthrough;                   \
+       case 1: fn(__VA_ARGS__); fallthrough;                   \
        case 0: break;                                          \
                                                                \
        default:                                                \
index d043c2f..54dfba8 100644 (file)
@@ -477,6 +477,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                      struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *) regs->regs[31];
+       ri->fp = NULL;
 
        /* Replace the return addr with trampoline addr */
        regs->regs[31] = (unsigned long)kretprobe_trampoline;
@@ -488,57 +489,8 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 static int __kprobes trampoline_probe_handler(struct kprobe *p,
                                                struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address = (unsigned long)kretprobe_trampoline;
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because an multiple functions in the call path
-        * have a return probe installed on them, and/or more than one return
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               if (ri->rp && ri->rp->handler)
-                       ri->rp->handler(ri, regs);
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-       instruction_pointer(regs) = orig_ret_address;
-
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
+       instruction_pointer(regs) = __kretprobe_trampoline_handler(regs,
+                                               kretprobe_trampoline, NULL);
        /*
         * By returning a non-zero value, we are telling
         * kprobe_handler() that we don't want the post_handler
index efce5de..011eb6b 100644 (file)
@@ -1898,8 +1898,8 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
                                (base_id >= 64 && base_id < 90) ||
                                (base_id >= 128 && base_id < 164) ||
                                (base_id >= 192 && base_id < 200) ||
-                               (base_id >= 256 && base_id < 274) ||
-                               (base_id >= 320 && base_id < 358) ||
+                               (base_id >= 256 && base_id < 275) ||
+                               (base_id >= 320 && base_id < 361) ||
                                (base_id >= 384 && base_id < 574))
                                break;
 
index 2f51350..1dbfb5a 100644 (file)
@@ -239,6 +239,8 @@ static int bmips_boot_secondary(int cpu, struct task_struct *idle)
  */
 static void bmips_init_secondary(void)
 {
+       bmips_cpu_setup();
+
        switch (current_cpu_type()) {
        case CPU_BMIPS4350:
        case CPU_BMIPS4380:
index f9df9ed..cf72a02 100644 (file)
@@ -25,8 +25,8 @@
 15     n32     ioctl                           compat_sys_ioctl
 16     n32     pread64                         sys_pread64
 17     n32     pwrite64                        sys_pwrite64
-18     n32     readv                           compat_sys_readv
-19     n32     writev                          compat_sys_writev
+18     n32     readv                           sys_readv
+19     n32     writev                          sys_writev
 20     n32     access                          sys_access
 21     n32     pipe                            sysm_pipe
 22     n32     _newselect                      compat_sys_select
 157    n32     sync                            sys_sync
 158    n32     acct                            sys_acct
 159    n32     settimeofday                    compat_sys_settimeofday
-160    n32     mount                           compat_sys_mount
+160    n32     mount                           sys_mount
 161    n32     umount2                         sys_umount
 162    n32     swapon                          sys_swapon
 163    n32     swapoff                         sys_swapoff
 267    n32     splice                          sys_splice
 268    n32     sync_file_range                 sys_sync_file_range
 269    n32     tee                             sys_tee
-270    n32     vmsplice                        compat_sys_vmsplice
+270    n32     vmsplice                        sys_vmsplice
 271    n32     move_pages                      compat_sys_move_pages
 272    n32     set_robust_list                 compat_sys_set_robust_list
 273    n32     get_robust_list                 compat_sys_get_robust_list
 306    n32     syncfs                          sys_syncfs
 307    n32     sendmmsg                        compat_sys_sendmmsg
 308    n32     setns                           sys_setns
-309    n32     process_vm_readv                compat_sys_process_vm_readv
-310    n32     process_vm_writev               compat_sys_process_vm_writev
+309    n32     process_vm_readv                sys_process_vm_readv
+310    n32     process_vm_writev               sys_process_vm_writev
 311    n32     kcmp                            sys_kcmp
 312    n32     finit_module                    sys_finit_module
 313    n32     sched_setattr                   sys_sched_setattr
index 195b43c..a17aab5 100644 (file)
@@ -29,7 +29,7 @@
 18     o32     unused18                        sys_ni_syscall
 19     o32     lseek                           sys_lseek
 20     o32     getpid                          sys_getpid
-21     o32     mount                           sys_mount                       compat_sys_mount
+21     o32     mount                           sys_mount
 22     o32     umount                          sys_oldumount
 23     o32     setuid                          sys_setuid
 24     o32     getuid                          sys_getuid
 142    o32     _newselect                      sys_select                      compat_sys_select
 143    o32     flock                           sys_flock
 144    o32     msync                           sys_msync
-145    o32     readv                           sys_readv                       compat_sys_readv
-146    o32     writev                          sys_writev                      compat_sys_writev
+145    o32     readv                           sys_readv
+146    o32     writev                          sys_writev
 147    o32     cacheflush                      sys_cacheflush
 148    o32     cachectl                        sys_cachectl
 149    o32     sysmips                         __sys_sysmips
 304    o32     splice                          sys_splice
 305    o32     sync_file_range                 sys_sync_file_range             sys32_sync_file_range
 306    o32     tee                             sys_tee
-307    o32     vmsplice                        sys_vmsplice                    compat_sys_vmsplice
+307    o32     vmsplice                        sys_vmsplice
 308    o32     move_pages                      sys_move_pages                  compat_sys_move_pages
 309    o32     set_robust_list                 sys_set_robust_list             compat_sys_set_robust_list
 310    o32     get_robust_list                 sys_get_robust_list             compat_sys_get_robust_list
 342    o32     syncfs                          sys_syncfs
 343    o32     sendmmsg                        sys_sendmmsg                    compat_sys_sendmmsg
 344    o32     setns                           sys_setns
-345    o32     process_vm_readv                sys_process_vm_readv            compat_sys_process_vm_readv
-346    o32     process_vm_writev               sys_process_vm_writev           compat_sys_process_vm_writev
+345    o32     process_vm_readv                sys_process_vm_readv
+346    o32     process_vm_writev               sys_process_vm_writev
 347    o32     kcmp                            sys_kcmp
 348    o32     finit_module                    sys_finit_module
 349    o32     sched_setattr                   sys_sched_setattr
index 38aa07c..cf78859 100644 (file)
@@ -1287,6 +1287,18 @@ static int enable_restore_fp_context(int msa)
                err = own_fpu_inatomic(1);
                if (msa && !err) {
                        enable_msa();
+                       /*
+                        * with MSA enabled, userspace can see MSACSR
+                        * and MSA regs, but the values in them are from
+                        * other task before current task, restore them
+                        * from saved fp/msa context
+                        */
+                       write_msa_csr(current->thread.fpu.msacsr);
+                       /*
+                        * own_fpu_inatomic(1) just restore low 64bit,
+                        * fix the high 64bit
+                        */
+                       init_msa_upper();
                        set_thread_flag(TIF_USEDMSA);
                        set_thread_flag(TIF_MSA_CTX_LIVE);
                }
index f185a85..5e97e9d 100644 (file)
@@ -202,6 +202,7 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        /* These must appear regardless of  .  */
        .gptab.sdata : {
index 7de85d2..0c50ac4 100644 (file)
@@ -137,6 +137,8 @@ extern void kvm_init_loongson_ipi(struct kvm *kvm);
 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
        switch (type) {
+       case KVM_VM_MIPS_AUTO:
+               break;
 #ifdef CONFIG_KVM_MIPS_VZ
        case KVM_VM_MIPS_VZ:
 #else
index 87fda07..a46db08 100644 (file)
@@ -308,8 +308,8 @@ EXPORT_SYMBOL(csum_partial)
 /*
  * checksum and copy routines based on memcpy.S
  *
- *     csum_partial_copy_nocheck(src, dst, len, sum)
- *     __csum_partial_copy_kernel(src, dst, len, sum, errp)
+ *     csum_partial_copy_nocheck(src, dst, len)
+ *     __csum_partial_copy_kernel(src, dst, len)
  *
  * See "Spec" in memcpy.S for details. Unlike __copy_user, all
  * function in this file use the standard calling convention.
@@ -318,26 +318,11 @@ EXPORT_SYMBOL(csum_partial)
 #define src a0
 #define dst a1
 #define len a2
-#define psum a3
 #define sum v0
 #define odd t8
-#define errptr t9
 
 /*
- * The exception handler for loads requires that:
- *  1- AT contain the address of the byte just past the end of the source
- *     of the copy,
- *  2- src_entry <= src < AT, and
- *  3- (dst - src) == (dst_entry - src_entry),
- * The _entry suffix denotes values when __copy_user was called.
- *
- * (1) is set up up by __csum_partial_copy_from_user and maintained by
- *     not writing AT in __csum_partial_copy
- * (2) is met by incrementing src by the number of bytes copied
- * (3) is met by not doing loads between a pair of increments of dst and src
- *
- * The exception handlers for stores stores -EFAULT to errptr and return.
- * These handlers do not need to overwrite any data.
+ * All exception handlers simply return 0.
  */
 
 /* Instruction type */
@@ -358,11 +343,11 @@ EXPORT_SYMBOL(csum_partial)
  * addr    : Address
  * handler : Exception handler
  */
-#define EXC(insn, type, reg, addr, handler)    \
+#define EXC(insn, type, reg, addr)             \
        .if \mode == LEGACY_MODE;               \
 9:             insn reg, addr;                 \
                .section __ex_table,"a";        \
-               PTR     9b, handler;            \
+               PTR     9b, .L_exc;             \
                .previous;                      \
        /* This is enabled in EVA mode */       \
        .else;                                  \
@@ -371,7 +356,7 @@ EXPORT_SYMBOL(csum_partial)
                    ((\to == USEROP) && (type == ST_INSN));     \
 9:                     __BUILD_EVA_INSN(insn##e, reg, addr);   \
                        .section __ex_table,"a";                \
-                       PTR     9b, handler;                    \
+                       PTR     9b, .L_exc;                     \
                        .previous;                              \
                .else;                                          \
                        /* EVA without exception */             \
@@ -384,14 +369,14 @@ EXPORT_SYMBOL(csum_partial)
 #ifdef USE_DOUBLE
 
 #define LOADK  ld /* No exception */
-#define LOAD(reg, addr, handler)       EXC(ld, LD_INSN, reg, addr, handler)
-#define LOADBU(reg, addr, handler)     EXC(lbu, LD_INSN, reg, addr, handler)
-#define LOADL(reg, addr, handler)      EXC(ldl, LD_INSN, reg, addr, handler)
-#define LOADR(reg, addr, handler)      EXC(ldr, LD_INSN, reg, addr, handler)
-#define STOREB(reg, addr, handler)     EXC(sb, ST_INSN, reg, addr, handler)
-#define STOREL(reg, addr, handler)     EXC(sdl, ST_INSN, reg, addr, handler)
-#define STORER(reg, addr, handler)     EXC(sdr, ST_INSN, reg, addr, handler)
-#define STORE(reg, addr, handler)      EXC(sd, ST_INSN, reg, addr, handler)
+#define LOAD(reg, addr)                EXC(ld, LD_INSN, reg, addr)
+#define LOADBU(reg, addr)      EXC(lbu, LD_INSN, reg, addr)
+#define LOADL(reg, addr)       EXC(ldl, LD_INSN, reg, addr)
+#define LOADR(reg, addr)       EXC(ldr, LD_INSN, reg, addr)
+#define STOREB(reg, addr)      EXC(sb, ST_INSN, reg, addr)
+#define STOREL(reg, addr)      EXC(sdl, ST_INSN, reg, addr)
+#define STORER(reg, addr)      EXC(sdr, ST_INSN, reg, addr)
+#define STORE(reg, addr)       EXC(sd, ST_INSN, reg, addr)
 #define ADD    daddu
 #define SUB    dsubu
 #define SRL    dsrl
@@ -404,14 +389,14 @@ EXPORT_SYMBOL(csum_partial)
 #else
 
 #define LOADK  lw /* No exception */
-#define LOAD(reg, addr, handler)       EXC(lw, LD_INSN, reg, addr, handler)
-#define LOADBU(reg, addr, handler)     EXC(lbu, LD_INSN, reg, addr, handler)
-#define LOADL(reg, addr, handler)      EXC(lwl, LD_INSN, reg, addr, handler)
-#define LOADR(reg, addr, handler)      EXC(lwr, LD_INSN, reg, addr, handler)
-#define STOREB(reg, addr, handler)     EXC(sb, ST_INSN, reg, addr, handler)
-#define STOREL(reg, addr, handler)     EXC(swl, ST_INSN, reg, addr, handler)
-#define STORER(reg, addr, handler)     EXC(swr, ST_INSN, reg, addr, handler)
-#define STORE(reg, addr, handler)      EXC(sw, ST_INSN, reg, addr, handler)
+#define LOAD(reg, addr)                EXC(lw, LD_INSN, reg, addr)
+#define LOADBU(reg, addr)      EXC(lbu, LD_INSN, reg, addr)
+#define LOADL(reg, addr)       EXC(lwl, LD_INSN, reg, addr)
+#define LOADR(reg, addr)       EXC(lwr, LD_INSN, reg, addr)
+#define STOREB(reg, addr)      EXC(sb, ST_INSN, reg, addr)
+#define STOREL(reg, addr)      EXC(swl, ST_INSN, reg, addr)
+#define STORER(reg, addr)      EXC(swr, ST_INSN, reg, addr)
+#define STORE(reg, addr)       EXC(sw, ST_INSN, reg, addr)
 #define ADD    addu
 #define SUB    subu
 #define SRL    srl
@@ -450,22 +435,9 @@ EXPORT_SYMBOL(csum_partial)
        .set    at=v1
 #endif
 
-       .macro __BUILD_CSUM_PARTIAL_COPY_USER mode, from, to, __nocheck
+       .macro __BUILD_CSUM_PARTIAL_COPY_USER mode, from, to
 
-       PTR_ADDU        AT, src, len    /* See (1) above. */
-       /* initialize __nocheck if this the first time we execute this
-        * macro
-        */
-#ifdef CONFIG_64BIT
-       move    errptr, a4
-#else
-       lw      errptr, 16(sp)
-#endif
-       .if \__nocheck == 1
-       FEXPORT(csum_partial_copy_nocheck)
-       EXPORT_SYMBOL(csum_partial_copy_nocheck)
-       .endif
-       move    sum, zero
+       li      sum, -1
        move    odd, zero
        /*
         * Note: dst & src may be unaligned, len may be 0
@@ -497,31 +469,31 @@ EXPORT_SYMBOL(csum_partial)
        SUB     len, 8*NBYTES           # subtract here for bgez loop
        .align  4
 1:
-       LOAD(t0, UNIT(0)(src), .Ll_exc\@)
-       LOAD(t1, UNIT(1)(src), .Ll_exc_copy\@)
-       LOAD(t2, UNIT(2)(src), .Ll_exc_copy\@)
-       LOAD(t3, UNIT(3)(src), .Ll_exc_copy\@)
-       LOAD(t4, UNIT(4)(src), .Ll_exc_copy\@)
-       LOAD(t5, UNIT(5)(src), .Ll_exc_copy\@)
-       LOAD(t6, UNIT(6)(src), .Ll_exc_copy\@)
-       LOAD(t7, UNIT(7)(src), .Ll_exc_copy\@)
+       LOAD(t0, UNIT(0)(src))
+       LOAD(t1, UNIT(1)(src))
+       LOAD(t2, UNIT(2)(src))
+       LOAD(t3, UNIT(3)(src))
+       LOAD(t4, UNIT(4)(src))
+       LOAD(t5, UNIT(5)(src))
+       LOAD(t6, UNIT(6)(src))
+       LOAD(t7, UNIT(7)(src))
        SUB     len, len, 8*NBYTES
        ADD     src, src, 8*NBYTES
-       STORE(t0, UNIT(0)(dst), .Ls_exc\@)
+       STORE(t0, UNIT(0)(dst))
        ADDC(t0, t1)
-       STORE(t1, UNIT(1)(dst), .Ls_exc\@)
+       STORE(t1, UNIT(1)(dst))
        ADDC(sum, t0)
-       STORE(t2, UNIT(2)(dst), .Ls_exc\@)
+       STORE(t2, UNIT(2)(dst))
        ADDC(t2, t3)
-       STORE(t3, UNIT(3)(dst), .Ls_exc\@)
+       STORE(t3, UNIT(3)(dst))
        ADDC(sum, t2)
-       STORE(t4, UNIT(4)(dst), .Ls_exc\@)
+       STORE(t4, UNIT(4)(dst))
        ADDC(t4, t5)
-       STORE(t5, UNIT(5)(dst), .Ls_exc\@)
+       STORE(t5, UNIT(5)(dst))
        ADDC(sum, t4)
-       STORE(t6, UNIT(6)(dst), .Ls_exc\@)
+       STORE(t6, UNIT(6)(dst))
        ADDC(t6, t7)
-       STORE(t7, UNIT(7)(dst), .Ls_exc\@)
+       STORE(t7, UNIT(7)(dst))
        ADDC(sum, t6)
        .set    reorder                         /* DADDI_WAR */
        ADD     dst, dst, 8*NBYTES
@@ -541,19 +513,19 @@ EXPORT_SYMBOL(csum_partial)
        /*
         * len >= 4*NBYTES
         */
-       LOAD(t0, UNIT(0)(src), .Ll_exc\@)
-       LOAD(t1, UNIT(1)(src), .Ll_exc_copy\@)
-       LOAD(t2, UNIT(2)(src), .Ll_exc_copy\@)
-       LOAD(t3, UNIT(3)(src), .Ll_exc_copy\@)
+       LOAD(t0, UNIT(0)(src))
+       LOAD(t1, UNIT(1)(src))
+       LOAD(t2, UNIT(2)(src))
+       LOAD(t3, UNIT(3)(src))
        SUB     len, len, 4*NBYTES
        ADD     src, src, 4*NBYTES
-       STORE(t0, UNIT(0)(dst), .Ls_exc\@)
+       STORE(t0, UNIT(0)(dst))
        ADDC(t0, t1)
-       STORE(t1, UNIT(1)(dst), .Ls_exc\@)
+       STORE(t1, UNIT(1)(dst))
        ADDC(sum, t0)
-       STORE(t2, UNIT(2)(dst), .Ls_exc\@)
+       STORE(t2, UNIT(2)(dst))
        ADDC(t2, t3)
-       STORE(t3, UNIT(3)(dst), .Ls_exc\@)
+       STORE(t3, UNIT(3)(dst))
        ADDC(sum, t2)
        .set    reorder                         /* DADDI_WAR */
        ADD     dst, dst, 4*NBYTES
@@ -566,10 +538,10 @@ EXPORT_SYMBOL(csum_partial)
        beq     rem, len, .Lcopy_bytes\@
         nop
 1:
-       LOAD(t0, 0(src), .Ll_exc\@)
+       LOAD(t0, 0(src))
        ADD     src, src, NBYTES
        SUB     len, len, NBYTES
-       STORE(t0, 0(dst), .Ls_exc\@)
+       STORE(t0, 0(dst))
        ADDC(sum, t0)
        .set    reorder                         /* DADDI_WAR */
        ADD     dst, dst, NBYTES
@@ -592,10 +564,10 @@ EXPORT_SYMBOL(csum_partial)
         ADD    t1, dst, len    # t1 is just past last byte of dst
        li      bits, 8*NBYTES
        SLL     rem, len, 3     # rem = number of bits to keep
-       LOAD(t0, 0(src), .Ll_exc\@)
+       LOAD(t0, 0(src))
        SUB     bits, bits, rem # bits = number of bits to discard
        SHIFT_DISCARD t0, t0, bits
-       STREST(t0, -1(t1), .Ls_exc\@)
+       STREST(t0, -1(t1))
        SHIFT_DISCARD_REVERT t0, t0, bits
        .set reorder
        ADDC(sum, t0)
@@ -612,12 +584,12 @@ EXPORT_SYMBOL(csum_partial)
         * Set match = (src and dst have same alignment)
         */
 #define match rem
-       LDFIRST(t3, FIRST(0)(src), .Ll_exc\@)
+       LDFIRST(t3, FIRST(0)(src))
        ADD     t2, zero, NBYTES
-       LDREST(t3, REST(0)(src), .Ll_exc_copy\@)
+       LDREST(t3, REST(0)(src))
        SUB     t2, t2, t1      # t2 = number of bytes copied
        xor     match, t0, t1
-       STFIRST(t3, FIRST(0)(dst), .Ls_exc\@)
+       STFIRST(t3, FIRST(0)(dst))
        SLL     t4, t1, 3               # t4 = number of bits to discard
        SHIFT_DISCARD t3, t3, t4
        /* no SHIFT_DISCARD_REVERT to handle odd buffer properly */
@@ -639,26 +611,26 @@ EXPORT_SYMBOL(csum_partial)
  * It's OK to load FIRST(N+1) before REST(N) because the two addresses
  * are to the same unit (unless src is aligned, but it's not).
  */
-       LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
-       LDFIRST(t1, FIRST(1)(src), .Ll_exc_copy\@)
+       LDFIRST(t0, FIRST(0)(src))
+       LDFIRST(t1, FIRST(1)(src))
        SUB     len, len, 4*NBYTES
-       LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
-       LDREST(t1, REST(1)(src), .Ll_exc_copy\@)
-       LDFIRST(t2, FIRST(2)(src), .Ll_exc_copy\@)
-       LDFIRST(t3, FIRST(3)(src), .Ll_exc_copy\@)
-       LDREST(t2, REST(2)(src), .Ll_exc_copy\@)
-       LDREST(t3, REST(3)(src), .Ll_exc_copy\@)
+       LDREST(t0, REST(0)(src))
+       LDREST(t1, REST(1)(src))
+       LDFIRST(t2, FIRST(2)(src))
+       LDFIRST(t3, FIRST(3)(src))
+       LDREST(t2, REST(2)(src))
+       LDREST(t3, REST(3)(src))
        ADD     src, src, 4*NBYTES
 #ifdef CONFIG_CPU_SB1
        nop                             # improves slotting
 #endif
-       STORE(t0, UNIT(0)(dst), .Ls_exc\@)
+       STORE(t0, UNIT(0)(dst))
        ADDC(t0, t1)
-       STORE(t1, UNIT(1)(dst), .Ls_exc\@)
+       STORE(t1, UNIT(1)(dst))
        ADDC(sum, t0)
-       STORE(t2, UNIT(2)(dst), .Ls_exc\@)
+       STORE(t2, UNIT(2)(dst))
        ADDC(t2, t3)
-       STORE(t3, UNIT(3)(dst), .Ls_exc\@)
+       STORE(t3, UNIT(3)(dst))
        ADDC(sum, t2)
        .set    reorder                         /* DADDI_WAR */
        ADD     dst, dst, 4*NBYTES
@@ -671,11 +643,11 @@ EXPORT_SYMBOL(csum_partial)
        beq     rem, len, .Lcopy_bytes\@
         nop
 1:
-       LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
-       LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
+       LDFIRST(t0, FIRST(0)(src))
+       LDREST(t0, REST(0)(src))
        ADD     src, src, NBYTES
        SUB     len, len, NBYTES
-       STORE(t0, 0(dst), .Ls_exc\@)
+       STORE(t0, 0(dst))
        ADDC(sum, t0)
        .set    reorder                         /* DADDI_WAR */
        ADD     dst, dst, NBYTES
@@ -696,11 +668,10 @@ EXPORT_SYMBOL(csum_partial)
 #endif
        move    t2, zero        # partial word
        li      t3, SHIFT_START # shift
-/* use .Ll_exc_copy here to return correct sum on fault */
 #define COPY_BYTE(N)                   \
-       LOADBU(t0, N(src), .Ll_exc_copy\@);     \
+       LOADBU(t0, N(src));             \
        SUB     len, len, 1;            \
-       STOREB(t0, N(dst), .Ls_exc\@);  \
+       STOREB(t0, N(dst));             \
        SLLV    t0, t0, t3;             \
        addu    t3, SHIFT_INC;          \
        beqz    len, .Lcopy_bytes_done\@; \
@@ -714,9 +685,9 @@ EXPORT_SYMBOL(csum_partial)
        COPY_BYTE(4)
        COPY_BYTE(5)
 #endif
-       LOADBU(t0, NBYTES-2(src), .Ll_exc_copy\@)
+       LOADBU(t0, NBYTES-2(src))
        SUB     len, len, 1
-       STOREB(t0, NBYTES-2(dst), .Ls_exc\@)
+       STOREB(t0, NBYTES-2(dst))
        SLLV    t0, t0, t3
        or      t2, t0
 .Lcopy_bytes_done\@:
@@ -753,97 +724,31 @@ EXPORT_SYMBOL(csum_partial)
 #endif
        .set    pop
        .set reorder
-       ADDC32(sum, psum)
        jr      ra
        .set noreorder
+       .endm
 
-.Ll_exc_copy\@:
-       /*
-        * Copy bytes from src until faulting load address (or until a
-        * lb faults)
-        *
-        * When reached by a faulting LDFIRST/LDREST, THREAD_BUADDR($28)
-        * may be more than a byte beyond the last address.
-        * Hence, the lb below may get an exception.
-        *
-        * Assumes src < THREAD_BUADDR($28)
-        */
-       LOADK   t0, TI_TASK($28)
-        li     t2, SHIFT_START
-       LOADK   t0, THREAD_BUADDR(t0)
-1:
-       LOADBU(t1, 0(src), .Ll_exc\@)
-       ADD     src, src, 1
-       sb      t1, 0(dst)      # can't fault -- we're copy_from_user
-       SLLV    t1, t1, t2
-       addu    t2, SHIFT_INC
-       ADDC(sum, t1)
-       .set    reorder                         /* DADDI_WAR */
-       ADD     dst, dst, 1
-       bne     src, t0, 1b
-       .set    noreorder
-.Ll_exc\@:
-       LOADK   t0, TI_TASK($28)
-        nop
-       LOADK   t0, THREAD_BUADDR(t0)   # t0 is just past last good address
-        nop
-       SUB     len, AT, t0             # len number of uncopied bytes
-       /*
-        * Here's where we rely on src and dst being incremented in tandem,
-        *   See (3) above.
-        * dst += (fault addr - src) to put dst at first byte to clear
-        */
-       ADD     dst, t0                 # compute start address in a1
-       SUB     dst, src
-       /*
-        * Clear len bytes starting at dst.  Can't call __bzero because it
-        * might modify len.  An inefficient loop for these rare times...
-        */
-       .set    reorder                         /* DADDI_WAR */
-       SUB     src, len, 1
-       beqz    len, .Ldone\@
-       .set    noreorder
-1:     sb      zero, 0(dst)
-       ADD     dst, dst, 1
-       .set    push
-       .set    noat
-#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
-       bnez    src, 1b
-        SUB    src, src, 1
-#else
-       li      v1, 1
-       bnez    src, 1b
-        SUB    src, src, v1
-#endif
-       li      v1, -EFAULT
-       b       .Ldone\@
-        sw     v1, (errptr)
-
-.Ls_exc\@:
-       li      v0, -1 /* invalid checksum */
-       li      v1, -EFAULT
+       .set noreorder
+.L_exc:
        jr      ra
-        sw     v1, (errptr)
-       .set    pop
-       .endm
+        li     v0, 0
 
-LEAF(__csum_partial_copy_kernel)
-EXPORT_SYMBOL(__csum_partial_copy_kernel)
+FEXPORT(__csum_partial_copy_nocheck)
+EXPORT_SYMBOL(__csum_partial_copy_nocheck)
 #ifndef CONFIG_EVA
 FEXPORT(__csum_partial_copy_to_user)
 EXPORT_SYMBOL(__csum_partial_copy_to_user)
 FEXPORT(__csum_partial_copy_from_user)
 EXPORT_SYMBOL(__csum_partial_copy_from_user)
 #endif
-__BUILD_CSUM_PARTIAL_COPY_USER LEGACY_MODE USEROP USEROP 1
-END(__csum_partial_copy_kernel)
+__BUILD_CSUM_PARTIAL_COPY_USER LEGACY_MODE USEROP USEROP
 
 #ifdef CONFIG_EVA
 LEAF(__csum_partial_copy_to_user)
-__BUILD_CSUM_PARTIAL_COPY_USER EVA_MODE KERNELOP USEROP 0
+__BUILD_CSUM_PARTIAL_COPY_USER EVA_MODE KERNELOP USEROP
 END(__csum_partial_copy_to_user)
 
 LEAF(__csum_partial_copy_from_user)
-__BUILD_CSUM_PARTIAL_COPY_USER EVA_MODE USEROP KERNELOP 0
+__BUILD_CSUM_PARTIAL_COPY_USER EVA_MODE USEROP KERNELOP
 END(__csum_partial_copy_from_user)
 #endif
index 4ab55f1..ae023b9 100644 (file)
@@ -44,6 +44,10 @@ ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS
   endif
 endif
 
+# Some -march= flags enable MMI instructions, and GCC complains about that
+# support being enabled alongside -msoft-float. Thus explicitly disable MMI.
+cflags-y += $(call cc-option,-mno-loongson-mmi)
+
 #
 # Loongson Machines' Support
 #
index f130f62..00055d4 100644 (file)
@@ -95,10 +95,8 @@ static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
                        if (res)
                                goto fault;
 
-                       set_fpr64(current->thread.fpu.fpr,
-                               insn.loongson3_lswc2_format.rt, value);
-                       set_fpr64(current->thread.fpu.fpr,
-                               insn.loongson3_lswc2_format.rq, value_next);
+                       set_fpr64(&current->thread.fpu.fpr[insn.loongson3_lswc2_format.rt], 0, value);
+                       set_fpr64(&current->thread.fpu.fpr[insn.loongson3_lswc2_format.rq], 0, value_next);
                        compute_return_epc(regs);
                        own_fpu(1);
                }
@@ -130,15 +128,13 @@ static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
                                goto sigbus;
 
                        lose_fpu(1);
-                       value_next = get_fpr64(current->thread.fpu.fpr,
-                                       insn.loongson3_lswc2_format.rq);
+                       value_next = get_fpr64(&current->thread.fpu.fpr[insn.loongson3_lswc2_format.rq], 0);
 
                        StoreDW(addr + 8, value_next, res);
                        if (res)
                                goto fault;
 
-                       value = get_fpr64(current->thread.fpu.fpr,
-                                       insn.loongson3_lswc2_format.rt);
+                       value = get_fpr64(&current->thread.fpu.fpr[insn.loongson3_lswc2_format.rt], 0);
 
                        StoreDW(addr, value, res);
                        if (res)
@@ -204,8 +200,7 @@ static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
                        if (res)
                                goto fault;
 
-                       set_fpr64(current->thread.fpu.fpr,
-                                       insn.loongson3_lsdc2_format.rt, value);
+                       set_fpr64(&current->thread.fpu.fpr[insn.loongson3_lsdc2_format.rt], 0, value);
                        compute_return_epc(regs);
                        own_fpu(1);
 
@@ -221,8 +216,7 @@ static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
                        if (res)
                                goto fault;
 
-                       set_fpr64(current->thread.fpu.fpr,
-                                       insn.loongson3_lsdc2_format.rt, value);
+                       set_fpr64(&current->thread.fpu.fpr[insn.loongson3_lsdc2_format.rt], 0, value);
                        compute_return_epc(regs);
                        own_fpu(1);
                        break;
@@ -286,8 +280,7 @@ static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
                                goto sigbus;
 
                        lose_fpu(1);
-                       value = get_fpr64(current->thread.fpu.fpr,
-                                       insn.loongson3_lsdc2_format.rt);
+                       value = get_fpr64(&current->thread.fpu.fpr[insn.loongson3_lsdc2_format.rt], 0);
 
                        StoreW(addr, value, res);
                        if (res)
@@ -305,8 +298,7 @@ static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
                                goto sigbus;
 
                        lose_fpu(1);
-                       value = get_fpr64(current->thread.fpu.fpr,
-                                       insn.loongson3_lsdc2_format.rt);
+                       value = get_fpr64(&current->thread.fpu.fpr[insn.loongson3_lsdc2_format.rt], 0);
 
                        StoreDW(addr, value, res);
                        if (res)
index fc5a6d2..0ef7170 100644 (file)
@@ -1712,7 +1712,11 @@ static void setup_scache(void)
                                printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n",
                                       scache_size >> 10,
                                       way_string[c->scache.ways], c->scache.linesz);
+
+                               if (current_cpu_type() == CPU_BMIPS5000)
+                                       c->options |= MIPS_CPU_INCLUSIVE_CACHES;
                        }
+
 #else
                        if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
                                panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
index 1493c49..55d7b7f 100644 (file)
@@ -245,7 +245,6 @@ static int mipsxx_perfcount_handler(void)
 
        switch (counters) {
 #define HANDLE_COUNTER(n)                                              \
-       fallthrough;                                                    \
        case n + 1:                                                     \
                control = r_c0_perfctrl ## n();                         \
                counter = r_c0_perfcntr ## n();                         \
@@ -256,8 +255,11 @@ static int mipsxx_perfcount_handler(void)
                        handled = IRQ_HANDLED;                          \
                }
        HANDLE_COUNTER(3)
+       fallthrough;
        HANDLE_COUNTER(2)
+       fallthrough;
        HANDLE_COUNTER(1)
+       fallthrough;
        HANDLE_COUNTER(0)
        }
 
index 0ecffb6..eeeec18 100644 (file)
@@ -143,7 +143,10 @@ static struct platform_device sc26xx_pdev = {
        },
 };
 
-static u32 a20r_ack_hwint(void)
+/*
+ * Trigger chipset to update CPU's CAUSE IP field
+ */
+static u32 a20r_update_cause_ip(void)
 {
        u32 status = read_c0_status();
 
@@ -205,12 +208,14 @@ static void a20r_hwint(void)
        int irq;
 
        clear_c0_status(IE_IRQ0);
-       status = a20r_ack_hwint();
+       status = a20r_update_cause_ip();
        cause = read_c0_cause();
 
        irq = ffs(((cause & status) >> 8) & 0xf8);
        if (likely(irq > 0))
                do_IRQ(SNI_A20R_IRQ_BASE + irq - 1);
+
+       a20r_update_cause_ip();
        set_c0_status(IE_IRQ0);
 }
 
@@ -222,8 +227,8 @@ void __init sni_a20r_irq_init(void)
                irq_set_chip_and_handler(i, &a20r_irq_type, handle_level_irq);
        sni_hwint = a20r_hwint;
        change_c0_status(ST0_IM, IE_IRQ0);
-       if (request_irq(SNI_A20R_IRQ_BASE + 3, sni_isa_irq_handler, 0, "ISA",
-                       NULL))
+       if (request_irq(SNI_A20R_IRQ_BASE + 3, sni_isa_irq_handler,
+                       IRQF_SHARED, "ISA", sni_isa_irq_handler))
                pr_err("Failed to register ISA interrupt\n");
 }
 
index fb45ec4..51ef800 100644 (file)
@@ -34,3 +34,8 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
 {
        return !flags;
 }
+
+static inline int arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
index 62bdafb..9edd7ed 100644 (file)
@@ -45,7 +45,7 @@ void save_fpu(struct task_struct *tsk)
                              : /* no output */
                              : "r" (&tsk->thread.fpu)
                              : "memory");
-               /* fall through */
+               fallthrough;
        case SP32_DP16_reg:
                asm volatile ("fsdi $fd15, [%0+0x78]\n\t"
                              "fsdi $fd14, [%0+0x70]\n\t"
@@ -58,7 +58,7 @@ void save_fpu(struct task_struct *tsk)
                              : /* no output */
                              : "r" (&tsk->thread.fpu)
                              : "memory");
-               /* fall through */
+               fallthrough;
        case SP16_DP8_reg:
                asm volatile ("fsdi $fd7,  [%0+0x38]\n\t"
                              "fsdi $fd6,  [%0+0x30]\n\t"
@@ -67,7 +67,7 @@ void save_fpu(struct task_struct *tsk)
                              : /* no output */
                              : "r" (&tsk->thread.fpu)
                              : "memory");
-               /* fall through */
+               fallthrough;
        case SP8_DP4_reg:
                asm volatile ("fsdi $fd3,  [%1+0x18]\n\t"
                              "fsdi $fd2,  [%1+0x10]\n\t"
@@ -108,7 +108,7 @@ void load_fpu(const struct fpu_struct *fpregs)
                              "fldi $fd16, [%0+0x80]\n\t"
                              : /* no output */
                              : "r" (fpregs));
-               /* fall through */
+               fallthrough;
        case SP32_DP16_reg:
                asm volatile ("fldi $fd15, [%0+0x78]\n\t"
                              "fldi $fd14, [%0+0x70]\n\t"
@@ -120,7 +120,7 @@ void load_fpu(const struct fpu_struct *fpregs)
                              "fldi $fd8,  [%0+0x40]\n\t"
                              : /* no output */
                              : "r" (fpregs));
-               /* fall through */
+               fallthrough;
        case SP16_DP8_reg:
                asm volatile ("fldi $fd7,  [%0+0x38]\n\t"
                              "fldi $fd6,  [%0+0x30]\n\t"
@@ -128,7 +128,7 @@ void load_fpu(const struct fpu_struct *fpregs)
                              "fldi $fd4,  [%0+0x20]\n\t"
                              : /* no output */
                              : "r" (fpregs));
-               /* fall through */
+               fallthrough;
        case SP8_DP4_reg:
                asm volatile ("fldi $fd3,  [%1+0x18]\n\t"
                              "fldi $fd2,  [%1+0x10]\n\t"
index 330b19f..36e25a4 100644 (file)
@@ -316,7 +316,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
                                regs->uregs[0] = -EINTR;
                                break;
                        }
-                       /* Else, fall through */
+                       fallthrough;
                case -ERESTARTNOINTR:
                        regs->uregs[0] = regs->orig_r0;
                        regs->ipc -= 4;
@@ -361,7 +361,7 @@ static void do_signal(struct pt_regs *regs)
                switch (regs->uregs[0]) {
                case -ERESTART_RESTARTBLOCK:
                        regs->uregs[15] = __NR_restart_syscall;
-                       /* Fall through */
+                       fallthrough;
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
index 7a6c1ce..6a91b96 100644 (file)
@@ -64,6 +64,7 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        DISCARDS
 }
index b4316c3..69004e0 100644 (file)
 
 /* Take these from lib/checksum.c */
 extern __wsum csum_partial(const void *buff, int len, __wsum sum);
-__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len,
-                               __wsum sum);
-#define csum_partial_copy_nocheck csum_partial_copy_nocheck
-
 extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
 extern __sum16 ip_compute_csum(const void *buff, int len);
 
index c55a7cf..126e114 100644 (file)
@@ -58,6 +58,7 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        DISCARDS
 }
index f039021..120f500 100644 (file)
@@ -165,19 +165,19 @@ struct __large_struct {
 
 #define __get_user_nocheck(x, ptr, size)                       \
 ({                                                             \
-       long __gu_err, __gu_val;                                \
-       __get_user_size(__gu_val, (ptr), (size), __gu_err);     \
-       (x) = (__force __typeof__(*(ptr)))__gu_val;             \
+       long __gu_err;                                          \
+       __get_user_size((x), (ptr), (size), __gu_err);          \
        __gu_err;                                               \
 })
 
 #define __get_user_check(x, ptr, size)                                 \
 ({                                                                     \
-       long __gu_err = -EFAULT, __gu_val = 0;                          \
+       long __gu_err = -EFAULT;                                        \
        const __typeof__(*(ptr)) __user *__gu_addr = (ptr);             \
-       if (access_ok(__gu_addr, size))                 \
-               __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
-       (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
+       if (access_ok(__gu_addr, size))                                 \
+               __get_user_size((x), __gu_addr, (size), __gu_err);      \
+       else                                                            \
+               (x) = (__typeof__(*(ptr))) 0;                           \
        __gu_err;                                                       \
 })
 
@@ -191,11 +191,13 @@ do {                                                                      \
        case 2: __get_user_asm(x, ptr, retval, "l.lhz"); break;         \
        case 4: __get_user_asm(x, ptr, retval, "l.lwz"); break;         \
        case 8: __get_user_asm2(x, ptr, retval); break;                 \
-       default: (x) = __get_user_bad();                                \
+       default: (x) = (__typeof__(*(ptr)))__get_user_bad();            \
        }                                                               \
 } while (0)
 
 #define __get_user_asm(x, addr, err, op)               \
+{                                                      \
+       unsigned long __gu_tmp;                         \
        __asm__ __volatile__(                           \
                "1:     "op" %1,0(%2)\n"                \
                "2:\n"                                  \
@@ -209,10 +211,14 @@ do {                                                                      \
                "       .align 2\n"                     \
                "       .long 1b,3b\n"                  \
                ".previous"                             \
-               : "=r"(err), "=r"(x)                    \
-               : "r"(addr), "i"(-EFAULT), "0"(err))
+               : "=r"(err), "=r"(__gu_tmp)             \
+               : "r"(addr), "i"(-EFAULT), "0"(err));   \
+       (x) = (__typeof__(*(addr)))__gu_tmp;            \
+}
 
 #define __get_user_asm2(x, addr, err)                  \
+{                                                      \
+       unsigned long long __gu_tmp;                    \
        __asm__ __volatile__(                           \
                "1:     l.lwz %1,0(%2)\n"               \
                "2:     l.lwz %H1,4(%2)\n"              \
@@ -229,8 +235,11 @@ do {                                                                       \
                "       .long 1b,4b\n"                  \
                "       .long 2b,4b\n"                  \
                ".previous"                             \
-               : "=r"(err), "=&r"(x)                   \
-               : "r"(addr), "i"(-EFAULT), "0"(err))
+               : "=r"(err), "=&r"(__gu_tmp)            \
+               : "r"(addr), "i"(-EFAULT), "0"(err));   \
+       (x) = (__typeof__(*(addr)))(                    \
+               (__typeof__((x)-(x)))__gu_tmp);         \
+}
 
 /* more complex routines */
 
index b18e775..13c87f1 100644 (file)
@@ -80,6 +80,16 @@ static void __init setup_memory(void)
         */
        memblock_reserve(__pa(_stext), _end - _stext);
 
+#ifdef CONFIG_BLK_DEV_INITRD
+       /* Then reserve the initrd, if any */
+       if (initrd_start && (initrd_end > initrd_start)) {
+               unsigned long aligned_start = ALIGN_DOWN(initrd_start, PAGE_SIZE);
+               unsigned long aligned_end = ALIGN(initrd_end, PAGE_SIZE);
+
+               memblock_reserve(__pa(aligned_start), aligned_end - aligned_start);
+       }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
        early_init_fdt_reserve_self();
        early_init_fdt_scan_reserved_mem();
 
index 97804f2..c779364 100644 (file)
@@ -244,7 +244,7 @@ int do_signal(struct pt_regs *regs, int syscall)
                switch (retval) {
                case -ERESTART_RESTARTBLOCK:
                        restart = -2;
-                       /* Fall through */
+                       fallthrough;
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
index 22fbc5f..d5c7bb0 100644 (file)
@@ -103,6 +103,7 @@ SECTIONS
        /* Throw in the debugging sections */
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
         /* Sections to be discarded -- must be last */
        DISCARDS
index 08f56af..534a52e 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-static void cache_loop(struct page *page, const unsigned int reg)
+static __always_inline void cache_loop(struct page *page, const unsigned int reg)
 {
        unsigned long paddr = page_to_pfn(page) << PAGE_SHIFT;
        unsigned long line = paddr & ~(L1_CACHE_BYTES - 1);
index 2ac3a64..ab7b439 100644 (file)
@@ -84,6 +84,7 @@ SECTIONS
        }
 
        STABS_DEBUG
+       ELF_DETAILS
        .note 0 : { *(.note) }
 
        /* Sections to be discarded */
index fe8c63b..3c43bac 100644 (file)
 extern __wsum csum_partial(const void *, int, __wsum);
 
 /*
- * The same as csum_partial, but copies from src while it checksums.
- *
- * Here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-extern __wsum csum_partial_copy_nocheck(const void *, void *, int, __wsum);
-
-/*
  *     Optimized for IP headers, which always checksum on 4 octet boundaries.
  *
  *     Written by Randolph Chung <tausq@debian.org>, and then mucked with by
@@ -181,25 +173,5 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
        return csum_fold(sum);
 }
 
-/* 
- *     Copy and checksum to user
- */
-#define HAVE_CSUM_COPY_USER
-static __inline__ __wsum csum_and_copy_to_user(const void *src,
-                                                     void __user *dst,
-                                                     int len, __wsum sum,
-                                                     int *err_ptr)
-{
-       /* code stolen from include/asm-mips64 */
-       sum = csum_partial(src, len, sum);
-        
-       if (copy_to_user(dst, src, len)) {
-               *err_ptr = -EFAULT;
-               return (__force __wsum)-1;
-       }
-
-       return sum;
-}
-
 #endif
 
index 2f4f66a..8f33085 100644 (file)
@@ -22,8 +22,6 @@ typedef u32   compat_dev_t;
 typedef u16    compat_nlink_t;
 typedef u16    compat_ipc_pid_t;
 typedef u32    compat_caddr_t;
-typedef s64    compat_s64;
-typedef u64    compat_u64;
 
 struct compat_stat {
        compat_dev_t            st_dev; /* dev_t is 32 bits on parisc */
index 77ec518..6d21a51 100644 (file)
@@ -191,80 +191,11 @@ static struct kprobe trampoline_p = {
 static int __kprobes trampoline_probe_handler(struct kprobe *p,
                                              struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address = (unsigned long)trampoline_p.addr;
-       kprobe_opcode_t *correct_ret_addr = NULL;
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because multiple functions in the call path have
-        * a return probe installed on them, and/or more than one return
-        * probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
-       correct_ret_addr = ri->ret_addr;
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               if (ri->rp && ri->rp->handler) {
-                       __this_cpu_write(current_kprobe, &ri->rp->kp);
-                       get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
-                       ri->ret_addr = correct_ret_addr;
-                       ri->rp->handler(ri, regs);
-                       __this_cpu_write(current_kprobe, NULL);
-               }
-
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
+       unsigned long orig_ret_address;
 
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
+       orig_ret_address = __kretprobe_trampoline_handler(regs, trampoline_p.addr, NULL);
        instruction_pointer_set(regs, orig_ret_address);
+
        return 1;
 }
 
@@ -272,6 +203,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                      struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *)regs->gr[2];
+       ri->fp = NULL;
 
        /* Replace the return addr with trampoline addr. */
        regs->gr[2] = (unsigned long)trampoline_p.addr;
index 5df5d4c..3c037fc 100644 (file)
@@ -502,7 +502,7 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
                        regs->gr[28] = -EINTR;
                        break;
                }
-               /* fallthrough */
+               fallthrough;
        case -ERESTARTNOINTR:
                check_syscallno_in_delay_branch(regs);
                break;
index def64d2..ae3dab3 100644 (file)
@@ -29,7 +29,7 @@
 18     common  stat                    sys_newstat                     compat_sys_newstat
 19     common  lseek                   sys_lseek                       compat_sys_lseek
 20     common  getpid                  sys_getpid
-21     common  mount                   sys_mount                       compat_sys_mount
+21     common  mount                   sys_mount
 22     common  bind                    sys_bind
 23     common  setuid                  sys_setuid
 24     common  getuid                  sys_getuid
 142    common  _newselect              sys_select                      compat_sys_select
 143    common  flock                   sys_flock
 144    common  msync                   sys_msync
-145    common  readv                   sys_readv                       compat_sys_readv
-146    common  writev                  sys_writev                      compat_sys_writev
+145    common  readv                   sys_readv
+146    common  writev                  sys_writev
 147    common  getsid                  sys_getsid
 148    common  fdatasync               sys_fdatasync
 149    common  _sysctl                 sys_ni_syscall
 292    32      sync_file_range         parisc_sync_file_range
 292    64      sync_file_range         sys_sync_file_range
 293    common  tee                     sys_tee
-294    common  vmsplice                sys_vmsplice                    compat_sys_vmsplice
+294    common  vmsplice                sys_vmsplice
 295    common  move_pages              sys_move_pages                  compat_sys_move_pages
 296    common  getcpu                  sys_getcpu
 297    common  epoll_pwait             sys_epoll_pwait                 compat_sys_epoll_pwait
 327    common  syncfs                  sys_syncfs
 328    common  setns                   sys_setns
 329    common  sendmmsg                sys_sendmmsg                    compat_sys_sendmmsg
-330    common  process_vm_readv        sys_process_vm_readv            compat_sys_process_vm_readv
-331    common  process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
+330    common  process_vm_readv        sys_process_vm_readv
+331    common  process_vm_writev       sys_process_vm_writev
 332    common  kcmp                    sys_kcmp
 333    common  finit_module            sys_finit_module
 334    common  sched_setattr           sys_sched_setattr
index 43875c2..a52c7ab 100644 (file)
@@ -437,7 +437,6 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
                break;
 
        default:
-               /* Fall through */
                break;
 
        }
@@ -644,12 +643,12 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
 
        case 15:
                /* Data TLB miss fault/Data page fault */
-               /* Fall through */
+               fallthrough;
        case 16:
                /* Non-access instruction TLB miss fault */
                /* The instruction TLB entry needed for the target address of the FIC
                   is absent, and hardware can't find it, so we get to cleanup */
-               /* Fall through */
+               fallthrough;
        case 17:
                /* Non-access data TLB miss fault/Non-access data page fault */
                /* FIXME: 
@@ -673,7 +672,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
                        handle_unaligned(regs);
                        return;
                }
-               /* Fall Through */
+               fallthrough;
        case 26: 
                /* PCXL: Data memory access rights trap */
                fault_address = regs->ior;
@@ -683,7 +682,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
        case 19:
                /* Data memory break trap */
                regs->gr[0] |= PSW_X; /* So we can single-step over the trap */
-               /* fall thru */
+               fallthrough;
        case 21:
                /* Page reference trap */
                handle_gdb_break(regs, TRAP_HWBKPT);
@@ -730,7 +729,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
                        }
                        mmap_read_unlock(current->mm);
                }
-               /* Fall Through */
+               fallthrough;
        case 27: 
                /* Data memory protection ID trap */
                if (code == 27 && !user_mode(regs) &&
index 53e29d8..2769eb9 100644 (file)
@@ -164,6 +164,7 @@ SECTIONS
        _end = . ;
 
        STABS_DEBUG
+       ELF_DETAILS
        .note 0 : { *(.note) }
 
        /* Sections to be discarded */
index c6f1615..4818f3d 100644 (file)
@@ -106,20 +106,3 @@ __wsum csum_partial(const void *buff, int len, __wsum sum)
 }
 
 EXPORT_SYMBOL(csum_partial);
-
-/*
- * copy while checksumming, otherwise like csum_partial
- */
-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                      int len, __wsum sum)
-{
-       /*
-        * It's 2:30 am and I don't feel like doing it real ...
-        * This is lots slower than the real thing (tm)
-        */
-       sum = csum_partial(src, len, sum);
-       memcpy(dst, src, len);
-
-       return sum;
-}
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
index 4bfe2da..716960f 100644 (file)
@@ -67,7 +67,7 @@ parisc_acctyp(unsigned long code, unsigned int inst)
        case 0x30000000: /* coproc2 */
                if (bit22set(inst))
                        return VM_WRITE;
-               /* fall through */
+               fallthrough;
 
        case 0x0: /* indexed/memory management */
                if (bit22set(inst)) {
@@ -370,7 +370,7 @@ bad_area:
                        }
 
                        /* probably address is outside of mapped file */
-                       /* fall through */
+                       fallthrough;
                case 17:        /* NA data TLB miss / page fault */
                case 18:        /* Unaligned access - PCXS only */
                        signo = SIGBUS;
index 1f48bbf..5920361 100644 (file)
@@ -116,7 +116,6 @@ config PPC
        #
        select ARCH_32BIT_OFF_T if PPC32
        select ARCH_HAS_DEBUG_VIRTUAL
-       select ARCH_HAS_DEBUG_VM_PGTABLE
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_FORTIFY_SOURCE
@@ -136,7 +135,7 @@ config PPC
        select ARCH_HAS_STRICT_KERNEL_RWX       if (PPC32 && !HIBERNATION)
        select ARCH_HAS_TICK_BROADCAST          if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_HAS_UACCESS_FLUSHCACHE
-       select ARCH_HAS_UACCESS_MCSAFE          if PPC64
+       select ARCH_HAS_COPY_MC                 if PPC64
        select ARCH_HAS_UBSAN_SANITIZE_ALL
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select ARCH_KEEP_MEMBLOCK
@@ -246,6 +245,7 @@ config PPC
        select OLD_SIGACTION                    if PPC32
        select OLD_SIGSUSPEND
        select PCI_DOMAINS                      if PCI
+       select PCI_MSI_ARCH_FALLBACKS           if PCI_MSI
        select PCI_SYSCALL                      if PCI
        select PPC_DAWR                         if PPC64
        select RTC_LIB
@@ -860,6 +860,18 @@ config PPC_SUBPAGE_PROT
 
          If unsure, say N here.
 
+config PPC_PROT_SAO_LPAR
+       bool "Support PROT_SAO mappings in LPARs"
+       depends on PPC_BOOK3S_64
+       help
+         This option adds support for PROT_SAO mappings from userspace
+         inside LPARs on supported CPUs.
+
+         This may cause issues when performing guest migration from
+         a CPU that supports SAO to one that does not.
+
+         If unsure, say N here.
+
 config PPC_COPRO_BASE
        bool
 
index af9af03..15ed8d0 100644 (file)
@@ -108,7 +108,6 @@ CONFIG_FB_NVIDIA=y
 CONFIG_FB_NVIDIA_I2C=y
 CONFIG_FB_RADEON=y
 # CONFIG_LCD_CLASS_DEVICE is not set
-CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
index 5e6f92b..66e9a0f 100644 (file)
@@ -743,7 +743,6 @@ CONFIG_FB_TRIDENT=m
 CONFIG_FB_SM501=m
 CONFIG_FB_IBM_GXT4500=y
 CONFIG_LCD_PLATFORM=m
-CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_LOGO=y
index dce86e7..c1c1ef9 100644 (file)
@@ -9,6 +9,7 @@
 #include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/random.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/cpufeature.h>
@@ -22,10 +23,11 @@ static unsigned long iterations = 10000;
 static int __init crc_test_init(void)
 {
        u16 crc16 = 0, verify16 = 0;
-       u32 crc32 = 0, verify32 = 0;
        __le32 verify32le = 0;
        unsigned char *data;
+       u32 verify32 = 0;
        unsigned long i;
+       __le32 crc32;
        int ret;
 
        struct crypto_shash *crct10dif_tfm;
@@ -98,7 +100,7 @@ static int __init crc_test_init(void)
                        crypto_shash_final(crc32c_shash, (u8 *)(&crc32));
                        verify32 = le32_to_cpu(verify32le);
                        verify32le = ~cpu_to_le32(__crc32c_le(~verify32, data+offset, len));
-                       if (crc32 != (u32)verify32le) {
+                       if (crc32 != verify32le) {
                                pr_err("FAILURE in CRC32: got 0x%08x expected 0x%08x (len %lu)\n",
                                       crc32, verify32, len);
                                break;
index 55442d4..b392384 100644 (file)
@@ -239,14 +239,14 @@ static inline void early_init_mmu_secondary(void)
 
 extern void hash__setup_initial_memory_limit(phys_addr_t first_memblock_base,
                                         phys_addr_t first_memblock_size);
-extern void radix__setup_initial_memory_limit(phys_addr_t first_memblock_base,
-                                        phys_addr_t first_memblock_size);
 static inline void setup_initial_memory_limit(phys_addr_t first_memblock_base,
                                              phys_addr_t first_memblock_size)
 {
-       if (early_radix_enabled())
-               return radix__setup_initial_memory_limit(first_memblock_base,
-                                                  first_memblock_size);
+       /*
+        * Hash has more strict restrictions. At this point we don't
+        * know which translations we will pick. Hence go with hash
+        * restrictions.
+        */
        return hash__setup_initial_memory_limit(first_memblock_base,
                                           first_memblock_size);
 }
index 6de56c3..495fc0c 100644 (file)
 #define _PAGE_RW               (_PAGE_READ | _PAGE_WRITE)
 #define _PAGE_RWX              (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC)
 #define _PAGE_PRIVILEGED       0x00008 /* kernel access only */
-
-#define _PAGE_CACHE_CTL                0x00030 /* Bits for the folowing cache modes */
-                       /*      No bits set is normal cacheable memory */
-                       /*      0x00010 unused, is SAO bit on radix POWER9 */
+#define _PAGE_SAO              0x00010 /* Strong access order */
 #define _PAGE_NON_IDEMPOTENT   0x00020 /* non idempotent memory */
 #define _PAGE_TOLERANT         0x00030 /* tolerant memory, cache inhibited */
-
 #define _PAGE_DIRTY            0x00080 /* C: page changed */
 #define _PAGE_ACCESSED         0x00100 /* R: page referenced */
 /*
@@ -828,6 +824,8 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
        return hash__set_pte_at(mm, addr, ptep, pte, percpu);
 }
 
+#define _PAGE_CACHE_CTL        (_PAGE_SAO | _PAGE_NON_IDEMPOTENT | _PAGE_TOLERANT)
+
 #define pgprot_noncached pgprot_noncached
 static inline pgprot_t pgprot_noncached(pgprot_t prot)
 {
index 9cce061..82f099b 100644 (file)
  * Like csum_partial, this must be called with even lengths,
  * except for the last fragment.
  */
-extern __wsum csum_partial_copy_generic(const void *src, void *dst,
-                                             int len, __wsum sum,
-                                             int *src_err, int *dst_err);
+extern __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
 
 #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
 extern __wsum csum_and_copy_from_user(const void __user *src, void *dst,
-                                     int len, __wsum sum, int *err_ptr);
+                                     int len);
 #define HAVE_CSUM_COPY_USER
 extern __wsum csum_and_copy_to_user(const void *src, void __user *dst,
-                                   int len, __wsum sum, int *err_ptr);
+                                   int len);
 
-#define csum_partial_copy_nocheck(src, dst, len, sum)   \
-        csum_partial_copy_generic((src), (dst), (len), (sum), NULL, NULL)
+#define _HAVE_ARCH_CSUM_AND_COPY
+#define csum_partial_copy_nocheck(src, dst, len)   \
+        csum_partial_copy_generic((src), (dst), (len))
 
 
 /*
index 3e3cdfa..9191fc2 100644 (file)
@@ -27,8 +27,6 @@ typedef s16           compat_nlink_t;
 typedef u16            compat_ipc_pid_t;
 typedef u32            compat_caddr_t;
 typedef __kernel_fsid_t        compat_fsid_t;
-typedef s64            compat_s64;
-typedef u64            compat_u64;
 
 struct compat_stat {
        compat_dev_t    st_dev;
index e005b45..32a15dc 100644 (file)
@@ -196,7 +196,7 @@ static inline void cpu_feature_keys_init(void) { }
 #define CPU_FTR_SPURR                  LONG_ASM_CONST(0x0000000001000000)
 #define CPU_FTR_DSCR                   LONG_ASM_CONST(0x0000000002000000)
 #define CPU_FTR_VSX                    LONG_ASM_CONST(0x0000000004000000)
-// Free                                        LONG_ASM_CONST(0x0000000008000000)
+#define CPU_FTR_SAO                    LONG_ASM_CONST(0x0000000008000000)
 #define CPU_FTR_CP_USE_DCBTZ           LONG_ASM_CONST(0x0000000010000000)
 #define CPU_FTR_UNALIGNED_LD_STD       LONG_ASM_CONST(0x0000000020000000)
 #define CPU_FTR_ASYM_SMT               LONG_ASM_CONST(0x0000000040000000)
@@ -441,7 +441,7 @@ static inline void cpu_feature_keys_init(void) { }
            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_ASYM_SMT | \
+           CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
            CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
            CPU_FTR_CFAR | CPU_FTR_HVMODE | \
            CPU_FTR_VMX_COPY | CPU_FTR_HAS_PPR | CPU_FTR_DABRX )
@@ -450,7 +450,7 @@ static inline void cpu_feature_keys_init(void) { }
            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_DSCR | CPU_FTR_SAO  | \
            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_DAWR | \
@@ -461,7 +461,7 @@ static inline void cpu_feature_keys_init(void) { }
            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_DSCR | CPU_FTR_SAO  | \
            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 | \
@@ -479,7 +479,7 @@ static inline void cpu_feature_keys_init(void) { }
            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_DSCR | CPU_FTR_SAO  | \
            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 | \
index 3a0db7b..35060be 100644 (file)
@@ -200,17 +200,14 @@ static inline bool arch_irqs_disabled(void)
 #define powerpc_local_irq_pmu_save(flags)                      \
         do {                                                   \
                raw_local_irq_pmu_save(flags);                  \
-               trace_hardirqs_off();                           \
+               if (!raw_irqs_disabled_flags(flags))            \
+                       trace_hardirqs_off();                   \
        } while(0)
 #define powerpc_local_irq_pmu_restore(flags)                   \
        do {                                                    \
-               if (raw_irqs_disabled_flags(flags)) {           \
-                       raw_local_irq_pmu_restore(flags);       \
-                       trace_hardirqs_off();                   \
-               } else {                                        \
+               if (!raw_irqs_disabled_flags(flags))            \
                        trace_hardirqs_on();                    \
-                       raw_local_irq_pmu_restore(flags);       \
-               }                                               \
+               raw_local_irq_pmu_restore(flags);               \
        } while(0)
 #else
 #define powerpc_local_irq_pmu_save(flags)                      \
index 7c07728..7cb6d18 100644 (file)
 #include <linux/pkeys.h>
 #include <asm/cpu_has_feature.h>
 
-#ifdef CONFIG_PPC_MEM_KEYS
 static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
                unsigned long pkey)
 {
-       return pkey_to_vmflag_bits(pkey);
+#ifdef CONFIG_PPC_MEM_KEYS
+       return (((prot & PROT_SAO) ? VM_SAO : 0) | pkey_to_vmflag_bits(pkey));
+#else
+       return ((prot & PROT_SAO) ? VM_SAO : 0);
+#endif
 }
 #define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey)
 
 static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags)
 {
-       return __pgprot(vmflag_to_pte_pkey_bits(vm_flags));
+#ifdef CONFIG_PPC_MEM_KEYS
+       return (vm_flags & VM_SAO) ?
+               __pgprot(_PAGE_SAO | vmflag_to_pte_pkey_bits(vm_flags)) :
+               __pgprot(0 | vmflag_to_pte_pkey_bits(vm_flags));
+#else
+       return (vm_flags & VM_SAO) ? __pgprot(_PAGE_SAO) : __pgprot(0);
+#endif
 }
 #define arch_vm_get_page_prot(vm_flags) arch_vm_get_page_prot(vm_flags)
-#endif
+
+static inline bool arch_validate_prot(unsigned long prot, unsigned long addr)
+{
+       if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM | PROT_SAO))
+               return false;
+       if (prot & PROT_SAO) {
+               if (!cpu_has_feature(CPU_FTR_SAO))
+                       return false;
+               if (firmware_has_feature(FW_FEATURE_LPAR) &&
+                   !IS_ENABLED(CONFIG_PPC_PROT_SAO_LPAR))
+                       return false;
+       }
+       return true;
+}
+#define arch_validate_prot arch_validate_prot
 
 #endif /* CONFIG_PPC64 */
 #endif /* _ASM_POWERPC_MMAN_H */
index 59ee9fa..6cb8aa3 100644 (file)
@@ -82,6 +82,8 @@
  */
 #include <asm/nohash/pte-book3e.h>
 
+#define _PAGE_SAO      0
+
 #define PTE_RPN_MASK   (~((1UL << PTE_RPN_SHIFT) - 1))
 
 /*
index 283552c..2aa0e31 100644 (file)
@@ -53,9 +53,7 @@ void *__memmove(void *to, const void *from, __kernel_size_t n);
 #ifndef CONFIG_KASAN
 #define __HAVE_ARCH_MEMSET32
 #define __HAVE_ARCH_MEMSET64
-#define __HAVE_ARCH_MEMCPY_MCSAFE
 
-extern int memcpy_mcsafe(void *dst, const void *src, __kernel_size_t sz);
 extern void *__memset16(uint16_t *, uint16_t v, __kernel_size_t);
 extern void *__memset32(uint32_t *, uint32_t v, __kernel_size_t);
 extern void *__memset64(uint64_t *, uint64_t v, __kernel_size_t);
index 0069990..20a3537 100644 (file)
@@ -435,6 +435,32 @@ do {                                                               \
 extern unsigned long __copy_tofrom_user(void __user *to,
                const void __user *from, unsigned long size);
 
+#ifdef CONFIG_ARCH_HAS_COPY_MC
+unsigned long __must_check
+copy_mc_generic(void *to, const void *from, unsigned long size);
+
+static inline unsigned long __must_check
+copy_mc_to_kernel(void *to, const void *from, unsigned long size)
+{
+       return copy_mc_generic(to, from, size);
+}
+#define copy_mc_to_kernel copy_mc_to_kernel
+
+static inline unsigned long __must_check
+copy_mc_to_user(void __user *to, const void *from, unsigned long n)
+{
+       if (likely(check_copy_size(from, n, true))) {
+               if (access_ok(to, n)) {
+                       allow_write_to_user(to, n);
+                       n = copy_mc_generic((void *)to, from, n);
+                       prevent_write_to_user(to, n);
+               }
+       }
+
+       return n;
+}
+#endif
+
 #ifdef __powerpc64__
 static inline unsigned long
 raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
@@ -523,20 +549,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
        return ret;
 }
 
-static __always_inline unsigned long __must_check
-copy_to_user_mcsafe(void __user *to, const void *from, unsigned long n)
-{
-       if (likely(check_copy_size(from, n, true))) {
-               if (access_ok(to, n)) {
-                       allow_write_to_user(to, n);
-                       n = memcpy_mcsafe((void *)to, from, n);
-                       prevent_write_to_user(to, n);
-               }
-       }
-
-       return n;
-}
-
 unsigned long __arch_clear_user(void __user *addr, unsigned long size);
 
 static inline unsigned long clear_user(void __user *addr, unsigned long size)
index 3a70035..c0c7372 100644 (file)
@@ -11,7 +11,7 @@
 #include <asm-generic/mman-common.h>
 
 
-#define PROT_SAO       0x10            /* Unsupported since v5.9 */
+#define PROT_SAO       0x10            /* Strong Access Ordering */
 
 #define MAP_RENAME      MAP_ANONYMOUS   /* In SunOS terminology */
 #define MAP_NORESERVE   0x40            /* don't reserve swap pages */
index 569fecd..9053fc9 100644 (file)
@@ -120,7 +120,8 @@ u64 dma_iommu_get_required_mask(struct device *dev)
        if (!tbl)
                return 0;
 
-       mask = 1ULL < (fls_long(tbl->it_offset + tbl->it_size) - 1);
+       mask = 1ULL << (fls_long(tbl->it_offset + tbl->it_size) +
+                       tbl->it_page_shift - 1);
        mask += mask - 1;
 
        return mask;
index 8dc46f3..f204ad7 100644 (file)
@@ -653,7 +653,7 @@ static struct dt_cpu_feature_match __initdata
        {"processor-control-facility-v3", feat_enable_dbell, CPU_FTR_DBELL},
        {"processor-utilization-of-resources-register", feat_enable_purr, 0},
        {"no-execute", feat_enable, 0},
-       /* strong-access-ordering is unused */
+       {"strong-access-ordering", feat_enable, CPU_FTR_SAO},
        {"cache-inhibited-large-page", feat_enable_large_ci, 0},
        {"coprocessor-icswx", feat_enable, 0},
        {"hypervisor-virtualization-interrupt", feat_enable_hvi, 0},
index 33a42e4..733e40e 100644 (file)
@@ -113,6 +113,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM)
        ld      r11,exception_marker@toc(r2)
        std     r11,-16(r10)            /* "regshere" marker */
 
+BEGIN_FTR_SECTION
+       HMT_MEDIUM
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+
        /*
         * RECONCILE_IRQ_STATE without calling trace_hardirqs_off(), which
         * would clobber syscall parameters. Also we always enter with IRQs
index 6ab9b4d..01ab216 100644 (file)
@@ -218,6 +218,7 @@ bool arch_kprobe_on_func_entry(unsigned long offset)
 void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *)regs->link;
+       ri->fp = NULL;
 
        /* Replace the return addr with trampoline addr */
        regs->link = (unsigned long)kretprobe_trampoline;
@@ -396,50 +397,9 @@ asm(".global kretprobe_trampoline\n"
  */
 static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because an multiple functions in the call path
-        * have a return probe installed on them, and/or more than one return
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               if (ri->rp && ri->rp->handler)
-                       ri->rp->handler(ri, regs);
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
+       unsigned long orig_ret_address;
 
+       orig_ret_address = __kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
        /*
         * We get here through one of two paths:
         * 1. by taking a trap -> kprobe_handler() -> here
@@ -458,13 +418,6 @@ static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
        regs->nip = orig_ret_address - 4;
        regs->link = orig_ret_address;
 
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
-
        return 0;
 }
 NOKPROBE_SYMBOL(trampoline_probe_handler);
index 016bd83..73a5704 100644 (file)
@@ -548,7 +548,7 @@ void notrace restore_math(struct pt_regs *regs)
         * are live for the user thread).
         */
        if ((!(msr & MSR_FP)) && should_restore_fp())
-               new_msr |= MSR_FP | current->thread.fpexc_mode;
+               new_msr |= MSR_FP;
 
        if ((!(msr & MSR_VEC)) && should_restore_altivec())
                new_msr |= MSR_VEC;
@@ -559,11 +559,17 @@ void notrace restore_math(struct pt_regs *regs)
        }
 
        if (new_msr) {
+               unsigned long fpexc_mode = 0;
+
                msr_check_and_set(new_msr);
 
-               if (new_msr & MSR_FP)
+               if (new_msr & MSR_FP) {
                        do_restore_fp();
 
+                       // This also covers VSX, because VSX implies FP
+                       fpexc_mode = current->thread.fpexc_mode;
+               }
+
                if (new_msr & MSR_VEC)
                        do_restore_altivec();
 
@@ -572,7 +578,7 @@ void notrace restore_math(struct pt_regs *regs)
 
                msr_check_and_clear(new_msr);
 
-               regs->msr |= new_msr;
+               regs->msr |= new_msr | fpexc_mode;
        }
 }
 #endif
index c2d737f..9d7fb4c 100644 (file)
@@ -34,7 +34,7 @@
 18     spu     oldstat                         sys_ni_syscall
 19     common  lseek                           sys_lseek                       compat_sys_lseek
 20     common  getpid                          sys_getpid
-21     nospu   mount                           sys_mount                       compat_sys_mount
+21     nospu   mount                           sys_mount
 22     32      umount                          sys_oldumount
 22     64      umount                          sys_ni_syscall
 22     spu     umount                          sys_ni_syscall
 142    common  _newselect                      sys_select                      compat_sys_select
 143    common  flock                           sys_flock
 144    common  msync                           sys_msync
-145    common  readv                           sys_readv                       compat_sys_readv
-146    common  writev                          sys_writev                      compat_sys_writev
+145    common  readv                           sys_readv
+146    common  writev                          sys_writev
 147    common  getsid                          sys_getsid
 148    common  fdatasync                       sys_fdatasync
 149    nospu   _sysctl                         sys_ni_syscall
 282    common  unshare                         sys_unshare
 283    common  splice                          sys_splice
 284    common  tee                             sys_tee
-285    common  vmsplice                        sys_vmsplice                    compat_sys_vmsplice
+285    common  vmsplice                        sys_vmsplice
 286    common  openat                          sys_openat                      compat_sys_openat
 287    common  mkdirat                         sys_mkdirat
 288    common  mknodat                         sys_mknodat
 348    common  syncfs                          sys_syncfs
 349    common  sendmmsg                        sys_sendmmsg                    compat_sys_sendmmsg
 350    common  setns                           sys_setns
-351    nospu   process_vm_readv                sys_process_vm_readv            compat_sys_process_vm_readv
-352    nospu   process_vm_writev               sys_process_vm_writev           compat_sys_process_vm_writev
+351    nospu   process_vm_readv                sys_process_vm_readv
+352    nospu   process_vm_writev               sys_process_vm_writev
 353    nospu   finit_module                    sys_finit_module
 354    nospu   kcmp                            sys_kcmp
 355    common  sched_setattr                   sys_sched_setattr
index 87ab115..e147bbd 100644 (file)
@@ -50,7 +50,7 @@ $(obj-vdso32): %.o: %.S FORCE
 
 # actual build commands
 quiet_cmd_vdso32ld = VDSO32L $@
-      cmd_vdso32ld = $(VDSOCC) $(c_flags) $(CC32FLAGS) -o $@ $(call cc-ldoption, -Wl$(comma)--orphan-handling=warn) -Wl,-T$(filter %.lds,$^) $(filter %.o,$^)
+      cmd_vdso32ld = $(VDSOCC) $(c_flags) $(CC32FLAGS) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^)
 quiet_cmd_vdso32as = VDSO32A $@
       cmd_vdso32as = $(VDSOCC) $(a_flags) $(CC32FLAGS) -c -o $@ $<
 
index 4c98546..5206c2e 100644 (file)
@@ -111,7 +111,6 @@ SECTIONS
                *(.note.GNU-stack)
                *(.data .data.* .gnu.linkonce.d.* .sdata*)
                *(.bss .sbss .dynbss .dynsbss)
-               *(.glink .iplt .plt .rela*)
        }
 }
 
index 38c317f..32ebb35 100644 (file)
@@ -34,7 +34,7 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE
 
 # actual build commands
 quiet_cmd_vdso64ld = VDSO64L $@
-      cmd_vdso64ld = $(CC) $(c_flags) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^) $(call cc-ldoption, -Wl$(comma)--orphan-handling=warn)
+      cmd_vdso64ld = $(CC) $(c_flags) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^)
 
 # install commands for the unstripped file
 quiet_cmd_vdso_install = INSTALL $@
index 4e3a8d4..256fb97 100644 (file)
@@ -30,7 +30,7 @@ SECTIONS
        . = ALIGN(16);
        .text           : {
                *(.text .stub .text.* .gnu.linkonce.t.* __ftr_alt_*)
-               *(.sfpr)
+               *(.sfpr .glink)
        }                                               :text
        PROVIDE(__etext = .);
        PROVIDE(_etext = .);
@@ -111,7 +111,6 @@ SECTIONS
                *(.branch_lt)
                *(.data .data.* .gnu.linkonce.d.* .sdata*)
                *(.bss .sbss .dynbss .dynsbss)
-               *(.glink .iplt .plt .rela*)
        }
 }
 
index 326e113..e0548b4 100644 (file)
@@ -360,8 +360,8 @@ SECTIONS
        PROVIDE32 (end = .);
 
        STABS_DEBUG
-
        DWARF_DEBUG
+       ELF_DETAILS
 
        DISCARDS
        /DISCARD/ : {
index d66a645..69a91b5 100644 (file)
@@ -39,7 +39,7 @@ obj-$(CONFIG_PPC_BOOK3S_64) += copyuser_power7.o copypage_power7.o \
                               memcpy_power7.o
 
 obj64-y        += copypage_64.o copyuser_64.o mem_64.o hweight_64.o \
-          memcpy_64.o memcpy_mcsafe_64.o
+          memcpy_64.o copy_mc_64.o
 
 ifndef CONFIG_PPC_QUEUED_SPINLOCKS
 obj64-$(CONFIG_SMP)    += locks.o
index ecd150d..ec5cd2d 100644 (file)
@@ -78,12 +78,10 @@ EXPORT_SYMBOL(__csum_partial)
 
 /*
  * Computes the checksum of a memory block at src, length len,
- * and adds in "sum" (32-bit), while copying the block to dst.
- * If an access exception occurs on src or dst, it stores -EFAULT
- * to *src_err or *dst_err respectively, and (for an error on
- * src) zeroes the rest of dst.
+ * and adds in 0xffffffff, while copying the block to dst.
+ * If an access exception occurs it returns zero.
  *
- * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err)
+ * csum_partial_copy_generic(src, dst, len)
  */
 #define CSUM_COPY_16_BYTES_WITHEX(n)   \
 8 ## n ## 0:                   \
@@ -108,14 +106,14 @@ EXPORT_SYMBOL(__csum_partial)
        adde    r12,r12,r10
 
 #define CSUM_COPY_16_BYTES_EXCODE(n)           \
-       EX_TABLE(8 ## n ## 0b, src_error);      \
-       EX_TABLE(8 ## n ## 1b, src_error);      \
-       EX_TABLE(8 ## n ## 2b, src_error);      \
-       EX_TABLE(8 ## n ## 3b, src_error);      \
-       EX_TABLE(8 ## n ## 4b, dst_error);      \
-       EX_TABLE(8 ## n ## 5b, dst_error);      \
-       EX_TABLE(8 ## n ## 6b, dst_error);      \
-       EX_TABLE(8 ## n ## 7b, dst_error);
+       EX_TABLE(8 ## n ## 0b, fault);  \
+       EX_TABLE(8 ## n ## 1b, fault);  \
+       EX_TABLE(8 ## n ## 2b, fault);  \
+       EX_TABLE(8 ## n ## 3b, fault);  \
+       EX_TABLE(8 ## n ## 4b, fault);  \
+       EX_TABLE(8 ## n ## 5b, fault);  \
+       EX_TABLE(8 ## n ## 6b, fault);  \
+       EX_TABLE(8 ## n ## 7b, fault);
 
        .text
        .stabs  "arch/powerpc/lib/",N_SO,0,0,0f
@@ -127,11 +125,8 @@ LG_CACHELINE_BYTES = L1_CACHE_SHIFT
 CACHELINE_MASK = (L1_CACHE_BYTES-1)
 
 _GLOBAL(csum_partial_copy_generic)
-       stwu    r1,-16(r1)
-       stw     r7,12(r1)
-       stw     r8,8(r1)
-
-       addic   r12,r6,0
+       li      r12,-1
+       addic   r0,r0,0                 /* clear carry */
        addi    r6,r4,-4
        neg     r0,r4
        addi    r4,r3,-4
@@ -246,34 +241,19 @@ _GLOBAL(csum_partial_copy_generic)
        rlwinm  r3,r3,8,0,31    /* odd destination address: rotate one byte */
        blr
 
-/* read fault */
-src_error:
-       lwz     r7,12(r1)
-       addi    r1,r1,16
-       cmpwi   cr0,r7,0
-       beqlr
-       li      r0,-EFAULT
-       stw     r0,0(r7)
-       blr
-/* write fault */
-dst_error:
-       lwz     r8,8(r1)
-       addi    r1,r1,16
-       cmpwi   cr0,r8,0
-       beqlr
-       li      r0,-EFAULT
-       stw     r0,0(r8)
+fault:
+       li      r3,0
        blr
 
-       EX_TABLE(70b, src_error);
-       EX_TABLE(71b, dst_error);
-       EX_TABLE(72b, src_error);
-       EX_TABLE(73b, dst_error);
-       EX_TABLE(54b, dst_error);
+       EX_TABLE(70b, fault);
+       EX_TABLE(71b, fault);
+       EX_TABLE(72b, fault);
+       EX_TABLE(73b, fault);
+       EX_TABLE(54b, fault);
 
 /*
  * this stuff handles faults in the cacheline loop and branches to either
- * src_error (if in read part) or dst_error (if in write part)
+ * fault (if in read part) or fault (if in write part)
  */
        CSUM_COPY_16_BYTES_EXCODE(0)
 #if L1_CACHE_BYTES >= 32
@@ -290,12 +270,12 @@ dst_error:
 #endif
 #endif
 
-       EX_TABLE(30b, src_error);
-       EX_TABLE(31b, dst_error);
-       EX_TABLE(40b, src_error);
-       EX_TABLE(41b, dst_error);
-       EX_TABLE(50b, src_error);
-       EX_TABLE(51b, dst_error);
+       EX_TABLE(30b, fault);
+       EX_TABLE(31b, fault);
+       EX_TABLE(40b, fault);
+       EX_TABLE(41b, fault);
+       EX_TABLE(50b, fault);
+       EX_TABLE(51b, fault);
 
 EXPORT_SYMBOL(csum_partial_copy_generic)
 
index 514978f..98ff51b 100644 (file)
@@ -182,34 +182,33 @@ EXPORT_SYMBOL(__csum_partial)
 
        .macro srcnr
 100:
-       EX_TABLE(100b,.Lsrc_error_nr)
+       EX_TABLE(100b,.Lerror_nr)
        .endm
 
        .macro source
 150:
-       EX_TABLE(150b,.Lsrc_error)
+       EX_TABLE(150b,.Lerror)
        .endm
 
        .macro dstnr
 200:
-       EX_TABLE(200b,.Ldest_error_nr)
+       EX_TABLE(200b,.Lerror_nr)
        .endm
 
        .macro dest
 250:
-       EX_TABLE(250b,.Ldest_error)
+       EX_TABLE(250b,.Lerror)
        .endm
 
 /*
  * Computes the checksum of a memory block at src, length len,
- * and adds in "sum" (32-bit), while copying the block to dst.
- * If an access exception occurs on src or dst, it stores -EFAULT
- * to *src_err or *dst_err respectively. The caller must take any action
- * required in this case (zeroing memory, recalculating partial checksum etc).
+ * and adds in 0xffffffff (32-bit), while copying the block to dst.
+ * If an access exception occurs, it returns 0.
  *
- * csum_partial_copy_generic(r3=src, r4=dst, r5=len, r6=sum, r7=src_err, r8=dst_err)
+ * csum_partial_copy_generic(r3=src, r4=dst, r5=len)
  */
 _GLOBAL(csum_partial_copy_generic)
+       li      r6,-1
        addic   r0,r6,0                 /* clear carry */
 
        srdi.   r6,r5,3                 /* less than 8 bytes? */
@@ -401,29 +400,15 @@ dstnr;    stb     r6,0(r4)
        srdi    r3,r3,32
        blr
 
-.Lsrc_error:
+.Lerror:
        ld      r14,STK_REG(R14)(r1)
        ld      r15,STK_REG(R15)(r1)
        ld      r16,STK_REG(R16)(r1)
        addi    r1,r1,STACKFRAMESIZE
-.Lsrc_error_nr:
-       cmpdi   0,r7,0
-       beqlr
-       li      r6,-EFAULT
-       stw     r6,0(r7)
+.Lerror_nr:
+       li      r3,0
        blr
 
-.Ldest_error:
-       ld      r14,STK_REG(R14)(r1)
-       ld      r15,STK_REG(R15)(r1)
-       ld      r16,STK_REG(R16)(r1)
-       addi    r1,r1,STACKFRAMESIZE
-.Ldest_error_nr:
-       cmpdi   0,r8,0
-       beqlr
-       li      r6,-EFAULT
-       stw     r6,0(r8)
-       blr
 EXPORT_SYMBOL(csum_partial_copy_generic)
 
 /*
index fabe4db..b895166 100644 (file)
 #include <linux/uaccess.h>
 
 __wsum csum_and_copy_from_user(const void __user *src, void *dst,
-                              int len, __wsum sum, int *err_ptr)
+                              int len)
 {
-       unsigned int csum;
+       __wsum csum;
 
        might_sleep();
-       allow_read_from_user(src, len);
-
-       *err_ptr = 0;
-
-       if (!len) {
-               csum = 0;
-               goto out;
-       }
 
-       if (unlikely((len < 0) || !access_ok(src, len))) {
-               *err_ptr = -EFAULT;
-               csum = (__force unsigned int)sum;
-               goto out;
-       }
+       if (unlikely(!access_ok(src, len)))
+               return 0;
 
-       csum = csum_partial_copy_generic((void __force *)src, dst,
-                                        len, sum, err_ptr, NULL);
-
-       if (unlikely(*err_ptr)) {
-               int missing = __copy_from_user(dst, src, len);
-
-               if (missing) {
-                       memset(dst + len - missing, 0, missing);
-                       *err_ptr = -EFAULT;
-               } else {
-                       *err_ptr = 0;
-               }
+       allow_read_from_user(src, len);
 
-               csum = csum_partial(dst, len, sum);
-       }
+       csum = csum_partial_copy_generic((void __force *)src, dst, len);
 
-out:
        prevent_read_from_user(src, len);
-       return (__force __wsum)csum;
+       return csum;
 }
 EXPORT_SYMBOL(csum_and_copy_from_user);
 
-__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
-                            __wsum sum, int *err_ptr)
+__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len)
 {
-       unsigned int csum;
+       __wsum csum;
 
        might_sleep();
-       allow_write_to_user(dst, len);
-
-       *err_ptr = 0;
-
-       if (!len) {
-               csum = 0;
-               goto out;
-       }
+       if (unlikely(!access_ok(dst, len)))
+               return 0;
 
-       if (unlikely((len < 0) || !access_ok(dst, len))) {
-               *err_ptr = -EFAULT;
-               csum = -1; /* invalid checksum */
-               goto out;
-       }
-
-       csum = csum_partial_copy_generic(src, (void __force *)dst,
-                                        len, sum, NULL, err_ptr);
-
-       if (unlikely(*err_ptr)) {
-               csum = csum_partial(src, len, sum);
+       allow_write_to_user(dst, len);
 
-               if (copy_to_user(dst, src, len)) {
-                       *err_ptr = -EFAULT;
-                       csum = -1; /* invalid checksum */
-               }
-       }
+       csum = csum_partial_copy_generic(src, (void __force *)dst, len);
 
-out:
        prevent_write_to_user(dst, len);
-       return (__force __wsum)csum;
+       return csum;
 }
 EXPORT_SYMBOL(csum_and_copy_to_user);
similarity index 98%
rename from arch/powerpc/lib/memcpy_mcsafe_64.S
rename to arch/powerpc/lib/copy_mc_64.S
index cb882d9..88d46c4 100644 (file)
@@ -50,7 +50,7 @@ err3; stb     r0,0(r3)
        blr
 
 
-_GLOBAL(memcpy_mcsafe)
+_GLOBAL(copy_mc_generic)
        mr      r7,r5
        cmpldi  r5,16
        blt     .Lshort_copy
@@ -239,4 +239,4 @@ err1;       stb     r0,0(r3)
 15:    li      r3,0
        blr
 
-EXPORT_SYMBOL_GPL(memcpy_mcsafe);
+EXPORT_SYMBOL_GPL(copy_mc_generic);
index 890a71c..c663e7b 100644 (file)
@@ -232,6 +232,8 @@ unsigned long htab_convert_pte_flags(unsigned long pteflags)
                rflags |= HPTE_R_I;
        else if ((pteflags & _PAGE_CACHE_CTL) == _PAGE_NON_IDEMPOTENT)
                rflags |= (HPTE_R_I | HPTE_R_G);
+       else if ((pteflags & _PAGE_CACHE_CTL) == _PAGE_SAO)
+               rflags |= (HPTE_R_W | HPTE_R_I | HPTE_R_M);
        else
                /*
                 * Add memory coherence if cache inhibited is not set
index 28c7849..d5f0c10 100644 (file)
@@ -734,21 +734,6 @@ void radix__mmu_cleanup_all(void)
        }
 }
 
-void radix__setup_initial_memory_limit(phys_addr_t first_memblock_base,
-                               phys_addr_t first_memblock_size)
-{
-       /*
-        * We don't currently support the first MEMBLOCK not mapping 0
-        * physical on those processors
-        */
-       BUG_ON(first_memblock_base != 0);
-
-       /*
-        * Radix mode is not limited by RMA / VRMA addressing.
-        */
-       ppc64_rma_size = ULONG_MAX;
-}
-
 #ifdef CONFIG_MEMORY_HOTPLUG
 static void free_pte_table(pte_t *pte_start, pmd_t *pmd)
 {
index 02e127f..8459056 100644 (file)
@@ -433,9 +433,16 @@ void __init mmu_early_init_devtree(void)
        if (!(mfmsr() & MSR_HV))
                early_check_vec5();
 
-       if (early_radix_enabled())
+       if (early_radix_enabled()) {
                radix__early_init_devtree();
-       else
+               /*
+                * We have finalized the translation we are going to use by now.
+                * Radix mode is not limited by RMA / VRMA addressing.
+                * Hence don't limit memblock allocations.
+                */
+               ppc64_rma_size = ULONG_MAX;
+               memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
+       } else
                hash__early_init_devtree();
 }
 #endif /* CONFIG_PPC_BOOK3S_64 */
index 16d09b3..e809cb5 100644 (file)
@@ -475,7 +475,6 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
                case BPF_JMP | BPF_JSET | BPF_K:
                case BPF_JMP | BPF_JSET | BPF_X:
                        true_cond = COND_NE;
-                       /* Fall through */
                cond_branch:
                        /* same targets, can avoid doing the test :) */
                        if (filter[i].jt == filter[i].jf) {
index 93d20e1..08643cb 100644 (file)
@@ -1557,9 +1557,16 @@ nocheck:
        ret = 0;
  out:
        if (has_branch_stack(event)) {
-               power_pmu_bhrb_enable(event);
-               cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
-                                       event->attr.branch_sample_type);
+               u64 bhrb_filter = -1;
+
+               if (ppmu->bhrb_filter_map)
+                       bhrb_filter = ppmu->bhrb_filter_map(
+                               event->attr.branch_sample_type);
+
+               if (bhrb_filter != -1) {
+                       cpuhw->bhrb_filter = bhrb_filter;
+                       power_pmu_bhrb_enable(event);
+               }
        }
 
        perf_pmu_enable(event->pmu);
@@ -1881,7 +1888,6 @@ static int power_pmu_event_init(struct perf_event *event)
        int n;
        int err;
        struct cpu_hw_events *cpuhw;
-       u64 bhrb_filter;
 
        if (!ppmu)
                return -ENOENT;
@@ -1987,7 +1993,10 @@ static int power_pmu_event_init(struct perf_event *event)
        err = power_check_constraints(cpuhw, events, cflags, n + 1);
 
        if (has_branch_stack(event)) {
-               bhrb_filter = ppmu->bhrb_filter_map(
+               u64 bhrb_filter = -1;
+
+               if (ppmu->bhrb_filter_map)
+                       bhrb_filter = ppmu->bhrb_filter_map(
                                        event->attr.branch_sample_type);
 
                if (bhrb_filter == -1) {
index a45d694..62d0b54 100644 (file)
@@ -1289,7 +1289,7 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem,
        header->misc = 0;
 
        if (cpu_has_feature(CPU_FTR_ARCH_31)) {
-               switch (IMC_TRACE_RECORD_VAL_HVPR(mem->val)) {
+               switch (IMC_TRACE_RECORD_VAL_HVPR(be64_to_cpu(READ_ONCE(mem->val)))) {
                case 0:/* when MSR HV and PR not set in the trace-record */
                        header->misc |= PERF_RECORD_MISC_GUEST_KERNEL;
                        break;
@@ -1297,7 +1297,7 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem,
                        header->misc |= PERF_RECORD_MISC_GUEST_USER;
                        break;
                case 2: /* MSR HV is 1 and PR is 0 */
-                       header->misc |= PERF_RECORD_MISC_HYPERVISOR;
+                       header->misc |= PERF_RECORD_MISC_KERNEL;
                        break;
                case 3: /* MSR HV is 1 and PR is 1 */
                        header->misc |= PERF_RECORD_MISC_USER;
index 87737ec..1dc9d3c 100644 (file)
@@ -36,7 +36,7 @@ config PPC_BOOK3S_6xx
        select PPC_HAVE_PMU_SUPPORT
        select PPC_HAVE_KUEP
        select PPC_HAVE_KUAP
-       select HAVE_ARCH_VMAP_STACK
+       select HAVE_ARCH_VMAP_STACK if !ADB_PMU
 
 config PPC_BOOK3S_601
        bool "PowerPC 601"
index 77513a8..345ab06 100644 (file)
@@ -1223,7 +1223,7 @@ static void __init pnv_probe_idle_states(void)
                return;
        }
 
-       if (pvr_version_is(PVR_POWER9))
+       if (cpu_has_feature(CPU_FTR_ARCH_300))
                pnv_power9_idle_init();
 
        for (i = 0; i < nr_pnv_idle_states; i++)
index f439f0d..a88a707 100644 (file)
@@ -822,7 +822,7 @@ free_stats:
        kfree(stats);
        return rc ? rc : seq_buf_used(&s);
 }
-DEVICE_ATTR_RO(perf_stats);
+DEVICE_ATTR_ADMIN_RO(perf_stats);
 
 static ssize_t flags_show(struct device *dev,
                          struct device_attribute *attr, char *buf)
index df18372..7766e12 100644 (file)
@@ -32,6 +32,7 @@ config RISCV
        select ARCH_WANT_FRAME_POINTERS
        select ARCH_WANT_HUGE_PMD_SHARE if 64BIT
        select CLONE_BACKWARDS
+       select CLINT_TIMER if !MMU
        select COMMON_CLK
        select EDAC_SUPPORT
        select GENERIC_ARCH_TOPOLOGY if SMP
index c1df56c..d2d0ff6 100644 (file)
                        #clock-cells = <1>;
                };
 
-               clint0: interrupt-controller@2000000 {
+               clint0: clint@2000000 {
+                       #interrupt-cells = <1>;
                        compatible = "riscv,clint0";
                        reg = <0x2000000 0xC000>;
-                       interrupts-extended = <&cpu0_intc 3>,  <&cpu1_intc 3>;
+                       interrupts-extended =  <&cpu0_intc 3 &cpu0_intc 7
+                                               &cpu1_intc 3 &cpu1_intc 7>;
                        clocks = <&sysctl K210_CLK_ACLK>;
                };
 
diff --git a/arch/riscv/include/asm/clint.h b/arch/riscv/include/asm/clint.h
new file mode 100644 (file)
index 0000000..0789fd3
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 Google, Inc
+ */
+
+#ifndef _ASM_RISCV_CLINT_H
+#define _ASM_RISCV_CLINT_H
+
+#include <linux/types.h>
+#include <asm/mmio.h>
+
+#ifdef CONFIG_RISCV_M_MODE
+/*
+ * This lives in the CLINT driver, but is accessed directly by timex.h to avoid
+ * any overhead when accessing the MMIO timer.
+ *
+ * The ISA defines mtime as a 64-bit memory-mapped register that increments at
+ * a constant frequency, but it doesn't define some other constraints we depend
+ * on (most notably ordering constraints, but also some simpler stuff like the
+ * memory layout).  Thus, this is called "clint_time_val" instead of something
+ * like "riscv_mtime", to signify that these non-ISA assumptions must hold.
+ */
+extern u64 __iomem *clint_time_val;
+#endif
+
+#endif
index ace8a6e..845002c 100644 (file)
@@ -66,6 +66,13 @@ do {                                                                 \
  * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here.
  */
 #define MCOUNT_INSN_SIZE 8
+
+#ifndef __ASSEMBLY__
+struct dyn_ftrace;
+int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
+#define ftrace_init_nop ftrace_init_nop
+#endif
+
 #endif
 
 #endif /* _ASM_RISCV_FTRACE_H */
index d95f7b2..5962f88 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <linux/random.h>
 #include <linux/version.h>
-#include <asm/timex.h>
 
 extern unsigned long __stack_chk_guard;
 
@@ -18,12 +17,9 @@ extern unsigned long __stack_chk_guard;
 static __always_inline void boot_init_stack_canary(void)
 {
        unsigned long canary;
-       unsigned long tsc;
 
        /* Try to get a semi random initial value. */
        get_random_bytes(&canary, sizeof(canary));
-       tsc = get_cycles();
-       canary += tsc + (tsc << BITS_PER_LONG/2);
        canary ^= LINUX_VERSION_CODE;
        canary &= CANARY_MASK;
 
index a3fb85d..ab10490 100644 (file)
 
 typedef unsigned long cycles_t;
 
+#ifdef CONFIG_RISCV_M_MODE
+
+#include <asm/clint.h>
+
+#ifdef CONFIG_64BIT
+static inline cycles_t get_cycles(void)
+{
+       return readq_relaxed(clint_time_val);
+}
+#else /* !CONFIG_64BIT */
+static inline u32 get_cycles(void)
+{
+       return readl_relaxed(((u32 *)clint_time_val));
+}
+#define get_cycles get_cycles
+
+static inline u32 get_cycles_hi(void)
+{
+       return readl_relaxed(((u32 *)clint_time_val) + 1);
+}
+#define get_cycles_hi get_cycles_hi
+#endif /* CONFIG_64BIT */
+
+/*
+ * Much like MIPS, we may not have a viable counter to use at an early point
+ * in the boot process. Unfortunately we don't have a fallback, so instead
+ * we just return 0.
+ */
+static inline unsigned long random_get_entropy(void)
+{
+       if (unlikely(clint_time_val == NULL))
+               return 0;
+       return get_cycles();
+}
+#define random_get_entropy()   random_get_entropy()
+
+#else /* CONFIG_RISCV_M_MODE */
+
 static inline cycles_t get_cycles(void)
 {
        return csr_read(CSR_TIME);
@@ -41,6 +79,8 @@ static inline u64 get_cycles64(void)
 }
 #endif /* CONFIG_64BIT */
 
+#endif /* !CONFIG_RISCV_M_MODE */
+
 #define ARCH_HAS_READ_CURRENT_TIMER
 static inline int read_current_timer(unsigned long *timer_val)
 {
index 2ff63d0..99e12fa 100644 (file)
@@ -97,6 +97,25 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
        return __ftrace_modify_call(rec->ip, addr, false);
 }
 
+
+/*
+ * This is called early on, and isn't wrapped by
+ * ftrace_arch_code_modify_{prepare,post_process}() and therefor doesn't hold
+ * text_mutex, which triggers a lockdep failure.  SMP isn't running so we could
+ * just directly poke the text, but it's simpler to just take the lock
+ * ourselves.
+ */
+int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
+{
+       int out;
+
+       ftrace_arch_code_modify_prepare();
+       out = ftrace_make_nop(mod, rec, MCOUNT_ADDR);
+       ftrace_arch_code_modify_post_process();
+
+       return out;
+}
+
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
        int ret = __ftrace_modify_call((unsigned long)&ftrace_call,
index 17ba190..e996e08 100644 (file)
@@ -250,7 +250,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
                                regs->a0 = -EINTR;
                                break;
                        }
-                       /* fallthrough */
+                       fallthrough;
                case -ERESTARTNOINTR:
                         regs->a0 = regs->orig_a0;
                        regs->epc -= 0x4;
index f3586e3..67db80e 100644 (file)
@@ -22,13 +22,11 @@ SECTIONS
        /* Beginning of code and text segment */
        . = LOAD_OFFSET;
        _start = .;
-       _stext = .;
        HEAD_TEXT_SECTION
        . = ALIGN(PAGE_SIZE);
 
        __init_begin = .;
        INIT_TEXT_SECTION(PAGE_SIZE)
-       INIT_DATA_SECTION(16)
        . = ALIGN(8);
        __soc_early_init_table : {
                __soc_early_init_table_start = .;
@@ -55,6 +53,7 @@ SECTIONS
        . = ALIGN(SECTION_ALIGN);
        .text : {
                _text = .;
+               _stext = .;
                TEXT_TEXT
                SCHED_TEXT
                CPUIDLE_TEXT
@@ -67,6 +66,8 @@ SECTIONS
                _etext = .;
        }
 
+       INIT_DATA_SECTION(16)
+
        /* Start of data section */
        _sdata = .;
        RO_DATA(SECTION_ALIGN)
@@ -97,6 +98,7 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        DISCARDS
 }
index 787c75f..f750e01 100644 (file)
@@ -226,12 +226,11 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
 
        ptep = &fixmap_pte[pte_index(addr)];
 
-       if (pgprot_val(prot)) {
+       if (pgprot_val(prot))
                set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
-       } else {
+       else
                pte_clear(&init_mm, addr, ptep);
-               local_flush_tlb_page(addr);
-       }
+       local_flush_tlb_page(addr);
 }
 
 static pte_t *__init get_pte_virt(phys_addr_t pa)
@@ -516,6 +515,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 #else
        dtb_early_va = (void *)dtb_pa;
 #endif
+       dtb_early_pa = dtb_pa;
 }
 
 static inline void setup_vm_final(void)
index bc5f220..579575f 100644 (file)
@@ -1020,7 +1020,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
                        emit_zext64(dst, ctx);
                        break;
                }
-               /* Fallthrough. */
+               fallthrough;
 
        case BPF_ALU | BPF_ADD | BPF_X:
        case BPF_ALU | BPF_SUB | BPF_X:
@@ -1079,7 +1079,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
                case 16:
                        emit(rv_slli(lo(rd), lo(rd), 16), ctx);
                        emit(rv_srli(lo(rd), lo(rd), 16), ctx);
-                       /* Fallthrough. */
+                       fallthrough;
                case 32:
                        if (!ctx->prog->aux->verifier_zext)
                                emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
index 3d86e12..0a38993 100644 (file)
@@ -30,7 +30,7 @@ config GENERIC_BUG_RELATIVE_POINTERS
        def_bool y
 
 config GENERIC_LOCKBREAK
-       def_bool y if PREEMPTTION
+       def_bool y if PREEMPTION
 
 config PGSTE
        def_bool y if KVM
@@ -185,6 +185,7 @@ config S390
        select OLD_SIGSUSPEND3
        select PCI_DOMAINS              if PCI
        select PCI_MSI                  if PCI
+       select PCI_MSI_ARCH_FALLBACKS   if PCI_MSI
        select SPARSE_IRQ
        select SYSCTL_EXCEPTION_TRACE
        select THREAD_INFO_IN_TASK
index 0cf9a82..7228aab 100644 (file)
@@ -626,6 +626,7 @@ CONFIG_NTFS_RW=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_INODE64=y
 CONFIG_HUGETLBFS=y
 CONFIG_CONFIGFS_FS=m
 CONFIG_ECRYPT_FS=m
@@ -807,6 +808,7 @@ CONFIG_DEBUG_NOTIFIERS=y
 CONFIG_BUG_ON_DATA_CORRUPTION=y
 CONFIG_DEBUG_CREDENTIALS=y
 CONFIG_RCU_TORTURE_TEST=m
+CONFIG_RCU_REF_SCALE_TEST=m
 CONFIG_RCU_CPU_STALL_TIMEOUT=300
 # CONFIG_RCU_TRACE is not set
 CONFIG_LATENCYTOP=y
@@ -818,6 +820,7 @@ CONFIG_PREEMPT_TRACER=y
 CONFIG_SCHED_TRACER=y
 CONFIG_FTRACE_SYSCALLS=y
 CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_BPF_KPROBE_OVERRIDE=y
 CONFIG_HIST_TRIGGERS=y
 CONFIG_S390_PTDUMP=y
 CONFIG_NOTIFIER_ERROR_INJECTION=m
@@ -829,6 +832,7 @@ CONFIG_FAIL_MAKE_REQUEST=y
 CONFIG_FAIL_IO_TIMEOUT=y
 CONFIG_FAIL_FUTEX=y
 CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAIL_FUNCTION=y
 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_LKDTM=m
 CONFIG_TEST_LIST_SORT=y
index 5df9759..fab03b7 100644 (file)
@@ -617,6 +617,7 @@ CONFIG_NTFS_RW=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_INODE64=y
 CONFIG_HUGETLBFS=y
 CONFIG_CONFIGFS_FS=m
 CONFIG_ECRYPT_FS=m
@@ -763,6 +764,7 @@ CONFIG_PANIC_ON_OOPS=y
 CONFIG_TEST_LOCKUP=m
 CONFIG_BUG_ON_DATA_CORRUPTION=y
 CONFIG_RCU_TORTURE_TEST=m
+CONFIG_RCU_REF_SCALE_TEST=m
 CONFIG_RCU_CPU_STALL_TIMEOUT=60
 CONFIG_LATENCYTOP=y
 CONFIG_BOOTTIME_TRACING=y
@@ -771,6 +773,7 @@ CONFIG_STACK_TRACER=y
 CONFIG_SCHED_TRACER=y
 CONFIG_FTRACE_SYSCALLS=y
 CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_BPF_KPROBE_OVERRIDE=y
 CONFIG_HIST_TRIGGERS=y
 CONFIG_S390_PTDUMP=y
 CONFIG_LKDTM=m
index 4091c50..8f67c55 100644 (file)
@@ -74,5 +74,6 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_PANIC_ON_OOPS=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_RCU_TRACE is not set
 # CONFIG_FTRACE is not set
 # CONFIG_RUNTIME_TESTING_MENU is not set
index 6d01c96..6813bfa 100644 (file)
@@ -39,13 +39,6 @@ csum_partial(const void *buff, int len, __wsum sum)
        return sum;
 }
 
-static inline __wsum
-csum_partial_copy_nocheck (const void *src, void *dst, int len, __wsum sum)
-{
-        memcpy(dst,src,len);
-       return csum_partial(dst, len, sum);
-}
-
 /*
  *      Fold a partial checksum without adding pseudo headers
  */
index 9547cd5..ea5b9c3 100644 (file)
@@ -63,8 +63,6 @@ typedef u16           compat_nlink_t;
 typedef u16            compat_ipc_pid_t;
 typedef u32            compat_caddr_t;
 typedef __kernel_fsid_t        compat_fsid_t;
-typedef s64            compat_s64;
-typedef u64            compat_u64;
 
 typedef struct {
        u32 mask;
index 50b4ce8..918f0ba 100644 (file)
@@ -29,7 +29,7 @@
        typedef typeof(pcp) pcp_op_T__;                                 \
        pcp_op_T__ old__, new__, prev__;                                \
        pcp_op_T__ *ptr__;                                              \
-       preempt_disable();                                              \
+       preempt_disable_notrace();                                      \
        ptr__ = raw_cpu_ptr(&(pcp));                                    \
        prev__ = *ptr__;                                                \
        do {                                                            \
@@ -37,7 +37,7 @@
                new__ = old__ op (val);                                 \
                prev__ = cmpxchg(ptr__, old__, new__);                  \
        } while (prev__ != old__);                                      \
-       preempt_enable();                                               \
+       preempt_enable_notrace();                                       \
        new__;                                                          \
 })
 
@@ -68,7 +68,7 @@
        typedef typeof(pcp) pcp_op_T__;                                 \
        pcp_op_T__ val__ = (val);                                       \
        pcp_op_T__ old__, *ptr__;                                       \
-       preempt_disable();                                              \
+       preempt_disable_notrace();                                      \
        ptr__ = raw_cpu_ptr(&(pcp));                            \
        if (__builtin_constant_p(val__) &&                              \
            ((szcast)val__ > -129) && ((szcast)val__ < 128)) {          \
@@ -84,7 +84,7 @@
                        : [val__] "d" (val__)                           \
                        : "cc");                                        \
        }                                                               \
-       preempt_enable();                                               \
+       preempt_enable_notrace();                                       \
 }
 
 #define this_cpu_add_4(pcp, val) arch_this_cpu_add(pcp, val, "laa", "asi", int)
        typedef typeof(pcp) pcp_op_T__;                                 \
        pcp_op_T__ val__ = (val);                                       \
        pcp_op_T__ old__, *ptr__;                                       \
-       preempt_disable();                                              \
+       preempt_disable_notrace();                                      \
        ptr__ = raw_cpu_ptr(&(pcp));                                    \
        asm volatile(                                                   \
                op "    %[old__],%[val__],%[ptr__]\n"                   \
                : [old__] "=d" (old__), [ptr__] "+Q" (*ptr__)           \
                : [val__] "d" (val__)                                   \
                : "cc");                                                \
-       preempt_enable();                                               \
+       preempt_enable_notrace();                                               \
        old__ + val__;                                                  \
 })
 
        typedef typeof(pcp) pcp_op_T__;                                 \
        pcp_op_T__ val__ = (val);                                       \
        pcp_op_T__ old__, *ptr__;                                       \
-       preempt_disable();                                              \
+       preempt_disable_notrace();                                      \
        ptr__ = raw_cpu_ptr(&(pcp));                                    \
        asm volatile(                                                   \
                op "    %[old__],%[val__],%[ptr__]\n"                   \
                : [old__] "=d" (old__), [ptr__] "+Q" (*ptr__)           \
                : [val__] "d" (val__)                                   \
                : "cc");                                                \
-       preempt_enable();                                               \
+       preempt_enable_notrace();                                       \
 }
 
 #define this_cpu_and_4(pcp, val)       arch_this_cpu_to_op(pcp, val, "lan")
        typedef typeof(pcp) pcp_op_T__;                                 \
        pcp_op_T__ ret__;                                               \
        pcp_op_T__ *ptr__;                                              \
-       preempt_disable();                                              \
+       preempt_disable_notrace();                                      \
        ptr__ = raw_cpu_ptr(&(pcp));                                    \
        ret__ = cmpxchg(ptr__, oval, nval);                             \
-       preempt_enable();                                               \
+       preempt_enable_notrace();                                       \
        ret__;                                                          \
 })
 
 ({                                                                     \
        typeof(pcp) *ptr__;                                             \
        typeof(pcp) ret__;                                              \
-       preempt_disable();                                              \
+       preempt_disable_notrace();                                      \
        ptr__ = raw_cpu_ptr(&(pcp));                                    \
        ret__ = xchg(ptr__, nval);                                      \
-       preempt_enable();                                               \
+       preempt_enable_notrace();                                       \
        ret__;                                                          \
 })
 
        typeof(pcp1) *p1__;                                             \
        typeof(pcp2) *p2__;                                             \
        int ret__;                                                      \
-       preempt_disable();                                              \
+       preempt_disable_notrace();                                      \
        p1__ = raw_cpu_ptr(&(pcp1));                                    \
        p2__ = raw_cpu_ptr(&(pcp2));                                    \
        ret__ = __cmpxchg_double(p1__, p2__, o1__, o2__, n1__, n2__);   \
-       preempt_enable();                                               \
+       preempt_enable_notrace();                                       \
        ret__;                                                          \
 })
 
index 7eb01a5..b55561c 100644 (file)
@@ -1260,26 +1260,44 @@ static inline pgd_t *pgd_offset_raw(pgd_t *pgd, unsigned long address)
 
 #define pgd_offset(mm, address) pgd_offset_raw(READ_ONCE((mm)->pgd), address)
 
-static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
+static inline p4d_t *p4d_offset_lockless(pgd_t *pgdp, pgd_t pgd, unsigned long address)
 {
-       if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R1)
-               return (p4d_t *) pgd_deref(*pgd) + p4d_index(address);
-       return (p4d_t *) pgd;
+       if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R1)
+               return (p4d_t *) pgd_deref(pgd) + p4d_index(address);
+       return (p4d_t *) pgdp;
 }
+#define p4d_offset_lockless p4d_offset_lockless
 
-static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
+static inline p4d_t *p4d_offset(pgd_t *pgdp, unsigned long address)
 {
-       if ((p4d_val(*p4d) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R2)
-               return (pud_t *) p4d_deref(*p4d) + pud_index(address);
-       return (pud_t *) p4d;
+       return p4d_offset_lockless(pgdp, *pgdp, address);
+}
+
+static inline pud_t *pud_offset_lockless(p4d_t *p4dp, p4d_t p4d, unsigned long address)
+{
+       if ((p4d_val(p4d) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R2)
+               return (pud_t *) p4d_deref(p4d) + pud_index(address);
+       return (pud_t *) p4dp;
+}
+#define pud_offset_lockless pud_offset_lockless
+
+static inline pud_t *pud_offset(p4d_t *p4dp, unsigned long address)
+{
+       return pud_offset_lockless(p4dp, *p4dp, address);
 }
 #define pud_offset pud_offset
 
-static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
+static inline pmd_t *pmd_offset_lockless(pud_t *pudp, pud_t pud, unsigned long address)
+{
+       if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R3)
+               return (pmd_t *) pud_deref(pud) + pmd_index(address);
+       return (pmd_t *) pudp;
+}
+#define pmd_offset_lockless pmd_offset_lockless
+
+static inline pmd_t *pmd_offset(pud_t *pudp, unsigned long address)
 {
-       if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R3)
-               return (pmd_t *) pud_deref(*pud) + pmd_index(address);
-       return (pmd_t *) pud;
+       return pmd_offset_lockless(pudp, *pudp, address);
 }
 #define pmd_offset pmd_offset
 
index faca269..a44ddc2 100644 (file)
@@ -26,6 +26,7 @@ void do_protection_exception(struct pt_regs *regs);
 void do_dat_exception(struct pt_regs *regs);
 void do_secure_storage_access(struct pt_regs *regs);
 void do_non_secure_storage_access(struct pt_regs *regs);
+void do_secure_storage_violation(struct pt_regs *regs);
 
 void addressing_exception(struct pt_regs *regs);
 void data_exception(struct pt_regs *regs);
index 88bb42c..f7f1e64 100644 (file)
@@ -33,21 +33,19 @@ void enabled_wait(void)
                PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
        clear_cpu_flag(CIF_NOHZ_DELAY);
 
-       trace_cpu_idle_rcuidle(1, smp_processor_id());
        local_irq_save(flags);
        /* Call the assembler magic in entry.S */
        psw_idle(idle, psw_mask);
        local_irq_restore(flags);
-       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 
        /* Account time spent with enabled wait psw loaded as idle time. */
-       write_seqcount_begin(&idle->seqcount);
+       raw_write_seqcount_begin(&idle->seqcount);
        idle_time = idle->clock_idle_exit - idle->clock_idle_enter;
        idle->clock_idle_enter = idle->clock_idle_exit = 0ULL;
        idle->idle_time += idle_time;
        idle->idle_count++;
        account_idle_time(cputime_to_nsecs(idle_time));
-       write_seqcount_end(&idle->seqcount);
+       raw_write_seqcount_end(&idle->seqcount);
 }
 NOKPROBE_SYMBOL(enabled_wait);
 
index d2a71d8..fc30e79 100644 (file)
@@ -228,6 +228,7 @@ NOKPROBE_SYMBOL(pop_kprobe);
 void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14];
+       ri->fp = NULL;
 
        /* Replace the return addr with trampoline addr */
        regs->gprs[14] = (unsigned long) &kretprobe_trampoline;
@@ -331,83 +332,7 @@ static void __used kretprobe_trampoline_holder(void)
  */
 static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address;
-       unsigned long trampoline_address;
-       kprobe_opcode_t *correct_ret_addr;
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because an multiple functions in the call path
-        * have a return probe installed on them, and/or more than one return
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       ri = NULL;
-       orig_ret_address = 0;
-       correct_ret_addr = NULL;
-       trampoline_address = (unsigned long) &kretprobe_trampoline;
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long) ri->ret_addr;
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
-       correct_ret_addr = ri->ret_addr;
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               orig_ret_address = (unsigned long) ri->ret_addr;
-
-               if (ri->rp && ri->rp->handler) {
-                       ri->ret_addr = correct_ret_addr;
-                       ri->rp->handler(ri, regs);
-               }
-
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       regs->psw.addr = orig_ret_address;
-
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
+       regs->psw.addr = __kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
        /*
         * By returning a non-zero value, we are telling
         * kprobe_handler() that we don't want the post_handler
index 2c27907..9a92638 100644 (file)
@@ -80,7 +80,7 @@ PGM_CHECK(do_dat_exception)           /* 3b */
 PGM_CHECK_DEFAULT                      /* 3c */
 PGM_CHECK(do_secure_storage_access)    /* 3d */
 PGM_CHECK(do_non_secure_storage_access)        /* 3e */
-PGM_CHECK_DEFAULT                      /* 3f */
+PGM_CHECK(do_secure_storage_violation) /* 3f */
 PGM_CHECK(monitor_event_exception)     /* 40 */
 PGM_CHECK_DEFAULT                      /* 41 */
 PGM_CHECK_DEFAULT                      /* 42 */
index e600f69..c2c1b4e 100644 (file)
@@ -619,7 +619,7 @@ static struct notifier_block kdump_mem_nb = {
 /*
  * Make sure that the area behind memory_end is protected
  */
-static void reserve_memory_end(void)
+static void __init reserve_memory_end(void)
 {
        if (memory_end_set)
                memblock_reserve(memory_end, ULONG_MAX);
@@ -628,7 +628,7 @@ static void reserve_memory_end(void)
 /*
  * Make sure that oldmem, where the dump is stored, is protected
  */
-static void reserve_oldmem(void)
+static void __init reserve_oldmem(void)
 {
 #ifdef CONFIG_CRASH_DUMP
        if (OLDMEM_BASE)
@@ -640,7 +640,7 @@ static void reserve_oldmem(void)
 /*
  * Make sure that oldmem, where the dump is stored, is protected
  */
-static void remove_oldmem(void)
+static void __init remove_oldmem(void)
 {
 #ifdef CONFIG_CRASH_DUMP
        if (OLDMEM_BASE)
index fc5419a..7f1266c 100644 (file)
@@ -19,7 +19,7 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
 
        unwind_for_each_frame(&state, task, regs, 0) {
                addr = unwind_get_return_address(&state);
-               if (!addr || !consume_entry(cookie, addr, false))
+               if (!addr || !consume_entry(cookie, addr))
                        break;
        }
 }
@@ -56,7 +56,7 @@ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
                        return -EINVAL;
 #endif
 
-               if (!consume_entry(cookie, addr, false))
+               if (!consume_entry(cookie, addr))
                        return -EINVAL;
        }
 
index 10456bc..1c3b481 100644 (file)
@@ -26,7 +26,7 @@
 16   32                lchown                  -                               sys_lchown16
 19   common    lseek                   sys_lseek                       compat_sys_lseek
 20   common    getpid                  sys_getpid                      sys_getpid
-21   common    mount                   sys_mount                       compat_sys_mount
+21   common    mount                   sys_mount                       sys_mount
 22   common    umount                  sys_oldumount                   sys_oldumount
 23   32                setuid                  -                               sys_setuid16
 24   32                getuid                  -                               sys_getuid16
 142  64                select                  sys_select                      -
 143  common    flock                   sys_flock                       sys_flock
 144  common    msync                   sys_msync                       sys_msync
-145  common    readv                   sys_readv                       compat_sys_readv
-146  common    writev                  sys_writev                      compat_sys_writev
+145  common    readv                   sys_readv                       sys_readv
+146  common    writev                  sys_writev                      sys_writev
 147  common    getsid                  sys_getsid                      sys_getsid
 148  common    fdatasync               sys_fdatasync                   sys_fdatasync
 149  common    _sysctl                 -                               -
 306  common    splice                  sys_splice                      sys_splice
 307  common    sync_file_range         sys_sync_file_range             compat_sys_s390_sync_file_range
 308  common    tee                     sys_tee                         sys_tee
-309  common    vmsplice                sys_vmsplice                    compat_sys_vmsplice
+309  common    vmsplice                sys_vmsplice                    sys_vmsplice
 310  common    move_pages              sys_move_pages                  compat_sys_move_pages
 311  common    getcpu                  sys_getcpu                      sys_getcpu
 312  common    epoll_pwait             sys_epoll_pwait                 compat_sys_epoll_pwait
 337  common    clock_adjtime           sys_clock_adjtime               sys_clock_adjtime32
 338  common    syncfs                  sys_syncfs                      sys_syncfs
 339  common    setns                   sys_setns                       sys_setns
-340  common    process_vm_readv        sys_process_vm_readv            compat_sys_process_vm_readv
-341  common    process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
+340  common    process_vm_readv        sys_process_vm_readv            sys_process_vm_readv
+341  common    process_vm_writev       sys_process_vm_writev           sys_process_vm_writev
 342  common    s390_runtime_instr      sys_s390_runtime_instr          sys_s390_runtime_instr
 343  common    kcmp                    sys_kcmp                        sys_kcmp
 344  common    finit_module            sys_finit_module                sys_finit_module
index 3769549..177ccfb 100644 (file)
@@ -181,6 +181,7 @@ SECTIONS
        /* Debugging sections.  */
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        /* Sections to be discarded */
        DISCARDS
index 4c8c063..996884d 100644 (file)
@@ -859,6 +859,21 @@ void do_non_secure_storage_access(struct pt_regs *regs)
 }
 NOKPROBE_SYMBOL(do_non_secure_storage_access);
 
+void do_secure_storage_violation(struct pt_regs *regs)
+{
+       /*
+        * Either KVM messed up the secure guest mapping or the same
+        * page is mapped into multiple secure guests.
+        *
+        * This exception is only triggered when a guest 2 is running
+        * and can therefore never occur in kernel context.
+        */
+       printk_ratelimited(KERN_WARNING
+                          "Secure storage violation in task: %s, pid %d\n",
+                          current->comm, current->pid);
+       send_sig(SIGSEGV, current, 0);
+}
+
 #else
 void do_secure_storage_access(struct pt_regs *regs)
 {
@@ -869,4 +884,9 @@ void do_non_secure_storage_access(struct pt_regs *regs)
 {
        default_trap_handler(regs);
 }
+
+void do_secure_storage_violation(struct pt_regs *regs)
+{
+       default_trap_handler(regs);
+}
 #endif
index 1aed1a4..eddf71c 100644 (file)
@@ -402,6 +402,7 @@ static int modify_p4d_table(pgd_t *pgd, unsigned long addr, unsigned long end,
                        pud = vmem_crst_alloc(_REGION3_ENTRY_EMPTY);
                        if (!pud)
                                goto out;
+                       p4d_populate(&init_mm, p4d, pud);
                }
                ret = modify_pud_table(p4d, addr, next, add, direct);
                if (ret)
index 4b62d6b..1804230 100644 (file)
@@ -668,6 +668,10 @@ EXPORT_SYMBOL_GPL(zpci_enable_device);
 int zpci_disable_device(struct zpci_dev *zdev)
 {
        zpci_dma_exit_device(zdev);
+       /*
+        * The zPCI function may already be disabled by the platform, this is
+        * detected in clp_disable_fh() which becomes a no-op.
+        */
        return clp_disable_fh(zdev);
 }
 EXPORT_SYMBOL_GPL(zpci_disable_device);
index 9a3a291..d9ae745 100644 (file)
@@ -143,6 +143,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
                        zpci_remove_device(zdev);
                }
 
+               zdev->fh = ccdf->fh;
+               zpci_disable_device(zdev);
                zdev->state = ZPCI_FN_STATE_STANDBY;
                if (!clp_get_state(ccdf->fid, &state) &&
                    state == ZPCI_FN_STATE_RESERVED) {
index f3dc3f2..143747c 100644 (file)
@@ -246,7 +246,7 @@ static int __init sh_early_platform_driver_probe_id(char *class_str,
                case EARLY_PLATFORM_ID_ERROR:
                        pr_warn("%s: unable to parse %s parameter\n",
                                class_str, epdrv->pdrv->driver.name);
-                       /* fall-through */
+                       fallthrough;
                case EARLY_PLATFORM_ID_UNSET:
                        match = NULL;
                        break;
index 91571a4..1a391e3 100644 (file)
@@ -30,10 +30,9 @@ asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
  * better 64-bit) boundary
  */
 
-asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
-                                           int len, __wsum sum,
-                                           int *src_err_ptr, int *dst_err_ptr);
+asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
 
+#define _HAVE_ARCH_CSUM_AND_COPY
 /*
  *     Note: when you get a NULL pointer exception here this means someone
  *     passed in an incorrect kernel address to one of these functions.
@@ -42,23 +41,18 @@ asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
  *     access_ok().
  */
 static inline
-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                int len, __wsum sum)
+__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
 {
-       return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL);
+       return csum_partial_copy_generic(src, dst, len);
 }
 
 #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
 static inline
-__wsum csum_and_copy_from_user(const void __user *src, void *dst,
-                                  int len, __wsum sum, int *err_ptr)
+__wsum csum_and_copy_from_user(const void __user *src, void *dst, int len)
 {
-       if (access_ok(src, len))
-               return csum_partial_copy_generic((__force const void *)src, dst,
-                                       len, sum, err_ptr, NULL);
-       if (len)
-               *err_ptr = -EFAULT;
-       return sum;
+       if (!access_ok(src, len))
+               return 0;
+       return csum_partial_copy_generic((__force const void *)src, dst, len);
 }
 
 /*
@@ -199,16 +193,10 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
 #define HAVE_CSUM_COPY_USER
 static inline __wsum csum_and_copy_to_user(const void *src,
                                           void __user *dst,
-                                          int len, __wsum sum,
-                                          int *err_ptr)
+                                          int len)
 {
-       if (access_ok(dst, len))
-               return csum_partial_copy_generic((__force const void *)src,
-                                               dst, len, sum, NULL, err_ptr);
-
-       if (len)
-               *err_ptr = -EFAULT;
-
-       return (__force __wsum)-1; /* invalid checksum */
+       if (!access_ok(dst, len))
+               return 0;
+       return csum_partial_copy_generic((__force const void *)src, dst, len);
 }
 #endif /* __ASM_SH_CHECKSUM_H */
index 1a0d7cf..100bf24 100644 (file)
@@ -8,7 +8,6 @@
 
 #ifdef CONFIG_SMP
 
-#include <linux/spinlock.h>
 #include <linux/atomic.h>
 #include <asm/current.h>
 #include <asm/percpu.h>
index 08e1af6..34e25a4 100644 (file)
@@ -486,7 +486,7 @@ static void print_sh_insn(u32 memaddr, u16 insn)
                                        pr_cont("xd%d", rn & ~1);
                                        break;
                                }
-                               /* else, fall through */
+                               fallthrough;
                        case D_REG_N:
                                pr_cont("dr%d", rn);
                                break;
@@ -495,7 +495,7 @@ static void print_sh_insn(u32 memaddr, u16 insn)
                                        pr_cont("xd%d", rm & ~1);
                                        break;
                                }
-                               /* else, fall through */
+                               fallthrough;
                        case D_REG_M:
                                pr_cont("dr%d", rm);
                                break;
index ad96310..91ab260 100644 (file)
@@ -370,7 +370,6 @@ syscall_trace_entry:
         nop
        cmp/eq  #-1, r0
        bt      syscall_exit
-       mov.l   r0, @(OFF_R0,r15)       ! Save return value
        !                       Reload R0-R4 from kernel stack, where the
        !                       parent may have modified them using
        !                       ptrace(POKEUSR).  (Note that R0-R2 are
index 0d5f3c9..e4147ef 100644 (file)
@@ -266,7 +266,7 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
                ptr = &remcomInBuffer[1];
                if (kgdb_hex2long(&ptr, &addr))
                        linux_regs->pc = addr;
-               /* fallthrough */
+               fallthrough;
        case 'D':
        case 'k':
                atomic_set(&kgdb_cpu_doing_single_step, -1);
index 318296f..756100b 100644 (file)
@@ -204,6 +204,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                      struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *) regs->pr;
+       ri->fp = NULL;
 
        /* Replace the return addr with trampoline addr */
        regs->pr = (unsigned long)kretprobe_trampoline;
@@ -302,62 +303,9 @@ static void __used kretprobe_trampoline_holder(void)
  */
 int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+       regs->pc = __kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
 
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because an multiple functions in the call path
-        * have a return probe installed on them, and/or more then one return
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               if (ri->rp && ri->rp->handler) {
-                       __this_cpu_write(current_kprobe, &ri->rp->kp);
-                       ri->rp->handler(ri, regs);
-                       __this_cpu_write(current_kprobe, NULL);
-               }
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
-       regs->pc = orig_ret_address;
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
-
-       return orig_ret_address;
+       return 1;
 }
 
 static int __kprobes post_kprobe_handler(struct pt_regs *regs)
index b05bf92..5281685 100644 (file)
@@ -455,16 +455,11 @@ long arch_ptrace(struct task_struct *child, long request,
 
 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
 {
-       long ret = 0;
-
        if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-           tracehook_report_syscall_entry(regs))
-               /*
-                * Tracing decided this syscall should not happen.
-                * We'll return a bogus call number to get an ENOSYS
-                * error, but leave the original number in regs->regs[0].
-                */
-               ret = -1L;
+           tracehook_report_syscall_entry(regs)) {
+               regs->regs[0] = -ENOSYS;
+               return -1;
+       }
 
        if (secure_computing() == -1)
                return -1;
@@ -475,7 +470,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
        audit_syscall_entry(regs->regs[3], regs->regs[4], regs->regs[5],
                            regs->regs[6], regs->regs[7]);
 
-       return ret ?: regs->regs[0];
+       return 0;
 }
 
 asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
index a0fbb84..4fe3f00 100644 (file)
@@ -418,7 +418,7 @@ handle_syscall_restart(unsigned long save_r0, struct pt_regs *regs,
                case -ERESTARTSYS:
                        if (!(sa->sa_flags & SA_RESTART))
                                goto no_system_call_restart;
-               /* fallthrough */
+                       fallthrough;
                case -ERESTARTNOINTR:
                        regs->regs[0] = save_r0;
                        regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
index bde7a6c..3161b9c 100644 (file)
@@ -76,6 +76,7 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        DISCARDS
 }
index 97b5c2d..3e07074 100644 (file)
@@ -173,47 +173,27 @@ ENTRY(csum_partial)
         mov    r6, r0
 
 /*
-unsigned int csum_partial_copy_generic (const char *src, char *dst, int len, 
-                                       int sum, int *src_err_ptr, int *dst_err_ptr)
+unsigned int csum_partial_copy_generic (const char *src, char *dst, int len)
  */ 
 
 /*
- * Copy from ds while checksumming, otherwise like csum_partial
- *
- * The macros SRC and DST specify the type of access for the instruction.
- * thus we can call a custom exception handler for all access types.
- *
- * FIXME: could someone double-check whether I haven't mixed up some SRC and
- *       DST definitions? It's damn hard to trigger all cases.  I hope I got
- *       them all but there's no guarantee.
+ * Copy from ds while checksumming, otherwise like csum_partial with initial
+ * sum being ~0U
  */
 
-#define SRC(...)                       \
+#define EXC(...)                       \
        9999: __VA_ARGS__ ;             \
        .section __ex_table, "a";       \
        .long 9999b, 6001f      ;       \
        .previous
 
-#define DST(...)                       \
-       9999: __VA_ARGS__ ;             \
-       .section __ex_table, "a";       \
-       .long 9999b, 6002f      ;       \
-       .previous
-
 !
 ! r4:  const char *SRC
 ! r5:  char *DST
 ! r6:  int LEN
-! r7:  int SUM
-!
-! on stack:
-! int *SRC_ERR_PTR
-! int *DST_ERR_PTR
 !
 ENTRY(csum_partial_copy_generic)
-       mov.l   r5,@-r15
-       mov.l   r6,@-r15
-
+       mov     #-1,r7
        mov     #3,r0           ! Check src and dest are equally aligned
        mov     r4,r1
        and     r0,r1
@@ -243,11 +223,11 @@ ENTRY(csum_partial_copy_generic)
        clrt
        .align  2
 5:
-SRC(   mov.b   @r4+,r1         )
-SRC(   mov.b   @r4+,r0         )
+EXC(   mov.b   @r4+,r1         )
+EXC(   mov.b   @r4+,r0         )
        extu.b  r1,r1
-DST(   mov.b   r1,@r5          )
-DST(   mov.b   r0,@(1,r5)      )
+EXC(   mov.b   r1,@r5          )
+EXC(   mov.b   r0,@(1,r5)      )
        extu.b  r0,r0
        add     #2,r5
 
@@ -276,8 +256,8 @@ DST(        mov.b   r0,@(1,r5)      )
        ! Handle first two bytes as a special case
        .align  2
 1:     
-SRC(   mov.w   @r4+,r0         )
-DST(   mov.w   r0,@r5          )
+EXC(   mov.w   @r4+,r0         )
+EXC(   mov.w   r0,@r5          )
        add     #2,r5
        extu.w  r0,r0
        addc    r0,r7
@@ -292,32 +272,32 @@ DST(      mov.w   r0,@r5          )
         clrt
        .align  2
 1:     
-SRC(   mov.l   @r4+,r0         )
-SRC(   mov.l   @r4+,r1         )
+EXC(   mov.l   @r4+,r0         )
+EXC(   mov.l   @r4+,r1         )
        addc    r0,r7
-DST(   mov.l   r0,@r5          )
-DST(   mov.l   r1,@(4,r5)      )
+EXC(   mov.l   r0,@r5          )
+EXC(   mov.l   r1,@(4,r5)      )
        addc    r1,r7
 
-SRC(   mov.l   @r4+,r0         )
-SRC(   mov.l   @r4+,r1         )
+EXC(   mov.l   @r4+,r0         )
+EXC(   mov.l   @r4+,r1         )
        addc    r0,r7
-DST(   mov.l   r0,@(8,r5)      )
-DST(   mov.l   r1,@(12,r5)     )
+EXC(   mov.l   r0,@(8,r5)      )
+EXC(   mov.l   r1,@(12,r5)     )
        addc    r1,r7
 
-SRC(   mov.l   @r4+,r0         )
-SRC(   mov.l   @r4+,r1         )
+EXC(   mov.l   @r4+,r0         )
+EXC(   mov.l   @r4+,r1         )
        addc    r0,r7
-DST(   mov.l   r0,@(16,r5)     )
-DST(   mov.l   r1,@(20,r5)     )
+EXC(   mov.l   r0,@(16,r5)     )
+EXC(   mov.l   r1,@(20,r5)     )
        addc    r1,r7
 
-SRC(   mov.l   @r4+,r0         )
-SRC(   mov.l   @r4+,r1         )
+EXC(   mov.l   @r4+,r0         )
+EXC(   mov.l   @r4+,r1         )
        addc    r0,r7
-DST(   mov.l   r0,@(24,r5)     )
-DST(   mov.l   r1,@(28,r5)     )
+EXC(   mov.l   r0,@(24,r5)     )
+EXC(   mov.l   r1,@(28,r5)     )
        addc    r1,r7
        add     #32,r5
        movt    r0
@@ -335,9 +315,9 @@ DST(        mov.l   r1,@(28,r5)     )
         clrt
        shlr2   r6
 3:     
-SRC(   mov.l   @r4+,r0 )
+EXC(   mov.l   @r4+,r0 )
        addc    r0,r7
-DST(   mov.l   r0,@r5  )
+EXC(   mov.l   r0,@r5  )
        add     #4,r5
        movt    r0
        dt      r6
@@ -353,8 +333,8 @@ DST(        mov.l   r0,@r5  )
        mov     #2,r1
        cmp/hs  r1,r6
        bf      5f
-SRC(   mov.w   @r4+,r0 )
-DST(   mov.w   r0,@r5  )
+EXC(   mov.w   @r4+,r0 )
+EXC(   mov.w   r0,@r5  )
        extu.w  r0,r0
        add     #2,r5
        cmp/eq  r1,r6
@@ -363,8 +343,8 @@ DST(        mov.w   r0,@r5  )
        shll16  r0
        addc    r0,r7
 5:     
-SRC(   mov.b   @r4+,r0 )
-DST(   mov.b   r0,@r5  )
+EXC(   mov.b   @r4+,r0 )
+EXC(   mov.b   r0,@r5  )
        extu.b  r0,r0
 #ifndef        __LITTLE_ENDIAN__
        shll8   r0
@@ -373,42 +353,13 @@ DST(      mov.b   r0,@r5  )
        mov     #0,r0
        addc    r0,r7
 7:
-5000:
 
 # Exception handler:
 .section .fixup, "ax"                                                  
 
 6001:
-       mov.l   @(8,r15),r0                     ! src_err_ptr
-       mov     #-EFAULT,r1
-       mov.l   r1,@r0
-
-       ! zero the complete destination - computing the rest
-       ! is too much work 
-       mov.l   @(4,r15),r5             ! dst
-       mov.l   @r15,r6                 ! len
-       mov     #0,r7
-1:     mov.b   r7,@r5
-       dt      r6
-       bf/s    1b
-        add    #1,r5
-       mov.l   8000f,r0
-       jmp     @r0
-        nop
-       .align  2
-8000:  .long   5000b
-
-6002:
-       mov.l   @(12,r15),r0                    ! dst_err_ptr
-       mov     #-EFAULT,r1
-       mov.l   r1,@r0
-       mov.l   8001f,r0
-       jmp     @r0
-        nop
-       .align  2
-8001:  .long   5000b
-
+       rts
+        mov    #0,r0
 .previous
-       add     #8,r15
        rts
         mov    r7,r0
index efeff2c..91ed110 100644 (file)
@@ -43,6 +43,7 @@ config SPARC
        select GENERIC_STRNLEN_USER
        select MODULES_USE_ELF_RELA
        select PCI_SYSCALL if PCI
+       select PCI_MSI_ARCH_FALLBACKS if PCI_MSI
        select ODD_RT_SIGACTION
        select OLD_SIGSUSPEND
        select CPU_NO_EFFICIENT_FFS
index a6256cb..f2ac133 100644 (file)
@@ -1,7 +1,9 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #ifndef ___ASM_SPARC_CHECKSUM_H
 #define ___ASM_SPARC_CHECKSUM_H
+#define _HAVE_ARCH_CSUM_AND_COPY
 #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
+#define HAVE_CSUM_COPY_USER
 #if defined(__sparc__) && defined(__arch64__)
 #include <asm/checksum_64.h>
 #else
index 479a0b8..ce11e0a 100644 (file)
@@ -42,7 +42,7 @@ __wsum csum_partial(const void *buff, int len, __wsum sum);
 unsigned int __csum_partial_copy_sparc_generic (const unsigned char *, unsigned char *);
 
 static inline __wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
+csum_partial_copy_nocheck(const void *src, void *dst, int len)
 {
        register unsigned int ret asm("o0") = (unsigned int)src;
        register char *d asm("o1") = dst;
@@ -50,9 +50,9 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
 
        __asm__ __volatile__ (
                "call __csum_partial_copy_sparc_generic\n\t"
-               " mov %6, %%g7\n"
+               " mov -1, %%g7\n"
        : "=&r" (ret), "=&r" (d), "=&r" (l)
-       : "0" (ret), "1" (d), "2" (l), "r" (sum)
+       : "0" (ret), "1" (d), "2" (l)
        : "o2", "o3", "o4", "o5", "o7",
          "g2", "g3", "g4", "g5", "g7",
          "memory", "cc");
@@ -60,65 +60,19 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
 }
 
 static inline __wsum
-csum_and_copy_from_user(const void __user *src, void *dst, int len,
-                           __wsum sum, int *err)
-  {
-       register unsigned long ret asm("o0") = (unsigned long)src;
-       register char *d asm("o1") = dst;
-       register int l asm("g1") = len;
-       register __wsum s asm("g7") = sum;
-
-       if (unlikely(!access_ok(src, len))) {
-               if (len)
-                       *err = -EFAULT;
-               return sum;
-       }
-
-       __asm__ __volatile__ (
-       ".section __ex_table,#alloc\n\t"
-       ".align 4\n\t"
-       ".word 1f,2\n\t"
-       ".previous\n"
-       "1:\n\t"
-       "call __csum_partial_copy_sparc_generic\n\t"
-       " st %8, [%%sp + 64]\n"
-       : "=&r" (ret), "=&r" (d), "=&r" (l), "=&r" (s)
-       : "0" (ret), "1" (d), "2" (l), "3" (s), "r" (err)
-       : "o2", "o3", "o4", "o5", "o7", "g2", "g3", "g4", "g5",
-         "cc", "memory");
-       return (__force __wsum)ret;
+csum_and_copy_from_user(const void __user *src, void *dst, int len)
+{
+       if (unlikely(!access_ok(src, len)))
+               return 0;
+       return csum_partial_copy_nocheck((__force void *)src, dst, len);
 }
 
-#define HAVE_CSUM_COPY_USER
-
 static inline __wsum
-csum_and_copy_to_user(const void *src, void __user *dst, int len,
-                         __wsum sum, int *err)
+csum_and_copy_to_user(const void *src, void __user *dst, int len)
 {
-       if (!access_ok(dst, len)) {
-               *err = -EFAULT;
-               return sum;
-       } else {
-               register unsigned long ret asm("o0") = (unsigned long)src;
-               register char __user *d asm("o1") = dst;
-               register int l asm("g1") = len;
-               register __wsum s asm("g7") = sum;
-
-               __asm__ __volatile__ (
-               ".section __ex_table,#alloc\n\t"
-               ".align 4\n\t"
-               ".word 1f,1\n\t"
-               ".previous\n"
-               "1:\n\t"
-               "call __csum_partial_copy_sparc_generic\n\t"
-               " st %8, [%%sp + 64]\n"
-               : "=&r" (ret), "=&r" (d), "=&r" (l), "=&r" (s)
-               : "0" (ret), "1" (d), "2" (l), "3" (s), "r" (err)
-               : "o2", "o3", "o4", "o5", "o7",
-                 "g2", "g3", "g4", "g5",
-                 "cc", "memory");
-               return (__force __wsum)ret;
-       }
+       if (!access_ok(dst, len))
+               return 0;
+       return csum_partial_copy_nocheck(src, (__force void *)dst, len);
 }
 
 /* ihl is always 5 or greater, almost always is 5, and iph is word aligned
index 0fa4433..d6b5946 100644 (file)
@@ -38,42 +38,9 @@ __wsum csum_partial(const void * buff, int len, __wsum sum);
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                int len, __wsum sum);
-
-long __csum_partial_copy_from_user(const void __user *src,
-                                  void *dst, int len,
-                                  __wsum sum);
-
-static inline __wsum
-csum_and_copy_from_user(const void __user *src,
-                           void *dst, int len,
-                           __wsum sum, int *err)
-{
-       long ret = __csum_partial_copy_from_user(src, dst, len, sum);
-       if (ret < 0)
-               *err = -EFAULT;
-       return (__force __wsum) ret;
-}
-
-/*
- *     Copy and checksum to user
- */
-#define HAVE_CSUM_COPY_USER
-long __csum_partial_copy_to_user(const void *src,
-                                void __user *dst, int len,
-                                __wsum sum);
-
-static inline __wsum
-csum_and_copy_to_user(const void *src,
-                     void __user *dst, int len,
-                     __wsum sum, int *err)
-{
-       long ret = __csum_partial_copy_to_user(src, dst, len, sum);
-       if (ret < 0)
-               *err = -EFAULT;
-       return (__force __wsum) ret;
-}
+__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
+__wsum csum_and_copy_from_user(const void __user *src, void *dst, int len);
+__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len);
 
 /* ihl is always 5 or greater, almost always is 5, and iph is word aligned
  * the majority of the time.
index 40a267b..b85842c 100644 (file)
@@ -21,8 +21,7 @@ typedef s16           compat_nlink_t;
 typedef u16            compat_ipc_pid_t;
 typedef u32            compat_caddr_t;
 typedef __kernel_fsid_t        compat_fsid_t;
-typedef s64            compat_s64;
-typedef u64            compat_u64;
+
 struct compat_stat {
        compat_dev_t    st_dev;
        compat_ino_t    st_ino;
index 4843f48..774a82b 100644 (file)
@@ -87,7 +87,6 @@ void auxio_set_lte(int on)
                __auxio_sbus_set_lte(on);
                break;
        case AUXIO_TYPE_EBUS:
-               /* FALL-THROUGH */
        default:
                break;
        }
index bfae98a..23f8838 100644 (file)
@@ -55,7 +55,7 @@ static int clock_board_calc_nslots(struct clock_board *p)
                        else
                                return 5;
                }
-               /* Fallthrough */
+               fallthrough;
        default:
                return 4;
        }
index 7580775..58ad3f7 100644 (file)
@@ -122,7 +122,7 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
                        linux_regs->pc = addr;
                        linux_regs->npc = addr + 4;
                }
-               /* fall through */
+               fallthrough;
 
        case 'D':
        case 'k':
index 5d6c2d2..177746a 100644 (file)
@@ -148,7 +148,7 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
                        linux_regs->tpc = addr;
                        linux_regs->tnpc = addr + 4;
                }
-               /* fall through */
+               fallthrough;
 
        case 'D':
        case 'k':
index dfbca24..217c21a 100644 (file)
@@ -453,6 +453,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                      struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *)(regs->u_regs[UREG_RETPC] + 8);
+       ri->fp = NULL;
 
        /* Replace the return addr with trampoline addr */
        regs->u_regs[UREG_RETPC] =
@@ -465,58 +466,12 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 static int __kprobes trampoline_probe_handler(struct kprobe *p,
                                              struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
+       unsigned long orig_ret_address = 0;
 
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because an multiple functions in the call path
-        * have a return probe installed on them, and/or more than one return
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               if (ri->rp && ri->rp->handler)
-                       ri->rp->handler(ri, regs);
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
+       orig_ret_address = __kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
        regs->tpc = orig_ret_address;
        regs->tnpc = orig_ret_address + 4;
 
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
        /*
         * By returning a non-zero value, we are telling
         * kprobe_handler() that we don't want the post_handler
index c0886b4..2a12c86 100644 (file)
@@ -359,7 +359,7 @@ int __init pcr_arch_init(void)
                 * counter overflow interrupt so we can't make use of
                 * their hardware currently.
                 */
-               /* fallthrough */
+               fallthrough;
        default:
                err = -ENODEV;
                goto out_unregister;
index da89022..3df960c 100644 (file)
@@ -224,7 +224,7 @@ void __init of_console_init(void)
 
                case PROMDEV_TTYB:
                        skip = 1;
-                       /* FALLTHRU */
+                       fallthrough;
 
                case PROMDEV_TTYA:
                        type = "serial";
index e2c6f0a..e9695a0 100644 (file)
@@ -646,7 +646,7 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs
        case ERESTARTSYS:
                if (!(sa->sa_flags & SA_RESTART))
                        goto no_system_call_restart;
-               /* fallthrough */
+               fallthrough;
        case ERESTARTNOINTR:
                regs->u_regs[UREG_I0] = orig_i0;
                regs->tpc -= 4;
@@ -686,7 +686,7 @@ void do_signal32(struct pt_regs * regs)
                                regs->tpc -= 4;
                                regs->tnpc -= 4;
                                pt_regs_clear_syscall(regs);
-                               /* fall through */
+                               fallthrough;
                        case ERESTART_RESTARTBLOCK:
                                regs->u_regs[UREG_G1] = __NR_restart_syscall;
                                regs->tpc -= 4;
index f1f8c8e..d0e0025 100644 (file)
@@ -440,7 +440,7 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
        case ERESTARTSYS:
                if (!(sa->sa_flags & SA_RESTART))
                        goto no_system_call_restart;
-               /* fallthrough */
+               fallthrough;
        case ERESTARTNOINTR:
                regs->u_regs[UREG_I0] = orig_i0;
                regs->pc -= 4;
@@ -506,7 +506,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
                                regs->pc -= 4;
                                regs->npc -= 4;
                                pt_regs_clear_syscall(regs);
-                               /* fall through */
+                               fallthrough;
                        case ERESTART_RESTARTBLOCK:
                                regs->u_regs[UREG_G1] = __NR_restart_syscall;
                                regs->pc -= 4;
index 6937339..255264b 100644 (file)
@@ -461,7 +461,7 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
        case ERESTARTSYS:
                if (!(sa->sa_flags & SA_RESTART))
                        goto no_system_call_restart;
-               /* fallthrough */
+               fallthrough;
        case ERESTARTNOINTR:
                regs->u_regs[UREG_I0] = orig_i0;
                regs->tpc -= 4;
@@ -532,7 +532,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
                                regs->tpc -= 4;
                                regs->tnpc -= 4;
                                pt_regs_clear_syscall(regs);
-                               /* fall through */
+                               fallthrough;
                        case ERESTART_RESTARTBLOCK:
                                regs->u_regs[UREG_G1] = __NR_restart_syscall;
                                regs->tpc -= 4;
index 4af114e..37ec52b 100644 (file)
@@ -38,7 +38,7 @@
 23     64      setuid                  sys_setuid
 24     32      getuid                  sys_getuid16
 24     64      getuid                  sys_getuid
-25     common  vmsplice                sys_vmsplice                    compat_sys_vmsplice
+25     common  vmsplice                sys_vmsplice
 26     common  ptrace                  sys_ptrace                      compat_sys_ptrace
 27     common  alarm                   sys_alarm
 28     common  sigaltstack             sys_sigaltstack                 compat_sys_sigaltstack
 117    common  getrusage               sys_getrusage                   compat_sys_getrusage
 118    common  getsockopt              sys_getsockopt                  sys_getsockopt
 119    common  getcwd                  sys_getcwd
-120    common  readv                   sys_readv                       compat_sys_readv
-121    common  writev                  sys_writev                      compat_sys_writev
+120    common  readv                   sys_readv
+121    common  writev                  sys_writev
 122    common  settimeofday            sys_settimeofday                compat_sys_settimeofday
 123    32      fchown                  sys_fchown16
 123    64      fchown                  sys_fchown
 164    64      utrap_install           sys_utrap_install
 165    common  quotactl                sys_quotactl
 166    common  set_tid_address         sys_set_tid_address
-167    common  mount                   sys_mount                       compat_sys_mount
+167    common  mount                   sys_mount
 168    common  ustat                   sys_ustat                       compat_sys_ustat
 169    common  setxattr                sys_setxattr
 170    common  lsetxattr               sys_lsetxattr
 335    common  syncfs                  sys_syncfs
 336    common  sendmmsg                sys_sendmmsg                    compat_sys_sendmmsg
 337    common  setns                   sys_setns
-338    common  process_vm_readv        sys_process_vm_readv            compat_sys_process_vm_readv
-339    common  process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
+338    common  process_vm_readv        sys_process_vm_readv
+339    common  process_vm_writev       sys_process_vm_writev
 340    32      kern_features           sys_ni_syscall                  sys_kern_features
 340    64      kern_features           sys_kern_features
 341    common  kcmp                    sys_kcmp
index f99e99e..d55ae65 100644 (file)
@@ -187,6 +187,7 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        DISCARDS
 }
index 6a5469c..7488d13 100644 (file)
@@ -144,44 +144,21 @@ cpte:     bne     csum_partial_end_cruft                  ! yep, handle it
 cpout: retl                                            ! get outta here
         mov    %o2, %o0                                ! return computed csum
 
-       .globl __csum_partial_copy_start, __csum_partial_copy_end
-__csum_partial_copy_start:
-
 /* Work around cpp -rob */
 #define ALLOC #alloc
 #define EXECINSTR #execinstr
-#define EX(x,y,a,b)                            \
-98:     x,y;                                    \
-        .section .fixup,ALLOC,EXECINSTR;       \
-        .align  4;                              \
-99:     ba 30f;                                 \
-         a, b, %o3;                             \
-        .section __ex_table,ALLOC;             \
-        .align  4;                              \
-        .word   98b, 99b;                       \
-        .text;                                  \
-        .align  4
-
-#define EX2(x,y)                               \
-98:     x,y;                                    \
-        .section __ex_table,ALLOC;             \
-        .align  4;                              \
-        .word   98b, 30f;                       \
-        .text;                                  \
-        .align  4
-
-#define EX3(x,y)                               \
+#define EX(x,y)                                        \
 98:     x,y;                                    \
         .section __ex_table,ALLOC;             \
         .align  4;                              \
-        .word   98b, 96f;                       \
+        .word   98b, cc_fault;                   \
         .text;                                  \
         .align  4
 
-#define EXT(start,end,handler)                 \
+#define EXT(start,end)                         \
         .section __ex_table,ALLOC;             \
         .align  4;                              \
-        .word   start, 0, end, handler;         \
+        .word   start, 0, end, cc_fault;         \
         .text;                                  \
         .align  4
 
@@ -252,21 +229,21 @@ __csum_partial_copy_start:
 cc_end_cruft:
        be      1f
         andcc  %o3, 4, %g0
-       EX(ldd  [%o0 + 0x00], %g2, and %o3, 0xf)
+       EX(ldd  [%o0 + 0x00], %g2)
        add     %o1, 8, %o1
        addcc   %g2, %g7, %g7
        add     %o0, 8, %o0
        addxcc  %g3, %g7, %g7
-       EX2(st  %g2, [%o1 - 0x08])
+       EX(st   %g2, [%o1 - 0x08])
        addx    %g0, %g7, %g7
        andcc   %o3, 4, %g0
-       EX2(st  %g3, [%o1 - 0x04])
+       EX(st   %g3, [%o1 - 0x04])
 1:     be      1f
         andcc  %o3, 3, %o3
-       EX(ld   [%o0 + 0x00], %g2, add %o3, 4)
+       EX(ld   [%o0 + 0x00], %g2)
        add     %o1, 4, %o1
        addcc   %g2, %g7, %g7
-       EX2(st  %g2, [%o1 - 0x04])
+       EX(st   %g2, [%o1 - 0x04])
        addx    %g0, %g7, %g7
        andcc   %o3, 3, %g0
        add     %o0, 4, %o0
@@ -276,14 +253,14 @@ cc_end_cruft:
         subcc  %o3, 2, %o3
        b       4f
         or     %g0, %g0, %o4
-2:     EX(lduh [%o0 + 0x00], %o4, add %o3, 2)
+2:     EX(lduh [%o0 + 0x00], %o4)
        add     %o0, 2, %o0
-       EX2(sth %o4, [%o1 + 0x00])
+       EX(sth  %o4, [%o1 + 0x00])
        be      6f
         add    %o1, 2, %o1
        sll     %o4, 16, %o4
-4:     EX(ldub [%o0 + 0x00], %o5, add %g0, 1)
-       EX2(stb %o5, [%o1 + 0x00])
+4:     EX(ldub [%o0 + 0x00], %o5)
+       EX(stb  %o5, [%o1 + 0x00])
        sll     %o5, 8, %o5
        or      %o5, %o4, %o4
 6:     addcc   %o4, %g7, %g7
@@ -306,9 +283,9 @@ cc_dword_align:
         andcc  %o0, 0x2, %g0
        be      1f
         andcc  %o0, 0x4, %g0
-       EX(lduh [%o0 + 0x00], %g4, add %g1, 0)
+       EX(lduh [%o0 + 0x00], %g4)
        sub     %g1, 2, %g1
-       EX2(sth %g4, [%o1 + 0x00])
+       EX(sth  %g4, [%o1 + 0x00])
        add     %o0, 2, %o0
        sll     %g4, 16, %g4
        addcc   %g4, %g7, %g7
@@ -322,9 +299,9 @@ cc_dword_align:
        or      %g3, %g7, %g7
 1:     be      3f
         andcc  %g1, 0xffffff80, %g0
-       EX(ld   [%o0 + 0x00], %g4, add %g1, 0)
+       EX(ld   [%o0 + 0x00], %g4)
        sub     %g1, 4, %g1
-       EX2(st  %g4, [%o1 + 0x00])
+       EX(st   %g4, [%o1 + 0x00])
        add     %o0, 4, %o0
        addcc   %g4, %g7, %g7
        add     %o1, 4, %o1
@@ -354,7 +331,7 @@ __csum_partial_copy_sparc_generic:
        CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
        CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
        CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-10:    EXT(5b, 10b, 20f)               ! note for exception handling
+10:    EXT(5b, 10b)                    ! note for exception handling
        sub     %g1, 128, %g1           ! detract from length
        addx    %g0, %g7, %g7           ! add in last carry bit
        andcc   %g1, 0xffffff80, %g0    ! more to csum?
@@ -379,7 +356,7 @@ cctbl:      CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5)
        CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3,%g4,%g5)
        CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3,%g4,%g5)
        CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5)
-12:    EXT(cctbl, 12b, 22f)            ! note for exception table handling
+12:    EXT(cctbl, 12b)                 ! note for exception table handling
        addx    %g0, %g7, %g7
        andcc   %o3, 0xf, %g0           ! check for low bits set
 ccte:  bne     cc_end_cruft            ! something left, handle it out of band
@@ -390,7 +367,7 @@ ccdbl:      CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o
        CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
        CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
        CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-11:    EXT(ccdbl, 11b, 21f)            ! note for exception table handling
+11:    EXT(ccdbl, 11b)                 ! note for exception table handling
        sub     %g1, 128, %g1           ! detract from length
        addx    %g0, %g7, %g7           ! add in last carry bit
        andcc   %g1, 0xffffff80, %g0    ! more to csum?
@@ -407,9 +384,9 @@ ccslow:     cmp     %g1, 0
        be,a    1f
         srl    %g1, 1, %g4             
        sub     %g1, 1, %g1     
-       EX(ldub [%o0], %g5, add %g1, 1)
+       EX(ldub [%o0], %g5)
        add     %o0, 1, %o0     
-       EX2(stb %g5, [%o1])
+       EX(stb  %g5, [%o1])
        srl     %g1, 1, %g4
        add     %o1, 1, %o1
 1:     cmp     %g4, 0          
@@ -418,34 +395,34 @@ ccslow:   cmp     %g1, 0
        andcc   %o0, 2, %g0     
        be,a    1f
         srl    %g4, 1, %g4
-       EX(lduh [%o0], %o4, add %g1, 0)
+       EX(lduh [%o0], %o4)
        sub     %g1, 2, %g1     
        srl     %o4, 8, %g2
        sub     %g4, 1, %g4     
-       EX2(stb %g2, [%o1])
+       EX(stb  %g2, [%o1])
        add     %o4, %g5, %g5
-       EX2(stb %o4, [%o1 + 1])
+       EX(stb  %o4, [%o1 + 1])
        add     %o0, 2, %o0     
        srl     %g4, 1, %g4
        add     %o1, 2, %o1
 1:     cmp     %g4, 0          
        be,a    2f
         andcc  %g1, 2, %g0
-       EX3(ld  [%o0], %o4)
+       EX(ld   [%o0], %o4)
 5:     srl     %o4, 24, %g2
        srl     %o4, 16, %g3
-       EX2(stb %g2, [%o1])
+       EX(stb  %g2, [%o1])
        srl     %o4, 8, %g2
-       EX2(stb %g3, [%o1 + 1])
+       EX(stb  %g3, [%o1 + 1])
        add     %o0, 4, %o0
-       EX2(stb %g2, [%o1 + 2])
+       EX(stb  %g2, [%o1 + 2])
        addcc   %o4, %g5, %g5
-       EX2(stb %o4, [%o1 + 3])
+       EX(stb  %o4, [%o1 + 3])
        addx    %g5, %g0, %g5   ! I am now to lazy to optimize this (question it
        add     %o1, 4, %o1     ! is worthy). Maybe some day - with the sll/srl
        subcc   %g4, 1, %g4     ! tricks
        bne,a   5b
-        EX3(ld [%o0], %o4)
+        EX(ld  [%o0], %o4)
        sll     %g5, 16, %g2
        srl     %g5, 16, %g5
        srl     %g2, 16, %g2
@@ -453,19 +430,19 @@ ccslow:   cmp     %g1, 0
        add     %g2, %g5, %g5 
 2:     be,a    3f              
         andcc  %g1, 1, %g0
-       EX(lduh [%o0], %o4, and %g1, 3)
+       EX(lduh [%o0], %o4)
        andcc   %g1, 1, %g0
        srl     %o4, 8, %g2
        add     %o0, 2, %o0     
-       EX2(stb %g2, [%o1])
+       EX(stb  %g2, [%o1])
        add     %g5, %o4, %g5
-       EX2(stb %o4, [%o1 + 1])
+       EX(stb  %o4, [%o1 + 1])
        add     %o1, 2, %o1
 3:     be,a    1f              
         sll    %g5, 16, %o4
-       EX(ldub [%o0], %g2, add %g0, 1)
+       EX(ldub [%o0], %g2)
        sll     %g2, 8, %o4     
-       EX2(stb %g2, [%o1])
+       EX(stb  %g2, [%o1])
        add     %g5, %o4, %g5
        sll     %g5, 16, %o4
 1:     addcc   %o4, %g5, %g5
@@ -481,113 +458,10 @@ ccslow:  cmp     %g1, 0
 4:     addcc   %g7, %g5, %g7
        retl    
         addx   %g0, %g7, %o0
-__csum_partial_copy_end:
 
 /* We do these strange calculations for the csum_*_from_user case only, ie.
  * we only bother with faults on loads... */
 
-/* o2 = ((g2%20)&3)*8
- * o3 = g1 - (g2/20)*32 - o2 */
-20:
-       cmp     %g2, 20
-       blu,a   1f
-        and    %g2, 3, %o2
-       sub     %g1, 32, %g1
-       b       20b
-        sub    %g2, 20, %g2
-1:
-       sll     %o2, 3, %o2
-       b       31f
-        sub    %g1, %o2, %o3
-
-/* o2 = (!(g2 & 15) ? 0 : (((g2 & 15) + 1) & ~1)*8)
- * o3 = g1 - (g2/16)*32 - o2 */
-21:
-       andcc   %g2, 15, %o3
-       srl     %g2, 4, %g2
-       be,a    1f
-        clr    %o2
-       add     %o3, 1, %o3
-       and     %o3, 14, %o3
-       sll     %o3, 3, %o2
-1:
-       sll     %g2, 5, %g2
-       sub     %g1, %g2, %o3
-       b       31f
-        sub    %o3, %o2, %o3
-
-/* o0 += (g2/10)*16 - 0x70
- * 01 += (g2/10)*16 - 0x70
- * o2 = (g2 % 10) ? 8 : 0
- * o3 += 0x70 - (g2/10)*16 - o2 */
-22:
-       cmp     %g2, 10
-       blu,a   1f
-        sub    %o0, 0x70, %o0
-       add     %o0, 16, %o0
-       add     %o1, 16, %o1
-       sub     %o3, 16, %o3
-       b       22b
-        sub    %g2, 10, %g2
-1:
-       sub     %o1, 0x70, %o1
-       add     %o3, 0x70, %o3
-       clr     %o2
-       tst     %g2
-       bne,a   1f
-        mov    8, %o2
-1:
-       b       31f
-        sub    %o3, %o2, %o3
-96:
-       and     %g1, 3, %g1
-       sll     %g4, 2, %g4
-       add     %g1, %g4, %o3
-30:
-/* %o1 is dst
- * %o3 is # bytes to zero out
- * %o4 is faulting address
- * %o5 is %pc where fault occurred */
-       clr     %o2
-31:
-/* %o0 is src
- * %o1 is dst
- * %o2 is # of bytes to copy from src to dst
- * %o3 is # bytes to zero out
- * %o4 is faulting address
- * %o5 is %pc where fault occurred */
-       save    %sp, -104, %sp
-        mov     %i5, %o0
-        mov     %i7, %o1
-        mov    %i4, %o2
-        call    lookup_fault
-        mov    %g7, %i4
-       cmp     %o0, 2
-       bne     1f      
-        add    %g0, -EFAULT, %i5
-       tst     %i2
-       be      2f
-        mov    %i0, %o1
-       mov     %i1, %o0
-5:
-       call    memcpy
-        mov    %i2, %o2
-       tst     %o0
-       bne,a   2f
-        add    %i3, %i2, %i3
-       add     %i1, %i2, %i1
-2:
-       mov     %i1, %o0
-6:
-       call    __bzero
-        mov    %i3, %o1
-1:
-       ld      [%sp + 168], %o2                ! struct_ptr of parent
-       st      %i5, [%o2]
+cc_fault:
        ret
-        restore
-
-        .section __ex_table,#alloc
-        .align 4
-        .word 5b,2
-       .word 6b,2
+        clr    %o0
index 26c644b..0c0268e 100644 (file)
        .globl          FUNC_NAME
        .type           FUNC_NAME,#function
        EXPORT_SYMBOL(FUNC_NAME)
-FUNC_NAME:             /* %o0=src, %o1=dst, %o2=len, %o3=sum */
+FUNC_NAME:             /* %o0=src, %o1=dst, %o2=len */
        LOAD(prefetch, %o0 + 0x000, #n_reads)
        xor             %o0, %o1, %g1
+       mov             1, %o3
        clr             %o4
        andcc           %g1, 0x3, %g0
        bne,pn          %icc, 95f
index d20b959..b0ba8d4 100644 (file)
@@ -9,14 +9,14 @@
        .section .fixup, "ax";  \
        .align 4;               \
 99:    retl;                   \
-        mov    -1, %o0;        \
+        mov    0, %o0;         \
        .section __ex_table,"a";\
        .align 4;               \
        .word 98b, 99b;         \
        .text;                  \
        .align 4;
 
-#define FUNC_NAME              __csum_partial_copy_from_user
+#define FUNC_NAME              csum_and_copy_from_user
 #define LOAD(type,addr,dest)   type##a [addr] %asi, dest
 
 #include "csum_copy.S"
index d71c0c8..91ba36d 100644 (file)
@@ -9,14 +9,14 @@
        .section .fixup,"ax";   \
        .align 4;               \
 99:    retl;                   \
-        mov    -1, %o0;        \
+        mov    0, %o0;         \
        .section __ex_table,"a";\
        .align 4;               \
        .word 98b, 99b;         \
        .text;                  \
        .align 4;
 
-#define FUNC_NAME              __csum_partial_copy_to_user
+#define FUNC_NAME              csum_and_copy_to_user
 #define STORE(type,src,addr)   type##a src, [addr] %asi
 
 #include "csum_copy.S"
index 72e560e..d5beec8 100644 (file)
@@ -359,7 +359,7 @@ static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs)
                        *pfsr |= (6 << 14);
                        return 0;                       /* simulate invalid_fp_register exception */
                }
-       /* fall through */
+               fallthrough;
        case 2:
                if (freg & 1) {                         /* doublewords must have bit 5 zeroed */
                        *pfsr |= (6 << 14);
@@ -380,7 +380,7 @@ static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs)
                        *pfsr |= (6 << 14);
                        return 0;                       /* simulate invalid_fp_register exception */
                }
-       /* fall through */
+               fallthrough;
        case 2:
                if (freg & 1) {                         /* doublewords must have bit 5 zeroed */
                        *pfsr |= (6 << 14);
@@ -408,13 +408,13 @@ static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs)
                        *pfsr |= (6 << 14);
                        return 0;                       /* simulate invalid_fp_register exception */
                }
-       /* fall through */
+               fallthrough;
        case 2:
                if (freg & 1) {                         /* doublewords must have bit 5 zeroed */
                        *pfsr |= (6 << 14);
                        return 0;
                }
-       /* fall through */
+               fallthrough;
        case 1:
                rd = (void *)&fregs[freg];
                break;
index 8071bfd..40ce087 100644 (file)
@@ -288,8 +288,6 @@ no_context:
                if (fixup > 10) {
                        extern const unsigned int __memset_start[];
                        extern const unsigned int __memset_end[];
-                       extern const unsigned int __csum_partial_copy_start[];
-                       extern const unsigned int __csum_partial_copy_end[];
 
 #ifdef DEBUG_EXCEPTIONS
                        printk("Exception: PC<%08lx> faddr<%08lx>\n",
@@ -298,9 +296,7 @@ no_context:
                                regs->pc, fixup, g2);
 #endif
                        if ((regs->pc >= (unsigned long)__memset_start &&
-                            regs->pc < (unsigned long)__memset_end) ||
-                           (regs->pc >= (unsigned long)__csum_partial_copy_start &&
-                            regs->pc < (unsigned long)__csum_partial_copy_end)) {
+                            regs->pc < (unsigned long)__memset_end)) {
                                regs->u_regs[UREG_I4] = address;
                                regs->u_regs[UREG_I5] = regs->pc;
                        }
index c8eabb9..b1dbf2f 100644 (file)
@@ -491,7 +491,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
                                } else {
                                        emit_loadimm(K, r_A);
                                }
-                               /* Fallthrough */
+                               fallthrough;
                        case BPF_RET | BPF_A:
                                if (seen_or_pass0) {
                                        if (i != flen - 1) {
index f500148..dacbfab 100644 (file)
@@ -164,8 +164,8 @@ SECTIONS
   PROVIDE (end = .);
 
   STABS_DEBUG
-
   DWARF_DEBUG
+  ELF_DETAILS
 
   DISCARDS
 }
index 3d57c71..88cd9b5 100644 (file)
@@ -70,7 +70,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
                                PT_REGS_SYSCALL_RET(regs) = -EINTR;
                                break;
                        }
-               /* fallthrough */
+                       fallthrough;
                case -ERESTARTNOINTR:
                        PT_REGS_RESTART_SYSCALL(regs);
                        PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
index 3b6dab3..45d957d 100644 (file)
@@ -108,8 +108,8 @@ SECTIONS
   PROVIDE (end = .);
 
   STABS_DEBUG
-
   DWARF_DEBUG
+  ELF_DETAILS
 
   DISCARDS
 }
index 7101ac6..835d930 100644 (file)
@@ -75,7 +75,7 @@ config X86
        select ARCH_HAS_PTE_DEVMAP              if X86_64
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_UACCESS_FLUSHCACHE      if X86_64
-       select ARCH_HAS_UACCESS_MCSAFE          if X86_64 && X86_MCE
+       select ARCH_HAS_COPY_MC                 if X86_64
        select ARCH_HAS_SET_MEMORY
        select ARCH_HAS_SET_DIRECT_MAP
        select ARCH_HAS_STRICT_KERNEL_RWX
@@ -215,6 +215,8 @@ config X86
        select HAVE_FUNCTION_ARG_ACCESS_API
        select HAVE_STACKPROTECTOR              if CC_HAS_SANE_STACKPROTECTOR
        select HAVE_STACK_VALIDATION            if X86_64
+       select HAVE_STATIC_CALL
+       select HAVE_STATIC_CALL_INLINE          if HAVE_STACK_VALIDATION
        select HAVE_RSEQ
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_UNSTABLE_SCHED_CLOCK
@@ -230,6 +232,7 @@ config X86
        select RTC_MC146818_LIB
        select SPARSE_IRQ
        select SRCU
+       select STACK_VALIDATION                 if HAVE_STACK_VALIDATION && (HAVE_STATIC_CALL_INLINE || RETPOLINE)
        select SYSCTL_EXCEPTION_TRACE
        select THREAD_INFO_IN_TASK
        select USER_STACKTRACE_SUPPORT
@@ -451,7 +454,6 @@ config GOLDFISH
 config RETPOLINE
        bool "Avoid speculative indirect branches in kernel"
        default y
-       select STACK_VALIDATION if HAVE_STACK_VALIDATION
        help
          Compile kernel with the retpoline compiler options to guard against
          kernel-to-user data leaks by avoiding speculative indirect
index ee1d3c5..27b5e2b 100644 (file)
@@ -62,7 +62,7 @@ config EARLY_PRINTK_USB_XDBC
          You should normally say N here, unless you want to debug early
          crashes or need a very simple printk logging facility.
 
-config MCSAFE_TEST
+config COPY_MC_TEST
        def_bool n
 
 config EFI_PGT_DUMP
index 4346ffb..154259f 100644 (file)
@@ -209,6 +209,10 @@ ifdef CONFIG_X86_64
 LDFLAGS_vmlinux += -z max-page-size=0x200000
 endif
 
+# We never want expected sections to be placed heuristically by the
+# linker. All sections should be explicitly named in the linker script.
+LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn)
+
 archscripts: scripts_basic
        $(Q)$(MAKE) $(build)=arch/x86/tools relocs
 
index 4ff0117..21d56ae 100644 (file)
@@ -54,7 +54,7 @@ int __cmdline_find_option(unsigned long cmdline_ptr, const char *option, char *b
                        /* else */
                        state = st_wordcmp;
                        opptr = option;
-                       /* fall through */
+                       fallthrough;
 
                case st_wordcmp:
                        if (c == '=' && !*opptr) {
@@ -129,7 +129,7 @@ int __cmdline_find_option_bool(unsigned long cmdline_ptr, const char *option)
                        state = st_wordcmp;
                        opptr = option;
                        wstart = pos;
-                       /* fall through */
+                       fallthrough;
 
                case st_wordcmp:
                        if (!*opptr)
index 3962f59..4fb989e 100644 (file)
@@ -29,7 +29,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
        vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 vmlinux.bin.zst
 
 KBUILD_CFLAGS := -m$(BITS) -O2
-KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC)
+KBUILD_CFLAGS += -fno-strict-aliasing -fPIE
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
 cflags-$(CONFIG_X86_32) := -march=i386
 cflags-$(CONFIG_X86_64) := -mcmodel=small
@@ -43,24 +43,21 @@ KBUILD_CFLAGS += -Wno-pointer-sign
 KBUILD_CFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
 KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
 KBUILD_CFLAGS += -D__DISABLE_EXPORTS
+# Disable relocation relaxation in case the link is not PIE.
+KBUILD_CFLAGS += $(call as-option,-Wa$(comma)-mrelax-relocations=no)
+KBUILD_CFLAGS += -include $(srctree)/include/linux/hidden.h
 
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 GCOV_PROFILE := n
 UBSAN_SANITIZE :=n
 
 KBUILD_LDFLAGS := -m elf_$(UTS_MACHINE)
+KBUILD_LDFLAGS += $(call ld-option,--no-ld-generated-unwind-info)
 # Compressed kernel should be built as PIE since it may be loaded at any
 # address by the bootloader.
-ifeq ($(CONFIG_X86_32),y)
-KBUILD_LDFLAGS += $(call ld-option, -pie) $(call ld-option, --no-dynamic-linker)
-else
-# To build 64-bit compressed kernel as PIE, we disable relocation
-# overflow check to avoid relocation overflow error with a new linker
-# command-line option, -z noreloc-overflow.
-KBUILD_LDFLAGS += $(shell $(LD) --help 2>&1 | grep -q "\-z noreloc-overflow" \
-       && echo "-z noreloc-overflow -pie --no-dynamic-linker")
-endif
-LDFLAGS_vmlinux := -T
+LDFLAGS_vmlinux := -pie $(call ld-option, --no-dynamic-linker)
+LDFLAGS_vmlinux += $(call ld-option, --orphan-handling=warn)
+LDFLAGS_vmlinux += -T
 
 hostprogs      := mkpiggy
 HOST_EXTRACFLAGS += -I$(srctree)/tools/include
@@ -94,30 +91,8 @@ vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o
 vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
 efi-obj-$(CONFIG_EFI_STUB) = $(objtree)/drivers/firmware/efi/libstub/lib.a
 
-# The compressed kernel is built with -fPIC/-fPIE so that a boot loader
-# can place it anywhere in memory and it will still run. However, since
-# it is executed as-is without any ELF relocation processing performed
-# (and has already had all relocation sections stripped from the binary),
-# none of the code can use data relocations (e.g. static assignments of
-# pointer values), since they will be meaningless at runtime. This check
-# will refuse to link the vmlinux if any of these relocations are found.
-quiet_cmd_check_data_rel = DATAREL $@
-define cmd_check_data_rel
-       for obj in $(filter %.o,$^); do \
-               $(READELF) -S $$obj | grep -qF .rel.local && { \
-                       echo "error: $$obj has data relocations!" >&2; \
-                       exit 1; \
-               } || true; \
-       done
-endef
-
-# We need to run two commands under "if_changed", so merge them into a
-# single invocation.
-quiet_cmd_check-and-link-vmlinux = LD      $@
-      cmd_check-and-link-vmlinux = $(cmd_check_data_rel); $(cmd_ld)
-
 $(obj)/vmlinux: $(vmlinux-objs-y) $(efi-obj-y) FORCE
-       $(call if_changed,check-and-link-vmlinux)
+       $(call if_changed,ld)
 
 OBJCOPYFLAGS_vmlinux.bin :=  -R .comment -S
 $(obj)/vmlinux.bin: vmlinux FORCE
index 03557f2..659fad5 100644 (file)
 #include <asm/bootparam.h>
 
 /*
- * The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X
- * relocation to get the symbol address in PIC.  When the compressed x86
- * kernel isn't built as PIC, the linker optimizes R_386_GOT32X
- * relocations to their fixed symbol addresses.  However, when the
- * compressed x86 kernel is loaded at a different address, it leads
- * to the following load failure:
- *
- *   Failed to allocate space for phdrs
- *
- * during the decompression stage.
- *
- * If the compressed x86 kernel is relocatable at run-time, it should be
- * compiled with -fPIE, instead of -fPIC, if possible and should be built as
- * Position Independent Executable (PIE) so that linker won't optimize
- * R_386_GOT32X relocation to its fixed symbol address.  Older
- * linkers generate R_386_32 relocations against locally defined symbols,
- * _bss, _ebss, _got, _egot and _end, in PIE.  It isn't wrong, just less
- * optimal than R_386_RELATIVE.  But the x86 kernel fails to properly handle
- * R_386_32 relocations when relocating the kernel.  To generate
- * R_386_RELATIVE relocations, we mark _bss, _ebss, _got, _egot and _end as
- * hidden:
+ * These symbols needed to be marked as .hidden to prevent the BFD linker from
+ * generating R_386_32 (rather than R_386_RELATIVE) relocations for them when
+ * the 32-bit compressed kernel is linked as PIE. This is no longer necessary,
+ * but it doesn't hurt to keep them .hidden.
  */
        .hidden _bss
        .hidden _ebss
-       .hidden _got
-       .hidden _egot
        .hidden _end
 
        __HEAD
@@ -77,10 +58,10 @@ SYM_FUNC_START(startup_32)
        leal    (BP_scratch+4)(%esi), %esp
        call    1f
 1:     popl    %edx
-       subl    $1b, %edx
+       addl    $_GLOBAL_OFFSET_TABLE_+(.-1b), %edx
 
        /* Load new GDT */
-       leal    gdt(%edx), %eax
+       leal    gdt@GOTOFF(%edx), %eax
        movl    %eax, 2(%eax)
        lgdt    (%eax)
 
@@ -93,14 +74,16 @@ SYM_FUNC_START(startup_32)
        movl    %eax, %ss
 
 /*
- * %edx contains the address we are loaded at by the boot loader and %ebx
- * contains the address where we should move the kernel image temporarily
- * for safe in-place decompression. %ebp contains the address that the kernel
- * will be decompressed to.
+ * %edx contains the address we are loaded at by the boot loader (plus the
+ * offset to the GOT).  The below code calculates %ebx to be the address where
+ * we should move the kernel image temporarily for safe in-place decompression
+ * (again, plus the offset to the GOT).
+ *
+ * %ebp is calculated to be the address that the kernel will be decompressed to.
  */
 
 #ifdef CONFIG_RELOCATABLE
-       movl    %edx, %ebx
+       leal    startup_32@GOTOFF(%edx), %ebx
 
 #ifdef CONFIG_EFI_STUB
 /*
@@ -111,7 +94,7 @@ SYM_FUNC_START(startup_32)
  *     image_offset = startup_32 - image_base
  * Otherwise image_offset will be zero and has no effect on the calculations.
  */
-       subl    image_offset(%edx), %ebx
+       subl    image_offset@GOTOFF(%edx), %ebx
 #endif
 
        movl    BP_kernel_alignment(%esi), %eax
@@ -128,10 +111,10 @@ SYM_FUNC_START(startup_32)
        movl    %ebx, %ebp      // Save the output address for later
        /* Target address to relocate to for decompression */
        addl    BP_init_size(%esi), %ebx
-       subl    $_end, %ebx
+       subl    $_end@GOTOFF, %ebx
 
        /* Set up the stack */
-       leal    boot_stack_end(%ebx), %esp
+       leal    boot_stack_end@GOTOFF(%ebx), %esp
 
        /* Zero EFLAGS */
        pushl   $0
@@ -142,8 +125,8 @@ SYM_FUNC_START(startup_32)
  * where decompression in place becomes safe.
  */
        pushl   %esi
-       leal    (_bss-4)(%edx), %esi
-       leal    (_bss-4)(%ebx), %edi
+       leal    (_bss@GOTOFF-4)(%edx), %esi
+       leal    (_bss@GOTOFF-4)(%ebx), %edi
        movl    $(_bss - startup_32), %ecx
        shrl    $2, %ecx
        std
@@ -156,14 +139,14 @@ SYM_FUNC_START(startup_32)
         * during extract_kernel below. To avoid any issues, repoint the GDTR
         * to the new copy of the GDT.
         */
-       leal    gdt(%ebx), %eax
+       leal    gdt@GOTOFF(%ebx), %eax
        movl    %eax, 2(%eax)
        lgdt    (%eax)
 
 /*
  * Jump to the relocated address.
  */
-       leal    .Lrelocated(%ebx), %eax
+       leal    .Lrelocated@GOTOFF(%ebx), %eax
        jmp     *%eax
 SYM_FUNC_END(startup_32)
 
@@ -173,7 +156,7 @@ SYM_FUNC_START_ALIAS(efi_stub_entry)
        add     $0x4, %esp
        movl    8(%esp), %esi   /* save boot_params pointer */
        call    efi_main
-       leal    startup_32(%eax), %eax
+       /* efi_main returns the possibly relocated address of startup_32 */
        jmp     *%eax
 SYM_FUNC_END(efi32_stub_entry)
 SYM_FUNC_END_ALIAS(efi_stub_entry)
@@ -186,40 +169,26 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
  * Clear BSS (stack is currently empty)
  */
        xorl    %eax, %eax
-       leal    _bss(%ebx), %edi
-       leal    _ebss(%ebx), %ecx
+       leal    _bss@GOTOFF(%ebx), %edi
+       leal    _ebss@GOTOFF(%ebx), %ecx
        subl    %edi, %ecx
        shrl    $2, %ecx
        rep     stosl
 
 /*
- * Adjust our own GOT
- */
-       leal    _got(%ebx), %edx
-       leal    _egot(%ebx), %ecx
-1:
-       cmpl    %ecx, %edx
-       jae     2f
-       addl    %ebx, (%edx)
-       addl    $4, %edx
-       jmp     1b
-2:
-
-/*
  * Do the extraction, and jump to the new kernel..
  */
-                               /* push arguments for extract_kernel: */
-       pushl   $z_output_len   /* decompressed length, end of relocs */
-
-       pushl   %ebp            /* output address */
-
-       pushl   $z_input_len    /* input_len */
-       leal    input_data(%ebx), %eax
-       pushl   %eax            /* input_data */
-       leal    boot_heap(%ebx), %eax
-       pushl   %eax            /* heap area */
-       pushl   %esi            /* real mode pointer */
-       call    extract_kernel  /* returns kernel location in %eax */
+       /* push arguments for extract_kernel: */
+
+       pushl   output_len@GOTOFF(%ebx) /* decompressed length, end of relocs */
+       pushl   %ebp                    /* output address */
+       pushl   input_len@GOTOFF(%ebx)  /* input_len */
+       leal    input_data@GOTOFF(%ebx), %eax
+       pushl   %eax                    /* input_data */
+       leal    boot_heap@GOTOFF(%ebx), %eax
+       pushl   %eax                    /* heap area */
+       pushl   %esi                    /* real mode pointer */
+       call    extract_kernel          /* returns kernel location in %eax */
        addl    $24, %esp
 
 /*
index 97d37f0..9e46729 100644 (file)
  */
        .hidden _bss
        .hidden _ebss
-       .hidden _got
-       .hidden _egot
        .hidden _end
 
        __HEAD
+
+/*
+ * This macro gives the relative virtual address of X, i.e. the offset of X
+ * from startup_32. This is the same as the link-time virtual address of X,
+ * since startup_32 is at 0, but defining it this way tells the
+ * assembler/linker that we do not want the actual run-time address of X. This
+ * prevents the linker from trying to create unwanted run-time relocation
+ * entries for the reference when the compressed kernel is linked as PIE.
+ *
+ * A reference X(%reg) will result in the link-time VA of X being stored with
+ * the instruction, and a run-time R_X86_64_RELATIVE relocation entry that
+ * adds the 64-bit base address where the kernel is loaded.
+ *
+ * Replacing it with (X-startup_32)(%reg) results in the offset being stored,
+ * and no run-time relocation.
+ *
+ * The macro should be used as a displacement with a base register containing
+ * the run-time address of startup_32 [i.e. rva(X)(%reg)], or as an immediate
+ * [$ rva(X)].
+ *
+ * This macro can only be used from within the .head.text section, since the
+ * expression requires startup_32 to be in the same section as the code being
+ * assembled.
+ */
+#define rva(X) ((X) - startup_32)
+
        .code32
 SYM_FUNC_START(startup_32)
        /*
@@ -67,10 +91,10 @@ SYM_FUNC_START(startup_32)
        leal    (BP_scratch+4)(%esi), %esp
        call    1f
 1:     popl    %ebp
-       subl    $1b, %ebp
+       subl    $ rva(1b), %ebp
 
        /* Load new GDT with the 64bit segments using 32bit descriptor */
-       leal    gdt(%ebp), %eax
+       leal    rva(gdt)(%ebp), %eax
        movl    %eax, 2(%eax)
        lgdt    (%eax)
 
@@ -83,7 +107,7 @@ SYM_FUNC_START(startup_32)
        movl    %eax, %ss
 
 /* setup a stack and make sure cpu supports long mode. */
-       leal    boot_stack_end(%ebp), %esp
+       leal    rva(boot_stack_end)(%ebp), %esp
 
        call    verify_cpu
        testl   %eax, %eax
@@ -110,7 +134,7 @@ SYM_FUNC_START(startup_32)
  *     image_offset = startup_32 - image_base
  * Otherwise image_offset will be zero and has no effect on the calculations.
  */
-       subl    image_offset(%ebp), %ebx
+       subl    rva(image_offset)(%ebp), %ebx
 #endif
 
        movl    BP_kernel_alignment(%esi), %eax
@@ -126,7 +150,7 @@ SYM_FUNC_START(startup_32)
 
        /* Target address to relocate to for decompression */
        addl    BP_init_size(%esi), %ebx
-       subl    $_end, %ebx
+       subl    $ rva(_end), %ebx
 
 /*
  * Prepare for entering 64 bit mode
@@ -154,19 +178,19 @@ SYM_FUNC_START(startup_32)
 1:
 
        /* Initialize Page tables to 0 */
-       leal    pgtable(%ebx), %edi
+       leal    rva(pgtable)(%ebx), %edi
        xorl    %eax, %eax
        movl    $(BOOT_INIT_PGT_SIZE/4), %ecx
        rep     stosl
 
        /* Build Level 4 */
-       leal    pgtable + 0(%ebx), %edi
+       leal    rva(pgtable + 0)(%ebx), %edi
        leal    0x1007 (%edi), %eax
        movl    %eax, 0(%edi)
        addl    %edx, 4(%edi)
 
        /* Build Level 3 */
-       leal    pgtable + 0x1000(%ebx), %edi
+       leal    rva(pgtable + 0x1000)(%ebx), %edi
        leal    0x1007(%edi), %eax
        movl    $4, %ecx
 1:     movl    %eax, 0x00(%edi)
@@ -177,7 +201,7 @@ SYM_FUNC_START(startup_32)
        jnz     1b
 
        /* Build Level 2 */
-       leal    pgtable + 0x2000(%ebx), %edi
+       leal    rva(pgtable + 0x2000)(%ebx), %edi
        movl    $0x00000183, %eax
        movl    $2048, %ecx
 1:     movl    %eax, 0(%edi)
@@ -188,7 +212,7 @@ SYM_FUNC_START(startup_32)
        jnz     1b
 
        /* Enable the boot page tables */
-       leal    pgtable(%ebx), %eax
+       leal    rva(pgtable)(%ebx), %eax
        movl    %eax, %cr3
 
        /* Enable Long mode in EFER (Extended Feature Enable Register) */
@@ -213,14 +237,14 @@ SYM_FUNC_START(startup_32)
         * We place all of the values on our mini stack so lret can
         * used to perform that far jump.
         */
-       leal    startup_64(%ebp), %eax
+       leal    rva(startup_64)(%ebp), %eax
 #ifdef CONFIG_EFI_MIXED
-       movl    efi32_boot_args(%ebp), %edi
+       movl    rva(efi32_boot_args)(%ebp), %edi
        cmp     $0, %edi
        jz      1f
-       leal    efi64_stub_entry(%ebp), %eax
-       movl    efi32_boot_args+4(%ebp), %esi
-       movl    efi32_boot_args+8(%ebp), %edx   // saved bootparams pointer
+       leal    rva(efi64_stub_entry)(%ebp), %eax
+       movl    rva(efi32_boot_args+4)(%ebp), %esi
+       movl    rva(efi32_boot_args+8)(%ebp), %edx      // saved bootparams pointer
        cmpl    $0, %edx
        jnz     1f
        /*
@@ -231,7 +255,7 @@ SYM_FUNC_START(startup_32)
         * the correct stack alignment for entry.
         */
        subl    $40, %esp
-       leal    efi_pe_entry(%ebp), %eax
+       leal    rva(efi_pe_entry)(%ebp), %eax
        movl    %edi, %ecx                      // MS calling convention
        movl    %esi, %edx
 1:
@@ -257,18 +281,18 @@ SYM_FUNC_START(efi32_stub_entry)
 
        call    1f
 1:     pop     %ebp
-       subl    $1b, %ebp
+       subl    $ rva(1b), %ebp
 
-       movl    %esi, efi32_boot_args+8(%ebp)
+       movl    %esi, rva(efi32_boot_args+8)(%ebp)
 SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL)
-       movl    %ecx, efi32_boot_args(%ebp)
-       movl    %edx, efi32_boot_args+4(%ebp)
-       movb    $0, efi_is64(%ebp)
+       movl    %ecx, rva(efi32_boot_args)(%ebp)
+       movl    %edx, rva(efi32_boot_args+4)(%ebp)
+       movb    $0, rva(efi_is64)(%ebp)
 
        /* Save firmware GDTR and code/data selectors */
-       sgdtl   efi32_boot_gdt(%ebp)
-       movw    %cs, efi32_boot_cs(%ebp)
-       movw    %ds, efi32_boot_ds(%ebp)
+       sgdtl   rva(efi32_boot_gdt)(%ebp)
+       movw    %cs, rva(efi32_boot_cs)(%ebp)
+       movw    %ds, rva(efi32_boot_ds)(%ebp)
 
        /* Disable paging */
        movl    %cr0, %eax
@@ -347,30 +371,11 @@ SYM_CODE_START(startup_64)
 
        /* Target address to relocate to for decompression */
        movl    BP_init_size(%rsi), %ebx
-       subl    $_end, %ebx
+       subl    $ rva(_end), %ebx
        addq    %rbp, %rbx
 
        /* Set up the stack */
-       leaq    boot_stack_end(%rbx), %rsp
-
-       /*
-        * paging_prepare() and cleanup_trampoline() below can have GOT
-        * references. Adjust the table with address we are running at.
-        *
-        * Zero RAX for adjust_got: the GOT was not adjusted before;
-        * there's no adjustment to undo.
-        */
-       xorq    %rax, %rax
-
-       /*
-        * Calculate the address the binary is loaded at and use it as
-        * a GOT adjustment.
-        */
-       call    1f
-1:     popq    %rdi
-       subq    $1b, %rdi
-
-       call    .Ladjust_got
+       leaq    rva(boot_stack_end)(%rbx), %rsp
 
        /*
         * At this point we are in long mode with 4-level paging enabled,
@@ -444,7 +449,7 @@ SYM_CODE_START(startup_64)
        lretq
 trampoline_return:
        /* Restore the stack, the 32-bit trampoline uses its own stack */
-       leaq    boot_stack_end(%rbx), %rsp
+       leaq    rva(boot_stack_end)(%rbx), %rsp
 
        /*
         * cleanup_trampoline() would restore trampoline memory.
@@ -456,7 +461,7 @@ trampoline_return:
         * this function call.
         */
        pushq   %rsi
-       leaq    top_pgtable(%rbx), %rdi
+       leaq    rva(top_pgtable)(%rbx), %rdi
        call    cleanup_trampoline
        popq    %rsi
 
@@ -464,30 +469,15 @@ trampoline_return:
        pushq   $0
        popfq
 
-       /*
-        * Previously we've adjusted the GOT with address the binary was
-        * loaded at. Now we need to re-adjust for relocation address.
-        *
-        * Calculate the address the binary is loaded at, so that we can
-        * undo the previous GOT adjustment.
-        */
-       call    1f
-1:     popq    %rax
-       subq    $1b, %rax
-
-       /* The new adjustment is the relocation address */
-       movq    %rbx, %rdi
-       call    .Ladjust_got
-
 /*
  * Copy the compressed kernel to the end of our buffer
  * where decompression in place becomes safe.
  */
        pushq   %rsi
        leaq    (_bss-8)(%rip), %rsi
-       leaq    (_bss-8)(%rbx), %rdi
-       movq    $_bss /* - $startup_32 */, %rcx
-       shrq    $3, %rcx
+       leaq    rva(_bss-8)(%rbx), %rdi
+       movl    $(_bss - startup_32), %ecx
+       shrl    $3, %ecx
        std
        rep     movsq
        cld
@@ -498,15 +488,15 @@ trampoline_return:
         * during extract_kernel below. To avoid any issues, repoint the GDTR
         * to the new copy of the GDT.
         */
-       leaq    gdt64(%rbx), %rax
-       leaq    gdt(%rbx), %rdx
+       leaq    rva(gdt64)(%rbx), %rax
+       leaq    rva(gdt)(%rbx), %rdx
        movq    %rdx, 2(%rax)
        lgdt    (%rax)
 
 /*
  * Jump to the relocated address.
  */
-       leaq    .Lrelocated(%rbx), %rax
+       leaq    rva(.Lrelocated)(%rbx), %rax
        jmp     *%rax
 SYM_CODE_END(startup_64)
 
@@ -518,7 +508,7 @@ SYM_FUNC_START_ALIAS(efi_stub_entry)
        movq    %rdx, %rbx                      /* save boot_params pointer */
        call    efi_main
        movq    %rbx,%rsi
-       leaq    startup_64(%rax), %rax
+       leaq    rva(startup_64)(%rax), %rax
        jmp     *%rax
 SYM_FUNC_END(efi64_stub_entry)
 SYM_FUNC_END_ALIAS(efi_stub_entry)
@@ -544,9 +534,9 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
        movq    %rsi, %rdi              /* real mode address */
        leaq    boot_heap(%rip), %rsi   /* malloc area for uncompression */
        leaq    input_data(%rip), %rdx  /* input_data */
-       movl    $z_input_len, %ecx      /* input_len */
+       movl    input_len(%rip), %ecx   /* input_len */
        movq    %rbp, %r8               /* output target address */
-       movl    $z_output_len, %r9d     /* decompressed length, end of relocs */
+       movl    output_len(%rip), %r9d  /* decompressed length, end of relocs */
        call    extract_kernel          /* returns kernel location in %rax */
        popq    %rsi
 
@@ -556,27 +546,6 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
        jmp     *%rax
 SYM_FUNC_END(.Lrelocated)
 
-/*
- * Adjust the global offset table
- *
- * RAX is the previous adjustment of the table to undo (use 0 if it's the
- * first time we touch GOT).
- * RDI is the new adjustment to apply.
- */
-.Ladjust_got:
-       /* Walk through the GOT adding the address to the entries */
-       leaq    _got(%rip), %rdx
-       leaq    _egot(%rip), %rcx
-1:
-       cmpq    %rcx, %rdx
-       jae     2f
-       subq    %rax, (%rdx)    /* Undo previous adjustment */
-       addq    %rdi, (%rdx)    /* Apply the new adjustment */
-       addq    $8, %rdx
-       jmp     1b
-2:
-       ret
-
        .code32
 /*
  * This is the 32-bit trampoline that will be copied over to low memory.
@@ -702,7 +671,7 @@ SYM_DATA(efi_is64, .byte 1)
 #define BS32_handle_protocol   88 // offsetof(efi_boot_services_32_t, handle_protocol)
 #define LI32_image_base                32 // offsetof(efi_loaded_image_32_t, image_base)
 
-       .text
+       __HEAD
        .code32
 SYM_FUNC_START(efi32_pe_entry)
 /*
@@ -724,12 +693,12 @@ SYM_FUNC_START(efi32_pe_entry)
 
        call    1f
 1:     pop     %ebx
-       subl    $1b, %ebx
+       subl    $ rva(1b), %ebx
 
        /* Get the loaded image protocol pointer from the image handle */
        leal    -4(%ebp), %eax
        pushl   %eax                            // &loaded_image
-       leal    loaded_image_proto(%ebx), %eax
+       leal    rva(loaded_image_proto)(%ebx), %eax
        pushl   %eax                            // pass the GUID address
        pushl   8(%ebp)                         // pass the image handle
 
@@ -764,7 +733,7 @@ SYM_FUNC_START(efi32_pe_entry)
         * use it before we get to the 64-bit efi_pe_entry() in C code.
         */
        subl    %esi, %ebx
-       movl    %ebx, image_offset(%ebp)        // save image_offset
+       movl    %ebx, rva(image_offset)(%ebp)   // save image_offset
        jmp     efi32_pe_stub_entry
 
 2:     popl    %edi                            // restore callee-save registers
index 0048269..877970d 100644 (file)
 #define STATIC
 #include <linux/decompress/mm.h>
 
+#define _SETUP
+#include <asm/setup.h> /* For COMMAND_LINE_SIZE */
+#undef _SETUP
+
 #ifdef CONFIG_X86_5LEVEL
 unsigned int __pgtable_l5_enabled;
 unsigned int pgdir_shift __ro_after_init = 39;
@@ -87,8 +91,11 @@ static unsigned long get_boot_seed(void)
 static bool memmap_too_large;
 
 
-/* Store memory limit specified by "mem=nn[KMG]" or "memmap=nn[KMG]" */
-static unsigned long long mem_limit = ULLONG_MAX;
+/*
+ * Store memory limit: MAXMEM on 64-bit and KERNEL_IMAGE_SIZE on 32-bit.
+ * It may be reduced by "mem=nn[KMG]" or "memmap=nn[KMG]" command line options.
+ */
+static u64 mem_limit;
 
 /* Number of immovable memory regions */
 static int num_immovable_mem;
@@ -131,8 +138,7 @@ enum parse_mode {
 };
 
 static int
-parse_memmap(char *p, unsigned long long *start, unsigned long long *size,
-               enum parse_mode mode)
+parse_memmap(char *p, u64 *start, u64 *size, enum parse_mode mode)
 {
        char *oldp;
 
@@ -162,7 +168,7 @@ parse_memmap(char *p, unsigned long long *start, unsigned long long *size,
                         */
                        *size = 0;
                } else {
-                       unsigned long long flags;
+                       u64 flags;
 
                        /*
                         * efi_fake_mem=nn@ss:attr the attr specifies
@@ -178,7 +184,7 @@ parse_memmap(char *p, unsigned long long *start, unsigned long long *size,
                        }
                        *size = 0;
                }
-               /* Fall through */
+               fallthrough;
        default:
                /*
                 * If w/o offset, only size specified, memmap=nn[KMG] has the
@@ -201,7 +207,7 @@ static void mem_avoid_memmap(enum parse_mode mode, char *str)
 
        while (str && (i < MAX_MEMMAP_REGIONS)) {
                int rc;
-               unsigned long long start, size;
+               u64 start, size;
                char *k = strchr(str, ',');
 
                if (k)
@@ -214,7 +220,7 @@ static void mem_avoid_memmap(enum parse_mode mode, char *str)
 
                if (start == 0) {
                        /* Store the specified memory limit if size > 0 */
-                       if (size > 0)
+                       if (size > 0 && size < mem_limit)
                                mem_limit = size;
 
                        continue;
@@ -261,15 +267,15 @@ static void parse_gb_huge_pages(char *param, char *val)
 static void handle_mem_options(void)
 {
        char *args = (char *)get_cmd_line_ptr();
-       size_t len = strlen((char *)args);
+       size_t len;
        char *tmp_cmdline;
        char *param, *val;
        u64 mem_size;
 
-       if (!strstr(args, "memmap=") && !strstr(args, "mem=") &&
-               !strstr(args, "hugepages"))
+       if (!args)
                return;
 
+       len = strnlen(args, COMMAND_LINE_SIZE-1);
        tmp_cmdline = malloc(len + 1);
        if (!tmp_cmdline)
                error("Failed to allocate space for tmp_cmdline");
@@ -284,14 +290,12 @@ static void handle_mem_options(void)
        while (*args) {
                args = next_arg(args, &param, &val);
                /* Stop at -- */
-               if (!val && strcmp(param, "--") == 0) {
-                       warn("Only '--' specified in cmdline");
-                       goto out;
-               }
+               if (!val && strcmp(param, "--") == 0)
+                       break;
 
                if (!strcmp(param, "memmap")) {
                        mem_avoid_memmap(PARSE_MEMMAP, val);
-               } else if (strstr(param, "hugepages")) {
+               } else if (IS_ENABLED(CONFIG_X86_64) && strstr(param, "hugepages")) {
                        parse_gb_huge_pages(param, val);
                } else if (!strcmp(param, "mem")) {
                        char *p = val;
@@ -300,21 +304,23 @@ static void handle_mem_options(void)
                                continue;
                        mem_size = memparse(p, &p);
                        if (mem_size == 0)
-                               goto out;
+                               break;
 
-                       mem_limit = mem_size;
+                       if (mem_size < mem_limit)
+                               mem_limit = mem_size;
                } else if (!strcmp(param, "efi_fake_mem")) {
                        mem_avoid_memmap(PARSE_EFI, val);
                }
        }
 
-out:
        free(tmp_cmdline);
        return;
 }
 
 /*
- * In theory, KASLR can put the kernel anywhere in the range of [16M, 64T).
+ * In theory, KASLR can put the kernel anywhere in the range of [16M, MAXMEM)
+ * on 64-bit, and [16M, KERNEL_IMAGE_SIZE) on 32-bit.
+ *
  * The mem_avoid array is used to store the ranges that need to be avoided
  * when KASLR searches for an appropriate random address. We must avoid any
  * regions that are unsafe to overlap with during decompression, and other
@@ -392,8 +398,7 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
 {
        unsigned long init_size = boot_params->hdr.init_size;
        u64 initrd_start, initrd_size;
-       u64 cmd_line, cmd_line_size;
-       char *ptr;
+       unsigned long cmd_line, cmd_line_size;
 
        /*
         * Avoid the region that is unsafe to overlap during
@@ -414,16 +419,15 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
        /* No need to set mapping for initrd, it will be handled in VO. */
 
        /* Avoid kernel command line. */
-       cmd_line  = (u64)boot_params->ext_cmd_line_ptr << 32;
-       cmd_line |= boot_params->hdr.cmd_line_ptr;
+       cmd_line = get_cmd_line_ptr();
        /* Calculate size of cmd_line. */
-       ptr = (char *)(unsigned long)cmd_line;
-       for (cmd_line_size = 0; ptr[cmd_line_size++];)
-               ;
-       mem_avoid[MEM_AVOID_CMDLINE].start = cmd_line;
-       mem_avoid[MEM_AVOID_CMDLINE].size = cmd_line_size;
-       add_identity_map(mem_avoid[MEM_AVOID_CMDLINE].start,
-                        mem_avoid[MEM_AVOID_CMDLINE].size);
+       if (cmd_line) {
+               cmd_line_size = strnlen((char *)cmd_line, COMMAND_LINE_SIZE-1) + 1;
+               mem_avoid[MEM_AVOID_CMDLINE].start = cmd_line;
+               mem_avoid[MEM_AVOID_CMDLINE].size = cmd_line_size;
+               add_identity_map(mem_avoid[MEM_AVOID_CMDLINE].start,
+                                mem_avoid[MEM_AVOID_CMDLINE].size);
+       }
 
        /* Avoid boot parameters. */
        mem_avoid[MEM_AVOID_BOOTPARAMS].start = (unsigned long)boot_params;
@@ -454,7 +458,7 @@ static bool mem_avoid_overlap(struct mem_vector *img,
 {
        int i;
        struct setup_data *ptr;
-       unsigned long earliest = img->start + img->size;
+       u64 earliest = img->start + img->size;
        bool is_overlapping = false;
 
        for (i = 0; i < MEM_AVOID_MAX; i++) {
@@ -499,18 +503,16 @@ static bool mem_avoid_overlap(struct mem_vector *img,
 }
 
 struct slot_area {
-       unsigned long addr;
-       int num;
+       u64 addr;
+       unsigned long num;
 };
 
 #define MAX_SLOT_AREA 100
 
 static struct slot_area slot_areas[MAX_SLOT_AREA];
-
+static unsigned int slot_area_index;
 static unsigned long slot_max;
 
-static unsigned long slot_area_index;
-
 static void store_slot_info(struct mem_vector *region, unsigned long image_size)
 {
        struct slot_area slot_area;
@@ -519,13 +521,10 @@ static void store_slot_info(struct mem_vector *region, unsigned long image_size)
                return;
 
        slot_area.addr = region->start;
-       slot_area.num = (region->size - image_size) /
-                       CONFIG_PHYSICAL_ALIGN + 1;
+       slot_area.num = 1 + (region->size - image_size) / CONFIG_PHYSICAL_ALIGN;
 
-       if (slot_area.num > 0) {
-               slot_areas[slot_area_index++] = slot_area;
-               slot_max += slot_area.num;
-       }
+       slot_areas[slot_area_index++] = slot_area;
+       slot_max += slot_area.num;
 }
 
 /*
@@ -535,57 +534,53 @@ static void store_slot_info(struct mem_vector *region, unsigned long image_size)
 static void
 process_gb_huge_pages(struct mem_vector *region, unsigned long image_size)
 {
-       unsigned long addr, size = 0;
+       u64 pud_start, pud_end;
+       unsigned long gb_huge_pages;
        struct mem_vector tmp;
-       int i = 0;
 
-       if (!max_gb_huge_pages) {
+       if (!IS_ENABLED(CONFIG_X86_64) || !max_gb_huge_pages) {
                store_slot_info(region, image_size);
                return;
        }
 
-       addr = ALIGN(region->start, PUD_SIZE);
-       /* Did we raise the address above the passed in memory entry? */
-       if (addr < region->start + region->size)
-               size = region->size - (addr - region->start);
-
-       /* Check how many 1GB huge pages can be filtered out: */
-       while (size > PUD_SIZE && max_gb_huge_pages) {
-               size -= PUD_SIZE;
-               max_gb_huge_pages--;
-               i++;
-       }
+       /* Are there any 1GB pages in the region? */
+       pud_start = ALIGN(region->start, PUD_SIZE);
+       pud_end = ALIGN_DOWN(region->start + region->size, PUD_SIZE);
 
        /* No good 1GB huge pages found: */
-       if (!i) {
+       if (pud_start >= pud_end) {
                store_slot_info(region, image_size);
                return;
        }
 
-       /*
-        * Skip those 'i'*1GB good huge pages, and continue checking and
-        * processing the remaining head or tail part of the passed region
-        * if available.
-        */
-
-       if (addr >= region->start + image_size) {
+       /* Check if the head part of the region is usable. */
+       if (pud_start >= region->start + image_size) {
                tmp.start = region->start;
-               tmp.size = addr - region->start;
+               tmp.size = pud_start - region->start;
                store_slot_info(&tmp, image_size);
        }
 
-       size  = region->size - (addr - region->start) - i * PUD_SIZE;
-       if (size >= image_size) {
-               tmp.start = addr + i * PUD_SIZE;
-               tmp.size = size;
+       /* Skip the good 1GB pages. */
+       gb_huge_pages = (pud_end - pud_start) >> PUD_SHIFT;
+       if (gb_huge_pages > max_gb_huge_pages) {
+               pud_end = pud_start + (max_gb_huge_pages << PUD_SHIFT);
+               max_gb_huge_pages = 0;
+       } else {
+               max_gb_huge_pages -= gb_huge_pages;
+       }
+
+       /* Check if the tail part of the region is usable. */
+       if (region->start + region->size >= pud_end + image_size) {
+               tmp.start = pud_end;
+               tmp.size = region->start + region->size - pud_end;
                store_slot_info(&tmp, image_size);
        }
 }
 
-static unsigned long slots_fetch_random(void)
+static u64 slots_fetch_random(void)
 {
        unsigned long slot;
-       int i;
+       unsigned int i;
 
        /* Handle case of no slots stored. */
        if (slot_max == 0)
@@ -598,7 +593,7 @@ static unsigned long slots_fetch_random(void)
                        slot -= slot_areas[i].num;
                        continue;
                }
-               return slot_areas[i].addr + slot * CONFIG_PHYSICAL_ALIGN;
+               return slot_areas[i].addr + ((u64)slot * CONFIG_PHYSICAL_ALIGN);
        }
 
        if (i == slot_area_index)
@@ -611,49 +606,23 @@ static void __process_mem_region(struct mem_vector *entry,
                                 unsigned long image_size)
 {
        struct mem_vector region, overlap;
-       unsigned long start_orig, end;
-       struct mem_vector cur_entry;
-
-       /* On 32-bit, ignore entries entirely above our maximum. */
-       if (IS_ENABLED(CONFIG_X86_32) && entry->start >= KERNEL_IMAGE_SIZE)
-               return;
+       u64 region_end;
 
-       /* Ignore entries entirely below our minimum. */
-       if (entry->start + entry->size < minimum)
-               return;
-
-       /* Ignore entries above memory limit */
-       end = min(entry->size + entry->start, mem_limit);
-       if (entry->start >= end)
-               return;
-       cur_entry.start = entry->start;
-       cur_entry.size = end - entry->start;
-
-       region.start = cur_entry.start;
-       region.size = cur_entry.size;
+       /* Enforce minimum and memory limit. */
+       region.start = max_t(u64, entry->start, minimum);
+       region_end = min(entry->start + entry->size, mem_limit);
 
        /* Give up if slot area array is full. */
        while (slot_area_index < MAX_SLOT_AREA) {
-               start_orig = region.start;
-
-               /* Potentially raise address to minimum location. */
-               if (region.start < minimum)
-                       region.start = minimum;
-
                /* Potentially raise address to meet alignment needs. */
                region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN);
 
                /* Did we raise the address above the passed in memory entry? */
-               if (region.start > cur_entry.start + cur_entry.size)
+               if (region.start > region_end)
                        return;
 
                /* Reduce size by any delta from the original address. */
-               region.size -= region.start - start_orig;
-
-               /* On 32-bit, reduce region size to fit within max size. */
-               if (IS_ENABLED(CONFIG_X86_32) &&
-                   region.start + region.size > KERNEL_IMAGE_SIZE)
-                       region.size = KERNEL_IMAGE_SIZE - region.start;
+               region.size = region_end - region.start;
 
                /* Return if region can't contain decompressed kernel */
                if (region.size < image_size)
@@ -666,27 +635,19 @@ static void __process_mem_region(struct mem_vector *entry,
                }
 
                /* Store beginning of region if holds at least image_size. */
-               if (overlap.start > region.start + image_size) {
-                       struct mem_vector beginning;
-
-                       beginning.start = region.start;
-                       beginning.size = overlap.start - region.start;
-                       process_gb_huge_pages(&beginning, image_size);
+               if (overlap.start >= region.start + image_size) {
+                       region.size = overlap.start - region.start;
+                       process_gb_huge_pages(&region, image_size);
                }
 
-               /* Return if overlap extends to or past end of region. */
-               if (overlap.start + overlap.size >= region.start + region.size)
-                       return;
-
                /* Clip off the overlapping region and start over. */
-               region.size -= overlap.start - region.start + overlap.size;
                region.start = overlap.start + overlap.size;
        }
 }
 
 static bool process_mem_region(struct mem_vector *region,
-                              unsigned long long minimum,
-                              unsigned long long image_size)
+                              unsigned long minimum,
+                              unsigned long image_size)
 {
        int i;
        /*
@@ -709,7 +670,7 @@ static bool process_mem_region(struct mem_vector *region,
         * immovable memory and @region.
         */
        for (i = 0; i < num_immovable_mem; i++) {
-               unsigned long long start, end, entry_end, region_end;
+               u64 start, end, entry_end, region_end;
                struct mem_vector entry;
 
                if (!mem_overlaps(region, &immovable_mem[i]))
@@ -736,8 +697,8 @@ static bool process_mem_region(struct mem_vector *region,
 
 #ifdef CONFIG_EFI
 /*
- * Returns true if mirror region found (and must have been processed
- * for slots adding)
+ * Returns true if we processed the EFI memmap, which we prefer over the E820
+ * table if it is available.
  */
 static bool
 process_efi_entries(unsigned long minimum, unsigned long image_size)
@@ -839,20 +800,30 @@ static void process_e820_entries(unsigned long minimum,
 static unsigned long find_random_phys_addr(unsigned long minimum,
                                           unsigned long image_size)
 {
+       u64 phys_addr;
+
+       /* Bail out early if it's impossible to succeed. */
+       if (minimum + image_size > mem_limit)
+               return 0;
+
        /* Check if we had too many memmaps. */
        if (memmap_too_large) {
                debug_putstr("Aborted memory entries scan (more than 4 memmap= args)!\n");
                return 0;
        }
 
-       /* Make sure minimum is aligned. */
-       minimum = ALIGN(minimum, CONFIG_PHYSICAL_ALIGN);
+       if (!process_efi_entries(minimum, image_size))
+               process_e820_entries(minimum, image_size);
 
-       if (process_efi_entries(minimum, image_size))
-               return slots_fetch_random();
+       phys_addr = slots_fetch_random();
 
-       process_e820_entries(minimum, image_size);
-       return slots_fetch_random();
+       /* Perform a final check to make sure the address is in range. */
+       if (phys_addr < minimum || phys_addr + image_size > mem_limit) {
+               warn("Invalid physical address chosen!\n");
+               return 0;
+       }
+
+       return (unsigned long)phys_addr;
 }
 
 static unsigned long find_random_virt_addr(unsigned long minimum,
@@ -860,18 +831,12 @@ static unsigned long find_random_virt_addr(unsigned long minimum,
 {
        unsigned long slots, random_addr;
 
-       /* Make sure minimum is aligned. */
-       minimum = ALIGN(minimum, CONFIG_PHYSICAL_ALIGN);
-       /* Align image_size for easy slot calculations. */
-       image_size = ALIGN(image_size, CONFIG_PHYSICAL_ALIGN);
-
        /*
         * There are how many CONFIG_PHYSICAL_ALIGN-sized slots
         * that can hold image_size within the range of minimum to
         * KERNEL_IMAGE_SIZE?
         */
-       slots = (KERNEL_IMAGE_SIZE - minimum - image_size) /
-                CONFIG_PHYSICAL_ALIGN + 1;
+       slots = 1 + (KERNEL_IMAGE_SIZE - minimum - image_size) / CONFIG_PHYSICAL_ALIGN;
 
        random_addr = kaslr_get_random_long("Virtual") % slots;
 
@@ -908,6 +873,11 @@ void choose_random_location(unsigned long input,
        /* Prepare to add new identity pagetables on demand. */
        initialize_identity_maps();
 
+       if (IS_ENABLED(CONFIG_X86_32))
+               mem_limit = KERNEL_IMAGE_SIZE;
+       else
+               mem_limit = MAXMEM;
+
        /* Record the various known unsafe memory ranges. */
        mem_avoid_init(input, input_size, *output);
 
@@ -917,6 +887,8 @@ void choose_random_location(unsigned long input,
         * location:
         */
        min_addr = min(*output, 512UL << 20);
+       /* Make sure minimum is aligned. */
+       min_addr = ALIGN(min_addr, CONFIG_PHYSICAL_ALIGN);
 
        /* Walk available memory entries to find a random address. */
        random_addr = find_random_phys_addr(min_addr, output_size);
index 726e264..3efce27 100644 (file)
@@ -70,8 +70,8 @@ int cmdline_find_option(const char *option, char *buffer, int bufsize);
 int cmdline_find_option_bool(const char *option);
 
 struct mem_vector {
-       unsigned long long start;
-       unsigned long long size;
+       u64 start;
+       u64 size;
 };
 
 #if CONFIG_RANDOMIZE_BASE
index 7e01248..52aa56c 100644 (file)
@@ -60,6 +60,12 @@ int main(int argc, char *argv[])
        printf(".incbin \"%s\"\n", argv[1]);
        printf("input_data_end:\n");
 
+       printf(".section \".rodata\",\"a\",@progbits\n");
+       printf(".globl input_len\n");
+       printf("input_len:\n\t.long %lu\n", ilen);
+       printf(".globl output_len\n");
+       printf("output_len:\n\t.long %lu\n", (unsigned long)olen);
+
        retval = 0;
 bail:
        if (f)
index 8f1025d..112b237 100644 (file)
@@ -42,12 +42,6 @@ SECTIONS
                *(.rodata.*)
                _erodata = . ;
        }
-       .got : {
-               _got = .;
-               KEEP(*(.got.plt))
-               KEEP(*(.got))
-               _egot = .;
-       }
        .data : {
                _data = . ;
                *(.data)
@@ -75,5 +69,49 @@ SECTIONS
        . = ALIGN(PAGE_SIZE);   /* keep ZO size page aligned */
        _end = .;
 
+       STABS_DEBUG
+       DWARF_DEBUG
+       ELF_DETAILS
+
        DISCARDS
+       /DISCARD/ : {
+               *(.dynamic) *(.dynsym) *(.dynstr) *(.dynbss)
+               *(.hash) *(.gnu.hash)
+               *(.note.*)
+       }
+
+       .got.plt (INFO) : {
+               *(.got.plt)
+       }
+       ASSERT(SIZEOF(.got.plt) == 0 ||
+#ifdef CONFIG_X86_64
+              SIZEOF(.got.plt) == 0x18,
+#else
+              SIZEOF(.got.plt) == 0xc,
+#endif
+              "Unexpected GOT/PLT entries detected!")
+
+       /*
+        * Sections that should stay zero sized, which is safer to
+        * explicitly check instead of blindly discarding.
+        */
+       .got : {
+               *(.got)
+       }
+       ASSERT(SIZEOF(.got) == 0, "Unexpected GOT entries detected!")
+
+       .plt : {
+               *(.plt) *(.plt.*)
+       }
+       ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!")
+
+       .rel.dyn : {
+               *(.rel.*) *(.rel_*)
+       }
+       ASSERT(SIZEOF(.rel.dyn) == 0, "Unexpected run-time relocations (.rel) detected!")
+
+       .rela.dyn : {
+               *(.rela.*) *(.rela_*)
+       }
+       ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!")
 }
index 24c9552..49546c2 100644 (file)
@@ -20,7 +20,7 @@ SECTIONS
        .initdata       : { *(.initdata) }
        __end_init = .;
 
-       .text           : { *(.text) }
+       .text           : { *(.text .text.*) }
        .text32         : { *(.text32) }
 
        . = ALIGN(16);
index c8b8c1a..a3725ad 100644 (file)
@@ -416,8 +416,6 @@ int main(int argc, char ** argv)
        /* Set the default root device */
        put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
 
-       printf("Setup is %d bytes (padded to %d bytes).\n", c, i);
-
        /* Open and stat the kernel file */
        fd = open(argv[2], O_RDONLY);
        if (fd < 0)
@@ -425,7 +423,6 @@ int main(int argc, char ** argv)
        if (fstat(fd, &sb))
                die("Unable to stat `%s': %m", argv[2]);
        sz = sb.st_size;
-       printf("System is %d kB\n", (sz+1023)/1024);
        kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
        if (kernel == MAP_FAILED)
                die("Unable to mmap '%s': %m", argv[2]);
@@ -488,7 +485,6 @@ int main(int argc, char ** argv)
        }
 
        /* Write the CRC */
-       printf("CRC %x\n", crc);
        put_unaligned_le32(crc, buf);
        if (fwrite(buf, 1, 4, dest) != 4)
                die("Writing CRC failed");
index d7577fe..7821079 100644 (file)
@@ -19,6 +19,7 @@ CONFIG_CGROUP_CPUACCT=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
+# CONFIG_64BIT is not set
 CONFIG_SMP=y
 CONFIG_X86_GENERIC=y
 CONFIG_HPET_TIMER=y
@@ -186,7 +187,6 @@ CONFIG_DRM_I915=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_EFI=y
-CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
index f856001..9936528 100644 (file)
@@ -181,7 +181,6 @@ CONFIG_DRM_I915=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_EFI=y
-CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
index 6737bce..c025a01 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/jump_label.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/sizes.h>
 
 #include <asm/cpufeature.h>
 #include <asm/fpu/api.h>
index e67a591..7b3a1cf 100644 (file)
@@ -12,6 +12,7 @@
 #include <crypto/internal/skcipher.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/sizes.h>
 #include <asm/simd.h>
 
 asmlinkage void chacha_block_xor_ssse3(u32 *state, u8 *dst, const u8 *src,
index d2d069b..feccb52 100644 (file)
@@ -28,9 +28,9 @@
 #define SCALE_F        sizeof(unsigned long)
 
 #ifdef CONFIG_X86_64
-#define REX_PRE "0x48, "
+#define CRC32_INST "crc32q %1, %q0"
 #else
-#define REX_PRE
+#define CRC32_INST "crc32l %1, %0"
 #endif
 
 #ifdef CONFIG_X86_64
@@ -48,11 +48,8 @@ asmlinkage unsigned int crc_pcl(const u8 *buffer, int len,
 static u32 crc32c_intel_le_hw_byte(u32 crc, unsigned char const *data, size_t length)
 {
        while (length--) {
-               __asm__ __volatile__(
-                       ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
-                       :"=S"(crc)
-                       :"0"(crc), "c"(*data)
-               );
+               asm("crc32b %1, %0"
+                   : "+r" (crc) : "rm" (*data));
                data++;
        }
 
@@ -66,11 +63,8 @@ static u32 __pure crc32c_intel_le_hw(u32 crc, unsigned char const *p, size_t len
        unsigned long *ptmp = (unsigned long *)p;
 
        while (iquotient--) {
-               __asm__ __volatile__(
-                       ".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;"
-                       :"=S"(crc)
-                       :"0"(crc), "c"(*ptmp)
-               );
+               asm(CRC32_INST
+                   : "+r" (crc) : "rm" (*ptmp));
                ptmp++;
        }
 
index 8acbb65..5af8021 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/jump_label.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/scatterlist.h>
 
 #include <asm/cpufeature.h>
 #include <asm/processor.h>
@@ -45,11 +46,11 @@ static inline u64 add_scalar(u64 *out, const u64 *f1, u64 f2)
 
        asm volatile(
                /* Clear registers to propagate the carry bit */
-               "  xor %%r8, %%r8;"
-               "  xor %%r9, %%r9;"
-               "  xor %%r10, %%r10;"
-               "  xor %%r11, %%r11;"
-               "  xor %1, %1;"
+               "  xor %%r8d, %%r8d;"
+               "  xor %%r9d, %%r9d;"
+               "  xor %%r10d, %%r10d;"
+               "  xor %%r11d, %%r11d;"
+               "  xor %k1, %k1;"
 
                /* Begin addition chain */
                "  addq 0(%3), %0;"
@@ -93,7 +94,7 @@ static inline void fadd(u64 *out, const u64 *f1, const u64 *f2)
                "  cmovc %0, %%rax;"
 
                /* Step 2: Add carry*38 to the original sum */
-               "  xor %%rcx, %%rcx;"
+               "  xor %%ecx, %%ecx;"
                "  add %%rax, %%r8;"
                "  adcx %%rcx, %%r9;"
                "  movq %%r9, 8(%1);"
@@ -165,28 +166,28 @@ static inline void fmul(u64 *out, const u64 *f1, const u64 *f2, u64 *tmp)
 
                /* Compute src1[0] * src2 */
                "  movq 0(%1), %%rdx;"
-               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 0(%0);"
+               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  movq %%r8, 0(%0);"
                "  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 8(%0);"
                "  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"
                "  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
                                                   "  adox %%rdx, %%rax;"
                /* Compute src1[1] * src2 */
                "  movq 8(%1), %%rdx;"
-               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
+               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
                "  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 16(%0);"
                "  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
                "  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
                                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
                /* Compute src1[2] * src2 */
                "  movq 16(%1), %%rdx;"
-               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 16(%0), %%r8;"    "  movq %%r8, 16(%0);"
+               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 16(%0), %%r8;"   "  movq %%r8, 16(%0);"
                "  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 24(%0);"
                "  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
                "  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
                                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
                /* Compute src1[3] * src2 */
                "  movq 24(%1), %%rdx;"
-               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 24(%0), %%r8;"    "  movq %%r8, 24(%0);"
+               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 24(%0), %%r8;"   "  movq %%r8, 24(%0);"
                "  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 32(%0);"
                "  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  movq %%rbx, 40(%0);"    "  mov $0, %%r8;"
                "  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 48(%0);"    "  mov $0, %%rax;"
@@ -200,7 +201,7 @@ static inline void fmul(u64 *out, const u64 *f1, const u64 *f2, u64 *tmp)
                /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
                "  mov $38, %%rdx;"
                "  mulxq 32(%1), %%r8, %%r13;"
-               "  xor %3, %3;"
+               "  xor %k3, %k3;"
                "  adoxq 0(%1), %%r8;"
                "  mulxq 40(%1), %%r9, %%rbx;"
                "  adcx %%r13, %%r9;"
@@ -246,28 +247,28 @@ static inline void fmul2(u64 *out, const u64 *f1, const u64 *f2, u64 *tmp)
 
                /* Compute src1[0] * src2 */
                "  movq 0(%1), %%rdx;"
-               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 0(%0);"
+               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  movq %%r8, 0(%0);"
                "  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 8(%0);"
                "  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"
                "  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
                                                   "  adox %%rdx, %%rax;"
                /* Compute src1[1] * src2 */
                "  movq 8(%1), %%rdx;"
-               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
+               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
                "  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 16(%0);"
                "  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
                "  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
                                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
                /* Compute src1[2] * src2 */
                "  movq 16(%1), %%rdx;"
-               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 16(%0), %%r8;"    "  movq %%r8, 16(%0);"
+               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 16(%0), %%r8;"   "  movq %%r8, 16(%0);"
                "  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 24(%0);"
                "  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
                "  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
                                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
                /* Compute src1[3] * src2 */
                "  movq 24(%1), %%rdx;"
-               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 24(%0), %%r8;"    "  movq %%r8, 24(%0);"
+               "  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 24(%0), %%r8;"   "  movq %%r8, 24(%0);"
                "  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 32(%0);"
                "  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  movq %%rbx, 40(%0);"    "  mov $0, %%r8;"
                "  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 48(%0);"    "  mov $0, %%rax;"
@@ -277,29 +278,29 @@ static inline void fmul2(u64 *out, const u64 *f1, const u64 *f2, u64 *tmp)
 
                /* Compute src1[0] * src2 */
                "  movq 32(%1), %%rdx;"
-               "  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 64(%0);"
-               "  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 72(%0);"
+               "  mulxq 32(%3), %%r8, %%r9;"      "  xor %%r10d, %%r10d;"   "  movq %%r8, 64(%0);"
+               "  mulxq 40(%3), %%r10, %%r11;"    "  adox %%r9, %%r10;"     "  movq %%r10, 72(%0);"
                "  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"
                "  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
                                                   "  adox %%rdx, %%rax;"
                /* Compute src1[1] * src2 */
                "  movq 40(%1), %%rdx;"
-               "  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 72(%0), %%r8;"    "  movq %%r8, 72(%0);"
-               "  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 80(%0);"
+               "  mulxq 32(%3), %%r8, %%r9;"      "  xor %%r10d, %%r10d;"   "  adcxq 72(%0), %%r8;"   "  movq %%r8, 72(%0);"
+               "  mulxq 40(%3), %%r10, %%r11;"    "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 80(%0);"
                "  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
                "  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
                                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
                /* Compute src1[2] * src2 */
                "  movq 48(%1), %%rdx;"
-               "  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 80(%0), %%r8;"    "  movq %%r8, 80(%0);"
-               "  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 88(%0);"
+               "  mulxq 32(%3), %%r8, %%r9;"      "  xor %%r10d, %%r10d;"   "  adcxq 80(%0), %%r8;"   "  movq %%r8, 80(%0);"
+               "  mulxq 40(%3), %%r10, %%r11;"    "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 88(%0);"
                "  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
                "  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
                                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
                /* Compute src1[3] * src2 */
                "  movq 56(%1), %%rdx;"
-               "  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 88(%0), %%r8;"    "  movq %%r8, 88(%0);"
-               "  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 96(%0);"
+               "  mulxq 32(%3), %%r8, %%r9;"      "  xor %%r10d, %%r10d;"   "  adcxq 88(%0), %%r8;"   "  movq %%r8, 88(%0);"
+               "  mulxq 40(%3), %%r10, %%r11;"    "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 96(%0);"
                "  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  movq %%rbx, 104(%0);"    "  mov $0, %%r8;"
                "  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 112(%0);"    "  mov $0, %%rax;"
                                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"     "  movq %%rax, 120(%0);"
@@ -312,7 +313,7 @@ static inline void fmul2(u64 *out, const u64 *f1, const u64 *f2, u64 *tmp)
                /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
                "  mov $38, %%rdx;"
                "  mulxq 32(%1), %%r8, %%r13;"
-               "  xor %3, %3;"
+               "  xor %k3, %k3;"
                "  adoxq 0(%1), %%r8;"
                "  mulxq 40(%1), %%r9, %%rbx;"
                "  adcx %%r13, %%r9;"
@@ -345,7 +346,7 @@ static inline void fmul2(u64 *out, const u64 *f1, const u64 *f2, u64 *tmp)
                /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
                "  mov $38, %%rdx;"
                "  mulxq 96(%1), %%r8, %%r13;"
-               "  xor %3, %3;"
+               "  xor %k3, %k3;"
                "  adoxq 64(%1), %%r8;"
                "  mulxq 104(%1), %%r9, %%rbx;"
                "  adcx %%r13, %%r9;"
@@ -516,7 +517,7 @@ static inline void fsqr(u64 *out, const u64 *f, u64 *tmp)
 
                /* Step 1: Compute all partial products */
                "  movq 0(%1), %%rdx;"                                       /* f[0] */
-               "  mulxq 8(%1), %%r8, %%r14;"      "  xor %%r15, %%r15;"     /* f[1]*f[0] */
+               "  mulxq 8(%1), %%r8, %%r14;"      "  xor %%r15d, %%r15d;"   /* f[1]*f[0] */
                "  mulxq 16(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
                "  mulxq 24(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
                "  movq 24(%1), %%rdx;"                                      /* f[3] */
@@ -526,7 +527,7 @@ static inline void fsqr(u64 *out, const u64 *f, u64 *tmp)
                "  mulxq 16(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
 
                /* Step 2: Compute two parallel carry chains */
-               "  xor %%r15, %%r15;"
+               "  xor %%r15d, %%r15d;"
                "  adox %%rax, %%r10;"
                "  adcx %%r8, %%r8;"
                "  adox %%rcx, %%r11;"
@@ -563,7 +564,7 @@ static inline void fsqr(u64 *out, const u64 *f, u64 *tmp)
                /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
                "  mov $38, %%rdx;"
                "  mulxq 32(%1), %%r8, %%r13;"
-               "  xor %%rcx, %%rcx;"
+               "  xor %%ecx, %%ecx;"
                "  adoxq 0(%1), %%r8;"
                "  mulxq 40(%1), %%r9, %%rbx;"
                "  adcx %%r13, %%r9;"
@@ -607,7 +608,7 @@ static inline void fsqr2(u64 *out, const u64 *f, u64 *tmp)
        asm volatile(
                /* Step 1: Compute all partial products */
                "  movq 0(%1), %%rdx;"                                       /* f[0] */
-               "  mulxq 8(%1), %%r8, %%r14;"      "  xor %%r15, %%r15;"     /* f[1]*f[0] */
+               "  mulxq 8(%1), %%r8, %%r14;"      "  xor %%r15d, %%r15d;"   /* f[1]*f[0] */
                "  mulxq 16(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
                "  mulxq 24(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
                "  movq 24(%1), %%rdx;"                                      /* f[3] */
@@ -617,7 +618,7 @@ static inline void fsqr2(u64 *out, const u64 *f, u64 *tmp)
                "  mulxq 16(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
 
                /* Step 2: Compute two parallel carry chains */
-               "  xor %%r15, %%r15;"
+               "  xor %%r15d, %%r15d;"
                "  adox %%rax, %%r10;"
                "  adcx %%r8, %%r8;"
                "  adox %%rcx, %%r11;"
@@ -647,7 +648,7 @@ static inline void fsqr2(u64 *out, const u64 *f, u64 *tmp)
 
                /* Step 1: Compute all partial products */
                "  movq 32(%1), %%rdx;"                                       /* f[0] */
-               "  mulxq 40(%1), %%r8, %%r14;"      "  xor %%r15, %%r15;"     /* f[1]*f[0] */
+               "  mulxq 40(%1), %%r8, %%r14;"     "  xor %%r15d, %%r15d;"   /* f[1]*f[0] */
                "  mulxq 48(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
                "  mulxq 56(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
                "  movq 56(%1), %%rdx;"                                      /* f[3] */
@@ -657,7 +658,7 @@ static inline void fsqr2(u64 *out, const u64 *f, u64 *tmp)
                "  mulxq 48(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
 
                /* Step 2: Compute two parallel carry chains */
-               "  xor %%r15, %%r15;"
+               "  xor %%r15d, %%r15d;"
                "  adox %%rax, %%r10;"
                "  adcx %%r8, %%r8;"
                "  adox %%rcx, %%r11;"
@@ -692,7 +693,7 @@ static inline void fsqr2(u64 *out, const u64 *f, u64 *tmp)
                /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
                "  mov $38, %%rdx;"
                "  mulxq 32(%1), %%r8, %%r13;"
-               "  xor %%rcx, %%rcx;"
+               "  xor %%ecx, %%ecx;"
                "  adoxq 0(%1), %%r8;"
                "  mulxq 40(%1), %%r9, %%rbx;"
                "  adcx %%r13, %%r9;"
@@ -725,7 +726,7 @@ static inline void fsqr2(u64 *out, const u64 *f, u64 *tmp)
                /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
                "  mov $38, %%rdx;"
                "  mulxq 96(%1), %%r8, %%r13;"
-               "  xor %%rcx, %%rcx;"
+               "  xor %%ecx, %%ecx;"
                "  adoxq 64(%1), %%r8;"
                "  mulxq 104(%1), %%r9, %%rbx;"
                "  adcx %%r13, %%r9;"
index 80fcb85..8ea5ab0 100644 (file)
@@ -10,6 +10,7 @@
 #include <crypto/internal/simd.h>
 #include <crypto/nhpoly1305.h>
 #include <linux/module.h>
+#include <linux/sizes.h>
 #include <asm/simd.h>
 
 asmlinkage void nh_avx2(const u32 *key, const u8 *message, size_t message_len,
index cc6b7c1..2b353d4 100644 (file)
@@ -10,6 +10,7 @@
 #include <crypto/internal/simd.h>
 #include <crypto/nhpoly1305.h>
 #include <linux/module.h>
+#include <linux/sizes.h>
 #include <asm/simd.h>
 
 asmlinkage void nh_sse2(const u32 *key, const u8 *message, size_t message_len,
index 137edcf..7d56801 100644 (file)
@@ -246,7 +246,7 @@ $code.=<<___ if (!$kernel);
 ___
 &declare_function("poly1305_init_x86_64", 32, 3);
 $code.=<<___;
-       xor     %rax,%rax
+       xor     %eax,%eax
        mov     %rax,0($ctx)            # initialize hash value
        mov     %rax,8($ctx)
        mov     %rax,16($ctx)
@@ -2853,7 +2853,7 @@ $code.=<<___;
 .type  poly1305_init_base2_44,\@function,3
 .align 32
 poly1305_init_base2_44:
-       xor     %rax,%rax
+       xor     %eax,%eax
        mov     %rax,0($ctx)            # initialize hash value
        mov     %rax,8($ctx)
        mov     %rax,16($ctx)
@@ -3947,7 +3947,7 @@ xor128_decrypt_n_pad:
        mov     \$16,$len
        sub     %r10,$len
        xor     %eax,%eax
-       xor     %r11,%r11
+       xor     %r11d,%r11d
 .Loop_dec_byte:
        mov     ($inp,$otp),%r11b
        mov     ($otp),%al
@@ -4085,7 +4085,7 @@ avx_handler:
        .long   0xa548f3fc              # cld; rep movsq
 
        mov     $disp,%rsi
-       xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
+       xor     %ecx,%ecx               # arg1, UNW_FLAG_NHANDLER
        mov     8(%rsi),%rdx            # arg2, disp->ImageBase
        mov     0(%rsi),%r8             # arg3, disp->ControlPc
        mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
index dfe921e..e508dbd 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/jump_label.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/sizes.h>
 #include <asm/intel-family.h>
 #include <asm/simd.h>
 
@@ -157,9 +158,6 @@ static unsigned int crypto_poly1305_setdctxkey(struct poly1305_desc_ctx *dctx,
                        dctx->s[1] = get_unaligned_le32(&inp[4]);
                        dctx->s[2] = get_unaligned_le32(&inp[8]);
                        dctx->s[3] = get_unaligned_le32(&inp[12]);
-                       inp += POLY1305_BLOCK_SIZE;
-                       len -= POLY1305_BLOCK_SIZE;
-                       acc += POLY1305_BLOCK_SIZE;
                        dctx->sset = true;
                }
        }
index ae9b0d4..07a9331 100644 (file)
@@ -6,7 +6,6 @@
 #include <asm/percpu.h>
 #include <asm/asm-offsets.h>
 #include <asm/processor-flags.h>
-#include <asm/inst.h>
 
 /*
 
index 48512c7..870efee 100644 (file)
@@ -60,16 +60,10 @@ __visible noinstr void do_syscall_64(unsigned long nr, struct pt_regs *regs)
 #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
 static __always_inline unsigned int syscall_32_enter(struct pt_regs *regs)
 {
-       unsigned int nr = (unsigned int)regs->orig_ax;
-
        if (IS_ENABLED(CONFIG_IA32_EMULATION))
                current_thread_info()->status |= TS_COMPAT;
-       /*
-        * Subtlety here: if ptrace pokes something larger than 2^32-1 into
-        * orig_ax, the unsigned int return value truncates it.  This may
-        * or may not be necessary, but it matches the old asm behavior.
-        */
-       return (unsigned int)syscall_enter_from_user_mode(regs, nr);
+
+       return (unsigned int)regs->orig_ax;
 }
 
 /*
@@ -91,15 +85,29 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 {
        unsigned int nr = syscall_32_enter(regs);
 
+       /*
+        * Subtlety here: if ptrace pokes something larger than 2^32-1 into
+        * orig_ax, the unsigned int return value truncates it.  This may
+        * or may not be necessary, but it matches the old asm behavior.
+        */
+       nr = (unsigned int)syscall_enter_from_user_mode(regs, nr);
+
        do_syscall_32_irqs_on(regs, nr);
        syscall_exit_to_user_mode(regs);
 }
 
 static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
 {
-       unsigned int nr = syscall_32_enter(regs);
+       unsigned int nr = syscall_32_enter(regs);
        int res;
 
+       /*
+        * This cannot use syscall_enter_from_user_mode() as it has to
+        * fetch EBP before invoking any of the syscall entry work
+        * functions.
+        */
+       syscall_enter_from_user_mode_prepare(regs);
+
        instrumentation_begin();
        /* Fetch EBP from where the vDSO stashed it. */
        if (IS_ENABLED(CONFIG_X86_64)) {
@@ -122,6 +130,9 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
                return false;
        }
 
+       /* The case truncates any ptrace induced syscall nr > 2^32 -1 */
+       nr = (unsigned int)syscall_enter_from_user_mode_work(regs, nr);
+
        /* Now this is just like a normal syscall. */
        do_syscall_32_irqs_on(regs, nr);
        syscall_exit_to_user_mode(regs);
@@ -288,7 +299,7 @@ __visible noinstr void xen_pv_evtchn_do_upcall(struct pt_regs *regs)
        old_regs = set_irq_regs(regs);
 
        instrumentation_begin();
-       run_on_irqstack_cond(__xen_pv_evtchn_do_upcall, NULL, regs);
+       run_on_irqstack_cond(__xen_pv_evtchn_do_upcall, regs);
        instrumentation_begin();
 
        set_irq_regs(old_regs);
index 70dea93..826e734 100644 (file)
 .code64
 .section .entry.text, "ax"
 
-#ifdef CONFIG_PARAVIRT
+#ifdef CONFIG_PARAVIRT_XXL
 SYM_CODE_START(native_usergs_sysret64)
        UNWIND_HINT_EMPTY
        swapgs
        sysretq
 SYM_CODE_END(native_usergs_sysret64)
-#endif /* CONFIG_PARAVIRT */
+#endif /* CONFIG_PARAVIRT_XXL */
 
 /*
  * 64-bit SYSCALL instruction entry. Up to 6 arguments in registers.
@@ -682,6 +682,8 @@ SYM_CODE_END(.Lbad_gs)
  * rdx: Function argument (can be NULL if none)
  */
 SYM_FUNC_START(asm_call_on_stack)
+SYM_INNER_LABEL(asm_call_sysvec_on_stack, SYM_L_GLOBAL)
+SYM_INNER_LABEL(asm_call_irq_on_stack, SYM_L_GLOBAL)
        /*
         * Save the frame pointer unconditionally. This allows the ORC
         * unwinder to handle the stack switch.
@@ -840,8 +842,9 @@ SYM_CODE_START_LOCAL(paranoid_entry)
         * retrieve and set the current CPUs kernel GSBASE. The stored value
         * has to be restored in paranoid_exit unconditionally.
         *
-        * The MSR write ensures that no subsequent load is based on a
-        * mispredicted GSBASE. No extra FENCE required.
+        * The unconditional write to GS base below ensures that no subsequent
+        * loads based on a mispredicted GS base can happen, therefore no LFENCE
+        * is needed here.
         */
        SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx
        ret
index 1583831..f2fe0a3 100644 (file)
  * Reuse the 64-bit entry points for the x32 versions that occupy different
  * slots in the syscall table.
  */
+#define __x32_sys_readv                __x64_sys_readv
+#define __x32_sys_writev       __x64_sys_writev
 #define __x32_sys_getsockopt   __x64_sys_getsockopt
 #define __x32_sys_setsockopt   __x64_sys_setsockopt
+#define __x32_sys_vmsplice     __x64_sys_vmsplice
+#define __x32_sys_process_vm_readv     __x64_sys_process_vm_readv
+#define __x32_sys_process_vm_writev    __x64_sys_process_vm_writev
 
 #define __SYSCALL_64(nr, sym)
 
index 9d11028..9b6931f 100644 (file)
@@ -32,7 +32,7 @@
 18     i386    oldstat                 sys_stat
 19     i386    lseek                   sys_lseek                       compat_sys_lseek
 20     i386    getpid                  sys_getpid
-21     i386    mount                   sys_mount                       compat_sys_mount
+21     i386    mount                   sys_mount
 22     i386    umount                  sys_oldumount
 23     i386    setuid                  sys_setuid16
 24     i386    getuid                  sys_getuid16
 128    i386    init_module             sys_init_module
 129    i386    delete_module           sys_delete_module
 130    i386    get_kernel_syms
-131    i386    quotactl                sys_quotactl                    compat_sys_quotactl32
+131    i386    quotactl                sys_quotactl
 132    i386    getpgid                 sys_getpgid
 133    i386    fchdir                  sys_fchdir
 134    i386    bdflush                 sys_bdflush
 142    i386    _newselect              sys_select                      compat_sys_select
 143    i386    flock                   sys_flock
 144    i386    msync                   sys_msync
-145    i386    readv                   sys_readv                       compat_sys_readv
-146    i386    writev                  sys_writev                      compat_sys_writev
+145    i386    readv                   sys_readv
+146    i386    writev                  sys_writev
 147    i386    getsid                  sys_getsid
 148    i386    fdatasync               sys_fdatasync
 149    i386    _sysctl                 sys_ni_syscall
 313    i386    splice                  sys_splice
 314    i386    sync_file_range         sys_ia32_sync_file_range
 315    i386    tee                     sys_tee
-316    i386    vmsplice                sys_vmsplice                    compat_sys_vmsplice
+316    i386    vmsplice                sys_vmsplice
 317    i386    move_pages              sys_move_pages                  compat_sys_move_pages
 318    i386    getcpu                  sys_getcpu
 319    i386    epoll_pwait             sys_epoll_pwait
 344    i386    syncfs                  sys_syncfs
 345    i386    sendmmsg                sys_sendmmsg                    compat_sys_sendmmsg
 346    i386    setns                   sys_setns
-347    i386    process_vm_readv        sys_process_vm_readv            compat_sys_process_vm_readv
-348    i386    process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
+347    i386    process_vm_readv        sys_process_vm_readv
+348    i386    process_vm_writev       sys_process_vm_writev
 349    i386    kcmp                    sys_kcmp
 350    i386    finit_module            sys_finit_module
 351    i386    sched_setattr           sys_sched_setattr
index f30d6ae..3478096 100644 (file)
 512    x32     rt_sigaction            compat_sys_rt_sigaction
 513    x32     rt_sigreturn            compat_sys_x32_rt_sigreturn
 514    x32     ioctl                   compat_sys_ioctl
-515    x32     readv                   compat_sys_readv
-516    x32     writev                  compat_sys_writev
+515    x32     readv                   sys_readv
+516    x32     writev                  sys_writev
 517    x32     recvfrom                compat_sys_recvfrom
 518    x32     sendmsg                 compat_sys_sendmsg
 519    x32     recvmsg                 compat_sys_recvmsg
 529    x32     waitid                  compat_sys_waitid
 530    x32     set_robust_list         compat_sys_set_robust_list
 531    x32     get_robust_list         compat_sys_get_robust_list
-532    x32     vmsplice                compat_sys_vmsplice
+532    x32     vmsplice                sys_vmsplice
 533    x32     move_pages              compat_sys_move_pages
 534    x32     preadv                  compat_sys_preadv64
 535    x32     pwritev                 compat_sys_pwritev64
 536    x32     rt_tgsigqueueinfo       compat_sys_rt_tgsigqueueinfo
 537    x32     recvmmsg                compat_sys_recvmmsg_time64
 538    x32     sendmmsg                compat_sys_sendmmsg
-539    x32     process_vm_readv        compat_sys_process_vm_readv
-540    x32     process_vm_writev       compat_sys_process_vm_writev
+539    x32     process_vm_readv        sys_process_vm_readv
+540    x32     process_vm_writev       sys_process_vm_writev
 541    x32     setsockopt              sys_setsockopt
 542    x32     getsockopt              sys_getsockopt
 543    x32     io_setup                compat_sys_io_setup
index 3a07ce3..f1f96d4 100644 (file)
@@ -29,11 +29,6 @@ SYM_CODE_START_NOALIGN(\name)
 SYM_CODE_END(\name)
        .endm
 
-#ifdef CONFIG_TRACE_IRQFLAGS
-       THUNK trace_hardirqs_on_thunk,trace_hardirqs_on_caller,1
-       THUNK trace_hardirqs_off_thunk,trace_hardirqs_off_caller,1
-#endif
-
 #ifdef CONFIG_PREEMPTION
        THUNK preempt_schedule_thunk, preempt_schedule
        THUNK preempt_schedule_notrace_thunk, preempt_schedule_notrace
index 84a4a73..283ed9d 100644 (file)
@@ -14,6 +14,7 @@
 #undef CONFIG_ILLEGAL_POINTER_VALUE
 #undef CONFIG_SPARSEMEM_VMEMMAP
 #undef CONFIG_NR_CPUS
+#undef CONFIG_PARAVIRT_XXL
 
 #define CONFIG_X86_32 1
 #define CONFIG_PGTABLE_LEVELS 2
index 26c3635..40669ea 100644 (file)
@@ -89,6 +89,7 @@ struct perf_ibs {
        u64                             max_period;
        unsigned long                   offset_mask[1];
        int                             offset_max;
+       unsigned int                    fetch_count_reset_broken : 1;
        struct cpu_perf_ibs __percpu    *pcpu;
 
        struct attribute                **format_attrs;
@@ -334,11 +335,18 @@ static u64 get_ibs_op_count(u64 config)
 {
        u64 count = 0;
 
-       if (config & IBS_OP_VAL)
-               count += (config & IBS_OP_MAX_CNT) << 4; /* cnt rolled over */
-
-       if (ibs_caps & IBS_CAPS_RDWROPCNT)
-               count += (config & IBS_OP_CUR_CNT) >> 32;
+       /*
+        * If the internal 27-bit counter rolled over, the count is MaxCnt
+        * and the lower 7 bits of CurCnt are randomized.
+        * Otherwise CurCnt has the full 27-bit current counter value.
+        */
+       if (config & IBS_OP_VAL) {
+               count = (config & IBS_OP_MAX_CNT) << 4;
+               if (ibs_caps & IBS_CAPS_OPCNTEXT)
+                       count += config & IBS_OP_MAX_CNT_EXT_MASK;
+       } else if (ibs_caps & IBS_CAPS_RDWROPCNT) {
+               count = (config & IBS_OP_CUR_CNT) >> 32;
+       }
 
        return count;
 }
@@ -363,7 +371,12 @@ perf_ibs_event_update(struct perf_ibs *perf_ibs, struct perf_event *event,
 static inline void perf_ibs_enable_event(struct perf_ibs *perf_ibs,
                                         struct hw_perf_event *hwc, u64 config)
 {
-       wrmsrl(hwc->config_base, hwc->config | config | perf_ibs->enable_mask);
+       u64 tmp = hwc->config | config;
+
+       if (perf_ibs->fetch_count_reset_broken)
+               wrmsrl(hwc->config_base, tmp & ~perf_ibs->enable_mask);
+
+       wrmsrl(hwc->config_base, tmp | perf_ibs->enable_mask);
 }
 
 /*
@@ -394,7 +407,7 @@ static void perf_ibs_start(struct perf_event *event, int flags)
        struct hw_perf_event *hwc = &event->hw;
        struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
        struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
-       u64 period;
+       u64 period, config = 0;
 
        if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
                return;
@@ -403,13 +416,19 @@ static void perf_ibs_start(struct perf_event *event, int flags)
        hwc->state = 0;
 
        perf_ibs_set_period(perf_ibs, hwc, &period);
+       if (perf_ibs == &perf_ibs_op && (ibs_caps & IBS_CAPS_OPCNTEXT)) {
+               config |= period & IBS_OP_MAX_CNT_EXT_MASK;
+               period &= ~IBS_OP_MAX_CNT_EXT_MASK;
+       }
+       config |= period >> 4;
+
        /*
         * Set STARTED before enabling the hardware, such that a subsequent NMI
         * must observe it.
         */
        set_bit(IBS_STARTED,    pcpu->state);
        clear_bit(IBS_STOPPING, pcpu->state);
-       perf_ibs_enable_event(perf_ibs, hwc, period >> 4);
+       perf_ibs_enable_event(perf_ibs, hwc, config);
 
        perf_event_update_userpage(event);
 }
@@ -577,7 +596,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
        struct perf_ibs_data ibs_data;
        int offset, size, check_rip, offset_max, throttle = 0;
        unsigned int msr;
-       u64 *buf, *config, period;
+       u64 *buf, *config, period, new_config = 0;
 
        if (!test_bit(IBS_STARTED, pcpu->state)) {
 fail:
@@ -626,18 +645,24 @@ fail:
                                       perf_ibs->offset_max,
                                       offset + 1);
        } while (offset < offset_max);
+       /*
+        * Read IbsBrTarget, IbsOpData4, and IbsExtdCtl separately
+        * depending on their availability.
+        * Can't add to offset_max as they are staggered
+        */
        if (event->attr.sample_type & PERF_SAMPLE_RAW) {
-               /*
-                * Read IbsBrTarget and IbsOpData4 separately
-                * depending on their availability.
-                * Can't add to offset_max as they are staggered
-                */
-               if (ibs_caps & IBS_CAPS_BRNTRGT) {
-                       rdmsrl(MSR_AMD64_IBSBRTARGET, *buf++);
-                       size++;
+               if (perf_ibs == &perf_ibs_op) {
+                       if (ibs_caps & IBS_CAPS_BRNTRGT) {
+                               rdmsrl(MSR_AMD64_IBSBRTARGET, *buf++);
+                               size++;
+                       }
+                       if (ibs_caps & IBS_CAPS_OPDATA4) {
+                               rdmsrl(MSR_AMD64_IBSOPDATA4, *buf++);
+                               size++;
+                       }
                }
-               if (ibs_caps & IBS_CAPS_OPDATA4) {
-                       rdmsrl(MSR_AMD64_IBSOPDATA4, *buf++);
+               if (perf_ibs == &perf_ibs_fetch && (ibs_caps & IBS_CAPS_FETCHCTLEXTD)) {
+                       rdmsrl(MSR_AMD64_ICIBSEXTDCTL, *buf++);
                        size++;
                }
        }
@@ -666,13 +691,17 @@ out:
        if (throttle) {
                perf_ibs_stop(event, 0);
        } else {
-               period >>= 4;
-
-               if ((ibs_caps & IBS_CAPS_RDWROPCNT) &&
-                   (*config & IBS_OP_CNT_CTL))
-                       period |= *config & IBS_OP_CUR_CNT_RAND;
+               if (perf_ibs == &perf_ibs_op) {
+                       if (ibs_caps & IBS_CAPS_OPCNTEXT) {
+                               new_config = period & IBS_OP_MAX_CNT_EXT_MASK;
+                               period &= ~IBS_OP_MAX_CNT_EXT_MASK;
+                       }
+                       if ((ibs_caps & IBS_CAPS_RDWROPCNT) && (*config & IBS_OP_CNT_CTL))
+                               new_config |= *config & IBS_OP_CUR_CNT_RAND;
+               }
+               new_config |= period >> 4;
 
-               perf_ibs_enable_event(perf_ibs, hwc, period);
+               perf_ibs_enable_event(perf_ibs, hwc, new_config);
        }
 
        perf_event_update_userpage(event);
@@ -733,12 +762,26 @@ static __init void perf_event_ibs_init(void)
 {
        struct attribute **attr = ibs_op_format_attrs;
 
+       /*
+        * Some chips fail to reset the fetch count when it is written; instead
+        * they need a 0-1 transition of IbsFetchEn.
+        */
+       if (boot_cpu_data.x86 >= 0x16 && boot_cpu_data.x86 <= 0x18)
+               perf_ibs_fetch.fetch_count_reset_broken = 1;
+
        perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch");
 
        if (ibs_caps & IBS_CAPS_OPCNT) {
                perf_ibs_op.config_mask |= IBS_OP_CNT_CTL;
                *attr++ = &format_attr_cnt_ctl.attr;
        }
+
+       if (ibs_caps & IBS_CAPS_OPCNTEXT) {
+               perf_ibs_op.max_period  |= IBS_OP_MAX_CNT_EXT_MASK;
+               perf_ibs_op.config_mask |= IBS_OP_MAX_CNT_EXT_MASK;
+               perf_ibs_op.cnt_mask    |= IBS_OP_MAX_CNT_EXT_MASK;
+       }
+
        perf_ibs_pmu_init(&perf_ibs_op, "ibs_op");
 
        register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs");
index fb61620..be50ef8 100644 (file)
@@ -379,7 +379,7 @@ static __init int _init_events_attrs(void)
        while (amd_iommu_v2_event_descs[i].attr.attr.name)
                i++;
 
-       attrs = kcalloc(i + 1, sizeof(struct attribute **), GFP_KERNEL);
+       attrs = kcalloc(i + 1, sizeof(*attrs), GFP_KERNEL);
        if (!attrs)
                return -ENOMEM;
 
index 76400c0..7f014d4 100644 (file)
@@ -181,28 +181,28 @@ static void amd_uncore_del(struct perf_event *event, int flags)
 }
 
 /*
- * Convert logical CPU number to L3 PMC Config ThreadMask format
+ * Return a full thread and slice mask unless user
+ * has provided them
  */
-static u64 l3_thread_slice_mask(int cpu)
+static u64 l3_thread_slice_mask(u64 config)
 {
-       u64 thread_mask, core = topology_core_id(cpu);
-       unsigned int shift, thread = 0;
+       if (boot_cpu_data.x86 <= 0x18)
+               return ((config & AMD64_L3_SLICE_MASK) ? : AMD64_L3_SLICE_MASK) |
+                      ((config & AMD64_L3_THREAD_MASK) ? : AMD64_L3_THREAD_MASK);
 
-       if (topology_smt_supported() && !topology_is_primary_thread(cpu))
-               thread = 1;
-
-       if (boot_cpu_data.x86 <= 0x18) {
-               shift = AMD64_L3_THREAD_SHIFT + 2 * (core % 4) + thread;
-               thread_mask = BIT_ULL(shift);
-
-               return AMD64_L3_SLICE_MASK | thread_mask;
-       }
-
-       core = (core << AMD64_L3_COREID_SHIFT) & AMD64_L3_COREID_MASK;
-       shift = AMD64_L3_THREAD_SHIFT + thread;
-       thread_mask = BIT_ULL(shift);
+       /*
+        * If the user doesn't specify a threadmask, they're not trying to
+        * count core 0, so we enable all cores & threads.
+        * We'll also assume that they want to count slice 0 if they specify
+        * a threadmask and leave sliceid and enallslices unpopulated.
+        */
+       if (!(config & AMD64_L3_F19H_THREAD_MASK))
+               return AMD64_L3_F19H_THREAD_MASK | AMD64_L3_EN_ALL_SLICES |
+                      AMD64_L3_EN_ALL_CORES;
 
-       return AMD64_L3_EN_ALL_SLICES | core | thread_mask;
+       return config & (AMD64_L3_F19H_THREAD_MASK | AMD64_L3_SLICEID_MASK |
+                        AMD64_L3_EN_ALL_CORES | AMD64_L3_EN_ALL_SLICES |
+                        AMD64_L3_COREID_MASK);
 }
 
 static int amd_uncore_event_init(struct perf_event *event)
@@ -232,7 +232,7 @@ static int amd_uncore_event_init(struct perf_event *event)
         * For other events, the two fields do not affect the count.
         */
        if (l3_mask && is_llc_event(event))
-               hwc->config |= l3_thread_slice_mask(event->cpu);
+               hwc->config |= l3_thread_slice_mask(event->attr.config);
 
        uncore = event_to_amd_uncore(event);
        if (!uncore)
@@ -274,47 +274,72 @@ static struct attribute_group amd_uncore_attr_group = {
        .attrs = amd_uncore_attrs,
 };
 
-/*
- * Similar to PMU_FORMAT_ATTR but allowing for format_attr to be assigned based
- * on family
- */
-#define AMD_FORMAT_ATTR(_dev, _name, _format)                               \
-static ssize_t                                                              \
-_dev##_show##_name(struct device *dev,                                      \
-               struct device_attribute *attr,                               \
-               char *page)                                                  \
-{                                                                           \
-       BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);                          \
-       return sprintf(page, _format "\n");                                  \
-}                                                                           \
-static struct device_attribute format_attr_##_dev##_name = __ATTR_RO(_dev);
-
-/* Used for each uncore counter type */
-#define AMD_ATTRIBUTE(_name)                                                \
-static struct attribute *amd_uncore_format_attr_##_name[] = {               \
-       &format_attr_event_##_name.attr,                                     \
-       &format_attr_umask.attr,                                             \
-       NULL,                                                                \
-};                                                                          \
-static struct attribute_group amd_uncore_format_group_##_name = {           \
-       .name = "format",                                                    \
-       .attrs = amd_uncore_format_attr_##_name,                             \
-};                                                                          \
-static const struct attribute_group *amd_uncore_attr_groups_##_name[] = {    \
-       &amd_uncore_attr_group,                                              \
-       &amd_uncore_format_group_##_name,                                    \
-       NULL,                                                                \
+#define DEFINE_UNCORE_FORMAT_ATTR(_var, _name, _format)                        \
+static ssize_t __uncore_##_var##_show(struct kobject *kobj,            \
+                               struct kobj_attribute *attr,            \
+                               char *page)                             \
+{                                                                      \
+       BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);                     \
+       return sprintf(page, _format "\n");                             \
+}                                                                      \
+static struct kobj_attribute format_attr_##_var =                      \
+       __ATTR(_name, 0444, __uncore_##_var##_show, NULL)
+
+DEFINE_UNCORE_FORMAT_ATTR(event12,     event,          "config:0-7,32-35");
+DEFINE_UNCORE_FORMAT_ATTR(event14,     event,          "config:0-7,32-35,59-60"); /* F17h+ DF */
+DEFINE_UNCORE_FORMAT_ATTR(event8,      event,          "config:0-7");             /* F17h+ L3 */
+DEFINE_UNCORE_FORMAT_ATTR(umask,       umask,          "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(coreid,      coreid,         "config:42-44");           /* F19h L3 */
+DEFINE_UNCORE_FORMAT_ATTR(slicemask,   slicemask,      "config:48-51");           /* F17h L3 */
+DEFINE_UNCORE_FORMAT_ATTR(threadmask8, threadmask,     "config:56-63");           /* F17h L3 */
+DEFINE_UNCORE_FORMAT_ATTR(threadmask2, threadmask,     "config:56-57");           /* F19h L3 */
+DEFINE_UNCORE_FORMAT_ATTR(enallslices, enallslices,    "config:46");              /* F19h L3 */
+DEFINE_UNCORE_FORMAT_ATTR(enallcores,  enallcores,     "config:47");              /* F19h L3 */
+DEFINE_UNCORE_FORMAT_ATTR(sliceid,     sliceid,        "config:48-50");           /* F19h L3 */
+
+static struct attribute *amd_uncore_df_format_attr[] = {
+       &format_attr_event12.attr, /* event14 if F17h+ */
+       &format_attr_umask.attr,
+       NULL,
+};
+
+static struct attribute *amd_uncore_l3_format_attr[] = {
+       &format_attr_event12.attr, /* event8 if F17h+ */
+       &format_attr_umask.attr,
+       NULL, /* slicemask if F17h,     coreid if F19h */
+       NULL, /* threadmask8 if F17h,   enallslices if F19h */
+       NULL, /*                        enallcores if F19h */
+       NULL, /*                        sliceid if F19h */
+       NULL, /*                        threadmask2 if F19h */
+       NULL,
+};
+
+static struct attribute_group amd_uncore_df_format_group = {
+       .name = "format",
+       .attrs = amd_uncore_df_format_attr,
 };
 
-AMD_FORMAT_ATTR(event, , "config:0-7,32-35");
-AMD_FORMAT_ATTR(umask, , "config:8-15");
-AMD_FORMAT_ATTR(event, _df, "config:0-7,32-35,59-60");
-AMD_FORMAT_ATTR(event, _l3, "config:0-7");
-AMD_ATTRIBUTE(df);
-AMD_ATTRIBUTE(l3);
+static struct attribute_group amd_uncore_l3_format_group = {
+       .name = "format",
+       .attrs = amd_uncore_l3_format_attr,
+};
+
+static const struct attribute_group *amd_uncore_df_attr_groups[] = {
+       &amd_uncore_attr_group,
+       &amd_uncore_df_format_group,
+       NULL,
+};
+
+static const struct attribute_group *amd_uncore_l3_attr_groups[] = {
+       &amd_uncore_attr_group,
+       &amd_uncore_l3_format_group,
+       NULL,
+};
 
 static struct pmu amd_nb_pmu = {
        .task_ctx_nr    = perf_invalid_context,
+       .attr_groups    = amd_uncore_df_attr_groups,
+       .name           = "amd_nb",
        .event_init     = amd_uncore_event_init,
        .add            = amd_uncore_add,
        .del            = amd_uncore_del,
@@ -326,6 +351,8 @@ static struct pmu amd_nb_pmu = {
 
 static struct pmu amd_llc_pmu = {
        .task_ctx_nr    = perf_invalid_context,
+       .attr_groups    = amd_uncore_l3_attr_groups,
+       .name           = "amd_l2",
        .event_init     = amd_uncore_event_init,
        .add            = amd_uncore_add,
        .del            = amd_uncore_del,
@@ -529,6 +556,8 @@ static int amd_uncore_cpu_dead(unsigned int cpu)
 
 static int __init amd_uncore_init(void)
 {
+       struct attribute **df_attr = amd_uncore_df_format_attr;
+       struct attribute **l3_attr = amd_uncore_l3_format_attr;
        int ret = -ENODEV;
 
        if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
@@ -538,6 +567,8 @@ static int __init amd_uncore_init(void)
        if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
                return -ENODEV;
 
+       num_counters_nb = NUM_COUNTERS_NB;
+       num_counters_llc = NUM_COUNTERS_L2;
        if (boot_cpu_data.x86 >= 0x17) {
                /*
                 * For F17h and above, the Northbridge counters are
@@ -545,27 +576,16 @@ static int __init amd_uncore_init(void)
                 * counters are supported too. The PMUs are exported
                 * based on family as either L2 or L3 and NB or DF.
                 */
-               num_counters_nb           = NUM_COUNTERS_NB;
                num_counters_llc          = NUM_COUNTERS_L3;
                amd_nb_pmu.name           = "amd_df";
                amd_llc_pmu.name          = "amd_l3";
-               format_attr_event_df.show = &event_show_df;
-               format_attr_event_l3.show = &event_show_l3;
                l3_mask                   = true;
-       } else {
-               num_counters_nb           = NUM_COUNTERS_NB;
-               num_counters_llc          = NUM_COUNTERS_L2;
-               amd_nb_pmu.name           = "amd_nb";
-               amd_llc_pmu.name          = "amd_l2";
-               format_attr_event_df      = format_attr_event;
-               format_attr_event_l3      = format_attr_event;
-               l3_mask                   = false;
        }
 
-       amd_nb_pmu.attr_groups  = amd_uncore_attr_groups_df;
-       amd_llc_pmu.attr_groups = amd_uncore_attr_groups_l3;
-
        if (boot_cpu_has(X86_FEATURE_PERFCTR_NB)) {
+               if (boot_cpu_data.x86 >= 0x17)
+                       *df_attr = &format_attr_event14.attr;
+
                amd_uncore_nb = alloc_percpu(struct amd_uncore *);
                if (!amd_uncore_nb) {
                        ret = -ENOMEM;
@@ -575,13 +595,29 @@ static int __init amd_uncore_init(void)
                if (ret)
                        goto fail_nb;
 
-               pr_info("%s NB counters detected\n",
-                       boot_cpu_data.x86_vendor == X86_VENDOR_HYGON ?
-                               "HYGON" : "AMD");
+               pr_info("%d %s %s counters detected\n", num_counters_nb,
+                       boot_cpu_data.x86_vendor == X86_VENDOR_HYGON ?  "HYGON" : "",
+                       amd_nb_pmu.name);
+
                ret = 0;
        }
 
        if (boot_cpu_has(X86_FEATURE_PERFCTR_LLC)) {
+               if (boot_cpu_data.x86 >= 0x19) {
+                       *l3_attr++ = &format_attr_event8.attr;
+                       *l3_attr++ = &format_attr_umask.attr;
+                       *l3_attr++ = &format_attr_coreid.attr;
+                       *l3_attr++ = &format_attr_enallslices.attr;
+                       *l3_attr++ = &format_attr_enallcores.attr;
+                       *l3_attr++ = &format_attr_sliceid.attr;
+                       *l3_attr++ = &format_attr_threadmask2.attr;
+               } else if (boot_cpu_data.x86 >= 0x17) {
+                       *l3_attr++ = &format_attr_event8.attr;
+                       *l3_attr++ = &format_attr_umask.attr;
+                       *l3_attr++ = &format_attr_slicemask.attr;
+                       *l3_attr++ = &format_attr_threadmask8.attr;
+               }
+
                amd_uncore_llc = alloc_percpu(struct amd_uncore *);
                if (!amd_uncore_llc) {
                        ret = -ENOMEM;
@@ -591,9 +627,9 @@ static int __init amd_uncore_init(void)
                if (ret)
                        goto fail_llc;
 
-               pr_info("%s LLC counters detected\n",
-                       boot_cpu_data.x86_vendor == X86_VENDOR_HYGON ?
-                               "HYGON" : "AMD");
+               pr_info("%d %s %s counters detected\n", num_counters_llc,
+                       boot_cpu_data.x86_vendor == X86_VENDOR_HYGON ?  "HYGON" : "",
+                       amd_llc_pmu.name);
                ret = 0;
        }
 
index 1cbf57d..a88c94d 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/nospec.h>
+#include <linux/static_call.h>
 
 #include <asm/apic.h>
 #include <asm/stacktrace.h>
@@ -52,6 +53,34 @@ DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
 DEFINE_STATIC_KEY_FALSE(rdpmc_never_available_key);
 DEFINE_STATIC_KEY_FALSE(rdpmc_always_available_key);
 
+/*
+ * This here uses DEFINE_STATIC_CALL_NULL() to get a static_call defined
+ * from just a typename, as opposed to an actual function.
+ */
+DEFINE_STATIC_CALL_NULL(x86_pmu_handle_irq,  *x86_pmu.handle_irq);
+DEFINE_STATIC_CALL_NULL(x86_pmu_disable_all, *x86_pmu.disable_all);
+DEFINE_STATIC_CALL_NULL(x86_pmu_enable_all,  *x86_pmu.enable_all);
+DEFINE_STATIC_CALL_NULL(x86_pmu_enable,             *x86_pmu.enable);
+DEFINE_STATIC_CALL_NULL(x86_pmu_disable,     *x86_pmu.disable);
+
+DEFINE_STATIC_CALL_NULL(x86_pmu_add,  *x86_pmu.add);
+DEFINE_STATIC_CALL_NULL(x86_pmu_del,  *x86_pmu.del);
+DEFINE_STATIC_CALL_NULL(x86_pmu_read, *x86_pmu.read);
+
+DEFINE_STATIC_CALL_NULL(x86_pmu_schedule_events,       *x86_pmu.schedule_events);
+DEFINE_STATIC_CALL_NULL(x86_pmu_get_event_constraints, *x86_pmu.get_event_constraints);
+DEFINE_STATIC_CALL_NULL(x86_pmu_put_event_constraints, *x86_pmu.put_event_constraints);
+
+DEFINE_STATIC_CALL_NULL(x86_pmu_start_scheduling,  *x86_pmu.start_scheduling);
+DEFINE_STATIC_CALL_NULL(x86_pmu_commit_scheduling, *x86_pmu.commit_scheduling);
+DEFINE_STATIC_CALL_NULL(x86_pmu_stop_scheduling,   *x86_pmu.stop_scheduling);
+
+DEFINE_STATIC_CALL_NULL(x86_pmu_sched_task,    *x86_pmu.sched_task);
+DEFINE_STATIC_CALL_NULL(x86_pmu_swap_task_ctx, *x86_pmu.swap_task_ctx);
+
+DEFINE_STATIC_CALL_NULL(x86_pmu_drain_pebs,   *x86_pmu.drain_pebs);
+DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_aliases, *x86_pmu.pebs_aliases);
+
 u64 __read_mostly hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
@@ -76,6 +105,9 @@ u64 x86_perf_event_update(struct perf_event *event)
        if (unlikely(!hwc->event_base))
                return 0;
 
+       if (unlikely(is_topdown_count(event)) && x86_pmu.update_topdown_event)
+               return x86_pmu.update_topdown_event(event);
+
        /*
         * Careful: an NMI might modify the previous event value.
         *
@@ -660,7 +692,7 @@ static void x86_pmu_disable(struct pmu *pmu)
        cpuc->enabled = 0;
        barrier();
 
-       x86_pmu.disable_all();
+       static_call(x86_pmu_disable_all)();
 }
 
 void x86_pmu_enable_all(int added)
@@ -907,8 +939,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
        if (cpuc->txn_flags & PERF_PMU_TXN_ADD)
                n0 -= cpuc->n_txn;
 
-       if (x86_pmu.start_scheduling)
-               x86_pmu.start_scheduling(cpuc);
+       static_call_cond(x86_pmu_start_scheduling)(cpuc);
 
        for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) {
                c = cpuc->event_constraint[i];
@@ -925,7 +956,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
                 * change due to external factors (sibling state, allow_tfa).
                 */
                if (!c || (c->flags & PERF_X86_EVENT_DYNAMIC)) {
-                       c = x86_pmu.get_event_constraints(cpuc, i, cpuc->event_list[i]);
+                       c = static_call(x86_pmu_get_event_constraints)(cpuc, i, cpuc->event_list[i]);
                        cpuc->event_constraint[i] = c;
                }
 
@@ -1008,8 +1039,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
        if (!unsched && assign) {
                for (i = 0; i < n; i++) {
                        e = cpuc->event_list[i];
-                       if (x86_pmu.commit_scheduling)
-                               x86_pmu.commit_scheduling(cpuc, i, assign[i]);
+                       static_call_cond(x86_pmu_commit_scheduling)(cpuc, i, assign[i]);
                }
        } else {
                for (i = n0; i < n; i++) {
@@ -1018,19 +1048,56 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
                        /*
                         * release events that failed scheduling
                         */
-                       if (x86_pmu.put_event_constraints)
-                               x86_pmu.put_event_constraints(cpuc, e);
+                       static_call_cond(x86_pmu_put_event_constraints)(cpuc, e);
 
                        cpuc->event_constraint[i] = NULL;
                }
        }
 
-       if (x86_pmu.stop_scheduling)
-               x86_pmu.stop_scheduling(cpuc);
+       static_call_cond(x86_pmu_stop_scheduling)(cpuc);
 
        return unsched ? -EINVAL : 0;
 }
 
+static int add_nr_metric_event(struct cpu_hw_events *cpuc,
+                              struct perf_event *event)
+{
+       if (is_metric_event(event)) {
+               if (cpuc->n_metric == INTEL_TD_METRIC_NUM)
+                       return -EINVAL;
+               cpuc->n_metric++;
+               cpuc->n_txn_metric++;
+       }
+
+       return 0;
+}
+
+static void del_nr_metric_event(struct cpu_hw_events *cpuc,
+                               struct perf_event *event)
+{
+       if (is_metric_event(event))
+               cpuc->n_metric--;
+}
+
+static int collect_event(struct cpu_hw_events *cpuc, struct perf_event *event,
+                        int max_count, int n)
+{
+
+       if (x86_pmu.intel_cap.perf_metrics && add_nr_metric_event(cpuc, event))
+               return -EINVAL;
+
+       if (n >= max_count + cpuc->n_metric)
+               return -EINVAL;
+
+       cpuc->event_list[n] = event;
+       if (is_counter_pair(&event->hw)) {
+               cpuc->n_pair++;
+               cpuc->n_txn_pair++;
+       }
+
+       return 0;
+}
+
 /*
  * dogrp: true if must collect siblings events (group)
  * returns total number of events and error code
@@ -1067,28 +1134,22 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader,
        }
 
        if (is_x86_event(leader)) {
-               if (n >= max_count)
+               if (collect_event(cpuc, leader, max_count, n))
                        return -EINVAL;
-               cpuc->event_list[n] = leader;
                n++;
-               if (is_counter_pair(&leader->hw))
-                       cpuc->n_pair++;
        }
+
        if (!dogrp)
                return n;
 
        for_each_sibling_event(event, leader) {
-               if (!is_x86_event(event) ||
-                   event->state <= PERF_EVENT_STATE_OFF)
+               if (!is_x86_event(event) || event->state <= PERF_EVENT_STATE_OFF)
                        continue;
 
-               if (n >= max_count)
+               if (collect_event(cpuc, event, max_count, n))
                        return -EINVAL;
 
-               cpuc->event_list[n] = event;
                n++;
-               if (is_counter_pair(&event->hw))
-                       cpuc->n_pair++;
        }
        return n;
 }
@@ -1110,11 +1171,16 @@ static inline void x86_assign_hw_event(struct perf_event *event,
                hwc->event_base = 0;
                break;
 
+       case INTEL_PMC_IDX_METRIC_BASE ... INTEL_PMC_IDX_METRIC_END:
+               /* All the metric events are mapped onto the fixed counter 3. */
+               idx = INTEL_PMC_IDX_FIXED_SLOTS;
+               /* fall through */
        case INTEL_PMC_IDX_FIXED ... INTEL_PMC_IDX_FIXED_BTS-1:
                hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
                hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0 +
                                (idx - INTEL_PMC_IDX_FIXED);
-               hwc->event_base_rdpmc = (idx - INTEL_PMC_IDX_FIXED) | 1<<30;
+               hwc->event_base_rdpmc = (idx - INTEL_PMC_IDX_FIXED) |
+                                       INTEL_PMC_FIXED_RDPMC_BASE;
                break;
 
        default:
@@ -1226,7 +1292,7 @@ static void x86_pmu_enable(struct pmu *pmu)
        cpuc->enabled = 1;
        barrier();
 
-       x86_pmu.enable_all(added);
+       static_call(x86_pmu_enable_all)(added);
 }
 
 static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left);
@@ -1245,6 +1311,10 @@ int x86_perf_event_set_period(struct perf_event *event)
        if (unlikely(!hwc->event_base))
                return 0;
 
+       if (unlikely(is_topdown_count(event)) &&
+           x86_pmu.set_topdown_event_period)
+               return x86_pmu.set_topdown_event_period(event);
+
        /*
         * If we are way outside a reasonable range then just skip forward:
         */
@@ -1284,11 +1354,11 @@ int x86_perf_event_set_period(struct perf_event *event)
        wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask);
 
        /*
-        * Clear the Merge event counter's upper 16 bits since
+        * Sign extend the Merge event counter's upper 16 bits since
         * we currently declare a 48-bit counter width
         */
        if (is_counter_pair(hwc))
-               wrmsrl(x86_pmu_event_addr(idx + 1), 0);
+               wrmsrl(x86_pmu_event_addr(idx + 1), 0xffff);
 
        /*
         * Due to erratum on certan cpu we need
@@ -1347,7 +1417,7 @@ static int x86_pmu_add(struct perf_event *event, int flags)
        if (cpuc->txn_flags & PERF_PMU_TXN_ADD)
                goto done_collect;
 
-       ret = x86_pmu.schedule_events(cpuc, n, assign);
+       ret = static_call(x86_pmu_schedule_events)(cpuc, n, assign);
        if (ret)
                goto out;
        /*
@@ -1365,13 +1435,11 @@ done_collect:
        cpuc->n_added += n - n0;
        cpuc->n_txn += n - n0;
 
-       if (x86_pmu.add) {
-               /*
-                * This is before x86_pmu_enable() will call x86_pmu_start(),
-                * so we enable LBRs before an event needs them etc..
-                */
-               x86_pmu.add(event);
-       }
+       /*
+        * This is before x86_pmu_enable() will call x86_pmu_start(),
+        * so we enable LBRs before an event needs them etc..
+        */
+       static_call_cond(x86_pmu_add)(event);
 
        ret = 0;
 out:
@@ -1399,7 +1467,7 @@ static void x86_pmu_start(struct perf_event *event, int flags)
        cpuc->events[idx] = event;
        __set_bit(idx, cpuc->active_mask);
        __set_bit(idx, cpuc->running);
-       x86_pmu.enable(event);
+       static_call(x86_pmu_enable)(event);
        perf_event_update_userpage(event);
 }
 
@@ -1469,7 +1537,7 @@ void x86_pmu_stop(struct perf_event *event, int flags)
        struct hw_perf_event *hwc = &event->hw;
 
        if (test_bit(hwc->idx, cpuc->active_mask)) {
-               x86_pmu.disable(event);
+               static_call(x86_pmu_disable)(event);
                __clear_bit(hwc->idx, cpuc->active_mask);
                cpuc->events[hwc->idx] = NULL;
                WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
@@ -1519,8 +1587,7 @@ static void x86_pmu_del(struct perf_event *event, int flags)
        if (i >= cpuc->n_events - cpuc->n_added)
                --cpuc->n_added;
 
-       if (x86_pmu.put_event_constraints)
-               x86_pmu.put_event_constraints(cpuc, event);
+       static_call_cond(x86_pmu_put_event_constraints)(cpuc, event);
 
        /* Delete the array entry. */
        while (++i < cpuc->n_events) {
@@ -1529,17 +1596,18 @@ static void x86_pmu_del(struct perf_event *event, int flags)
        }
        cpuc->event_constraint[i-1] = NULL;
        --cpuc->n_events;
+       if (x86_pmu.intel_cap.perf_metrics)
+               del_nr_metric_event(cpuc, event);
 
        perf_event_update_userpage(event);
 
 do_del:
-       if (x86_pmu.del) {
-               /*
-                * This is after x86_pmu_stop(); so we disable LBRs after any
-                * event can need them etc..
-                */
-               x86_pmu.del(event);
-       }
+
+       /*
+        * This is after x86_pmu_stop(); so we disable LBRs after any
+        * event can need them etc..
+        */
+       static_call_cond(x86_pmu_del)(event);
 }
 
 int x86_pmu_handle_irq(struct pt_regs *regs)
@@ -1617,7 +1685,7 @@ perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs)
                return NMI_DONE;
 
        start_clock = sched_clock();
-       ret = x86_pmu.handle_irq(regs);
+       ret = static_call(x86_pmu_handle_irq)(regs);
        finish_clock = sched_clock();
 
        perf_sample_event_took(finish_clock - start_clock);
@@ -1830,6 +1898,38 @@ ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event)
 static struct attribute_group x86_pmu_attr_group;
 static struct attribute_group x86_pmu_caps_group;
 
+static void x86_pmu_static_call_update(void)
+{
+       static_call_update(x86_pmu_handle_irq, x86_pmu.handle_irq);
+       static_call_update(x86_pmu_disable_all, x86_pmu.disable_all);
+       static_call_update(x86_pmu_enable_all, x86_pmu.enable_all);
+       static_call_update(x86_pmu_enable, x86_pmu.enable);
+       static_call_update(x86_pmu_disable, x86_pmu.disable);
+
+       static_call_update(x86_pmu_add, x86_pmu.add);
+       static_call_update(x86_pmu_del, x86_pmu.del);
+       static_call_update(x86_pmu_read, x86_pmu.read);
+
+       static_call_update(x86_pmu_schedule_events, x86_pmu.schedule_events);
+       static_call_update(x86_pmu_get_event_constraints, x86_pmu.get_event_constraints);
+       static_call_update(x86_pmu_put_event_constraints, x86_pmu.put_event_constraints);
+
+       static_call_update(x86_pmu_start_scheduling, x86_pmu.start_scheduling);
+       static_call_update(x86_pmu_commit_scheduling, x86_pmu.commit_scheduling);
+       static_call_update(x86_pmu_stop_scheduling, x86_pmu.stop_scheduling);
+
+       static_call_update(x86_pmu_sched_task, x86_pmu.sched_task);
+       static_call_update(x86_pmu_swap_task_ctx, x86_pmu.swap_task_ctx);
+
+       static_call_update(x86_pmu_drain_pebs, x86_pmu.drain_pebs);
+       static_call_update(x86_pmu_pebs_aliases, x86_pmu.pebs_aliases);
+}
+
+static void _x86_pmu_read(struct perf_event *event)
+{
+       x86_perf_event_update(event);
+}
+
 static int __init init_hw_perf_events(void)
 {
        struct x86_pmu_quirk *quirk;
@@ -1898,6 +1998,11 @@ static int __init init_hw_perf_events(void)
        pr_info("... fixed-purpose events:   %d\n",     x86_pmu.num_counters_fixed);
        pr_info("... event mask:             %016Lx\n", x86_pmu.intel_ctrl);
 
+       if (!x86_pmu.read)
+               x86_pmu.read = _x86_pmu_read;
+
+       x86_pmu_static_call_update();
+
        /*
         * Install callbacks. Core will call them for each online
         * cpu.
@@ -1934,11 +2039,9 @@ out:
 }
 early_initcall(init_hw_perf_events);
 
-static inline void x86_pmu_read(struct perf_event *event)
+static void x86_pmu_read(struct perf_event *event)
 {
-       if (x86_pmu.read)
-               return x86_pmu.read(event);
-       x86_perf_event_update(event);
+       static_call(x86_pmu_read)(event);
 }
 
 /*
@@ -1962,6 +2065,8 @@ static void x86_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags)
 
        perf_pmu_disable(pmu);
        __this_cpu_write(cpu_hw_events.n_txn, 0);
+       __this_cpu_write(cpu_hw_events.n_txn_pair, 0);
+       __this_cpu_write(cpu_hw_events.n_txn_metric, 0);
 }
 
 /*
@@ -1987,6 +2092,8 @@ static void x86_pmu_cancel_txn(struct pmu *pmu)
         */
        __this_cpu_sub(cpu_hw_events.n_added, __this_cpu_read(cpu_hw_events.n_txn));
        __this_cpu_sub(cpu_hw_events.n_events, __this_cpu_read(cpu_hw_events.n_txn));
+       __this_cpu_sub(cpu_hw_events.n_pair, __this_cpu_read(cpu_hw_events.n_txn_pair));
+       __this_cpu_sub(cpu_hw_events.n_metric, __this_cpu_read(cpu_hw_events.n_txn_metric));
        perf_pmu_enable(pmu);
 }
 
@@ -2015,7 +2122,7 @@ static int x86_pmu_commit_txn(struct pmu *pmu)
        if (!x86_pmu_initialized())
                return -EAGAIN;
 
-       ret = x86_pmu.schedule_events(cpuc, n, assign);
+       ret = static_call(x86_pmu_schedule_events)(cpuc, n, assign);
        if (ret)
                return ret;
 
@@ -2208,17 +2315,15 @@ static void x86_pmu_event_unmapped(struct perf_event *event, struct mm_struct *m
 
 static int x86_pmu_event_idx(struct perf_event *event)
 {
-       int idx = event->hw.idx;
+       struct hw_perf_event *hwc = &event->hw;
 
-       if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
+       if (!(hwc->flags & PERF_X86_EVENT_RDPMC_ALLOWED))
                return 0;
 
-       if (x86_pmu.num_counters_fixed && idx >= INTEL_PMC_IDX_FIXED) {
-               idx -= INTEL_PMC_IDX_FIXED;
-               idx |= 1 << 30;
-       }
-
-       return idx + 1;
+       if (is_metric_idx(hwc->idx))
+               return INTEL_PMC_FIXED_RDPMC_METRICS + 1;
+       else
+               return hwc->event_base_rdpmc + 1;
 }
 
 static ssize_t get_attr_rdpmc(struct device *cdev,
@@ -2308,15 +2413,13 @@ static const struct attribute_group *x86_pmu_attr_groups[] = {
 
 static void x86_pmu_sched_task(struct perf_event_context *ctx, bool sched_in)
 {
-       if (x86_pmu.sched_task)
-               x86_pmu.sched_task(ctx, sched_in);
+       static_call_cond(x86_pmu_sched_task)(ctx, sched_in);
 }
 
 static void x86_pmu_swap_task_ctx(struct perf_event_context *prev,
                                  struct perf_event_context *next)
 {
-       if (x86_pmu.swap_task_ctx)
-               x86_pmu.swap_task_ctx(prev, next);
+       static_call_cond(x86_pmu_swap_task_ctx)(prev, next);
 }
 
 void perf_check_microcode(void)
index 5096347..f1926e9 100644 (file)
@@ -243,10 +243,14 @@ static struct extra_reg intel_skl_extra_regs[] __read_mostly = {
 
 static struct event_constraint intel_icl_event_constraints[] = {
        FIXED_EVENT_CONSTRAINT(0x00c0, 0),      /* INST_RETIRED.ANY */
-       INTEL_UEVENT_CONSTRAINT(0x1c0, 0),      /* INST_RETIRED.PREC_DIST */
+       FIXED_EVENT_CONSTRAINT(0x01c0, 0),      /* INST_RETIRED.PREC_DIST */
        FIXED_EVENT_CONSTRAINT(0x003c, 1),      /* CPU_CLK_UNHALTED.CORE */
        FIXED_EVENT_CONSTRAINT(0x0300, 2),      /* CPU_CLK_UNHALTED.REF */
        FIXED_EVENT_CONSTRAINT(0x0400, 3),      /* SLOTS */
+       METRIC_EVENT_CONSTRAINT(INTEL_TD_METRIC_RETIRING, 0),
+       METRIC_EVENT_CONSTRAINT(INTEL_TD_METRIC_BAD_SPEC, 1),
+       METRIC_EVENT_CONSTRAINT(INTEL_TD_METRIC_FE_BOUND, 2),
+       METRIC_EVENT_CONSTRAINT(INTEL_TD_METRIC_BE_BOUND, 3),
        INTEL_EVENT_CONSTRAINT_RANGE(0x03, 0x0a, 0xf),
        INTEL_EVENT_CONSTRAINT_RANGE(0x1f, 0x28, 0xf),
        INTEL_EVENT_CONSTRAINT(0x32, 0xf),      /* SW_PREFETCH_ACCESS.* */
@@ -309,6 +313,12 @@ EVENT_ATTR_STR_HT(topdown-recovery-bubbles, td_recovery_bubbles,
 EVENT_ATTR_STR_HT(topdown-recovery-bubbles.scale, td_recovery_bubbles_scale,
        "4", "2");
 
+EVENT_ATTR_STR(slots,                  slots,          "event=0x00,umask=0x4");
+EVENT_ATTR_STR(topdown-retiring,       td_retiring,    "event=0x00,umask=0x80");
+EVENT_ATTR_STR(topdown-bad-spec,       td_bad_spec,    "event=0x00,umask=0x81");
+EVENT_ATTR_STR(topdown-fe-bound,       td_fe_bound,    "event=0x00,umask=0x82");
+EVENT_ATTR_STR(topdown-be-bound,       td_be_bound,    "event=0x00,umask=0x83");
+
 static struct attribute *snb_events_attrs[] = {
        EVENT_PTR(td_slots_issued),
        EVENT_PTR(td_slots_retired),
@@ -2165,11 +2175,24 @@ static inline void intel_clear_masks(struct perf_event *event, int idx)
 static void intel_pmu_disable_fixed(struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
-       int idx = hwc->idx - INTEL_PMC_IDX_FIXED;
        u64 ctrl_val, mask;
+       int idx = hwc->idx;
 
-       mask = 0xfULL << (idx * 4);
+       if (is_topdown_idx(idx)) {
+               struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+               /*
+                * When there are other active TopDown events,
+                * don't disable the fixed counter 3.
+                */
+               if (*(u64 *)cpuc->active_mask & INTEL_PMC_OTHER_TOPDOWN_BITS(idx))
+                       return;
+               idx = INTEL_PMC_IDX_FIXED_SLOTS;
+       }
 
+       intel_clear_masks(event, idx);
+
+       mask = 0xfULL << ((idx - INTEL_PMC_IDX_FIXED) * 4);
        rdmsrl(hwc->config_base, ctrl_val);
        ctrl_val &= ~mask;
        wrmsrl(hwc->config_base, ctrl_val);
@@ -2180,17 +2203,28 @@ static void intel_pmu_disable_event(struct perf_event *event)
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
 
-       if (idx < INTEL_PMC_IDX_FIXED) {
+       switch (idx) {
+       case 0 ... INTEL_PMC_IDX_FIXED - 1:
                intel_clear_masks(event, idx);
                x86_pmu_disable_event(event);
-       } else if (idx < INTEL_PMC_IDX_FIXED_BTS) {
-               intel_clear_masks(event, idx);
+               break;
+       case INTEL_PMC_IDX_FIXED ... INTEL_PMC_IDX_FIXED_BTS - 1:
+       case INTEL_PMC_IDX_METRIC_BASE ... INTEL_PMC_IDX_METRIC_END:
                intel_pmu_disable_fixed(event);
-       } else if (idx == INTEL_PMC_IDX_FIXED_BTS) {
+               break;
+       case INTEL_PMC_IDX_FIXED_BTS:
                intel_pmu_disable_bts();
                intel_pmu_drain_bts_buffer();
-       } else if (idx == INTEL_PMC_IDX_FIXED_VLBR)
+               return;
+       case INTEL_PMC_IDX_FIXED_VLBR:
                intel_clear_masks(event, idx);
+               break;
+       default:
+               intel_clear_masks(event, idx);
+               pr_warn("Failed to disable the event with invalid index %d\n",
+                       idx);
+               return;
+       }
 
        /*
         * Needs to be called after x86_pmu_disable_event,
@@ -2208,10 +2242,189 @@ static void intel_pmu_del_event(struct perf_event *event)
                intel_pmu_pebs_del(event);
 }
 
+static int icl_set_topdown_event_period(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       s64 left = local64_read(&hwc->period_left);
+
+       /*
+        * The values in PERF_METRICS MSR are derived from fixed counter 3.
+        * Software should start both registers, PERF_METRICS and fixed
+        * counter 3, from zero.
+        * Clear PERF_METRICS and Fixed counter 3 in initialization.
+        * After that, both MSRs will be cleared for each read.
+        * Don't need to clear them again.
+        */
+       if (left == x86_pmu.max_period) {
+               wrmsrl(MSR_CORE_PERF_FIXED_CTR3, 0);
+               wrmsrl(MSR_PERF_METRICS, 0);
+               hwc->saved_slots = 0;
+               hwc->saved_metric = 0;
+       }
+
+       if ((hwc->saved_slots) && is_slots_event(event)) {
+               wrmsrl(MSR_CORE_PERF_FIXED_CTR3, hwc->saved_slots);
+               wrmsrl(MSR_PERF_METRICS, hwc->saved_metric);
+       }
+
+       perf_event_update_userpage(event);
+
+       return 0;
+}
+
+static inline u64 icl_get_metrics_event_value(u64 metric, u64 slots, int idx)
+{
+       u32 val;
+
+       /*
+        * The metric is reported as an 8bit integer fraction
+        * suming up to 0xff.
+        * slots-in-metric = (Metric / 0xff) * slots
+        */
+       val = (metric >> ((idx - INTEL_PMC_IDX_METRIC_BASE) * 8)) & 0xff;
+       return  mul_u64_u32_div(slots, val, 0xff);
+}
+
+static u64 icl_get_topdown_value(struct perf_event *event,
+                                      u64 slots, u64 metrics)
+{
+       int idx = event->hw.idx;
+       u64 delta;
+
+       if (is_metric_idx(idx))
+               delta = icl_get_metrics_event_value(metrics, slots, idx);
+       else
+               delta = slots;
+
+       return delta;
+}
+
+static void __icl_update_topdown_event(struct perf_event *event,
+                                      u64 slots, u64 metrics,
+                                      u64 last_slots, u64 last_metrics)
+{
+       u64 delta, last = 0;
+
+       delta = icl_get_topdown_value(event, slots, metrics);
+       if (last_slots)
+               last = icl_get_topdown_value(event, last_slots, last_metrics);
+
+       /*
+        * The 8bit integer fraction of metric may be not accurate,
+        * especially when the changes is very small.
+        * For example, if only a few bad_spec happens, the fraction
+        * may be reduced from 1 to 0. If so, the bad_spec event value
+        * will be 0 which is definitely less than the last value.
+        * Avoid update event->count for this case.
+        */
+       if (delta > last) {
+               delta -= last;
+               local64_add(delta, &event->count);
+       }
+}
+
+static void update_saved_topdown_regs(struct perf_event *event,
+                                     u64 slots, u64 metrics)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct perf_event *other;
+       int idx;
+
+       event->hw.saved_slots = slots;
+       event->hw.saved_metric = metrics;
+
+       for_each_set_bit(idx, cpuc->active_mask, INTEL_PMC_IDX_TD_BE_BOUND + 1) {
+               if (!is_topdown_idx(idx))
+                       continue;
+               other = cpuc->events[idx];
+               other->hw.saved_slots = slots;
+               other->hw.saved_metric = metrics;
+       }
+}
+
+/*
+ * Update all active Topdown events.
+ *
+ * The PERF_METRICS and Fixed counter 3 are read separately. The values may be
+ * modify by a NMI. PMU has to be disabled before calling this function.
+ */
+static u64 icl_update_topdown_event(struct perf_event *event)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct perf_event *other;
+       u64 slots, metrics;
+       bool reset = true;
+       int idx;
+
+       /* read Fixed counter 3 */
+       rdpmcl((3 | INTEL_PMC_FIXED_RDPMC_BASE), slots);
+       if (!slots)
+               return 0;
+
+       /* read PERF_METRICS */
+       rdpmcl(INTEL_PMC_FIXED_RDPMC_METRICS, metrics);
+
+       for_each_set_bit(idx, cpuc->active_mask, INTEL_PMC_IDX_TD_BE_BOUND + 1) {
+               if (!is_topdown_idx(idx))
+                       continue;
+               other = cpuc->events[idx];
+               __icl_update_topdown_event(other, slots, metrics,
+                                          event ? event->hw.saved_slots : 0,
+                                          event ? event->hw.saved_metric : 0);
+       }
+
+       /*
+        * Check and update this event, which may have been cleared
+        * in active_mask e.g. x86_pmu_stop()
+        */
+       if (event && !test_bit(event->hw.idx, cpuc->active_mask)) {
+               __icl_update_topdown_event(event, slots, metrics,
+                                          event->hw.saved_slots,
+                                          event->hw.saved_metric);
+
+               /*
+                * In x86_pmu_stop(), the event is cleared in active_mask first,
+                * then drain the delta, which indicates context switch for
+                * counting.
+                * Save metric and slots for context switch.
+                * Don't need to reset the PERF_METRICS and Fixed counter 3.
+                * Because the values will be restored in next schedule in.
+                */
+               update_saved_topdown_regs(event, slots, metrics);
+               reset = false;
+       }
+
+       if (reset) {
+               /* The fixed counter 3 has to be written before the PERF_METRICS. */
+               wrmsrl(MSR_CORE_PERF_FIXED_CTR3, 0);
+               wrmsrl(MSR_PERF_METRICS, 0);
+               if (event)
+                       update_saved_topdown_regs(event, 0, 0);
+       }
+
+       return slots;
+}
+
+static void intel_pmu_read_topdown_event(struct perf_event *event)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+       /* Only need to call update_topdown_event() once for group read. */
+       if ((cpuc->txn_flags & PERF_PMU_TXN_READ) &&
+           !is_slots_event(event))
+               return;
+
+       perf_pmu_disable(event->pmu);
+       x86_pmu.update_topdown_event(event);
+       perf_pmu_enable(event->pmu);
+}
+
 static void intel_pmu_read_event(struct perf_event *event)
 {
        if (event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD)
                intel_pmu_auto_reload_read(event);
+       else if (is_topdown_count(event) && x86_pmu.update_topdown_event)
+               intel_pmu_read_topdown_event(event);
        else
                x86_perf_event_update(event);
 }
@@ -2219,8 +2432,22 @@ static void intel_pmu_read_event(struct perf_event *event)
 static void intel_pmu_enable_fixed(struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
-       int idx = hwc->idx - INTEL_PMC_IDX_FIXED;
        u64 ctrl_val, mask, bits = 0;
+       int idx = hwc->idx;
+
+       if (is_topdown_idx(idx)) {
+               struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+               /*
+                * When there are other active TopDown events,
+                * don't enable the fixed counter 3 again.
+                */
+               if (*(u64 *)cpuc->active_mask & INTEL_PMC_OTHER_TOPDOWN_BITS(idx))
+                       return;
+
+               idx = INTEL_PMC_IDX_FIXED_SLOTS;
+       }
+
+       intel_set_masks(event, idx);
 
        /*
         * Enable IRQ generation (0x8), if not PEBS,
@@ -2240,6 +2467,7 @@ static void intel_pmu_enable_fixed(struct perf_event *event)
        if (x86_pmu.version > 2 && hwc->config & ARCH_PERFMON_EVENTSEL_ANY)
                bits |= 0x4;
 
+       idx -= INTEL_PMC_IDX_FIXED;
        bits <<= (idx * 4);
        mask = 0xfULL << (idx * 4);
 
@@ -2262,18 +2490,27 @@ static void intel_pmu_enable_event(struct perf_event *event)
        if (unlikely(event->attr.precise_ip))
                intel_pmu_pebs_enable(event);
 
-       if (idx < INTEL_PMC_IDX_FIXED) {
+       switch (idx) {
+       case 0 ... INTEL_PMC_IDX_FIXED - 1:
                intel_set_masks(event, idx);
                __x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
-       } else if (idx < INTEL_PMC_IDX_FIXED_BTS) {
-               intel_set_masks(event, idx);
+               break;
+       case INTEL_PMC_IDX_FIXED ... INTEL_PMC_IDX_FIXED_BTS - 1:
+       case INTEL_PMC_IDX_METRIC_BASE ... INTEL_PMC_IDX_METRIC_END:
                intel_pmu_enable_fixed(event);
-       } else if (idx == INTEL_PMC_IDX_FIXED_BTS) {
+               break;
+       case INTEL_PMC_IDX_FIXED_BTS:
                if (!__this_cpu_read(cpu_hw_events.enabled))
                        return;
                intel_pmu_enable_bts(hwc->config);
-       } else if (idx == INTEL_PMC_IDX_FIXED_VLBR)
+               break;
+       case INTEL_PMC_IDX_FIXED_VLBR:
                intel_set_masks(event, idx);
+               break;
+       default:
+               pr_warn("Failed to enable the event with invalid index %d\n",
+                       idx);
+       }
 }
 
 static void intel_pmu_add_event(struct perf_event *event)
@@ -2389,7 +2626,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
        /*
         * PEBS overflow sets bit 62 in the global status register
         */
-       if (__test_and_clear_bit(62, (unsigned long *)&status)) {
+       if (__test_and_clear_bit(GLOBAL_STATUS_BUFFER_OVF_BIT, (unsigned long *)&status)) {
                u64 pebs_enabled = cpuc->pebs_enabled;
 
                handled++;
@@ -2410,7 +2647,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
        /*
         * Intel PT
         */
-       if (__test_and_clear_bit(55, (unsigned long *)&status)) {
+       if (__test_and_clear_bit(GLOBAL_STATUS_TRACE_TOPAPMI_BIT, (unsigned long *)&status)) {
                handled++;
                if (unlikely(perf_guest_cbs && perf_guest_cbs->is_in_guest() &&
                        perf_guest_cbs->handle_intel_pt_intr))
@@ -2420,6 +2657,15 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
        }
 
        /*
+        * Intel Perf mertrics
+        */
+       if (__test_and_clear_bit(GLOBAL_STATUS_PERF_METRICS_OVF_BIT, (unsigned long *)&status)) {
+               handled++;
+               if (x86_pmu.update_topdown_event)
+                       x86_pmu.update_topdown_event(NULL);
+       }
+
+       /*
         * Checkpointed counters can lead to 'spurious' PMIs because the
         * rollback caused by the PMI will have cleared the overflow status
         * bit. Therefore always force probe these counters.
@@ -3355,6 +3601,56 @@ static int intel_pmu_hw_config(struct perf_event *event)
        if (event->attr.type != PERF_TYPE_RAW)
                return 0;
 
+       /*
+        * Config Topdown slots and metric events
+        *
+        * The slots event on Fixed Counter 3 can support sampling,
+        * which will be handled normally in x86_perf_event_update().
+        *
+        * Metric events don't support sampling and require being paired
+        * with a slots event as group leader. When the slots event
+        * is used in a metrics group, it too cannot support sampling.
+        */
+       if (x86_pmu.intel_cap.perf_metrics && is_topdown_event(event)) {
+               if (event->attr.config1 || event->attr.config2)
+                       return -EINVAL;
+
+               /*
+                * The TopDown metrics events and slots event don't
+                * support any filters.
+                */
+               if (event->attr.config & X86_ALL_EVENT_FLAGS)
+                       return -EINVAL;
+
+               if (is_metric_event(event)) {
+                       struct perf_event *leader = event->group_leader;
+
+                       /* The metric events don't support sampling. */
+                       if (is_sampling_event(event))
+                               return -EINVAL;
+
+                       /* The metric events require a slots group leader. */
+                       if (!is_slots_event(leader))
+                               return -EINVAL;
+
+                       /*
+                        * The leader/SLOTS must not be a sampling event for
+                        * metric use; hardware requires it starts at 0 when used
+                        * in conjunction with MSR_PERF_METRICS.
+                        */
+                       if (is_sampling_event(leader))
+                               return -EINVAL;
+
+                       event->event_caps |= PERF_EV_CAP_SIBLING;
+                       /*
+                        * Only once we have a METRICs sibling do we
+                        * need TopDown magic.
+                        */
+                       leader->hw.flags |= PERF_X86_EVENT_TOPDOWN;
+                       event->hw.flags  |= PERF_X86_EVENT_TOPDOWN;
+               }
+       }
+
        if (!(event->attr.config & ARCH_PERFMON_EVENTSEL_ANY))
                return 0;
 
@@ -3787,6 +4083,17 @@ static void intel_pmu_cpu_starting(int cpu)
        if (x86_pmu.counter_freezing)
                enable_counter_freeze();
 
+       /* Disable perf metrics if any added CPU doesn't support it. */
+       if (x86_pmu.intel_cap.perf_metrics) {
+               union perf_capabilities perf_cap;
+
+               rdmsrl(MSR_IA32_PERF_CAPABILITIES, perf_cap.capabilities);
+               if (!perf_cap.perf_metrics) {
+                       x86_pmu.intel_cap.perf_metrics = 0;
+                       x86_pmu.intel_ctrl &= ~(1ULL << GLOBAL_CTRL_EN_PERF_METRICS);
+               }
+       }
+
        if (!cpuc->shared_regs)
                return;
 
@@ -4355,6 +4662,15 @@ static struct attribute *icl_events_attrs[] = {
        NULL,
 };
 
+static struct attribute *icl_td_events_attrs[] = {
+       EVENT_PTR(slots),
+       EVENT_PTR(td_retiring),
+       EVENT_PTR(td_bad_spec),
+       EVENT_PTR(td_fe_bound),
+       EVENT_PTR(td_be_bound),
+       NULL,
+};
+
 static struct attribute *icl_tsx_events_attrs[] = {
        EVENT_PTR(tx_start),
        EVENT_PTR(tx_abort),
@@ -4682,7 +4998,7 @@ __init int intel_pmu_init(void)
 
        case INTEL_FAM6_CORE2_MEROM:
                x86_add_quirk(intel_clovertown_quirk);
-               /* fall through */
+               fallthrough;
 
        case INTEL_FAM6_CORE2_MEROM_L:
        case INTEL_FAM6_CORE2_PENRYN:
@@ -4830,6 +5146,7 @@ __init int intel_pmu_init(void)
 
        case INTEL_FAM6_ATOM_TREMONT_D:
        case INTEL_FAM6_ATOM_TREMONT:
+       case INTEL_FAM6_ATOM_TREMONT_L:
                x86_pmu.late_ack = true;
                memcpy(hw_cache_event_ids, glp_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
@@ -5062,7 +5379,7 @@ __init int intel_pmu_init(void)
 
        case INTEL_FAM6_SKYLAKE_X:
                pmem = true;
-               /* fall through */
+               fallthrough;
        case INTEL_FAM6_SKYLAKE_L:
        case INTEL_FAM6_SKYLAKE:
        case INTEL_FAM6_KABYLAKE_L:
@@ -5114,7 +5431,7 @@ __init int intel_pmu_init(void)
        case INTEL_FAM6_ICELAKE_X:
        case INTEL_FAM6_ICELAKE_D:
                pmem = true;
-               /* fall through */
+               fallthrough;
        case INTEL_FAM6_ICELAKE_L:
        case INTEL_FAM6_ICELAKE:
        case INTEL_FAM6_TIGERLAKE_L:
@@ -5139,10 +5456,13 @@ __init int intel_pmu_init(void)
                        hsw_format_attr : nhm_format_attr;
                extra_skl_attr = skl_format_attr;
                mem_attr = icl_events_attrs;
+               td_attr = icl_td_events_attrs;
                tsx_attr = icl_tsx_events_attrs;
                x86_pmu.rtm_abort_event = X86_CONFIG(.event=0xca, .umask=0x02);
                x86_pmu.lbr_pt_coexist = true;
                intel_pmu_pebs_data_source_skl(pmem);
+               x86_pmu.update_topdown_event = icl_update_topdown_event;
+               x86_pmu.set_topdown_event_period = icl_set_topdown_event_period;
                pr_cont("Icelake events, ");
                name = "icelake";
                break;
@@ -5198,6 +5518,15 @@ __init int intel_pmu_init(void)
                 * counter, so do not extend mask to generic counters
                 */
                for_each_event_constraint(c, x86_pmu.event_constraints) {
+                       /*
+                        * Don't extend the topdown slots and metrics
+                        * events to the generic counters.
+                        */
+                       if (c->idxmsk64 & INTEL_PMC_MSK_TOPDOWN) {
+                               c->weight = hweight64(c->idxmsk64);
+                               continue;
+                       }
+
                        if (c->cmask == FIXED_EVENT_FLAGS
                            && c->idxmsk64 != INTEL_PMC_MSK_FIXED_REF_CYCLES) {
                                c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1;
@@ -5253,6 +5582,9 @@ __init int intel_pmu_init(void)
        if (x86_pmu.counter_freezing)
                x86_pmu.handle_irq = intel_pmu_handle_irq_v4;
 
+       if (x86_pmu.intel_cap.perf_metrics)
+               x86_pmu.intel_ctrl |= 1ULL << GLOBAL_CTRL_EN_PERF_METRICS;
+
        return 0;
 }
 
index 86848c5..404315d 100644 (file)
@@ -670,9 +670,7 @@ unlock:
 
 static inline void intel_pmu_drain_pebs_buffer(void)
 {
-       struct pt_regs regs;
-
-       x86_pmu.drain_pebs(&regs);
+       x86_pmu.drain_pebs(NULL);
 }
 
 /*
@@ -1737,6 +1735,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
        struct x86_perf_regs perf_regs;
        struct pt_regs *regs = &perf_regs.regs;
        void *at = get_next_pebs_record_by_bit(base, top, bit);
+       struct pt_regs dummy_iregs;
 
        if (hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) {
                /*
@@ -1749,6 +1748,9 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
        } else if (!intel_pmu_save_and_restart(event))
                return;
 
+       if (!iregs)
+               iregs = &dummy_iregs;
+
        while (count > 1) {
                setup_sample(event, iregs, at, &data, regs);
                perf_event_output(event, &data, regs);
@@ -1758,16 +1760,22 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
        }
 
        setup_sample(event, iregs, at, &data, regs);
-
-       /*
-        * All but the last records are processed.
-        * The last one is left to be able to call the overflow handler.
-        */
-       if (perf_event_overflow(event, &data, regs)) {
-               x86_pmu_stop(event, 0);
-               return;
+       if (iregs == &dummy_iregs) {
+               /*
+                * The PEBS records may be drained in the non-overflow context,
+                * e.g., large PEBS + context switch. Perf should treat the
+                * last record the same as other PEBS records, and doesn't
+                * invoke the generic overflow handler.
+                */
+               perf_event_output(event, &data, regs);
+       } else {
+               /*
+                * All but the last records are processed.
+                * The last one is left to be able to call the overflow handler.
+                */
+               if (perf_event_overflow(event, &data, regs))
+                       x86_pmu_stop(event, 0);
        }
-
 }
 
 static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
index 63f58bd..8961653 100644 (file)
@@ -1268,7 +1268,7 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
                        ret = X86_BR_ZERO_CALL;
                        break;
                }
-               /* fall through */
+               fallthrough;
        case 0x9a: /* call far absolute */
                ret = X86_BR_CALL;
                break;
index d5c6d3b..86d012b 100644 (file)
@@ -12,6 +12,8 @@ struct intel_uncore_type **uncore_mmio_uncores = empty_uncore;
 
 static bool pcidrv_registered;
 struct pci_driver *uncore_pci_driver;
+/* The PCI driver for the device which the uncore doesn't own. */
+struct pci_driver *uncore_pci_sub_driver;
 /* pci bus to socket mapping */
 DEFINE_RAW_SPINLOCK(pci2phy_map_lock);
 struct list_head pci2phy_map_head = LIST_HEAD_INIT(pci2phy_map_head);
@@ -989,65 +991,71 @@ uncore_types_init(struct intel_uncore_type **types, bool setid)
 }
 
 /*
- * add a pci uncore device
+ * Get the die information of a PCI device.
+ * @pdev: The PCI device.
+ * @phys_id: The physical socket id which the device maps to.
+ * @die: The die id which the device maps to.
  */
-static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int uncore_pci_get_dev_die_info(struct pci_dev *pdev,
+                                      int *phys_id, int *die)
 {
-       struct intel_uncore_type *type;
-       struct intel_uncore_pmu *pmu = NULL;
-       struct intel_uncore_box *box;
-       int phys_id, die, ret;
-
-       phys_id = uncore_pcibus_to_physid(pdev->bus);
-       if (phys_id < 0)
+       *phys_id = uncore_pcibus_to_physid(pdev->bus);
+       if (*phys_id < 0)
                return -ENODEV;
 
-       die = (topology_max_die_per_package() > 1) ? phys_id :
-                                       topology_phys_to_logical_pkg(phys_id);
-       if (die < 0)
+       *die = (topology_max_die_per_package() > 1) ? *phys_id :
+                               topology_phys_to_logical_pkg(*phys_id);
+       if (*die < 0)
                return -EINVAL;
 
-       if (UNCORE_PCI_DEV_TYPE(id->driver_data) == UNCORE_EXTRA_PCI_DEV) {
-               int idx = UNCORE_PCI_DEV_IDX(id->driver_data);
-
-               uncore_extra_pci_dev[die].dev[idx] = pdev;
-               pci_set_drvdata(pdev, NULL);
-               return 0;
-       }
-
-       type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)];
+       return 0;
+}
 
-       /*
-        * Some platforms, e.g.  Knights Landing, use a common PCI device ID
-        * for multiple instances of an uncore PMU device type. We should check
-        * PCI slot and func to indicate the uncore box.
-        */
-       if (id->driver_data & ~0xffff) {
-               struct pci_driver *pci_drv = pdev->driver;
-               const struct pci_device_id *ids = pci_drv->id_table;
-               unsigned int devfn;
-
-               while (ids && ids->vendor) {
-                       if ((ids->vendor == pdev->vendor) &&
-                           (ids->device == pdev->device)) {
-                               devfn = PCI_DEVFN(UNCORE_PCI_DEV_DEV(ids->driver_data),
-                                                 UNCORE_PCI_DEV_FUNC(ids->driver_data));
-                               if (devfn == pdev->devfn) {
-                                       pmu = &type->pmus[UNCORE_PCI_DEV_IDX(ids->driver_data)];
-                                       break;
-                               }
+/*
+ * Find the PMU of a PCI device.
+ * @pdev: The PCI device.
+ * @ids: The ID table of the available PCI devices with a PMU.
+ */
+static struct intel_uncore_pmu *
+uncore_pci_find_dev_pmu(struct pci_dev *pdev, const struct pci_device_id *ids)
+{
+       struct intel_uncore_pmu *pmu = NULL;
+       struct intel_uncore_type *type;
+       kernel_ulong_t data;
+       unsigned int devfn;
+
+       while (ids && ids->vendor) {
+               if ((ids->vendor == pdev->vendor) &&
+                   (ids->device == pdev->device)) {
+                       data = ids->driver_data;
+                       devfn = PCI_DEVFN(UNCORE_PCI_DEV_DEV(data),
+                                         UNCORE_PCI_DEV_FUNC(data));
+                       if (devfn == pdev->devfn) {
+                               type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(data)];
+                               pmu = &type->pmus[UNCORE_PCI_DEV_IDX(data)];
+                               break;
                        }
-                       ids++;
                }
-               if (pmu == NULL)
-                       return -ENODEV;
-       } else {
-               /*
-                * for performance monitoring unit with multiple boxes,
-                * each box has a different function id.
-                */
-               pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)];
+               ids++;
        }
+       return pmu;
+}
+
+/*
+ * Register the PMU for a PCI device
+ * @pdev: The PCI device.
+ * @type: The corresponding PMU type of the device.
+ * @pmu: The corresponding PMU of the device.
+ * @phys_id: The physical socket id which the device maps to.
+ * @die: The die id which the device maps to.
+ */
+static int uncore_pci_pmu_register(struct pci_dev *pdev,
+                                  struct intel_uncore_type *type,
+                                  struct intel_uncore_pmu *pmu,
+                                  int phys_id, int die)
+{
+       struct intel_uncore_box *box;
+       int ret;
 
        if (WARN_ON_ONCE(pmu->boxes[die] != NULL))
                return -EINVAL;
@@ -1067,7 +1075,6 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
        box->pci_dev = pdev;
        box->pmu = pmu;
        uncore_box_init(box);
-       pci_set_drvdata(pdev, box);
 
        pmu->boxes[die] = box;
        if (atomic_inc_return(&pmu->activeboxes) > 1)
@@ -1076,7 +1083,6 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
        /* First active box registers the pmu */
        ret = uncore_pmu_register(pmu);
        if (ret) {
-               pci_set_drvdata(pdev, NULL);
                pmu->boxes[die] = NULL;
                uncore_box_exit(box);
                kfree(box);
@@ -1084,18 +1090,87 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
        return ret;
 }
 
+/*
+ * add a pci uncore device
+ */
+static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct intel_uncore_type *type;
+       struct intel_uncore_pmu *pmu = NULL;
+       int phys_id, die, ret;
+
+       ret = uncore_pci_get_dev_die_info(pdev, &phys_id, &die);
+       if (ret)
+               return ret;
+
+       if (UNCORE_PCI_DEV_TYPE(id->driver_data) == UNCORE_EXTRA_PCI_DEV) {
+               int idx = UNCORE_PCI_DEV_IDX(id->driver_data);
+
+               uncore_extra_pci_dev[die].dev[idx] = pdev;
+               pci_set_drvdata(pdev, NULL);
+               return 0;
+       }
+
+       type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)];
+
+       /*
+        * Some platforms, e.g.  Knights Landing, use a common PCI device ID
+        * for multiple instances of an uncore PMU device type. We should check
+        * PCI slot and func to indicate the uncore box.
+        */
+       if (id->driver_data & ~0xffff) {
+               struct pci_driver *pci_drv = pdev->driver;
+
+               pmu = uncore_pci_find_dev_pmu(pdev, pci_drv->id_table);
+               if (pmu == NULL)
+                       return -ENODEV;
+       } else {
+               /*
+                * for performance monitoring unit with multiple boxes,
+                * each box has a different function id.
+                */
+               pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)];
+       }
+
+       ret = uncore_pci_pmu_register(pdev, type, pmu, phys_id, die);
+
+       pci_set_drvdata(pdev, pmu->boxes[die]);
+
+       return ret;
+}
+
+/*
+ * Unregister the PMU of a PCI device
+ * @pmu: The corresponding PMU is unregistered.
+ * @phys_id: The physical socket id which the device maps to.
+ * @die: The die id which the device maps to.
+ */
+static void uncore_pci_pmu_unregister(struct intel_uncore_pmu *pmu,
+                                     int phys_id, int die)
+{
+       struct intel_uncore_box *box = pmu->boxes[die];
+
+       if (WARN_ON_ONCE(phys_id != box->pci_phys_id))
+               return;
+
+       pmu->boxes[die] = NULL;
+       if (atomic_dec_return(&pmu->activeboxes) == 0)
+               uncore_pmu_unregister(pmu);
+       uncore_box_exit(box);
+       kfree(box);
+}
+
 static void uncore_pci_remove(struct pci_dev *pdev)
 {
        struct intel_uncore_box *box;
        struct intel_uncore_pmu *pmu;
        int i, phys_id, die;
 
-       phys_id = uncore_pcibus_to_physid(pdev->bus);
+       if (uncore_pci_get_dev_die_info(pdev, &phys_id, &die))
+               return;
 
        box = pci_get_drvdata(pdev);
        if (!box) {
-               die = (topology_max_die_per_package() > 1) ? phys_id :
-                                       topology_phys_to_logical_pkg(phys_id);
                for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) {
                        if (uncore_extra_pci_dev[die].dev[i] == pdev) {
                                uncore_extra_pci_dev[die].dev[i] = NULL;
@@ -1107,15 +1182,84 @@ static void uncore_pci_remove(struct pci_dev *pdev)
        }
 
        pmu = box->pmu;
-       if (WARN_ON_ONCE(phys_id != box->pci_phys_id))
-               return;
 
        pci_set_drvdata(pdev, NULL);
-       pmu->boxes[box->dieid] = NULL;
-       if (atomic_dec_return(&pmu->activeboxes) == 0)
-               uncore_pmu_unregister(pmu);
-       uncore_box_exit(box);
-       kfree(box);
+
+       uncore_pci_pmu_unregister(pmu, phys_id, die);
+}
+
+static int uncore_bus_notify(struct notifier_block *nb,
+                            unsigned long action, void *data)
+{
+       struct device *dev = data;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct intel_uncore_pmu *pmu;
+       int phys_id, die;
+
+       /* Unregister the PMU when the device is going to be deleted. */
+       if (action != BUS_NOTIFY_DEL_DEVICE)
+               return NOTIFY_DONE;
+
+       pmu = uncore_pci_find_dev_pmu(pdev, uncore_pci_sub_driver->id_table);
+       if (!pmu)
+               return NOTIFY_DONE;
+
+       if (uncore_pci_get_dev_die_info(pdev, &phys_id, &die))
+               return NOTIFY_DONE;
+
+       uncore_pci_pmu_unregister(pmu, phys_id, die);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block uncore_notifier = {
+       .notifier_call = uncore_bus_notify,
+};
+
+static void uncore_pci_sub_driver_init(void)
+{
+       const struct pci_device_id *ids = uncore_pci_sub_driver->id_table;
+       struct intel_uncore_type *type;
+       struct intel_uncore_pmu *pmu;
+       struct pci_dev *pci_sub_dev;
+       bool notify = false;
+       unsigned int devfn;
+       int phys_id, die;
+
+       while (ids && ids->vendor) {
+               pci_sub_dev = NULL;
+               type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(ids->driver_data)];
+               /*
+                * Search the available device, and register the
+                * corresponding PMU.
+                */
+               while ((pci_sub_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                                    ids->device, pci_sub_dev))) {
+                       devfn = PCI_DEVFN(UNCORE_PCI_DEV_DEV(ids->driver_data),
+                                         UNCORE_PCI_DEV_FUNC(ids->driver_data));
+                       if (devfn != pci_sub_dev->devfn)
+                               continue;
+
+                       pmu = &type->pmus[UNCORE_PCI_DEV_IDX(ids->driver_data)];
+                       if (!pmu)
+                               continue;
+
+                       if (uncore_pci_get_dev_die_info(pci_sub_dev,
+                                                       &phys_id, &die))
+                               continue;
+
+                       if (!uncore_pci_pmu_register(pci_sub_dev, type, pmu,
+                                                    phys_id, die))
+                               notify = true;
+               }
+               ids++;
+       }
+
+       if (notify && bus_register_notifier(&pci_bus_type, &uncore_notifier))
+               notify = false;
+
+       if (!notify)
+               uncore_pci_sub_driver = NULL;
 }
 
 static int __init uncore_pci_init(void)
@@ -1141,6 +1285,9 @@ static int __init uncore_pci_init(void)
        if (ret)
                goto errtype;
 
+       if (uncore_pci_sub_driver)
+               uncore_pci_sub_driver_init();
+
        pcidrv_registered = true;
        return 0;
 
@@ -1158,6 +1305,8 @@ static void uncore_pci_exit(void)
 {
        if (pcidrv_registered) {
                pcidrv_registered = false;
+               if (uncore_pci_sub_driver)
+                       bus_unregister_notifier(&pci_bus_type, &uncore_notifier);
                pci_unregister_driver(uncore_pci_driver);
                uncore_types_exit(uncore_pci_uncores);
                kfree(uncore_extra_pci_dev);
@@ -1478,12 +1627,12 @@ static const struct intel_uncore_init_fun icl_uncore_init __initconst = {
 };
 
 static const struct intel_uncore_init_fun tgl_uncore_init __initconst = {
-       .cpu_init = icl_uncore_cpu_init,
+       .cpu_init = tgl_uncore_cpu_init,
        .mmio_init = tgl_uncore_mmio_init,
 };
 
 static const struct intel_uncore_init_fun tgl_l_uncore_init __initconst = {
-       .cpu_init = icl_uncore_cpu_init,
+       .cpu_init = tgl_uncore_cpu_init,
        .mmio_init = tgl_l_uncore_mmio_init,
 };
 
index 105fdc6..83d2a7d 100644 (file)
@@ -552,6 +552,7 @@ extern struct intel_uncore_type **uncore_msr_uncores;
 extern struct intel_uncore_type **uncore_pci_uncores;
 extern struct intel_uncore_type **uncore_mmio_uncores;
 extern struct pci_driver *uncore_pci_driver;
+extern struct pci_driver *uncore_pci_sub_driver;
 extern raw_spinlock_t pci2phy_map_lock;
 extern struct list_head pci2phy_map_head;
 extern struct pci_extra_dev *uncore_extra_pci_dev;
@@ -567,6 +568,7 @@ void snb_uncore_cpu_init(void);
 void nhm_uncore_cpu_init(void);
 void skl_uncore_cpu_init(void);
 void icl_uncore_cpu_init(void);
+void tgl_uncore_cpu_init(void);
 void tgl_uncore_mmio_init(void);
 void tgl_l_uncore_mmio_init(void);
 int snb_pci2phy_map_init(int devid);
index 6a4ca27..39e632e 100644 (file)
 #define ICL_UNC_CBO_0_PER_CTR0                 0x702
 #define ICL_UNC_CBO_MSR_OFFSET                 0x8
 
+/* ICL ARB register */
+#define ICL_UNC_ARB_PER_CTR                    0x3b1
+#define ICL_UNC_ARB_PERFEVTSEL                 0x3b3
+
 DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
 DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
 DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
@@ -313,15 +317,21 @@ void skl_uncore_cpu_init(void)
        snb_uncore_arb.ops = &skl_uncore_msr_ops;
 }
 
+static struct intel_uncore_ops icl_uncore_msr_ops = {
+       .disable_event  = snb_uncore_msr_disable_event,
+       .enable_event   = snb_uncore_msr_enable_event,
+       .read_counter   = uncore_msr_read_counter,
+};
+
 static struct intel_uncore_type icl_uncore_cbox = {
        .name           = "cbox",
-       .num_counters   = 4,
+       .num_counters   = 2,
        .perf_ctr_bits  = 44,
        .perf_ctr       = ICL_UNC_CBO_0_PER_CTR0,
        .event_ctl      = SNB_UNC_CBO_0_PERFEVTSEL0,
        .event_mask     = SNB_UNC_RAW_EVENT_MASK,
        .msr_offset     = ICL_UNC_CBO_MSR_OFFSET,
-       .ops            = &skl_uncore_msr_ops,
+       .ops            = &icl_uncore_msr_ops,
        .format_group   = &snb_uncore_format_group,
 };
 
@@ -350,13 +360,25 @@ static struct intel_uncore_type icl_uncore_clockbox = {
        .single_fixed   = 1,
        .event_mask     = SNB_UNC_CTL_EV_SEL_MASK,
        .format_group   = &icl_uncore_clock_format_group,
-       .ops            = &skl_uncore_msr_ops,
+       .ops            = &icl_uncore_msr_ops,
        .event_descs    = icl_uncore_events,
 };
 
+static struct intel_uncore_type icl_uncore_arb = {
+       .name           = "arb",
+       .num_counters   = 1,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .perf_ctr       = ICL_UNC_ARB_PER_CTR,
+       .event_ctl      = ICL_UNC_ARB_PERFEVTSEL,
+       .event_mask     = SNB_UNC_RAW_EVENT_MASK,
+       .ops            = &icl_uncore_msr_ops,
+       .format_group   = &snb_uncore_format_group,
+};
+
 static struct intel_uncore_type *icl_msr_uncores[] = {
        &icl_uncore_cbox,
-       &snb_uncore_arb,
+       &icl_uncore_arb,
        &icl_uncore_clockbox,
        NULL,
 };
@@ -374,6 +396,21 @@ void icl_uncore_cpu_init(void)
 {
        uncore_msr_uncores = icl_msr_uncores;
        icl_uncore_cbox.num_boxes = icl_get_cbox_num();
+}
+
+static struct intel_uncore_type *tgl_msr_uncores[] = {
+       &icl_uncore_cbox,
+       &snb_uncore_arb,
+       &icl_uncore_clockbox,
+       NULL,
+};
+
+void tgl_uncore_cpu_init(void)
+{
+       uncore_msr_uncores = tgl_msr_uncores;
+       icl_uncore_cbox.num_boxes = icl_get_cbox_num();
+       icl_uncore_cbox.ops = &skl_uncore_msr_ops;
+       icl_uncore_clockbox.ops = &skl_uncore_msr_ops;
        snb_uncore_arb.ops = &skl_uncore_msr_ops;
 }
 
index 62e88ad..7bdb182 100644 (file)
 #define SNR_M2M_PCI_PMON_BOX_CTL               0x438
 #define SNR_M2M_PCI_PMON_UMASK_EXT             0xff
 
+/* SNR PCIE3 */
+#define SNR_PCIE3_PCI_PMON_CTL0                        0x508
+#define SNR_PCIE3_PCI_PMON_CTR0                        0x4e8
+#define SNR_PCIE3_PCI_PMON_BOX_CTL             0x4e0
+
 /* SNR IMC */
 #define SNR_IMC_MMIO_PMON_FIXED_CTL            0x54
 #define SNR_IMC_MMIO_PMON_FIXED_CTR            0x38
@@ -3749,7 +3754,9 @@ static int skx_iio_set_mapping(struct intel_uncore_type *type)
 
        ret = skx_iio_get_topology(type);
        if (ret)
-               return ret;
+               goto clear_attr_update;
+
+       ret = -ENOMEM;
 
        /* One more for NULL. */
        attrs = kcalloc((uncore_max_dies() + 1), sizeof(*attrs), GFP_KERNEL);
@@ -3781,8 +3788,9 @@ err:
        kfree(eas);
        kfree(attrs);
        kfree(type->topology);
+clear_attr_update:
        type->attr_update = NULL;
-       return -ENOMEM;
+       return ret;
 }
 
 static void skx_iio_cleanup_mapping(struct intel_uncore_type *type)
@@ -4551,12 +4559,46 @@ static struct intel_uncore_type snr_uncore_m2m = {
        .format_group   = &snr_m2m_uncore_format_group,
 };
 
+static void snr_uncore_pci_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, hwc->config_base, (u32)(hwc->config | SNBEP_PMON_CTL_EN));
+       pci_write_config_dword(pdev, hwc->config_base + 4, (u32)(hwc->config >> 32));
+}
+
+static struct intel_uncore_ops snr_pcie3_uncore_pci_ops = {
+       .init_box       = snr_m2m_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = snbep_uncore_pci_disable_event,
+       .enable_event   = snr_uncore_pci_enable_event,
+       .read_counter   = snbep_uncore_pci_read_counter,
+};
+
+static struct intel_uncore_type snr_uncore_pcie3 = {
+       .name           = "pcie3",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .perf_ctr       = SNR_PCIE3_PCI_PMON_CTR0,
+       .event_ctl      = SNR_PCIE3_PCI_PMON_CTL0,
+       .event_mask     = SKX_IIO_PMON_RAW_EVENT_MASK,
+       .event_mask_ext = SKX_IIO_PMON_RAW_EVENT_MASK_EXT,
+       .box_ctl        = SNR_PCIE3_PCI_PMON_BOX_CTL,
+       .ops            = &snr_pcie3_uncore_pci_ops,
+       .format_group   = &skx_uncore_iio_format_group,
+};
+
 enum {
        SNR_PCI_UNCORE_M2M,
+       SNR_PCI_UNCORE_PCIE3,
 };
 
 static struct intel_uncore_type *snr_pci_uncores[] = {
        [SNR_PCI_UNCORE_M2M]            = &snr_uncore_m2m,
+       [SNR_PCI_UNCORE_PCIE3]          = &snr_uncore_pcie3,
        NULL,
 };
 
@@ -4573,6 +4615,19 @@ static struct pci_driver snr_uncore_pci_driver = {
        .id_table       = snr_uncore_pci_ids,
 };
 
+static const struct pci_device_id snr_uncore_pci_sub_ids[] = {
+       { /* PCIe3 RP */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x334a),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(4, 0, SNR_PCI_UNCORE_PCIE3, 0),
+       },
+       { /* end: all zeroes */ }
+};
+
+static struct pci_driver snr_uncore_pci_sub_driver = {
+       .name           = "snr_uncore_sub",
+       .id_table       = snr_uncore_pci_sub_ids,
+};
+
 int snr_uncore_pci_init(void)
 {
        /* SNR UBOX DID */
@@ -4584,6 +4639,7 @@ int snr_uncore_pci_init(void)
 
        uncore_pci_uncores = snr_pci_uncores;
        uncore_pci_driver = &snr_uncore_pci_driver;
+       uncore_pci_sub_driver = &snr_uncore_pci_sub_driver;
        return 0;
 }
 
@@ -4751,10 +4807,10 @@ static struct uncore_event_desc snr_uncore_imc_freerunning_events[] = {
        INTEL_UNCORE_EVENT_DESC(dclk,           "event=0xff,umask=0x10"),
 
        INTEL_UNCORE_EVENT_DESC(read,           "event=0xff,umask=0x20"),
-       INTEL_UNCORE_EVENT_DESC(read.scale,     "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(read.scale,     "6.103515625e-5"),
        INTEL_UNCORE_EVENT_DESC(read.unit,      "MiB"),
        INTEL_UNCORE_EVENT_DESC(write,          "event=0xff,umask=0x21"),
-       INTEL_UNCORE_EVENT_DESC(write.scale,    "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(write.scale,    "6.103515625e-5"),
        INTEL_UNCORE_EVENT_DESC(write.unit,     "MiB"),
        { /* end: all zeroes */ },
 };
@@ -5212,17 +5268,17 @@ static struct uncore_event_desc icx_uncore_imc_freerunning_events[] = {
        INTEL_UNCORE_EVENT_DESC(dclk,                   "event=0xff,umask=0x10"),
 
        INTEL_UNCORE_EVENT_DESC(read,                   "event=0xff,umask=0x20"),
-       INTEL_UNCORE_EVENT_DESC(read.scale,             "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(read.scale,             "6.103515625e-5"),
        INTEL_UNCORE_EVENT_DESC(read.unit,              "MiB"),
        INTEL_UNCORE_EVENT_DESC(write,                  "event=0xff,umask=0x21"),
-       INTEL_UNCORE_EVENT_DESC(write.scale,            "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(write.scale,            "6.103515625e-5"),
        INTEL_UNCORE_EVENT_DESC(write.unit,             "MiB"),
 
        INTEL_UNCORE_EVENT_DESC(ddrt_read,              "event=0xff,umask=0x30"),
-       INTEL_UNCORE_EVENT_DESC(ddrt_read.scale,        "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(ddrt_read.scale,        "6.103515625e-5"),
        INTEL_UNCORE_EVENT_DESC(ddrt_read.unit,         "MiB"),
        INTEL_UNCORE_EVENT_DESC(ddrt_write,             "event=0xff,umask=0x31"),
-       INTEL_UNCORE_EVENT_DESC(ddrt_write.scale,       "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(ddrt_write.scale,       "6.103515625e-5"),
        INTEL_UNCORE_EVENT_DESC(ddrt_write.unit,        "MiB"),
        { /* end: all zeroes */ },
 };
index a949f6f..4be8f9c 100644 (file)
@@ -78,6 +78,7 @@ static bool test_intel(int idx, void *data)
        case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
        case INTEL_FAM6_ATOM_TREMONT_D:
        case INTEL_FAM6_ATOM_TREMONT:
+       case INTEL_FAM6_ATOM_TREMONT_L:
 
        case INTEL_FAM6_XEON_PHI_KNL:
        case INTEL_FAM6_XEON_PHI_KNM:
index 7b68ab5..ee2b9b9 100644 (file)
@@ -79,6 +79,31 @@ static inline bool constraint_match(struct event_constraint *c, u64 ecode)
 #define PERF_X86_EVENT_PEBS_VIA_PT     0x0800 /* use PT buffer for PEBS */
 #define PERF_X86_EVENT_PAIR            0x1000 /* Large Increment per Cycle */
 #define PERF_X86_EVENT_LBR_SELECT      0x2000 /* Save/Restore MSR_LBR_SELECT */
+#define PERF_X86_EVENT_TOPDOWN         0x4000 /* Count Topdown slots/metrics events */
+
+static inline bool is_topdown_count(struct perf_event *event)
+{
+       return event->hw.flags & PERF_X86_EVENT_TOPDOWN;
+}
+
+static inline bool is_metric_event(struct perf_event *event)
+{
+       u64 config = event->attr.config;
+
+       return ((config & ARCH_PERFMON_EVENTSEL_EVENT) == 0) &&
+               ((config & INTEL_ARCH_EVENT_MASK) >= INTEL_TD_METRIC_RETIRING)  &&
+               ((config & INTEL_ARCH_EVENT_MASK) <= INTEL_TD_METRIC_MAX);
+}
+
+static inline bool is_slots_event(struct perf_event *event)
+{
+       return (event->attr.config & INTEL_ARCH_EVENT_MASK) == INTEL_TD_SLOTS;
+}
+
+static inline bool is_topdown_event(struct perf_event *event)
+{
+       return is_metric_event(event) || is_slots_event(event);
+}
 
 struct amd_nb {
        int nb_id;  /* NorthBridge id */
@@ -210,6 +235,8 @@ struct cpu_hw_events {
                                             they've never been enabled yet */
        int                     n_txn;    /* the # last events in the below arrays;
                                             added in the current transaction */
+       int                     n_txn_pair;
+       int                     n_txn_metric;
        int                     assign[X86_PMC_IDX_MAX]; /* event to counter assignment */
        u64                     tags[X86_PMC_IDX_MAX];
 
@@ -285,6 +312,12 @@ struct cpu_hw_events {
        u64                             tfa_shadow;
 
        /*
+        * Perf Metrics
+        */
+       /* number of accepted metrics events */
+       int                             n_metric;
+
+       /*
         * AMD specific bits
         */
        struct amd_nb                   *amd_nb;
@@ -376,6 +409,19 @@ struct cpu_hw_events {
        EVENT_CONSTRAINT(c, (1ULL << (32+n)), FIXED_EVENT_FLAGS)
 
 /*
+ * The special metric counters do not actually exist. They are calculated from
+ * the combination of the FxCtr3 + MSR_PERF_METRICS.
+ *
+ * The special metric counters are mapped to a dummy offset for the scheduler.
+ * The sharing between multiple users of the same metric without multiplexing
+ * is not allowed, even though the hardware supports that in principle.
+ */
+
+#define METRIC_EVENT_CONSTRAINT(c, n)                                  \
+       EVENT_CONSTRAINT(c, (1ULL << (INTEL_PMC_IDX_METRIC_BASE + n)),  \
+                        INTEL_ARCH_EVENT_MASK)
+
+/*
  * Constraint on the Event code + UMask
  */
 #define INTEL_UEVENT_CONSTRAINT(c, n)  \
@@ -537,7 +583,7 @@ union perf_capabilities {
                 */
                u64     full_width_write:1;
                u64     pebs_baseline:1;
-               u64     pebs_metrics_available:1;
+               u64     perf_metrics:1;
                u64     pebs_output_pt_available:1;
        };
        u64     capabilities;
@@ -727,6 +773,12 @@ struct x86_pmu {
        atomic_t        lbr_exclusive[x86_lbr_exclusive_max];
 
        /*
+        * Intel perf metrics
+        */
+       u64             (*update_topdown_event)(struct perf_event *event);
+       int             (*set_topdown_event_period)(struct perf_event *event);
+
+       /*
         * perf task context (i.e. struct perf_event_context::task_ctx_data)
         * switch helper to bridge calls from perf/core to perf/x86.
         * See struct pmu::swap_task_ctx() usage for examples;
index 67b411f..7c0120e 100644 (file)
@@ -815,6 +815,7 @@ static const struct x86_cpu_id rapl_model_match[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X,    &model_spr),
        X86_MATCH_VENDOR_FAM(AMD,       0x17,           &model_amd_fam17h),
        X86_MATCH_VENDOR_FAM(HYGON,     0x18,           &model_amd_fam17h),
+       X86_MATCH_VENDOR_FAM(AMD,       0x19,           &model_amd_fam17h),
        {},
 };
 MODULE_DEVICE_TABLE(x86cpu, rapl_model_match);
index 6035df1..e04d90a 100644 (file)
@@ -148,9 +148,9 @@ static inline bool hv_reenlightenment_available(void)
         * Check for required features and priviliges to make TSC frequency
         * change notifications work.
         */
-       return ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
+       return ms_hyperv.features & HV_ACCESS_FREQUENCY_MSRS &&
                ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE &&
-               ms_hyperv.features & HV_X64_ACCESS_REENLIGHTENMENT;
+               ms_hyperv.features & HV_ACCESS_REENLIGHTENMENT;
 }
 
 DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_reenlightenment)
@@ -330,8 +330,8 @@ void __init hyperv_init(void)
                return;
 
        /* Absolutely required MSRs */
-       required_msrs = HV_X64_MSR_HYPERCALL_AVAILABLE |
-               HV_X64_MSR_VP_INDEX_AVAILABLE;
+       required_msrs = HV_MSR_HYPERCALL_AVAILABLE |
+               HV_MSR_VP_INDEX_AVAILABLE;
 
        if ((ms_hyperv.features & required_msrs) != required_msrs)
                return;
index 07f21a0..f3270c1 100644 (file)
@@ -66,7 +66,7 @@ void __init hv_init_spinlocks(void)
 {
        if (!hv_pvspin || !apic ||
            !(ms_hyperv.hints & HV_X64_CLUSTER_IPI_RECOMMENDED) ||
-           !(ms_hyperv.features & HV_X64_MSR_GUEST_IDLE_AVAILABLE)) {
+           !(ms_hyperv.features & HV_MSR_GUEST_IDLE_AVAILABLE)) {
                pr_info("PV spinlocks disabled\n");
                return;
        }
index ca09764..6d2df1e 100644 (file)
@@ -159,8 +159,6 @@ static inline u64 x86_default_get_root_pointer(void)
 extern int x86_acpi_numa_init(void);
 #endif /* CONFIG_ACPI_NUMA */
 
-#define acpi_unlazy_tlb(x)     leave_mm(x)
-
 #ifdef CONFIG_ACPI_APEI
 static inline pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr)
 {
index 2cc44e9..1c129ab 100644 (file)
@@ -519,6 +519,14 @@ static inline bool apic_id_is_primary_thread(unsigned int id) { return false; }
 static inline void apic_smt_update(void) { }
 #endif
 
+struct msi_msg;
+
+#ifdef CONFIG_PCI_MSI
+void x86_vector_msi_compose_msg(struct irq_data *data, struct msi_msg *msg);
+#else
+# define x86_vector_msi_compose_msg NULL
+#endif
+
 extern void ioapic_zap_locks(void);
 
 #endif /* _ASM_X86_APIC_H */
index 5a42f92..51e2bf2 100644 (file)
@@ -5,6 +5,7 @@
 #include <asm/string.h>
 #include <asm/page.h>
 #include <asm/checksum.h>
+#include <asm/mce.h>
 
 #include <asm-generic/asm-prototypes.h>
 
index 5c15f95..0603c74 100644 (file)
 # define _ASM_EXTABLE_UA(from, to)                             \
        _ASM_EXTABLE_HANDLE(from, to, ex_handler_uaccess)
 
+# define _ASM_EXTABLE_CPY(from, to)                            \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_copy)
+
 # define _ASM_EXTABLE_FAULT(from, to)                          \
        _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
 
-# define _ASM_NOKPROBE(entry)                                  \
+# ifdef CONFIG_KPROBES
+#  define _ASM_NOKPROBE(entry)                                 \
        .pushsection "_kprobe_blacklist","aw" ;                 \
        _ASM_ALIGN ;                                            \
        _ASM_PTR (entry);                                       \
        .popsection
+# else
+#  define _ASM_NOKPROBE(entry)
+# endif
 
 #else /* ! __ASSEMBLY__ */
 # define _EXPAND_EXTABLE_HANDLE(x) #x
 # define _ASM_EXTABLE_UA(from, to)                             \
        _ASM_EXTABLE_HANDLE(from, to, ex_handler_uaccess)
 
+# define _ASM_EXTABLE_CPY(from, to)                            \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_copy)
+
 # define _ASM_EXTABLE_FAULT(from, to)                          \
        _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
 
index 0ada98d..bca625a 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #define  _HAVE_ARCH_COPY_AND_CSUM_FROM_USER 1
 #define HAVE_CSUM_COPY_USER
+#define _HAVE_ARCH_CSUM_AND_COPY
 #ifdef CONFIG_X86_32
 # include <asm/checksum_32.h>
 #else
index 11624c8..17da953 100644 (file)
@@ -27,9 +27,7 @@ asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
  * better 64-bit) boundary
  */
 
-asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
-                                           int len, __wsum sum,
-                                           int *src_err_ptr, int *dst_err_ptr);
+asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
 
 /*
  *     Note: when you get a NULL pointer exception here this means someone
@@ -38,26 +36,20 @@ asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
  *     If you use these functions directly please don't forget the
  *     access_ok().
  */
-static inline __wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                              int len, __wsum sum)
+static inline __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
 {
-       return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL);
+       return csum_partial_copy_generic(src, dst, len);
 }
 
 static inline __wsum csum_and_copy_from_user(const void __user *src,
-                                            void *dst, int len,
-                                            __wsum sum, int *err_ptr)
+                                            void *dst, int len)
 {
        __wsum ret;
 
        might_sleep();
-       if (!user_access_begin(src, len)) {
-               if (len)
-                       *err_ptr = -EFAULT;
-               return sum;
-       }
-       ret = csum_partial_copy_generic((__force void *)src, dst,
-                                       len, sum, err_ptr, NULL);
+       if (!user_access_begin(src, len))
+               return 0;
+       ret = csum_partial_copy_generic((__force void *)src, dst, len);
        user_access_end();
 
        return ret;
@@ -178,23 +170,17 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
  */
 static inline __wsum csum_and_copy_to_user(const void *src,
                                           void __user *dst,
-                                          int len, __wsum sum,
-                                          int *err_ptr)
+                                          int len)
 {
        __wsum ret;
 
        might_sleep();
-       if (user_access_begin(dst, len)) {
-               ret = csum_partial_copy_generic(src, (__force void *)dst,
-                                               len, sum, NULL, err_ptr);
-               user_access_end();
-               return ret;
-       }
+       if (!user_access_begin(dst, len))
+               return 0;
 
-       if (len)
-               *err_ptr = -EFAULT;
-
-       return (__force __wsum)-1; /* invalid checksum */
+       ret = csum_partial_copy_generic(src, (__force void *)dst, len);
+       user_access_end();
+       return ret;
 }
 
 #endif /* _ASM_X86_CHECKSUM_32_H */
index 0a289b8..407beeb 100644 (file)
@@ -130,17 +130,11 @@ static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
 extern __wsum csum_partial(const void *buff, int len, __wsum sum);
 
 /* Do not call this directly. Use the wrappers below */
-extern __visible __wsum csum_partial_copy_generic(const void *src, const void *dst,
-                                       int len, __wsum sum,
-                                       int *src_err_ptr, int *dst_err_ptr);
+extern __visible __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
 
-
-extern __wsum csum_and_copy_from_user(const void __user *src, void *dst,
-                                         int len, __wsum isum, int *errp);
-extern __wsum csum_and_copy_to_user(const void *src, void __user *dst,
-                                       int len, __wsum isum, int *errp);
-extern __wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                       int len, __wsum sum);
+extern __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len);
+extern __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len);
+extern __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
 
 /**
  * ip_compute_csum - Compute an 16bit IP checksum.
index d4edf28..0e327a0 100644 (file)
@@ -27,8 +27,6 @@ typedef u16           compat_nlink_t;
 typedef u16            compat_ipc_pid_t;
 typedef u32            compat_caddr_t;
 typedef __kernel_fsid_t        compat_fsid_t;
-typedef s64 __attribute__((aligned(4))) compat_s64;
-typedef u64 __attribute__((aligned(4))) compat_u64;
 
 struct compat_stat {
        compat_dev_t    st_dev;
@@ -211,6 +209,7 @@ static inline bool in_compat_syscall(void)
        return in_32bit_syscall();
 }
 #define in_compat_syscall in_compat_syscall    /* override the generic impl */
+#define compat_need_64bit_alignment_fixup in_ia32_syscall
 #endif
 
 struct compat_siginfo;
diff --git a/arch/x86/include/asm/copy_mc_test.h b/arch/x86/include/asm/copy_mc_test.h
new file mode 100644 (file)
index 0000000..e4991ba
--- /dev/null
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _COPY_MC_TEST_H_
+#define _COPY_MC_TEST_H_
+
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_COPY_MC_TEST
+extern unsigned long copy_mc_test_src;
+extern unsigned long copy_mc_test_dst;
+
+static inline void copy_mc_inject_src(void *addr)
+{
+       if (addr)
+               copy_mc_test_src = (unsigned long) addr;
+       else
+               copy_mc_test_src = ~0UL;
+}
+
+static inline void copy_mc_inject_dst(void *addr)
+{
+       if (addr)
+               copy_mc_test_dst = (unsigned long) addr;
+       else
+               copy_mc_test_dst = ~0UL;
+}
+#else /* CONFIG_COPY_MC_TEST */
+static inline void copy_mc_inject_src(void *addr)
+{
+}
+
+static inline void copy_mc_inject_dst(void *addr)
+{
+}
+#endif /* CONFIG_COPY_MC_TEST */
+
+#else /* __ASSEMBLY__ */
+#include <asm/export.h>
+
+#ifdef CONFIG_COPY_MC_TEST
+.macro COPY_MC_TEST_CTL
+       .pushsection .data
+       .align 8
+       .globl copy_mc_test_src
+       copy_mc_test_src:
+               .quad 0
+       EXPORT_SYMBOL_GPL(copy_mc_test_src)
+       .globl copy_mc_test_dst
+       copy_mc_test_dst:
+               .quad 0
+       EXPORT_SYMBOL_GPL(copy_mc_test_dst)
+       .popsection
+.endm
+
+.macro COPY_MC_TEST_SRC reg count target
+       leaq \count(\reg), %r9
+       cmp copy_mc_test_src, %r9
+       ja \target
+.endm
+
+.macro COPY_MC_TEST_DST reg count target
+       leaq \count(\reg), %r9
+       cmp copy_mc_test_dst, %r9
+       ja \target
+.endm
+#else
+.macro COPY_MC_TEST_CTL
+.endm
+
+.macro COPY_MC_TEST_SRC reg count target
+.endm
+
+.macro COPY_MC_TEST_DST reg count target
+.endm
+#endif /* CONFIG_COPY_MC_TEST */
+#endif /* __ASSEMBLY__ */
+#endif /* _COPY_MC_TEST_H_ */
index 2901d5d..7b0afd5 100644 (file)
@@ -96,7 +96,7 @@
 #define X86_FEATURE_SYSCALL32          ( 3*32+14) /* "" syscall in IA32 userspace */
 #define X86_FEATURE_SYSENTER32         ( 3*32+15) /* "" sysenter in IA32 userspace */
 #define X86_FEATURE_REP_GOOD           ( 3*32+16) /* REP microcode works well */
-/* free                                        ( 3*32+17) */
+#define X86_FEATURE_SME_COHERENT       ( 3*32+17) /* "" AMD hardware-enforced cache coherency */
 #define X86_FEATURE_LFENCE_RDTSC       ( 3*32+18) /* "" LFENCE synchronizes RDTSC */
 #define X86_FEATURE_ACC_POWER          ( 3*32+19) /* AMD Accumulated Power Mechanism */
 #define X86_FEATURE_NOPL               ( 3*32+20) /* The NOPL (0F 1F) instructions */
 #define X86_FEATURE_FENCE_SWAPGS_USER  (11*32+ 4) /* "" LFENCE in user entry SWAPGS path */
 #define X86_FEATURE_FENCE_SWAPGS_KERNEL        (11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */
 #define X86_FEATURE_SPLIT_LOCK_DETECT  (11*32+ 6) /* #AC for split lock */
+#define X86_FEATURE_PER_THREAD_MBA     (11*32+ 7) /* "" Per-thread Memory Bandwidth Allocation */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX512_BF16                (12*32+ 5) /* AVX512 BFLOAT16 instructions */
 #define X86_FEATURE_CLDEMOTE           (16*32+25) /* CLDEMOTE instruction */
 #define X86_FEATURE_MOVDIRI            (16*32+27) /* MOVDIRI instruction */
 #define X86_FEATURE_MOVDIR64B          (16*32+28) /* MOVDIR64B instruction */
+#define X86_FEATURE_ENQCMD             (16*32+29) /* ENQCMD and ENQCMDS instructions */
 
 /* AMD-defined CPU features, CPUID level 0x80000007 (EBX), word 17 */
 #define X86_FEATURE_OVERFLOW_RECOV     (17*32+ 0) /* MCA overflow recovery support */
 #define X86_FEATURE_MD_CLEAR           (18*32+10) /* VERW clears CPU buffers */
 #define X86_FEATURE_TSX_FORCE_ABORT    (18*32+13) /* "" TSX_FORCE_ABORT */
 #define X86_FEATURE_SERIALIZE          (18*32+14) /* SERIALIZE instruction */
+#define X86_FEATURE_TSXLDTRK           (18*32+16) /* TSX Suspend Load Address Tracking */
 #define X86_FEATURE_PCONFIG            (18*32+18) /* Intel PCONFIG */
 #define X86_FEATURE_ARCH_LBR           (18*32+19) /* Intel ARCH LBR */
 #define X86_FEATURE_SPEC_CTRL          (18*32+26) /* "" Speculation Control (IBRS + IBPB) */
index e89558a..cfdf307 100644 (file)
@@ -90,8 +90,6 @@ static __always_inline bool hw_breakpoint_active(void)
        return __this_cpu_read(cpu_dr7) & DR_GLOBAL_ENABLE_MASK;
 }
 
-extern void aout_dump_debugregs(struct user *dump);
-
 extern void hw_breakpoint_restore(void);
 
 static __always_inline unsigned long local_db_save(void)
index 4ea8584..5861d34 100644 (file)
 # define DISABLE_PTI           (1 << (X86_FEATURE_PTI & 31))
 #endif
 
+#ifdef CONFIG_IOMMU_SUPPORT
+# define DISABLE_ENQCMD        0
+#else
+# define DISABLE_ENQCMD (1 << (X86_FEATURE_ENQCMD & 31))
+#endif
+
 /*
  * Make sure to add features to the correct mask
  */
@@ -75,7 +81,8 @@
 #define DISABLED_MASK13        0
 #define DISABLED_MASK14        0
 #define DISABLED_MASK15        0
-#define DISABLED_MASK16        (DISABLE_PKU|DISABLE_OSPKE|DISABLE_LA57|DISABLE_UMIP)
+#define DISABLED_MASK16        (DISABLE_PKU|DISABLE_OSPKE|DISABLE_LA57|DISABLE_UMIP| \
+                        DISABLE_ENQCMD)
 #define DISABLED_MASK17        0
 #define DISABLED_MASK18        0
 #define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
index a8f9315..6fe54b2 100644 (file)
@@ -18,8 +18,16 @@ static __always_inline void arch_check_user_regs(struct pt_regs *regs)
                 * state, not the interrupt state as imagined by Xen.
                 */
                unsigned long flags = native_save_fl();
-               WARN_ON_ONCE(flags & (X86_EFLAGS_AC | X86_EFLAGS_DF |
-                                     X86_EFLAGS_NT));
+               unsigned long mask = X86_EFLAGS_DF | X86_EFLAGS_NT;
+
+               /*
+                * For !SMAP hardware we patch out CLAC on entry.
+                */
+               if (boot_cpu_has(X86_FEATURE_SMAP) ||
+                   (IS_ENABLED(CONFIG_64_BIT) && boot_cpu_has(X86_FEATURE_XENPV)))
+                       mask |= X86_EFLAGS_AC;
+
+               WARN_ON_ONCE(flags & mask);
 
                /* We think we came from user mode. Make sure pt_regs agrees. */
                WARN_ON_ONCE(!user_mode(regs));
index d8c2198..1f0cbc5 100644 (file)
@@ -29,10 +29,17 @@ struct pt_regs;
                (b)->handler = (tmp).handler - (delta);         \
        } while (0)
 
+enum handler_type {
+       EX_HANDLER_NONE,
+       EX_HANDLER_FAULT,
+       EX_HANDLER_UACCESS,
+       EX_HANDLER_OTHER
+};
+
 extern int fixup_exception(struct pt_regs *regs, int trapnr,
                           unsigned long error_code, unsigned long fault_addr);
 extern int fixup_bug(struct pt_regs *regs, int trapnr);
-extern bool ex_has_fault_handler(unsigned long ip);
+extern enum handler_type ex_get_fault_handler_type(unsigned long ip);
 extern void early_fixup_exception(struct pt_regs *regs, int trapnr);
 
 #endif
index 0f0dd64..77217bd 100644 (file)
@@ -99,7 +99,7 @@ enum fixed_addresses {
        FIX_PCIE_MCFG,
 #endif
 #endif
-#ifdef CONFIG_PARAVIRT
+#ifdef CONFIG_PARAVIRT_XXL
        FIX_PARAVIRT_BOOTMAP,
 #endif
 #ifdef CONFIG_X86_INTEL_MID
index b774c52..dcd9503 100644 (file)
@@ -62,4 +62,16 @@ extern void switch_fpu_return(void);
  */
 extern int cpu_has_xfeatures(u64 xfeatures_mask, const char **feature_name);
 
+/*
+ * Tasks that are not using SVA have mm->pasid set to zero to note that they
+ * will not have the valid bit set in MSR_IA32_PASID while they are running.
+ */
+#define PASID_DISABLED 0
+
+#ifdef CONFIG_IOMMU_SUPPORT
+/* Update current's PASID MSR/state by mm's PASID. */
+void update_pasid(void);
+#else
+static inline void update_pasid(void) { }
+#endif
 #endif /* _ASM_X86_FPU_API_H */
index 0a460f2..eb1ed3b 100644 (file)
@@ -583,6 +583,13 @@ static inline void switch_fpu_finish(struct fpu *new_fpu)
                        pkru_val = pk->pkru;
        }
        __write_pkru(pkru_val);
+
+       /*
+        * Expensive PASID MSR write will be avoided in update_pasid() because
+        * TIF_NEED_FPU_LOAD was set. And the PASID state won't be updated
+        * unless it's different from mm->pasid to reduce overhead.
+        */
+       update_pasid();
 }
 
 /*
@@ -602,9 +609,7 @@ static inline u64 xgetbv(u32 index)
 {
        u32 eax, edx;
 
-       asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */
-                    : "=a" (eax), "=d" (edx)
-                    : "c" (index));
+       asm volatile("xgetbv" : "=a" (eax), "=d" (edx) : "c" (index));
        return eax + ((u64)edx << 32);
 }
 
@@ -613,8 +618,7 @@ static inline void xsetbv(u32 index, u64 value)
        u32 eax = value;
        u32 edx = value >> 32;
 
-       asm volatile(".byte 0x0f,0x01,0xd1" /* xsetbv */
-                    : : "a" (eax), "d" (edx), "c" (index));
+       asm volatile("xsetbv" :: "a" (eax), "d" (edx), "c" (index));
 }
 
 #endif /* _ASM_X86_FPU_INTERNAL_H */
index c87364e..f5a38a5 100644 (file)
@@ -114,7 +114,7 @@ enum xfeature {
        XFEATURE_Hi16_ZMM,
        XFEATURE_PT_UNIMPLEMENTED_SO_FAR,
        XFEATURE_PKRU,
-       XFEATURE_RSRVD_COMP_10,
+       XFEATURE_PASID,
        XFEATURE_RSRVD_COMP_11,
        XFEATURE_RSRVD_COMP_12,
        XFEATURE_RSRVD_COMP_13,
@@ -134,6 +134,7 @@ enum xfeature {
 #define XFEATURE_MASK_Hi16_ZMM         (1 << XFEATURE_Hi16_ZMM)
 #define XFEATURE_MASK_PT               (1 << XFEATURE_PT_UNIMPLEMENTED_SO_FAR)
 #define XFEATURE_MASK_PKRU             (1 << XFEATURE_PKRU)
+#define XFEATURE_MASK_PASID            (1 << XFEATURE_PASID)
 #define XFEATURE_MASK_LBR              (1 << XFEATURE_LBR)
 
 #define XFEATURE_MASK_FPSSE            (XFEATURE_MASK_FP | XFEATURE_MASK_SSE)
@@ -256,6 +257,14 @@ struct arch_lbr_state {
        struct lbr_entry                entries[];
 } __packed;
 
+/*
+ * State component 10 is supervisor state used for context-switching the
+ * PASID state.
+ */
+struct ia32_pasid_state {
+       u64 pasid;
+} __packed;
+
 struct xstate_header {
        u64                             xfeatures;
        u64                             xcomp_bv;
index 14ab815..47a9223 100644 (file)
@@ -35,7 +35,7 @@
                                      XFEATURE_MASK_BNDCSR)
 
 /* All currently supported supervisor features */
-#define XFEATURE_MASK_SUPERVISOR_SUPPORTED (0)
+#define XFEATURE_MASK_SUPERVISOR_SUPPORTED (XFEATURE_MASK_PASID)
 
 /*
  * A supervisor state component may not always contain valuable information,
index 296b346..fb42659 100644 (file)
 #define FRAME_END "pop %" _ASM_BP "\n"
 
 #ifdef CONFIG_X86_64
+
 #define ENCODE_FRAME_POINTER                   \
        "lea 1(%rsp), %rbp\n\t"
+
+static inline unsigned long encode_frame_pointer(struct pt_regs *regs)
+{
+       return (unsigned long)regs + 1;
+}
+
 #else /* !CONFIG_X86_64 */
+
 #define ENCODE_FRAME_POINTER                   \
        "movl %esp, %ebp\n\t"                   \
        "andl $0x7fffffff, %ebp\n\t"
+
+static inline unsigned long encode_frame_pointer(struct pt_regs *regs)
+{
+       return (unsigned long)regs & 0x7fffffff;
+}
+
 #endif /* CONFIG_X86_64 */
 
 #endif /* __ASSEMBLY__ */
 
 #define ENCODE_FRAME_POINTER
 
+static inline unsigned long encode_frame_pointer(struct pt_regs *regs)
+{
+       return 0;
+}
+
 #endif
 
 #define FRAME_BEGIN
index d552646..35cff5f 100644 (file)
@@ -57,7 +57,7 @@ static inline unsigned long x86_fsbase_read_cpu(void)
 {
        unsigned long fsbase;
 
-       if (static_cpu_has(X86_FEATURE_FSGSBASE))
+       if (boot_cpu_has(X86_FEATURE_FSGSBASE))
                fsbase = rdfsbase();
        else
                rdmsrl(MSR_FS_BASE, fsbase);
@@ -67,7 +67,7 @@ static inline unsigned long x86_fsbase_read_cpu(void)
 
 static inline void x86_fsbase_write_cpu(unsigned long fsbase)
 {
-       if (static_cpu_has(X86_FEATURE_FSGSBASE))
+       if (boot_cpu_has(X86_FEATURE_FSGSBASE))
                wrfsbase(fsbase);
        else
                wrmsrl(MSR_FS_BASE, fsbase);
index 74c1243..a4aeeaa 100644 (file)
@@ -36,61 +36,56 @@ struct msi_desc;
 enum irq_alloc_type {
        X86_IRQ_ALLOC_TYPE_IOAPIC = 1,
        X86_IRQ_ALLOC_TYPE_HPET,
-       X86_IRQ_ALLOC_TYPE_MSI,
-       X86_IRQ_ALLOC_TYPE_MSIX,
+       X86_IRQ_ALLOC_TYPE_PCI_MSI,
+       X86_IRQ_ALLOC_TYPE_PCI_MSIX,
        X86_IRQ_ALLOC_TYPE_DMAR,
        X86_IRQ_ALLOC_TYPE_UV,
+       X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT,
+       X86_IRQ_ALLOC_TYPE_HPET_GET_PARENT,
 };
 
+struct ioapic_alloc_info {
+       int                             pin;
+       int                             node;
+       u32                             trigger : 1;
+       u32                             polarity : 1;
+       u32                             valid : 1;
+       struct IO_APIC_route_entry      *entry;
+};
+
+struct uv_alloc_info {
+       int             limit;
+       int             blade;
+       unsigned long   offset;
+       char            *name;
+
+};
+
+/**
+ * irq_alloc_info - X86 specific interrupt allocation info
+ * @type:      X86 specific allocation type
+ * @flags:     Flags for allocation tweaks
+ * @devid:     Device ID for allocations
+ * @hwirq:     Associated hw interrupt number in the domain
+ * @mask:      CPU mask for vector allocation
+ * @desc:      Pointer to msi descriptor
+ * @data:      Allocation specific data
+ *
+ * @ioapic:    IOAPIC specific allocation data
+ * @uv:                UV specific allocation data
+*/
 struct irq_alloc_info {
        enum irq_alloc_type     type;
        u32                     flags;
-       const struct cpumask    *mask;  /* CPU mask for vector allocation */
+       u32                     devid;
+       irq_hw_number_t         hwirq;
+       const struct cpumask    *mask;
+       struct msi_desc         *desc;
+       void                    *data;
+
        union {
-               int             unused;
-#ifdef CONFIG_HPET_TIMER
-               struct {
-                       int             hpet_id;
-                       int             hpet_index;
-                       void            *hpet_data;
-               };
-#endif
-#ifdef CONFIG_PCI_MSI
-               struct {
-                       struct pci_dev  *msi_dev;
-                       irq_hw_number_t msi_hwirq;
-               };
-#endif
-#ifdef CONFIG_X86_IO_APIC
-               struct {
-                       int             ioapic_id;
-                       int             ioapic_pin;
-                       int             ioapic_node;
-                       u32             ioapic_trigger : 1;
-                       u32             ioapic_polarity : 1;
-                       u32             ioapic_valid : 1;
-                       struct IO_APIC_route_entry *ioapic_entry;
-               };
-#endif
-#ifdef CONFIG_DMAR_TABLE
-               struct {
-                       int             dmar_id;
-                       void            *dmar_data;
-               };
-#endif
-#ifdef CONFIG_X86_UV
-               struct {
-                       int             uv_limit;
-                       int             uv_blade;
-                       unsigned long   uv_offset;
-                       char            *uv_name;
-               };
-#endif
-#if IS_ENABLED(CONFIG_VMD)
-               struct {
-                       struct msi_desc *desc;
-               };
-#endif
+               struct ioapic_alloc_info        ioapic;
+               struct uv_alloc_info            uv;
        };
 };
 
index 7a4d206..0ed20e8 100644 (file)
 #define HYPERV_CPUID_MAX                       0x4000ffff
 
 /*
- * Aliases for Group A features that have X64 in the name.
- * On x86/x64 these are HYPERV_CPUID_FEATURES.EAX bits.
- */
-
-#define HV_X64_MSR_VP_RUNTIME_AVAILABLE                \
-               HV_MSR_VP_RUNTIME_AVAILABLE
-#define HV_X64_MSR_SYNIC_AVAILABLE             \
-               HV_MSR_SYNIC_AVAILABLE
-#define HV_X64_MSR_APIC_ACCESS_AVAILABLE       \
-               HV_MSR_APIC_ACCESS_AVAILABLE
-#define HV_X64_MSR_HYPERCALL_AVAILABLE         \
-               HV_MSR_HYPERCALL_AVAILABLE
-#define HV_X64_MSR_VP_INDEX_AVAILABLE          \
-               HV_MSR_VP_INDEX_AVAILABLE
-#define HV_X64_MSR_RESET_AVAILABLE             \
-               HV_MSR_RESET_AVAILABLE
-#define HV_X64_MSR_GUEST_IDLE_AVAILABLE                \
-               HV_MSR_GUEST_IDLE_AVAILABLE
-#define HV_X64_ACCESS_FREQUENCY_MSRS           \
-               HV_ACCESS_FREQUENCY_MSRS
-#define HV_X64_ACCESS_REENLIGHTENMENT          \
-               HV_ACCESS_REENLIGHTENMENT
-#define HV_X64_ACCESS_TSC_INVARIANT            \
-               HV_ACCESS_TSC_INVARIANT
-
-/*
- * Aliases for Group B features that have X64 in the name.
- * On x86/x64 these are HYPERV_CPUID_FEATURES.EBX bits.
- */
-#define HV_X64_POST_MESSAGES           HV_POST_MESSAGES
-#define HV_X64_SIGNAL_EVENTS           HV_SIGNAL_EVENTS
-
-/*
  * Group D Features.  The bit assignments are custom to each architecture.
  * On x86/x64 these are HYPERV_CPUID_FEATURES.EDX bits.
  */
index a433661..cdd41d0 100644 (file)
@@ -242,7 +242,7 @@ __visible noinstr void func(struct pt_regs *regs)                   \
        instrumentation_begin();                                        \
        irq_enter_rcu();                                                \
        kvm_set_cpu_l1tf_flush_l1d();                                   \
-       run_on_irqstack_cond(__##func, regs, regs);                     \
+       run_sysvec_on_irqstack_cond(__##func, regs);                    \
        irq_exit_rcu();                                                 \
        instrumentation_end();                                          \
        irqentry_exit(regs, state);                                     \
@@ -547,7 +547,7 @@ DECLARE_IDTENTRY_RAW(X86_TRAP_MC,   exc_machine_check);
 
 /* NMI */
 DECLARE_IDTENTRY_NMI(X86_TRAP_NMI,     exc_nmi);
-#if defined(CONFIG_XEN_PV) && defined(CONFIG_X86_64)
+#ifdef CONFIG_XEN_PV
 DECLARE_IDTENTRY_RAW(X86_TRAP_NMI,     xenpv_exc_nmi);
 #endif
 
@@ -557,7 +557,7 @@ DECLARE_IDTENTRY_DEBUG(X86_TRAP_DB, exc_debug);
 #else
 DECLARE_IDTENTRY_RAW(X86_TRAP_DB,      exc_debug);
 #endif
-#if defined(CONFIG_XEN_PV) && defined(CONFIG_X86_64)
+#ifdef CONFIG_XEN_PV
 DECLARE_IDTENTRY_RAW(X86_TRAP_DB,      xenpv_exc_debug);
 #endif
 
@@ -591,10 +591,6 @@ DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_VECTOR,              sysvec_call_function);
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
-# ifdef CONFIG_X86_UV
-DECLARE_IDTENTRY_SYSVEC(UV_BAU_MESSAGE,                        sysvec_uv_bau_message);
-# endif
-
 # ifdef CONFIG_X86_MCE_THRESHOLD
 DECLARE_IDTENTRY_SYSVEC(THRESHOLD_APIC_VECTOR,         sysvec_threshold);
 # endif
index e1aa17a..d726459 100644 (file)
@@ -401,7 +401,7 @@ extern bool phys_mem_access_encrypted(unsigned long phys_addr,
 
 /**
  * iosubmit_cmds512 - copy data to single MMIO location, in 512-bit units
- * @__dst: destination, in MMIO space (must be 512-bit aligned)
+ * @dst: destination, in MMIO space (must be 512-bit aligned)
  * @src: source
  * @count: number of 512 bits quantities to submit
  *
@@ -412,25 +412,14 @@ extern bool phys_mem_access_encrypted(unsigned long phys_addr,
  * Warning: Do not use this helper unless your driver has checked that the CPU
  * instruction is supported on the platform.
  */
-static inline void iosubmit_cmds512(void __iomem *__dst, const void *src,
+static inline void iosubmit_cmds512(void __iomem *dst, const void *src,
                                    size_t count)
 {
-       /*
-        * Note that this isn't an "on-stack copy", just definition of "dst"
-        * as a pointer to 64-bytes of stuff that is going to be overwritten.
-        * In the MOVDIR64B case that may be needed as you can use the
-        * MOVDIR64B instruction to copy arbitrary memory around. This trick
-        * lets the compiler know how much gets clobbered.
-        */
-       volatile struct { char _[64]; } *dst = __dst;
        const u8 *from = src;
        const u8 *end = from + count * 64;
 
        while (from < end) {
-               /* MOVDIR64B [rdx], rax */
-               asm volatile(".byte 0x66, 0x0f, 0x38, 0xf8, 0x02"
-                            : "=m" (dst)
-                            : "d" (from), "a" (dst));
+               movdir64b(dst, from);
                from += 64;
        }
 }
index 4bc985f..af4a151 100644 (file)
@@ -45,8 +45,6 @@ extern int irq_remap_enable_fault_handling(void);
 extern void panic_if_irq_remap(const char *msg);
 
 extern struct irq_domain *
-irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info);
-extern struct irq_domain *
 irq_remapping_get_irq_domain(struct irq_alloc_info *info);
 
 /* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */
@@ -74,12 +72,6 @@ static inline void panic_if_irq_remap(const char *msg)
 }
 
 static inline struct irq_domain *
-irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info)
-{
-       return NULL;
-}
-
-static inline struct irq_domain *
 irq_remapping_get_irq_domain(struct irq_alloc_info *info)
 {
        return NULL;
index 4ae66f0..7758169 100644 (file)
@@ -12,20 +12,50 @@ static __always_inline bool irqstack_active(void)
        return __this_cpu_read(irq_count) != -1;
 }
 
-void asm_call_on_stack(void *sp, void *func, void *arg);
+void asm_call_on_stack(void *sp, void (*func)(void), void *arg);
+void asm_call_sysvec_on_stack(void *sp, void (*func)(struct pt_regs *regs),
+                             struct pt_regs *regs);
+void asm_call_irq_on_stack(void *sp, void (*func)(struct irq_desc *desc),
+                          struct irq_desc *desc);
 
-static __always_inline void __run_on_irqstack(void *func, void *arg)
+static __always_inline void __run_on_irqstack(void (*func)(void))
 {
        void *tos = __this_cpu_read(hardirq_stack_ptr);
 
        __this_cpu_add(irq_count, 1);
-       asm_call_on_stack(tos - 8, func, arg);
+       asm_call_on_stack(tos - 8, func, NULL);
+       __this_cpu_sub(irq_count, 1);
+}
+
+static __always_inline void
+__run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs),
+                        struct pt_regs *regs)
+{
+       void *tos = __this_cpu_read(hardirq_stack_ptr);
+
+       __this_cpu_add(irq_count, 1);
+       asm_call_sysvec_on_stack(tos - 8, func, regs);
+       __this_cpu_sub(irq_count, 1);
+}
+
+static __always_inline void
+__run_irq_on_irqstack(void (*func)(struct irq_desc *desc),
+                     struct irq_desc *desc)
+{
+       void *tos = __this_cpu_read(hardirq_stack_ptr);
+
+       __this_cpu_add(irq_count, 1);
+       asm_call_irq_on_stack(tos - 8, func, desc);
        __this_cpu_sub(irq_count, 1);
 }
 
 #else /* CONFIG_X86_64 */
 static inline bool irqstack_active(void) { return false; }
-static inline void __run_on_irqstack(void *func, void *arg) { }
+static inline void __run_on_irqstack(void (*func)(void)) { }
+static inline void __run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs),
+                                           struct pt_regs *regs) { }
+static inline void __run_irq_on_irqstack(void (*func)(struct irq_desc *desc),
+                                        struct irq_desc *desc) { }
 #endif /* !CONFIG_X86_64 */
 
 static __always_inline bool irq_needs_irq_stack(struct pt_regs *regs)
@@ -37,17 +67,40 @@ static __always_inline bool irq_needs_irq_stack(struct pt_regs *regs)
        return !user_mode(regs) && !irqstack_active();
 }
 
-static __always_inline void run_on_irqstack_cond(void *func, void *arg,
+
+static __always_inline void run_on_irqstack_cond(void (*func)(void),
                                                 struct pt_regs *regs)
 {
-       void (*__func)(void *arg) = func;
+       lockdep_assert_irqs_disabled();
+
+       if (irq_needs_irq_stack(regs))
+               __run_on_irqstack(func);
+       else
+               func();
+}
+
+static __always_inline void
+run_sysvec_on_irqstack_cond(void (*func)(struct pt_regs *regs),
+                           struct pt_regs *regs)
+{
+       lockdep_assert_irqs_disabled();
 
+       if (irq_needs_irq_stack(regs))
+               __run_sysvec_on_irqstack(func, regs);
+       else
+               func(regs);
+}
+
+static __always_inline void
+run_irq_on_irqstack_cond(void (*func)(struct irq_desc *desc), struct irq_desc *desc,
+                        struct pt_regs *regs)
+{
        lockdep_assert_irqs_disabled();
 
        if (irq_needs_irq_stack(regs))
-               __run_on_irqstack(__func, arg);
+               __run_irq_on_irqstack(func, desc);
        else
-               __func(arg);
+               func(desc);
 }
 
 #endif
index c066ffa..cd684d4 100644 (file)
@@ -51,9 +51,13 @@ extern int mp_irqdomain_ioapic_idx(struct irq_domain *domain);
 #endif /* CONFIG_X86_IO_APIC */
 
 #ifdef CONFIG_PCI_MSI
-extern void arch_init_msi_domain(struct irq_domain *domain);
+void x86_create_pci_msi_domain(void);
+struct irq_domain *native_create_pci_msi_domain(void);
+extern struct irq_domain *x86_pci_msi_default_domain;
 #else
-static inline void arch_init_msi_domain(struct irq_domain *domain) { }
+static inline void x86_create_pci_msi_domain(void) { }
+#define native_create_pci_msi_domain   NULL
+#define x86_pci_msi_default_domain     NULL
 #endif
 
 #endif
index 143bc9a..991a7ad 100644 (file)
@@ -106,5 +106,9 @@ extern int kprobe_exceptions_notify(struct notifier_block *self,
 extern int kprobe_int3_handler(struct pt_regs *regs);
 extern int kprobe_debug_handler(struct pt_regs *regs);
 
+#else
+
+static inline int kprobe_debug_handler(struct pt_regs *regs) { return 0; }
+
 #endif /* CONFIG_KPROBES */
 #endif /* _ASM_X86_KPROBES_H */
index cf50382..a0f1478 100644 (file)
 #define        MCE_HANDLED_NFIT        BIT_ULL(3)
 #define        MCE_HANDLED_EDAC        BIT_ULL(4)
 #define        MCE_HANDLED_MCELOG      BIT_ULL(5)
+
+/*
+ * Indicates an MCE which has happened in kernel space but from
+ * which the kernel can recover simply by executing fixup_exception()
+ * so that an error is returned to the caller of the function that
+ * hit the machine check.
+ */
 #define MCE_IN_KERNEL_RECOV    BIT_ULL(6)
 
 /*
+ * Indicates an MCE that happened in kernel space while copying data
+ * from user. In this case fixup_exception() gets the kernel to the
+ * error exit for the copy function. Machine check handler can then
+ * treat it like a fault taken in user mode.
+ */
+#define MCE_IN_KERNEL_COPYIN   BIT_ULL(7)
+
+/*
  * This structure contains all data related to the MCE log.  Also
  * carries a signature to make it easier to find from external
  * debugging tools.  Each entry is only valid when its finished flag
@@ -174,6 +189,15 @@ extern void mce_unregister_decode_chain(struct notifier_block *nb);
 
 extern int mce_p5_enabled;
 
+#ifdef CONFIG_ARCH_HAS_COPY_MC
+extern void enable_copy_mc_fragile(void);
+unsigned long __must_check copy_mc_fragile(void *dst, const void *src, unsigned cnt);
+#else
+static inline void enable_copy_mc_fragile(void)
+{
+}
+#endif
+
 #ifdef CONFIG_X86_MCE
 int mcheck_init(void);
 void mcheck_cpu_init(struct cpuinfo_x86 *c);
@@ -200,12 +224,8 @@ void mce_setup(struct mce *m);
 void mce_log(struct mce *m);
 DECLARE_PER_CPU(struct device *, mce_device);
 
-/*
- * Maximum banks number.
- * This is the limit of the current register layout on
- * Intel CPUs.
- */
-#define MAX_NR_BANKS 32
+/* Maximum number of MCA banks per CPU. */
+#define MAX_NR_BANKS 64
 
 #ifdef CONFIG_X86_MCE_INTEL
 void mce_intel_feature_init(struct cpuinfo_x86 *c);
@@ -328,7 +348,6 @@ enum smca_bank_types {
 struct smca_hwid {
        unsigned int bank_type; /* Use with smca_bank_types for easy indexing. */
        u32 hwid_mcatype;       /* (hwid,mcatype) tuple */
-       u32 xec_bitmap;         /* Bitmap of valid ExtErrorCodes; current max is 21. */
        u8 count;               /* Number of instances. */
 };
 
diff --git a/arch/x86/include/asm/mcsafe_test.h b/arch/x86/include/asm/mcsafe_test.h
deleted file mode 100644 (file)
index eb59804..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _MCSAFE_TEST_H_
-#define _MCSAFE_TEST_H_
-
-#ifndef __ASSEMBLY__
-#ifdef CONFIG_MCSAFE_TEST
-extern unsigned long mcsafe_test_src;
-extern unsigned long mcsafe_test_dst;
-
-static inline void mcsafe_inject_src(void *addr)
-{
-       if (addr)
-               mcsafe_test_src = (unsigned long) addr;
-       else
-               mcsafe_test_src = ~0UL;
-}
-
-static inline void mcsafe_inject_dst(void *addr)
-{
-       if (addr)
-               mcsafe_test_dst = (unsigned long) addr;
-       else
-               mcsafe_test_dst = ~0UL;
-}
-#else /* CONFIG_MCSAFE_TEST */
-static inline void mcsafe_inject_src(void *addr)
-{
-}
-
-static inline void mcsafe_inject_dst(void *addr)
-{
-}
-#endif /* CONFIG_MCSAFE_TEST */
-
-#else /* __ASSEMBLY__ */
-#include <asm/export.h>
-
-#ifdef CONFIG_MCSAFE_TEST
-.macro MCSAFE_TEST_CTL
-       .pushsection .data
-       .align 8
-       .globl mcsafe_test_src
-       mcsafe_test_src:
-               .quad 0
-       EXPORT_SYMBOL_GPL(mcsafe_test_src)
-       .globl mcsafe_test_dst
-       mcsafe_test_dst:
-               .quad 0
-       EXPORT_SYMBOL_GPL(mcsafe_test_dst)
-       .popsection
-.endm
-
-.macro MCSAFE_TEST_SRC reg count target
-       leaq \count(\reg), %r9
-       cmp mcsafe_test_src, %r9
-       ja \target
-.endm
-
-.macro MCSAFE_TEST_DST reg count target
-       leaq \count(\reg), %r9
-       cmp mcsafe_test_dst, %r9
-       ja \target
-.endm
-#else
-.macro MCSAFE_TEST_CTL
-.endm
-
-.macro MCSAFE_TEST_SRC reg count target
-.endm
-
-.macro MCSAFE_TEST_DST reg count target
-.endm
-#endif /* CONFIG_MCSAFE_TEST */
-#endif /* __ASSEMBLY__ */
-#endif /* _MCSAFE_TEST_H_ */
index 0a301ad..9257667 100644 (file)
@@ -59,5 +59,6 @@ typedef struct {
        }
 
 void leave_mm(int cpu);
+#define leave_mm leave_mm
 
 #endif /* _ASM_X86_MMU_H */
index 606cbae..e90ac7e 100644 (file)
@@ -67,21 +67,11 @@ static inline void find_smp_config(void)
 #ifdef CONFIG_X86_MPPARSE
 extern void e820__memblock_alloc_reserved_mpc_new(void);
 extern int enable_update_mptable;
-extern int default_mpc_apic_id(struct mpc_cpu *m);
-extern void default_smp_read_mpc_oem(struct mpc_table *mpc);
-# ifdef CONFIG_X86_IO_APIC
-extern void default_mpc_oem_bus_info(struct mpc_bus *m, char *str);
-# else
-#  define default_mpc_oem_bus_info NULL
-# endif
 extern void default_find_smp_config(void);
 extern void default_get_smp_config(unsigned int early);
 #else
 static inline void e820__memblock_alloc_reserved_mpc_new(void) { }
 #define enable_update_mptable 0
-#define default_mpc_apic_id NULL
-#define default_smp_read_mpc_oem NULL
-#define default_mpc_oem_bus_info NULL
 #define default_find_smp_config x86_init_noop
 #define default_get_smp_config x86_init_uint_noop
 #endif
index 25ddd09..cd30013 100644 (file)
@@ -9,6 +9,4 @@ typedef struct irq_alloc_info msi_alloc_info_t;
 int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
                    msi_alloc_info_t *arg);
 
-void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc);
-
 #endif /* _ASM_X86_MSI_H */
index 2859ee4..c07a70c 100644 (file)
 #define MSR_IA32_LASTINTFROMIP         0x000001dd
 #define MSR_IA32_LASTINTTOIP           0x000001de
 
+#define MSR_IA32_PASID                 0x00000d93
+#define MSR_IA32_PASID_VALID           BIT_ULL(31)
+
 /* DEBUGCTLMSR bits (others vary by model): */
 #define DEBUGCTLMSR_LBR                        (1UL <<  0) /* last branch recording */
 #define DEBUGCTLMSR_BTF_SHIFT          1
 #define MSR_AMD64_IBSOP_REG_MASK       ((1UL<<MSR_AMD64_IBSOP_REG_COUNT)-1)
 #define MSR_AMD64_IBSCTL               0xc001103a
 #define MSR_AMD64_IBSBRTARGET          0xc001103b
+#define MSR_AMD64_ICIBSEXTDCTL         0xc001103c
 #define MSR_AMD64_IBSOPDATA4           0xc001103d
 #define MSR_AMD64_IBS_REG_COUNT_MAX    8 /* includes MSR_AMD64_IBSBRTARGET */
 #define MSR_AMD64_SEV                  0xc0010131
 #define MSR_CORE_PERF_FIXED_CTR0       0x00000309
 #define MSR_CORE_PERF_FIXED_CTR1       0x0000030a
 #define MSR_CORE_PERF_FIXED_CTR2       0x0000030b
+#define MSR_CORE_PERF_FIXED_CTR3       0x0000030c
 #define MSR_CORE_PERF_FIXED_CTR_CTRL   0x0000038d
 #define MSR_CORE_PERF_GLOBAL_STATUS    0x0000038e
 #define MSR_CORE_PERF_GLOBAL_CTRL      0x0000038f
 #define MSR_CORE_PERF_GLOBAL_OVF_CTRL  0x00000390
 
+#define MSR_PERF_METRICS               0x00000329
+
 /* PERF_GLOBAL_OVF_CTL bits */
 #define MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI_BIT       55
 #define MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI           (1ULL << MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI_BIT)
index 3d2afec..d25cc68 100644 (file)
@@ -160,8 +160,6 @@ static inline void wbinvd(void)
        PVOP_VCALL0(cpu.wbinvd);
 }
 
-#define get_kernel_rpl()  (pv_info.kernel_rpl)
-
 static inline u64 paravirt_read_msr(unsigned msr)
 {
        return PVOP_CALL1(u64, cpu.read_msr, msr);
@@ -277,12 +275,10 @@ static inline void load_TLS(struct thread_struct *t, unsigned cpu)
        PVOP_VCALL2(cpu.load_tls, t, cpu);
 }
 
-#ifdef CONFIG_X86_64
 static inline void load_gs_index(unsigned int gs)
 {
        PVOP_VCALL1(cpu.load_gs_index, gs);
 }
-#endif
 
 static inline void write_ldt_entry(struct desc_struct *dt, int entry,
                                   const void *desc)
@@ -375,52 +371,22 @@ static inline void paravirt_release_p4d(unsigned long pfn)
 
 static inline pte_t __pte(pteval_t val)
 {
-       pteval_t ret;
-
-       if (sizeof(pteval_t) > sizeof(long))
-               ret = PVOP_CALLEE2(pteval_t, mmu.make_pte, val, (u64)val >> 32);
-       else
-               ret = PVOP_CALLEE1(pteval_t, mmu.make_pte, val);
-
-       return (pte_t) { .pte = ret };
+       return (pte_t) { PVOP_CALLEE1(pteval_t, mmu.make_pte, val) };
 }
 
 static inline pteval_t pte_val(pte_t pte)
 {
-       pteval_t ret;
-
-       if (sizeof(pteval_t) > sizeof(long))
-               ret = PVOP_CALLEE2(pteval_t, mmu.pte_val,
-                                  pte.pte, (u64)pte.pte >> 32);
-       else
-               ret = PVOP_CALLEE1(pteval_t, mmu.pte_val, pte.pte);
-
-       return ret;
+       return PVOP_CALLEE1(pteval_t, mmu.pte_val, pte.pte);
 }
 
 static inline pgd_t __pgd(pgdval_t val)
 {
-       pgdval_t ret;
-
-       if (sizeof(pgdval_t) > sizeof(long))
-               ret = PVOP_CALLEE2(pgdval_t, mmu.make_pgd, val, (u64)val >> 32);
-       else
-               ret = PVOP_CALLEE1(pgdval_t, mmu.make_pgd, val);
-
-       return (pgd_t) { ret };
+       return (pgd_t) { PVOP_CALLEE1(pgdval_t, mmu.make_pgd, val) };
 }
 
 static inline pgdval_t pgd_val(pgd_t pgd)
 {
-       pgdval_t ret;
-
-       if (sizeof(pgdval_t) > sizeof(long))
-               ret =  PVOP_CALLEE2(pgdval_t, mmu.pgd_val,
-                                   pgd.pgd, (u64)pgd.pgd >> 32);
-       else
-               ret =  PVOP_CALLEE1(pgdval_t, mmu.pgd_val, pgd.pgd);
-
-       return ret;
+       return PVOP_CALLEE1(pgdval_t, mmu.pgd_val, pgd.pgd);
 }
 
 #define  __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
@@ -438,78 +404,34 @@ static inline void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned
                                           pte_t *ptep, pte_t old_pte, pte_t pte)
 {
 
-       if (sizeof(pteval_t) > sizeof(long))
-               /* 5 arg words */
-               pv_ops.mmu.ptep_modify_prot_commit(vma, addr, ptep, pte);
-       else
-               PVOP_VCALL4(mmu.ptep_modify_prot_commit,
-                           vma, addr, ptep, pte.pte);
+       PVOP_VCALL4(mmu.ptep_modify_prot_commit, vma, addr, ptep, pte.pte);
 }
 
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
-       if (sizeof(pteval_t) > sizeof(long))
-               PVOP_VCALL3(mmu.set_pte, ptep, pte.pte, (u64)pte.pte >> 32);
-       else
-               PVOP_VCALL2(mmu.set_pte, ptep, pte.pte);
-}
-
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
-                             pte_t *ptep, pte_t pte)
-{
-       if (sizeof(pteval_t) > sizeof(long))
-               /* 5 arg words */
-               pv_ops.mmu.set_pte_at(mm, addr, ptep, pte);
-       else
-               PVOP_VCALL4(mmu.set_pte_at, mm, addr, ptep, pte.pte);
+       PVOP_VCALL2(mmu.set_pte, ptep, pte.pte);
 }
 
 static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
 {
-       pmdval_t val = native_pmd_val(pmd);
-
-       if (sizeof(pmdval_t) > sizeof(long))
-               PVOP_VCALL3(mmu.set_pmd, pmdp, val, (u64)val >> 32);
-       else
-               PVOP_VCALL2(mmu.set_pmd, pmdp, val);
+       PVOP_VCALL2(mmu.set_pmd, pmdp, native_pmd_val(pmd));
 }
 
-#if CONFIG_PGTABLE_LEVELS >= 3
 static inline pmd_t __pmd(pmdval_t val)
 {
-       pmdval_t ret;
-
-       if (sizeof(pmdval_t) > sizeof(long))
-               ret = PVOP_CALLEE2(pmdval_t, mmu.make_pmd, val, (u64)val >> 32);
-       else
-               ret = PVOP_CALLEE1(pmdval_t, mmu.make_pmd, val);
-
-       return (pmd_t) { ret };
+       return (pmd_t) { PVOP_CALLEE1(pmdval_t, mmu.make_pmd, val) };
 }
 
 static inline pmdval_t pmd_val(pmd_t pmd)
 {
-       pmdval_t ret;
-
-       if (sizeof(pmdval_t) > sizeof(long))
-               ret =  PVOP_CALLEE2(pmdval_t, mmu.pmd_val,
-                                   pmd.pmd, (u64)pmd.pmd >> 32);
-       else
-               ret =  PVOP_CALLEE1(pmdval_t, mmu.pmd_val, pmd.pmd);
-
-       return ret;
+       return PVOP_CALLEE1(pmdval_t, mmu.pmd_val, pmd.pmd);
 }
 
 static inline void set_pud(pud_t *pudp, pud_t pud)
 {
-       pudval_t val = native_pud_val(pud);
-
-       if (sizeof(pudval_t) > sizeof(long))
-               PVOP_VCALL3(mmu.set_pud, pudp, val, (u64)val >> 32);
-       else
-               PVOP_VCALL2(mmu.set_pud, pudp, val);
+       PVOP_VCALL2(mmu.set_pud, pudp, native_pud_val(pud));
 }
-#if CONFIG_PGTABLE_LEVELS >= 4
+
 static inline pud_t __pud(pudval_t val)
 {
        pudval_t ret;
@@ -526,7 +448,7 @@ static inline pudval_t pud_val(pud_t pud)
 
 static inline void pud_clear(pud_t *pudp)
 {
-       set_pud(pudp, __pud(0));
+       set_pud(pudp, native_make_pud(0));
 }
 
 static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
@@ -563,40 +485,17 @@ static inline void __set_pgd(pgd_t *pgdp, pgd_t pgd)
 } while (0)
 
 #define pgd_clear(pgdp) do {                                           \
-       if (pgtable_l5_enabled())                                               \
-               set_pgd(pgdp, __pgd(0));                                \
+       if (pgtable_l5_enabled())                                       \
+               set_pgd(pgdp, native_make_pgd(0));                      \
 } while (0)
 
 #endif  /* CONFIG_PGTABLE_LEVELS == 5 */
 
 static inline void p4d_clear(p4d_t *p4dp)
 {
-       set_p4d(p4dp, __p4d(0));
+       set_p4d(p4dp, native_make_p4d(0));
 }
 
-#endif /* CONFIG_PGTABLE_LEVELS == 4 */
-
-#endif /* CONFIG_PGTABLE_LEVELS >= 3 */
-
-#ifdef CONFIG_X86_PAE
-/* Special-case pte-setting operations for PAE, which can't update a
-   64-bit pte atomically */
-static inline void set_pte_atomic(pte_t *ptep, pte_t pte)
-{
-       PVOP_VCALL3(mmu.set_pte_atomic, ptep, pte.pte, pte.pte >> 32);
-}
-
-static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
-                            pte_t *ptep)
-{
-       PVOP_VCALL3(mmu.pte_clear, mm, addr, ptep);
-}
-
-static inline void pmd_clear(pmd_t *pmdp)
-{
-       PVOP_VCALL1(mmu.pmd_clear, pmdp);
-}
-#else  /* !CONFIG_X86_PAE */
 static inline void set_pte_atomic(pte_t *ptep, pte_t pte)
 {
        set_pte(ptep, pte);
@@ -605,14 +504,13 @@ static inline void set_pte_atomic(pte_t *ptep, pte_t pte)
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
                             pte_t *ptep)
 {
-       set_pte_at(mm, addr, ptep, __pte(0));
+       set_pte(ptep, native_make_pte(0));
 }
 
 static inline void pmd_clear(pmd_t *pmdp)
 {
-       set_pmd(pmdp, __pmd(0));
+       set_pmd(pmdp, native_make_pmd(0));
 }
-#endif /* CONFIG_X86_PAE */
 
 #define  __HAVE_ARCH_START_CONTEXT_SWITCH
 static inline void arch_start_context_switch(struct task_struct *prev)
@@ -682,16 +580,9 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
 #endif /* SMP && PARAVIRT_SPINLOCKS */
 
 #ifdef CONFIG_X86_32
-#define PV_SAVE_REGS "pushl %ecx; pushl %edx;"
-#define PV_RESTORE_REGS "popl %edx; popl %ecx;"
-
 /* save and restore all caller-save registers, except return value */
 #define PV_SAVE_ALL_CALLER_REGS                "pushl %ecx;"
 #define PV_RESTORE_ALL_CALLER_REGS     "popl  %ecx;"
-
-#define PV_FLAGS_ARG "0"
-#define PV_EXTRA_CLOBBERS
-#define PV_VEXTRA_CLOBBERS
 #else
 /* save and restore all caller-save registers, except return value */
 #define PV_SAVE_ALL_CALLER_REGS                                                \
@@ -712,14 +603,6 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
        "pop %rsi;"                                                     \
        "pop %rdx;"                                                     \
        "pop %rcx;"
-
-/* We save some registers, but all of them, that's too much. We clobber all
- * caller saved registers but the argument parameter */
-#define PV_SAVE_REGS "pushq %%rdi;"
-#define PV_RESTORE_REGS "popq %%rdi;"
-#define PV_EXTRA_CLOBBERS EXTRA_CLOBBERS, "rcx" , "rdx", "rsi"
-#define PV_VEXTRA_CLOBBERS EXTRA_CLOBBERS, "rdi", "rcx" , "rdx", "rsi"
-#define PV_FLAGS_ARG "D"
 #endif
 
 /*
index 8dfcb25..0fad9f6 100644 (file)
@@ -68,13 +68,8 @@ struct paravirt_callee_save {
 /* general info */
 struct pv_info {
 #ifdef CONFIG_PARAVIRT_XXL
-       unsigned int kernel_rpl;
-       int shared_kernel_pmd;
-
-#ifdef CONFIG_X86_64
        u16 extra_user_64bit_cs;  /* __USER_CS if none */
 #endif
-#endif
 
        const char *name;
 };
@@ -126,9 +121,7 @@ struct pv_cpu_ops {
        void (*set_ldt)(const void *desc, unsigned entries);
        unsigned long (*store_tr)(void);
        void (*load_tls)(struct thread_struct *t, unsigned int cpu);
-#ifdef CONFIG_X86_64
        void (*load_gs_index)(unsigned int idx);
-#endif
        void (*write_ldt_entry)(struct desc_struct *ldt, int entrynum,
                                const void *desc);
        void (*write_gdt_entry)(struct desc_struct *,
@@ -249,8 +242,6 @@ struct pv_mmu_ops {
 
        /* Pagetable manipulation functions */
        void (*set_pte)(pte_t *ptep, pte_t pteval);
-       void (*set_pte_at)(struct mm_struct *mm, unsigned long addr,
-                          pte_t *ptep, pte_t pteval);
        void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval);
 
        pte_t (*ptep_modify_prot_start)(struct vm_area_struct *vma, unsigned long addr,
@@ -264,21 +255,11 @@ struct pv_mmu_ops {
        struct paravirt_callee_save pgd_val;
        struct paravirt_callee_save make_pgd;
 
-#if CONFIG_PGTABLE_LEVELS >= 3
-#ifdef CONFIG_X86_PAE
-       void (*set_pte_atomic)(pte_t *ptep, pte_t pteval);
-       void (*pte_clear)(struct mm_struct *mm, unsigned long addr,
-                         pte_t *ptep);
-       void (*pmd_clear)(pmd_t *pmdp);
-
-#endif /* CONFIG_X86_PAE */
-
        void (*set_pud)(pud_t *pudp, pud_t pudval);
 
        struct paravirt_callee_save pmd_val;
        struct paravirt_callee_save make_pmd;
 
-#if CONFIG_PGTABLE_LEVELS >= 4
        struct paravirt_callee_save pud_val;
        struct paravirt_callee_save make_pud;
 
@@ -291,10 +272,6 @@ struct pv_mmu_ops {
        void (*set_pgd)(pgd_t *pgdp, pgd_t pgdval);
 #endif /* CONFIG_PGTABLE_LEVELS >= 5 */
 
-#endif /* CONFIG_PGTABLE_LEVELS >= 4 */
-
-#endif /* CONFIG_PGTABLE_LEVELS >= 3 */
-
        struct pv_lazy_ops lazy_mode;
 
        /* dom0 ops */
index 7ccb338..d2c76c8 100644 (file)
@@ -105,17 +105,6 @@ static inline void early_quirks(void) { }
 
 extern void pci_iommu_alloc(void);
 
-#ifdef CONFIG_PCI_MSI
-/* implemented in arch/x86/kernel/apic/io_apic. */
-struct msi_desc;
-int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
-void native_teardown_msi_irq(unsigned int irq);
-void native_restore_msi_irqs(struct pci_dev *dev);
-#else
-#define native_setup_msi_irqs          NULL
-#define native_teardown_msi_irq                NULL
-#endif
-
 /* generic pci stuff */
 #include <asm-generic/pci.h>
 
index 73bb404..490411d 100644 (file)
@@ -114,9 +114,20 @@ extern const struct pci_raw_ops pci_direct_conf1;
 extern bool port_cf9_safe;
 
 /* arch_initcall level */
+#ifdef CONFIG_PCI_DIRECT
 extern int pci_direct_probe(void);
 extern void pci_direct_init(int type);
+#else
+static inline int pci_direct_probe(void) { return -1; }
+static inline  void pci_direct_init(int type) { }
+#endif
+
+#ifdef CONFIG_PCI_BIOS
 extern void pci_pcbios_init(void);
+#else
+static inline void pci_pcbios_init(void) { }
+#endif
+
 extern void __init dmi_check_pciprobe(void);
 extern void __init dmi_check_skip_isa_align(void);
 
index 0c1b137..6960cd6 100644 (file)
@@ -196,13 +196,29 @@ struct x86_pmu_capability {
  * Fixed-purpose performance events:
  */
 
+/* RDPMC offset for Fixed PMCs */
+#define INTEL_PMC_FIXED_RDPMC_BASE             (1 << 30)
+#define INTEL_PMC_FIXED_RDPMC_METRICS          (1 << 29)
+
 /*
- * All 3 fixed-mode PMCs are configured via this single MSR:
+ * All the fixed-mode PMCs are configured via this single MSR:
  */
 #define MSR_ARCH_PERFMON_FIXED_CTR_CTRL        0x38d
 
 /*
- * The counts are available in three separate MSRs:
+ * There is no event-code assigned to the fixed-mode PMCs.
+ *
+ * For a fixed-mode PMC, which has an equivalent event on a general-purpose
+ * PMC, the event-code of the equivalent event is used for the fixed-mode PMC,
+ * e.g., Instr_Retired.Any and CPU_CLK_Unhalted.Core.
+ *
+ * For a fixed-mode PMC, which doesn't have an equivalent event, a
+ * pseudo-encoding is used, e.g., CPU_CLK_Unhalted.Ref and TOPDOWN.SLOTS.
+ * The pseudo event-code for a fixed-mode PMC must be 0x00.
+ * The pseudo umask-code is 0xX. The X equals the index of the fixed
+ * counter + 1, e.g., the fixed counter 2 has the pseudo-encoding 0x0300.
+ *
+ * The counts are available in separate MSRs:
  */
 
 /* Instr_Retired.Any: */
@@ -213,29 +229,84 @@ struct x86_pmu_capability {
 #define MSR_ARCH_PERFMON_FIXED_CTR1    0x30a
 #define INTEL_PMC_IDX_FIXED_CPU_CYCLES (INTEL_PMC_IDX_FIXED + 1)
 
-/* CPU_CLK_Unhalted.Ref: */
+/* CPU_CLK_Unhalted.Ref: event=0x00,umask=0x3 (pseudo-encoding) */
 #define MSR_ARCH_PERFMON_FIXED_CTR2    0x30b
 #define INTEL_PMC_IDX_FIXED_REF_CYCLES (INTEL_PMC_IDX_FIXED + 2)
 #define INTEL_PMC_MSK_FIXED_REF_CYCLES (1ULL << INTEL_PMC_IDX_FIXED_REF_CYCLES)
 
+/* TOPDOWN.SLOTS: event=0x00,umask=0x4 (pseudo-encoding) */
+#define MSR_ARCH_PERFMON_FIXED_CTR3    0x30c
+#define INTEL_PMC_IDX_FIXED_SLOTS      (INTEL_PMC_IDX_FIXED + 3)
+#define INTEL_PMC_MSK_FIXED_SLOTS      (1ULL << INTEL_PMC_IDX_FIXED_SLOTS)
+
 /*
  * We model BTS tracing as another fixed-mode PMC.
  *
- * We choose a value in the middle of the fixed event range, since lower
+ * We choose the value 47 for the fixed index of BTS, since lower
  * values are used by actual fixed events and higher values are used
  * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr.
  */
-#define INTEL_PMC_IDX_FIXED_BTS                                (INTEL_PMC_IDX_FIXED + 16)
+#define INTEL_PMC_IDX_FIXED_BTS                        (INTEL_PMC_IDX_FIXED + 15)
+
+/*
+ * The PERF_METRICS MSR is modeled as several magic fixed-mode PMCs, one for
+ * each TopDown metric event.
+ *
+ * Internally the TopDown metric events are mapped to the FxCtr 3 (SLOTS).
+ */
+#define INTEL_PMC_IDX_METRIC_BASE              (INTEL_PMC_IDX_FIXED + 16)
+#define INTEL_PMC_IDX_TD_RETIRING              (INTEL_PMC_IDX_METRIC_BASE + 0)
+#define INTEL_PMC_IDX_TD_BAD_SPEC              (INTEL_PMC_IDX_METRIC_BASE + 1)
+#define INTEL_PMC_IDX_TD_FE_BOUND              (INTEL_PMC_IDX_METRIC_BASE + 2)
+#define INTEL_PMC_IDX_TD_BE_BOUND              (INTEL_PMC_IDX_METRIC_BASE + 3)
+#define INTEL_PMC_IDX_METRIC_END               INTEL_PMC_IDX_TD_BE_BOUND
+#define INTEL_PMC_MSK_TOPDOWN                  ((0xfull << INTEL_PMC_IDX_METRIC_BASE) | \
+                                               INTEL_PMC_MSK_FIXED_SLOTS)
 
-#define GLOBAL_STATUS_COND_CHG                         BIT_ULL(63)
-#define GLOBAL_STATUS_BUFFER_OVF                       BIT_ULL(62)
-#define GLOBAL_STATUS_UNC_OVF                          BIT_ULL(61)
-#define GLOBAL_STATUS_ASIF                             BIT_ULL(60)
-#define GLOBAL_STATUS_COUNTERS_FROZEN                  BIT_ULL(59)
-#define GLOBAL_STATUS_LBRS_FROZEN_BIT                  58
-#define GLOBAL_STATUS_LBRS_FROZEN                      BIT_ULL(GLOBAL_STATUS_LBRS_FROZEN_BIT)
-#define GLOBAL_STATUS_TRACE_TOPAPMI                    BIT_ULL(55)
+/*
+ * There is no event-code assigned to the TopDown events.
+ *
+ * For the slots event, use the pseudo code of the fixed counter 3.
+ *
+ * For the metric events, the pseudo event-code is 0x00.
+ * The pseudo umask-code starts from the middle of the pseudo event
+ * space, 0x80.
+ */
+#define INTEL_TD_SLOTS                         0x0400  /* TOPDOWN.SLOTS */
+/* Level 1 metrics */
+#define INTEL_TD_METRIC_RETIRING               0x8000  /* Retiring metric */
+#define INTEL_TD_METRIC_BAD_SPEC               0x8100  /* Bad speculation metric */
+#define INTEL_TD_METRIC_FE_BOUND               0x8200  /* FE bound metric */
+#define INTEL_TD_METRIC_BE_BOUND               0x8300  /* BE bound metric */
+#define INTEL_TD_METRIC_MAX                    INTEL_TD_METRIC_BE_BOUND
+#define INTEL_TD_METRIC_NUM                    4
+
+static inline bool is_metric_idx(int idx)
+{
+       return (unsigned)(idx - INTEL_PMC_IDX_METRIC_BASE) < INTEL_TD_METRIC_NUM;
+}
+
+static inline bool is_topdown_idx(int idx)
+{
+       return is_metric_idx(idx) || idx == INTEL_PMC_IDX_FIXED_SLOTS;
+}
 
+#define INTEL_PMC_OTHER_TOPDOWN_BITS(bit)      \
+                       (~(0x1ull << bit) & INTEL_PMC_MSK_TOPDOWN)
+
+#define GLOBAL_STATUS_COND_CHG                 BIT_ULL(63)
+#define GLOBAL_STATUS_BUFFER_OVF_BIT           62
+#define GLOBAL_STATUS_BUFFER_OVF               BIT_ULL(GLOBAL_STATUS_BUFFER_OVF_BIT)
+#define GLOBAL_STATUS_UNC_OVF                  BIT_ULL(61)
+#define GLOBAL_STATUS_ASIF                     BIT_ULL(60)
+#define GLOBAL_STATUS_COUNTERS_FROZEN          BIT_ULL(59)
+#define GLOBAL_STATUS_LBRS_FROZEN_BIT          58
+#define GLOBAL_STATUS_LBRS_FROZEN              BIT_ULL(GLOBAL_STATUS_LBRS_FROZEN_BIT)
+#define GLOBAL_STATUS_TRACE_TOPAPMI_BIT                55
+#define GLOBAL_STATUS_TRACE_TOPAPMI            BIT_ULL(GLOBAL_STATUS_TRACE_TOPAPMI_BIT)
+#define GLOBAL_STATUS_PERF_METRICS_OVF_BIT     48
+
+#define GLOBAL_CTRL_EN_PERF_METRICS            48
 /*
  * We model guest LBR event tracing as another fixed-mode PMC like BTS.
  *
@@ -334,6 +405,7 @@ struct pebs_xmm {
 #define IBS_OP_ENABLE          (1ULL<<17)
 #define IBS_OP_MAX_CNT         0x0000FFFFULL
 #define IBS_OP_MAX_CNT_EXT     0x007FFFFFULL   /* not a register bit mask */
+#define IBS_OP_MAX_CNT_EXT_MASK        (0x7FULL<<20)   /* separate upper 7 bits */
 #define IBS_RIP_INVALID                (1ULL<<38)
 
 #ifdef CONFIG_X86_LOCAL_APIC
index 80fbb4a..56baf43 100644 (file)
@@ -20,12 +20,7 @@ typedef union {
 } pte_t;
 #endif /* !__ASSEMBLY__ */
 
-#ifdef CONFIG_PARAVIRT_XXL
-#define SHARED_KERNEL_PMD      ((!static_cpu_has(X86_FEATURE_PTI) &&   \
-                                (pv_info.shared_kernel_pmd)))
-#else
 #define SHARED_KERNEL_PMD      (!static_cpu_has(X86_FEATURE_PTI))
-#endif
 
 #define ARCH_PAGE_TABLE_SYNC_MASK      (SHARED_KERNEL_PMD ? 0 : PGTBL_PMD_MODIFIED)
 
index b836138..5e0dcc2 100644 (file)
@@ -63,7 +63,6 @@ extern pmdval_t early_pmd_flags;
 #include <asm/paravirt.h>
 #else  /* !CONFIG_PARAVIRT_XXL */
 #define set_pte(ptep, pte)             native_set_pte(ptep, pte)
-#define set_pte_at(mm, addr, ptep, pte)        native_set_pte_at(mm, addr, ptep, pte)
 
 #define set_pte_atomic(ptep, pte)                                      \
        native_set_pte_atomic(ptep, pte)
@@ -1033,10 +1032,10 @@ static inline pud_t native_local_pudp_get_and_clear(pud_t *pudp)
        return res;
 }
 
-static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr,
-                                    pte_t *ptep , pte_t pte)
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep, pte_t pte)
 {
-       native_set_pte(ptep, pte);
+       set_pte(ptep, pte);
 }
 
 static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
index 8f63efb..52e5f5f 100644 (file)
@@ -159,6 +159,4 @@ extern unsigned int ptrs_per_p4d;
 
 #define PGD_KERNEL_START       ((PAGE_SIZE / 2) / sizeof(pgd_t))
 
-#define ARCH_PAGE_TABLE_SYNC_MASK      (pgtable_l5_enabled() ? PGTBL_PGD_MODIFIED : PGTBL_P4D_MODIFIED)
-
 #endif /* _ASM_X86_PGTABLE_64_DEFS_H */
index 97143d8..d8a82e6 100644 (file)
@@ -517,7 +517,7 @@ struct thread_struct {
        /* Save middle states of ptrace breakpoints */
        struct perf_event       *ptrace_bps[HBP_NUM];
        /* Debug status used for traps, single steps, etc... */
-       unsigned long           debugreg6;
+       unsigned long           virtual_dr6;
        /* Keep track of the exact dr7 value set by the user */
        unsigned long           ptrace_dr7;
        /* Fault info: */
index 40aa69d..d8324a2 100644 (file)
@@ -327,8 +327,8 @@ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
        static const unsigned int argument_offs[] = {
 #ifdef __i386__
                offsetof(struct pt_regs, ax),
-               offsetof(struct pt_regs, cx),
                offsetof(struct pt_regs, dx),
+               offsetof(struct pt_regs, cx),
 #define NR_REG_ARGUMENTS 3
 #else
                offsetof(struct pt_regs, di),
index 6847d85..3ff0d48 100644 (file)
@@ -54,7 +54,7 @@
 #endif
 
 #ifdef CONFIG_X86_64
-#ifdef CONFIG_PARAVIRT
+#ifdef CONFIG_PARAVIRT_XXL
 /* Paravirtualized systems may not have PSE or PGE available */
 #define NEED_PSE       0
 #define NEED_PGE       0
index 9646c30..5179209 100644 (file)
 
 #endif
 
-#ifndef CONFIG_PARAVIRT_XXL
-# define get_kernel_rpl()              0
-#endif
-
 #define IDT_ENTRIES                    256
 #define NUM_EXCEPTION_VECTORS          32
 
index 59a3e13..94624fb 100644 (file)
@@ -234,6 +234,76 @@ static inline void clwb(volatile void *__p)
 
 #define nop() asm volatile ("nop")
 
+static inline void serialize(void)
+{
+       /* Instruction opcode for SERIALIZE; supported in binutils >= 2.35. */
+       asm volatile(".byte 0xf, 0x1, 0xe8" ::: "memory");
+}
+
+/* The dst parameter must be 64-bytes aligned */
+static inline void movdir64b(void *dst, const void *src)
+{
+       const struct { char _[64]; } *__src = src;
+       struct { char _[64]; } *__dst = dst;
+
+       /*
+        * MOVDIR64B %(rdx), rax.
+        *
+        * Both __src and __dst must be memory constraints in order to tell the
+        * compiler that no other memory accesses should be reordered around
+        * this one.
+        *
+        * Also, both must be supplied as lvalues because this tells
+        * the compiler what the object is (its size) the instruction accesses.
+        * I.e., not the pointers but what they point to, thus the deref'ing '*'.
+        */
+       asm volatile(".byte 0x66, 0x0f, 0x38, 0xf8, 0x02"
+                    : "+m" (*__dst)
+                    :  "m" (*__src), "a" (__dst), "d" (__src));
+}
+
+/**
+ * enqcmds - Enqueue a command in supervisor (CPL0) mode
+ * @dst: destination, in MMIO space (must be 512-bit aligned)
+ * @src: 512 bits memory operand
+ *
+ * The ENQCMDS instruction allows software to write a 512-bit command to
+ * a 512-bit-aligned special MMIO region that supports the instruction.
+ * A return status is loaded into the ZF flag in the RFLAGS register.
+ * ZF = 0 equates to success, and ZF = 1 indicates retry or error.
+ *
+ * This function issues the ENQCMDS instruction to submit data from
+ * kernel space to MMIO space, in a unit of 512 bits. Order of data access
+ * is not guaranteed, nor is a memory barrier performed afterwards. It
+ * returns 0 on success and -EAGAIN on failure.
+ *
+ * Warning: Do not use this helper unless your driver has checked that the
+ * ENQCMDS instruction is supported on the platform and the device accepts
+ * ENQCMDS.
+ */
+static inline int enqcmds(void __iomem *dst, const void *src)
+{
+       const struct { char _[64]; } *__src = src;
+       struct { char _[64]; } *__dst = dst;
+       int zf;
+
+       /*
+        * ENQCMDS %(rdx), rax
+        *
+        * See movdir64b()'s comment on operand specification.
+        */
+       asm volatile(".byte 0xf3, 0x0f, 0x38, 0xf8, 0x02, 0x66, 0x90"
+                    CC_SET(z)
+                    : CC_OUT(z) (zf), "+m" (*__dst)
+                    : "m" (*__src), "a" (__dst), "d" (__src));
+
+       /* Submission failure is indicated via EFLAGS.ZF=1 */
+       if (zf)
+               return -EAGAIN;
+
+       return 0;
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_X86_SPECIAL_INSNS_H */
diff --git a/arch/x86/include/asm/static_call.h b/arch/x86/include/asm/static_call.h
new file mode 100644 (file)
index 0000000..c37f119
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_STATIC_CALL_H
+#define _ASM_STATIC_CALL_H
+
+#include <asm/text-patching.h>
+
+/*
+ * For CONFIG_HAVE_STATIC_CALL_INLINE, this is a temporary trampoline which
+ * uses the current value of the key->func pointer to do an indirect jump to
+ * the function.  This trampoline is only used during boot, before the call
+ * sites get patched by static_call_update().  The name of this trampoline has
+ * a magical aspect: objtool uses it to find static call sites so it can create
+ * the .static_call_sites section.
+ *
+ * For CONFIG_HAVE_STATIC_CALL, this is a permanent trampoline which
+ * does a direct jump to the function.  The direct jump gets patched by
+ * static_call_update().
+ *
+ * Having the trampoline in a special section forces GCC to emit a JMP.d32 when
+ * it does tail-call optimization on the call; since you cannot compute the
+ * relative displacement across sections.
+ */
+
+#define __ARCH_DEFINE_STATIC_CALL_TRAMP(name, insns)                   \
+       asm(".pushsection .static_call.text, \"ax\"             \n"     \
+           ".align 4                                           \n"     \
+           ".globl " STATIC_CALL_TRAMP_STR(name) "             \n"     \
+           STATIC_CALL_TRAMP_STR(name) ":                      \n"     \
+           insns "                                             \n"     \
+           ".type " STATIC_CALL_TRAMP_STR(name) ", @function   \n"     \
+           ".size " STATIC_CALL_TRAMP_STR(name) ", . - " STATIC_CALL_TRAMP_STR(name) " \n" \
+           ".popsection                                        \n")
+
+#define ARCH_DEFINE_STATIC_CALL_TRAMP(name, func)                      \
+       __ARCH_DEFINE_STATIC_CALL_TRAMP(name, ".byte 0xe9; .long " #func " - (. + 4)")
+
+#define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)                       \
+       __ARCH_DEFINE_STATIC_CALL_TRAMP(name, "ret; nop; nop; nop; nop")
+
+#endif /* _ASM_STATIC_CALL_H */
index 75314c3..6e45082 100644 (file)
@@ -82,38 +82,6 @@ int strcmp(const char *cs, const char *ct);
 
 #endif
 
-#define __HAVE_ARCH_MEMCPY_MCSAFE 1
-__must_check unsigned long __memcpy_mcsafe(void *dst, const void *src,
-               size_t cnt);
-DECLARE_STATIC_KEY_FALSE(mcsafe_key);
-
-/**
- * memcpy_mcsafe - copy memory with indication if a machine check happened
- *
- * @dst:       destination address
- * @src:       source address
- * @cnt:       number of bytes to copy
- *
- * Low level memory copy function that catches machine checks
- * We only call into the "safe" function on systems that can
- * actually do machine check recovery. Everyone else can just
- * use memcpy().
- *
- * Return 0 for success, or number of bytes not copied if there was an
- * exception.
- */
-static __always_inline __must_check unsigned long
-memcpy_mcsafe(void *dst, const void *src, size_t cnt)
-{
-#ifdef CONFIG_X86_MCE
-       if (static_branch_unlikely(&mcsafe_key))
-               return __memcpy_mcsafe(dst, src, cnt);
-       else
-#endif
-               memcpy(dst, src, cnt);
-       return 0;
-}
-
 #ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE
 #define __HAVE_ARCH_MEMCPY_FLUSHCACHE 1
 void __memcpy_flushcache(void *dst, const void *src, size_t cnt);
index fdb5b35..0fd4a9d 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/preempt.h>
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
+#include <asm/special_insns.h>
 
 #ifdef CONFIG_X86_32
 static inline void iret_to_self(void)
@@ -46,22 +47,34 @@ static inline void iret_to_self(void)
  *
  *  b) Text was modified on a different CPU, may subsequently be
  *     executed on this CPU, and you want to make sure the new version
- *     gets executed.  This generally means you're calling this in a IPI.
+ *     gets executed.  This generally means you're calling this in an IPI.
  *
  * If you're calling this for a different reason, you're probably doing
  * it wrong.
+ *
+ * Like all of Linux's memory ordering operations, this is a
+ * compiler barrier as well.
  */
 static inline void sync_core(void)
 {
        /*
-        * There are quite a few ways to do this.  IRET-to-self is nice
-        * because it works on every CPU, at any CPL (so it's compatible
-        * with paravirtualization), and it never exits to a hypervisor.
-        * The only down sides are that it's a bit slow (it seems to be
-        * a bit more than 2x slower than the fastest options) and that
-        * it unmasks NMIs.  The "push %cs" is needed because, in
-        * paravirtual environments, __KERNEL_CS may not be a valid CS
-        * value when we do IRET directly.
+        * The SERIALIZE instruction is the most straightforward way to
+        * do this, but it is not universally available.
+        */
+       if (static_cpu_has(X86_FEATURE_SERIALIZE)) {
+               serialize();
+               return;
+       }
+
+       /*
+        * For all other processors, there are quite a few ways to do this.
+        * IRET-to-self is nice because it works on every CPU, at any CPL
+        * (so it's compatible with paravirtualization), and it never exits
+        * to a hypervisor.  The only downsides are that it's a bit slow
+        * (it seems to be a bit more than 2x slower than the fastest
+        * options) and that it unmasks NMIs.  The "push %cs" is needed,
+        * because in paravirtual environments __KERNEL_CS may not be a
+        * valid CS value when we do IRET directly.
         *
         * In case NMI unmasking or performance ever becomes a problem,
         * the next best option appears to be MOV-to-CR2 and an
@@ -71,9 +84,6 @@ static inline void sync_core(void)
         * CPUID is the conventional way, but it's nasty: it doesn't
         * exist on some 486-like CPUs, and it usually exits to a
         * hypervisor.
-        *
-        * Like all of Linux's memory ordering operations, this is a
-        * compiler barrier as well.
         */
        iret_to_self();
 }
index 6593b42..b742178 100644 (file)
@@ -53,6 +53,9 @@ extern void text_poke_finish(void);
 #define INT3_INSN_SIZE         1
 #define INT3_INSN_OPCODE       0xCC
 
+#define RET_INSN_SIZE          1
+#define RET_INSN_OPCODE                0xC3
+
 #define CALL_INSN_SIZE         5
 #define CALL_INSN_OPCODE       0xE8
 
@@ -73,6 +76,7 @@ static __always_inline int text_opcode_size(u8 opcode)
 
        switch(opcode) {
        __CASE(INT3);
+       __CASE(RET);
        __CASE(CALL);
        __CASE(JMP32);
        __CASE(JMP8);
@@ -141,11 +145,26 @@ void int3_emulate_push(struct pt_regs *regs, unsigned long val)
 }
 
 static __always_inline
+unsigned long int3_emulate_pop(struct pt_regs *regs)
+{
+       unsigned long val = *(unsigned long *)regs->sp;
+       regs->sp += sizeof(unsigned long);
+       return val;
+}
+
+static __always_inline
 void int3_emulate_call(struct pt_regs *regs, unsigned long func)
 {
        int3_emulate_push(regs, regs->ip - INT3_INSN_SIZE + CALL_INSN_SIZE);
        int3_emulate_jmp(regs, func);
 }
+
+static __always_inline
+void int3_emulate_ret(struct pt_regs *regs)
+{
+       unsigned long ip = int3_emulate_pop(regs);
+       int3_emulate_jmp(regs, ip);
+}
 #endif /* !CONFIG_UML_X86 */
 
 #endif /* _ASM_X86_TEXT_PATCHING_H */
index 714b1a3..df0b7bf 100644 (file)
@@ -35,6 +35,8 @@ extern int panic_on_unrecovered_nmi;
 
 void math_emulate(struct math_emu_info *);
 
+bool fault_in_kernel_space(unsigned long address);
+
 #ifdef CONFIG_VMAP_STACK
 void __noreturn handle_stack_overflow(const char *message,
                                      struct pt_regs *regs,
index ecefaff..aa60c23 100644 (file)
@@ -96,25 +96,14 @@ static inline bool pagefault_disabled(void);
        likely(!__range_not_ok(addr, size, user_addr_max()));           \
 })
 
-/*
- * These are the main single-value transfer routines.  They automatically
- * use the right size if we just have the right pointer type.
- *
- * This gets kind of ugly. We want to return _two_ values in "get_user()"
- * and yet we don't want to do any pointers, because that is too much
- * of a performance impact. Thus we have a few rather ugly macros here,
- * and hide all the ugliness from the user.
- *
- * The "__xxx" versions of the user access functions are versions that
- * do not verify the address space, that must have been done previously
- * with a separate "access_ok()" call (this is used when we do multiple
- * accesses to the same area of user memory).
- */
-
 extern int __get_user_1(void);
 extern int __get_user_2(void);
 extern int __get_user_4(void);
 extern int __get_user_8(void);
+extern int __get_user_nocheck_1(void);
+extern int __get_user_nocheck_2(void);
+extern int __get_user_nocheck_4(void);
+extern int __get_user_nocheck_8(void);
 extern int __get_user_bad(void);
 
 #define __uaccess_begin() stac()
@@ -138,25 +127,12 @@ extern int __get_user_bad(void);
 #define __typefits(x,type,not) \
        __builtin_choose_expr(sizeof(x)<=sizeof(type),(unsigned type)0,not)
 
-/**
- * get_user - Get a simple variable from user space.
- * @x:   Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only. This function may sleep if pagefaults are
- *          enabled.
- *
- * This macro copies a single simple variable from user space to kernel
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Return: zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
 /*
+ * This is used for both get_user() and __get_user() to expand to
+ * the proper special function call that has odd calling conventions
+ * due to returning both a value and an error, and that depends on
+ * the size of the pointer passed in.
+ *
  * Careful: we have to cast the result to the type of the pointer
  * for sign reasons.
  *
@@ -169,13 +145,12 @@ extern int __get_user_bad(void);
  * Clang/LLVM cares about the size of the register, but still wants
  * the base register for something that ends up being a pair.
  */
-#define get_user(x, ptr)                                               \
+#define do_get_user_call(fn,x,ptr)                                     \
 ({                                                                     \
        int __ret_gu;                                                   \
        register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX);            \
        __chk_user_ptr(ptr);                                            \
-       might_fault();                                                  \
-       asm volatile("call __get_user_%P4"                              \
+       asm volatile("call __" #fn "_%P4"                               \
                     : "=a" (__ret_gu), "=r" (__val_gu),                \
                        ASM_CALL_CONSTRAINT                             \
                     : "0" (ptr), "i" (sizeof(*(ptr))));                \
@@ -183,10 +158,48 @@ extern int __get_user_bad(void);
        __builtin_expect(__ret_gu, 0);                                  \
 })
 
-#define __put_user_x(size, x, ptr, __ret_pu)                   \
-       asm volatile("call __put_user_" #size : "=a" (__ret_pu) \
-                    : "0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
+/**
+ * get_user - Get a simple variable from user space.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only. This function may sleep if pagefaults are
+ *          enabled.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Return: zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define get_user(x,ptr) ({ might_fault(); do_get_user_call(get_user,x,ptr); })
 
+/**
+ * __get_user - Get a simple variable from user space, with less checking.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only. This function may sleep if pagefaults are
+ *          enabled.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Return: zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define __get_user(x,ptr) do_get_user_call(get_user_nocheck,x,ptr)
 
 
 #ifdef CONFIG_X86_32
@@ -199,25 +212,41 @@ extern int __get_user_bad(void);
                     : : "A" (x), "r" (addr)                    \
                     : : label)
 
-#define __put_user_x8(x, ptr, __ret_pu)                                \
-       asm volatile("call __put_user_8" : "=a" (__ret_pu)      \
-                    : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
 #else
 #define __put_user_goto_u64(x, ptr, label) \
        __put_user_goto(x, ptr, "q", "er", label)
-#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
 #endif
 
 extern void __put_user_bad(void);
 
 /*
  * Strange magic calling convention: pointer in %ecx,
- * value in %eax(:%edx), return value in %eax. clobbers %rbx
+ * value in %eax(:%edx), return value in %ecx. clobbers %rbx
  */
 extern void __put_user_1(void);
 extern void __put_user_2(void);
 extern void __put_user_4(void);
 extern void __put_user_8(void);
+extern void __put_user_nocheck_1(void);
+extern void __put_user_nocheck_2(void);
+extern void __put_user_nocheck_4(void);
+extern void __put_user_nocheck_8(void);
+
+#define do_put_user_call(fn,x,ptr)                                     \
+({                                                                     \
+       int __ret_pu;                                                   \
+       register __typeof__(*(ptr)) __val_pu asm("%"_ASM_AX);           \
+       __chk_user_ptr(ptr);                                            \
+       __val_pu = (x);                                                 \
+       asm volatile("call __" #fn "_%P[size]"                          \
+                    : "=c" (__ret_pu),                                 \
+                       ASM_CALL_CONSTRAINT                             \
+                    : "0" (ptr),                                       \
+                      "r" (__val_pu),                                  \
+                      [size] "i" (sizeof(*(ptr)))                      \
+                    :"ebx");                                           \
+       __builtin_expect(__ret_pu, 0);                                  \
+})
 
 /**
  * put_user - Write a simple value into user space.
@@ -236,32 +265,29 @@ extern void __put_user_8(void);
  *
  * Return: zero on success, or -EFAULT on error.
  */
-#define put_user(x, ptr)                                       \
-({                                                             \
-       int __ret_pu;                                           \
-       __typeof__(*(ptr)) __pu_val;                            \
-       __chk_user_ptr(ptr);                                    \
-       might_fault();                                          \
-       __pu_val = x;                                           \
-       switch (sizeof(*(ptr))) {                               \
-       case 1:                                                 \
-               __put_user_x(1, __pu_val, ptr, __ret_pu);       \
-               break;                                          \
-       case 2:                                                 \
-               __put_user_x(2, __pu_val, ptr, __ret_pu);       \
-               break;                                          \
-       case 4:                                                 \
-               __put_user_x(4, __pu_val, ptr, __ret_pu);       \
-               break;                                          \
-       case 8:                                                 \
-               __put_user_x8(__pu_val, ptr, __ret_pu);         \
-               break;                                          \
-       default:                                                \
-               __put_user_x(X, __pu_val, ptr, __ret_pu);       \
-               break;                                          \
-       }                                                       \
-       __builtin_expect(__ret_pu, 0);                          \
-})
+#define put_user(x, ptr) ({ might_fault(); do_put_user_call(put_user,x,ptr); })
+
+/**
+ * __put_user - Write a simple value into user space, with less checking.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only. This function may sleep if pagefaults are
+ *          enabled.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Return: zero on success, or -EFAULT on error.
+ */
+#define __put_user(x, ptr) do_put_user_call(put_user_nocheck,x,ptr)
 
 #define __put_user_size(x, ptr, size, label)                           \
 do {                                                                   \
@@ -284,6 +310,55 @@ do {                                                                       \
        }                                                               \
 } while (0)
 
+#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
+
+#ifdef CONFIG_X86_32
+#define __get_user_asm_u64(x, ptr, label) do {                         \
+       unsigned int __gu_low, __gu_high;                               \
+       const unsigned int __user *__gu_ptr;                            \
+       __gu_ptr = (const void __user *)(ptr);                          \
+       __get_user_asm(__gu_low, ptr, "l", "=r", label);                \
+       __get_user_asm(__gu_high, ptr+1, "l", "=r", label);             \
+       (x) = ((unsigned long long)__gu_high << 32) | __gu_low;         \
+} while (0)
+#else
+#define __get_user_asm_u64(x, ptr, label)                              \
+       __get_user_asm(x, ptr, "q", "=r", label)
+#endif
+
+#define __get_user_size(x, ptr, size, label)                           \
+do {                                                                   \
+       __chk_user_ptr(ptr);                                            \
+       switch (size) {                                                 \
+       unsigned char x_u8__;                                           \
+       case 1:                                                         \
+               __get_user_asm(x_u8__, ptr, "b", "=q", label);          \
+               (x) = x_u8__;                                           \
+               break;                                                  \
+       case 2:                                                         \
+               __get_user_asm(x, ptr, "w", "=r", label);               \
+               break;                                                  \
+       case 4:                                                         \
+               __get_user_asm(x, ptr, "l", "=r", label);               \
+               break;                                                  \
+       case 8:                                                         \
+               __get_user_asm_u64(x, ptr, label);                      \
+               break;                                                  \
+       default:                                                        \
+               (x) = __get_user_bad();                                 \
+       }                                                               \
+} while (0)
+
+#define __get_user_asm(x, addr, itype, ltype, label)                   \
+       asm_volatile_goto("\n"                                          \
+                    "1:        mov"itype" %[umem],%[output]\n"         \
+                    _ASM_EXTABLE_UA(1b, %l2)                           \
+                    : [output] ltype(x)                                \
+                    : [umem] "m" (__m(addr))                           \
+                    : : label)
+
+#else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT
+
 #ifdef CONFIG_X86_32
 #define __get_user_asm_u64(x, ptr, retval)                             \
 ({                                                                     \
@@ -352,33 +427,7 @@ do {                                                                       \
                     : [umem] "m" (__m(addr)),                          \
                       [efault] "i" (-EFAULT), "0" (err))
 
-#define __put_user_nocheck(x, ptr, size)                       \
-({                                                             \
-       __label__ __pu_label;                                   \
-       int __pu_err = -EFAULT;                                 \
-       __typeof__(*(ptr)) __pu_val = (x);                      \
-       __typeof__(ptr) __pu_ptr = (ptr);                       \
-       __typeof__(size) __pu_size = (size);                    \
-       __uaccess_begin();                                      \
-       __put_user_size(__pu_val, __pu_ptr, __pu_size, __pu_label);     \
-       __pu_err = 0;                                           \
-__pu_label:                                                    \
-       __uaccess_end();                                        \
-       __builtin_expect(__pu_err, 0);                          \
-})
-
-#define __get_user_nocheck(x, ptr, size)                               \
-({                                                                     \
-       int __gu_err;                                                   \
-       __inttype(*(ptr)) __gu_val;                                     \
-       __typeof__(ptr) __gu_ptr = (ptr);                               \
-       __typeof__(size) __gu_size = (size);                            \
-       __uaccess_begin_nospec();                                       \
-       __get_user_size(__gu_val, __gu_ptr, __gu_size, __gu_err);       \
-       __uaccess_end();                                                \
-       (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
-       __builtin_expect(__gu_err, 0);                                  \
-})
+#endif // CONFIG_CC_ASM_GOTO_OUTPUT
 
 /* FIXME: this hack is definitely wrong -AK */
 struct __large_struct { unsigned long buf[100]; };
@@ -396,55 +445,6 @@ struct __large_struct { unsigned long buf[100]; };
                : : ltype(x), "m" (__m(addr))                           \
                : : label)
 
-/**
- * __get_user - Get a simple variable from user space, with less checking.
- * @x:   Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only. This function may sleep if pagefaults are
- *          enabled.
- *
- * This macro copies a single simple variable from user space to kernel
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Return: zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-
-#define __get_user(x, ptr)                                             \
-       __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
-
-/**
- * __put_user - Write a simple value into user space, with less checking.
- * @x:   Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only. This function may sleep if pagefaults are
- *          enabled.
- *
- * This macro copies a single simple value from kernel space to user
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Return: zero on success, or -EFAULT on error.
- */
-
-#define __put_user(x, ptr)                                             \
-       __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
-
 extern unsigned long
 copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
 extern __must_check long
@@ -455,6 +455,15 @@ extern __must_check long strnlen_user(const char __user *str, long n);
 unsigned long __must_check clear_user(void __user *mem, unsigned long len);
 unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
 
+#ifdef CONFIG_ARCH_HAS_COPY_MC
+unsigned long __must_check
+copy_mc_to_kernel(void *to, const void *from, unsigned len);
+#define copy_mc_to_kernel copy_mc_to_kernel
+
+unsigned long __must_check
+copy_mc_to_user(void *to, const void *from, unsigned len);
+#endif
+
 /*
  * movsl can be slow when source and dest are not both 8-byte aligned
  */
@@ -494,6 +503,14 @@ static __must_check __always_inline bool user_access_begin(const void __user *pt
 #define unsafe_put_user(x, ptr, label) \
        __put_user_size((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), label)
 
+#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
+#define unsafe_get_user(x, ptr, err_label)                                     \
+do {                                                                           \
+       __inttype(*(ptr)) __gu_val;                                             \
+       __get_user_size(__gu_val, (ptr), sizeof(*(ptr)), err_label);            \
+       (x) = (__force __typeof__(*(ptr)))__gu_val;                             \
+} while (0)
+#else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT
 #define unsafe_get_user(x, ptr, err_label)                                     \
 do {                                                                           \
        int __gu_err;                                                           \
@@ -502,6 +519,7 @@ do {                                                                                \
        (x) = (__force __typeof__(*(ptr)))__gu_val;                             \
        if (unlikely(__gu_err)) goto err_label;                                 \
 } while (0)
+#endif // CONFIG_CC_HAS_ASM_GOTO_OUTPUT
 
 /*
  * We want the unsafe accessors to always be inlined and use
@@ -528,6 +546,11 @@ do {                                                                       \
 
 #define HAVE_GET_KERNEL_NOFAULT
 
+#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
+#define __get_kernel_nofault(dst, src, type, err_label)                        \
+       __get_user_size(*((type *)(dst)), (__force type __user *)(src), \
+                       sizeof(type), err_label)
+#else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT
 #define __get_kernel_nofault(dst, src, type, err_label)                        \
 do {                                                                   \
        int __kr_err;                                                   \
@@ -537,6 +560,7 @@ do {                                                                        \
        if (unlikely(__kr_err))                                         \
                goto err_label;                                         \
 } while (0)
+#endif // CONFIG_CC_HAS_ASM_GOTO_OUTPUT
 
 #define __put_kernel_nofault(dst, src, type, err_label)                        \
        __put_user_size(*((type *)(src)), (__force type __user *)(dst), \
index bc10e3d..e7265a5 100644 (file)
@@ -47,22 +47,6 @@ copy_user_generic(void *to, const void *from, unsigned len)
 }
 
 static __always_inline __must_check unsigned long
-copy_to_user_mcsafe(void *to, const void *from, unsigned len)
-{
-       unsigned long ret;
-
-       __uaccess_begin();
-       /*
-        * Note, __memcpy_mcsafe() is explicitly used since it can
-        * handle exceptions / faults.  memcpy_mcsafe() may fall back to
-        * memcpy() which lacks this handling.
-        */
-       ret = __memcpy_mcsafe(to, from, len);
-       __uaccess_end();
-       return ret;
-}
-
-static __always_inline __must_check unsigned long
 raw_copy_from_user(void *dst, const void __user *src, unsigned long size)
 {
        return copy_user_generic(dst, (__force void *)src, size);
@@ -102,8 +86,4 @@ __copy_from_user_flushcache(void *dst, const void __user *src, unsigned size)
        kasan_check_write(dst, size);
        return __copy_user_flushcache(dst, src, size);
 }
-
-unsigned long
-mcsafe_handle_tail(char *to, char *from, unsigned len);
-
 #endif /* _ASM_X86_UACCESS_64_H */
index 70050d0..08b3d81 100644 (file)
@@ -5,8 +5,9 @@
 /*
  * UV BIOS layer definitions.
  *
- *  Copyright (c) 2008-2009 Silicon Graphics, Inc.  All Rights Reserved.
- *  Copyright (c) Russ Anderson <rja@sgi.com>
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+ * Copyright (C) 2007-2017 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) Russ Anderson <rja@sgi.com>
  */
 
 #include <linux/rtc.h>
@@ -71,6 +72,11 @@ struct uv_gam_range_entry {
        u32     limit;          /* PA bits 56:26 (UV_GAM_RANGE_SHFT) */
 };
 
+#define        UV_AT_SIZE      8       /* 7 character arch type + NULL char */
+struct uv_arch_type_entry {
+       char    archtype[UV_AT_SIZE];
+};
+
 #define        UV_SYSTAB_SIG                   "UVST"
 #define        UV_SYSTAB_VERSION_1             1       /* UV2/3 BIOS version */
 #define        UV_SYSTAB_VERSION_UV4           0x400   /* UV4 BIOS base version */
@@ -79,10 +85,14 @@ struct uv_gam_range_entry {
 #define        UV_SYSTAB_VERSION_UV4_3         0x403   /* - GAM Range PXM Value */
 #define        UV_SYSTAB_VERSION_UV4_LATEST    UV_SYSTAB_VERSION_UV4_3
 
+#define        UV_SYSTAB_VERSION_UV5           0x500   /* UV5 GAM base version */
+#define        UV_SYSTAB_VERSION_UV5_LATEST    UV_SYSTAB_VERSION_UV5
+
 #define        UV_SYSTAB_TYPE_UNUSED           0       /* End of table (offset == 0) */
 #define        UV_SYSTAB_TYPE_GAM_PARAMS       1       /* GAM PARAM conversions */
 #define        UV_SYSTAB_TYPE_GAM_RNG_TBL      2       /* GAM entry table */
-#define        UV_SYSTAB_TYPE_MAX              3
+#define        UV_SYSTAB_TYPE_ARCH_TYPE        3       /* UV arch type */
+#define        UV_SYSTAB_TYPE_MAX              4
 
 /*
  * The UV system table describes specific firmware
@@ -133,6 +143,7 @@ extern s64 uv_bios_reserved_page_pa(u64, u64 *, u64 *, u64 *);
 extern int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus);
 
 extern int uv_bios_init(void);
+extern unsigned long get_uv_systab_phys(bool msg);
 
 extern unsigned long sn_rtc_cycles_per_second;
 extern int uv_type;
index e48aea9..172d3e4 100644 (file)
@@ -35,10 +35,8 @@ extern int is_uv_hubbed(int uvtype);
 extern void uv_cpu_init(void);
 extern void uv_nmi_init(void);
 extern void uv_system_init(void);
-extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
-                                                const struct flush_tlb_info *info);
 
-#else  /* X86_UV */
+#else  /* !X86_UV */
 
 static inline enum uv_system_type get_uv_system_type(void) { return UV_NONE; }
 static inline bool is_early_uv_system(void)    { return 0; }
diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h
deleted file mode 100644 (file)
index cd24804..0000000
+++ /dev/null
@@ -1,755 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * SGI UV Broadcast Assist Unit definitions
- *
- * Copyright (C) 2008-2011 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_X86_UV_UV_BAU_H
-#define _ASM_X86_UV_UV_BAU_H
-
-#include <linux/bitmap.h>
-#include <asm/idtentry.h>
-
-#define BITSPERBYTE 8
-
-/*
- * Broadcast Assist Unit messaging structures
- *
- * Selective Broadcast activations are induced by software action
- * specifying a particular 8-descriptor "set" via a 6-bit index written
- * to an MMR.
- * Thus there are 64 unique 512-byte sets of SB descriptors - one set for
- * each 6-bit index value. These descriptor sets are mapped in sequence
- * starting with set 0 located at the address specified in the
- * BAU_SB_DESCRIPTOR_BASE register, set 1 is located at BASE + 512,
- * set 2 is at BASE + 2*512, set 3 at BASE + 3*512, and so on.
- *
- * We will use one set for sending BAU messages from each of the
- * cpu's on the uvhub.
- *
- * TLB shootdown will use the first of the 8 descriptors of each set.
- * Each of the descriptors is 64 bytes in size (8*64 = 512 bytes in a set).
- */
-
-#define MAX_CPUS_PER_UVHUB             128
-#define MAX_CPUS_PER_SOCKET            64
-#define ADP_SZ                         64 /* hardware-provided max. */
-#define UV_CPUS_PER_AS                 32 /* hardware-provided max. */
-#define ITEMS_PER_DESC                 8
-/* the 'throttle' to prevent the hardware stay-busy bug */
-#define MAX_BAU_CONCURRENT             3
-#define UV_ACT_STATUS_MASK             0x3
-#define UV_ACT_STATUS_SIZE             2
-#define UV_DISTRIBUTION_SIZE           256
-#define UV_SW_ACK_NPENDING             8
-#define UV_NET_ENDPOINT_INTD           0x28
-#define UV_PAYLOADQ_GNODE_SHIFT                49
-#define UV_PTC_BASENAME                        "sgi_uv/ptc_statistics"
-#define UV_BAU_BASENAME                        "sgi_uv/bau_tunables"
-#define UV_BAU_TUNABLES_DIR            "sgi_uv"
-#define UV_BAU_TUNABLES_FILE           "bau_tunables"
-#define WHITESPACE                     " \t\n"
-#define cpubit_isset(cpu, bau_local_cpumask) \
-       test_bit((cpu), (bau_local_cpumask).bits)
-
-/* [19:16] SOFT_ACK timeout period  19: 1 is urgency 7  17:16 1 is multiplier */
-/*
- * UV2: Bit 19 selects between
- *  (0): 10 microsecond timebase and
- *  (1): 80 microseconds
- *  we're using 560us
- */
-#define UV_INTD_SOFT_ACK_TIMEOUT_PERIOD        (15UL)
-/* assuming UV3 is the same */
-
-#define BAU_MISC_CONTROL_MULT_MASK     3
-
-#define UVH_AGING_PRESCALE_SEL         0x000000b000UL
-/* [30:28] URGENCY_7  an index into a table of times */
-#define BAU_URGENCY_7_SHIFT            28
-#define BAU_URGENCY_7_MASK             7
-
-#define UVH_TRANSACTION_TIMEOUT                0x000000b200UL
-/* [45:40] BAU - BAU transaction timeout select - a multiplier */
-#define BAU_TRANS_SHIFT                        40
-#define BAU_TRANS_MASK                 0x3f
-
-/*
- * shorten some awkward names
- */
-#define AS_PUSH_SHIFT UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT
-#define SOFTACK_MSHIFT UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT
-#define SOFTACK_PSHIFT UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT
-#define SOFTACK_TIMEOUT_PERIOD UV_INTD_SOFT_ACK_TIMEOUT_PERIOD
-#define PREFETCH_HINT_SHFT UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_PREFETCH_HINT_SHFT
-#define SB_STATUS_SHFT UV3H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT
-#define write_gmmr     uv_write_global_mmr64
-#define write_lmmr     uv_write_local_mmr
-#define read_lmmr      uv_read_local_mmr
-#define read_gmmr      uv_read_global_mmr64
-
-/*
- * bits in UVH_LB_BAU_SB_ACTIVATION_STATUS_0/1
- */
-#define DS_IDLE                                0
-#define DS_ACTIVE                      1
-#define DS_DESTINATION_TIMEOUT         2
-#define DS_SOURCE_TIMEOUT              3
-/*
- * bits put together from HRP_LB_BAU_SB_ACTIVATION_STATUS_0/1/2
- * values 1 and 3 will not occur
- *        Decoded meaning              ERROR  BUSY    AUX ERR
- * -------------------------------     ----   -----   -------
- * IDLE                                 0       0        0
- * BUSY (active)                        0       1        0
- * SW Ack Timeout (destination)         1       0        0
- * SW Ack INTD rejected (strong NACK)   1       0        1
- * Source Side Time Out Detected        1       1        0
- * Destination Side PUT Failed          1       1        1
- */
-#define UV2H_DESC_IDLE                 0
-#define UV2H_DESC_BUSY                 2
-#define UV2H_DESC_DEST_TIMEOUT         4
-#define UV2H_DESC_DEST_STRONG_NACK     5
-#define UV2H_DESC_SOURCE_TIMEOUT       6
-#define UV2H_DESC_DEST_PUT_ERR         7
-
-/*
- * delay for 'plugged' timeout retries, in microseconds
- */
-#define PLUGGED_DELAY                  10
-
-/*
- * threshholds at which to use IPI to free resources
- */
-/* after this # consecutive 'plugged' timeouts, use IPI to release resources */
-#define PLUGSB4RESET                   100
-/* after this many consecutive timeouts, use IPI to release resources */
-#define TIMEOUTSB4RESET                        1
-/* at this number uses of IPI to release resources, giveup the request */
-#define IPI_RESET_LIMIT                        1
-/* after this # consecutive successes, bump up the throttle if it was lowered */
-#define COMPLETE_THRESHOLD             5
-/* after this # of giveups (fall back to kernel IPI's) disable the use of
-   the BAU for a period of time */
-#define GIVEUP_LIMIT                   100
-
-#define UV_LB_SUBNODEID                        0x10
-
-#define UV_SA_SHFT UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT
-#define UV_SA_MASK UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK
-/* 4 bits of software ack period */
-#define UV2_ACK_MASK                   0x7UL
-#define UV2_ACK_UNITS_SHFT             3
-#define UV2_EXT_SHFT UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT
-
-/*
- * number of entries in the destination side payload queue
- */
-#define DEST_Q_SIZE                    20
-/*
- * number of destination side software ack resources
- */
-#define DEST_NUM_RESOURCES             8
-/*
- * completion statuses for sending a TLB flush message
- */
-#define FLUSH_RETRY_PLUGGED            1
-#define FLUSH_RETRY_TIMEOUT            2
-#define FLUSH_GIVEUP                   3
-#define FLUSH_COMPLETE                 4
-
-/*
- * tuning the action when the numalink network is extremely delayed
- */
-#define CONGESTED_RESPONSE_US          1000    /* 'long' response time, in
-                                                  microseconds */
-#define CONGESTED_REPS                 10      /* long delays averaged over
-                                                  this many broadcasts */
-#define DISABLED_PERIOD                        10      /* time for the bau to be
-                                                  disabled, in seconds */
-/* see msg_type: */
-#define MSG_NOOP                       0
-#define MSG_REGULAR                    1
-#define MSG_RETRY                      2
-
-#define BAU_DESC_QUALIFIER             0x534749
-
-enum uv_bau_version {
-       UV_BAU_V2 = 2,
-       UV_BAU_V3,
-       UV_BAU_V4,
-};
-
-/*
- * Distribution: 32 bytes (256 bits) (bytes 0-0x1f of descriptor)
- * If the 'multilevel' flag in the header portion of the descriptor
- * has been set to 0, then endpoint multi-unicast mode is selected.
- * The distribution specification (32 bytes) is interpreted as a 256-bit
- * distribution vector. Adjacent bits correspond to consecutive even numbered
- * nodeIDs. The result of adding the index of a given bit to the 15-bit
- * 'base_dest_nasid' field of the header corresponds to the
- * destination nodeID associated with that specified bit.
- */
-struct pnmask {
-       unsigned long           bits[BITS_TO_LONGS(UV_DISTRIBUTION_SIZE)];
-};
-
-/*
- * mask of cpu's on a uvhub
- * (during initialization we need to check that unsigned long has
- *  enough bits for max. cpu's per uvhub)
- */
-struct bau_local_cpumask {
-       unsigned long           bits;
-};
-
-/*
- * Payload: 16 bytes (128 bits) (bytes 0x20-0x2f of descriptor)
- * only 12 bytes (96 bits) of the payload area are usable.
- * An additional 3 bytes (bits 27:4) of the header address are carried
- * to the next bytes of the destination payload queue.
- * And an additional 2 bytes of the header Suppl_A field are also
- * carried to the destination payload queue.
- * But the first byte of the Suppl_A becomes bits 127:120 (the 16th byte)
- * of the destination payload queue, which is written by the hardware
- * with the s/w ack resource bit vector.
- * [ effective message contents (16 bytes (128 bits) maximum), not counting
- *   the s/w ack bit vector  ]
- */
-
-/**
- * struct uv2_3_bau_msg_payload - defines payload for INTD transactions
- * @address:           Signifies a page or all TLB's of the cpu
- * @sending_cpu:       CPU from which the message originates
- * @acknowledge_count: CPUs on the destination Hub that received the interrupt
- */
-struct uv2_3_bau_msg_payload {
-       u64 address;
-       u16 sending_cpu;
-       u16 acknowledge_count;
-};
-
-/**
- * struct uv4_bau_msg_payload - defines payload for INTD transactions
- * @address:           Signifies a page or all TLB's of the cpu
- * @sending_cpu:       CPU from which the message originates
- * @acknowledge_count: CPUs on the destination Hub that received the interrupt
- * @qualifier:         Set by source to verify origin of INTD broadcast
- */
-struct uv4_bau_msg_payload {
-       u64 address;
-       u16 sending_cpu;
-       u16 acknowledge_count;
-       u32 reserved:8;
-       u32 qualifier:24;
-};
-
-/*
- * UV2 Message header:  16 bytes (128 bits) (bytes 0x30-0x3f of descriptor)
- * see figure 9-2 of harp_sys.pdf
- * assuming UV3 is the same
- */
-struct uv2_3_bau_msg_header {
-       unsigned int    base_dest_nasid:15;     /* nasid of the first bit */
-       /* bits 14:0 */                         /* in uvhub map */
-       unsigned int    dest_subnodeid:5;       /* must be 0x10, for the LB */
-       /* bits 19:15 */
-       unsigned int    rsvd_1:1;               /* must be zero */
-       /* bit 20 */
-       /* Address bits 59:21 */
-       /* bits 25:2 of address (44:21) are payload */
-       /* these next 24 bits become bytes 12-14 of msg */
-       /* bits 28:21 land in byte 12 */
-       unsigned int    replied_to:1;           /* sent as 0 by the source to
-                                                  byte 12 */
-       /* bit 21 */
-       unsigned int    msg_type:3;             /* software type of the
-                                                  message */
-       /* bits 24:22 */
-       unsigned int    canceled:1;             /* message canceled, resource
-                                                  is to be freed*/
-       /* bit 25 */
-       unsigned int    payload_1:3;            /* not currently used */
-       /* bits 28:26 */
-
-       /* bits 36:29 land in byte 13 */
-       unsigned int    payload_2a:3;           /* not currently used */
-       unsigned int    payload_2b:5;           /* not currently used */
-       /* bits 36:29 */
-
-       /* bits 44:37 land in byte 14 */
-       unsigned int    payload_3:8;            /* not currently used */
-       /* bits 44:37 */
-
-       unsigned int    rsvd_2:7;               /* reserved */
-       /* bits 51:45 */
-       unsigned int    swack_flag:1;           /* software acknowledge flag */
-       /* bit 52 */
-       unsigned int    rsvd_3a:3;              /* must be zero */
-       unsigned int    rsvd_3b:8;              /* must be zero */
-       unsigned int    rsvd_3c:8;              /* must be zero */
-       unsigned int    rsvd_3d:3;              /* must be zero */
-       /* bits 74:53 */
-       unsigned int    fairness:3;             /* usually zero */
-       /* bits 77:75 */
-
-       unsigned int    sequence:16;            /* message sequence number */
-       /* bits 93:78  Suppl_A  */
-       unsigned int    chaining:1;             /* next descriptor is part of
-                                                  this activation*/
-       /* bit 94 */
-       unsigned int    multilevel:1;           /* multi-level multicast
-                                                  format */
-       /* bit 95 */
-       unsigned int    rsvd_4:24;              /* ordered / source node /
-                                                  source subnode / aging
-                                                  must be zero */
-       /* bits 119:96 */
-       unsigned int    command:8;              /* message type */
-       /* bits 127:120 */
-};
-
-/*
- * The activation descriptor:
- * The format of the message to send, plus all accompanying control
- * Should be 64 bytes
- */
-struct bau_desc {
-       struct pnmask                           distribution;
-       /*
-        * message template, consisting of header and payload:
-        */
-       union bau_msg_header {
-               struct uv2_3_bau_msg_header     uv2_3_hdr;
-       } header;
-
-       union bau_payload_header {
-               struct uv2_3_bau_msg_payload    uv2_3;
-               struct uv4_bau_msg_payload      uv4;
-       } payload;
-};
-/* UV2:
- *   -payload--    ---------header------
- *   bytes 0-11    bits 70-78  bits 21-44
- *       A           B  (2)      C (3)
- *
- *            A/B/C are moved to:
- *       A            C          B
- *   bytes 0-11  bytes 12-14  bytes 16-17  (byte 15 filled in by hw as vector)
- *   ------------payload queue-----------
- */
-
-/*
- * The payload queue on the destination side is an array of these.
- * With BAU_MISC_CONTROL set for software acknowledge mode, the messages
- * are 32 bytes (2 micropackets) (256 bits) in length, but contain only 17
- * bytes of usable data, including the sw ack vector in byte 15 (bits 127:120)
- * (12 bytes come from bau_msg_payload, 3 from payload_1, 2 from
- *  swack_vec and payload_2)
- * "Enabling Software Acknowledgment mode (see Section 4.3.3 Software
- *  Acknowledge Processing) also selects 32 byte (17 bytes usable) payload
- *  operation."
- */
-struct bau_pq_entry {
-       unsigned long   address;        /* signifies a page or all TLB's
-                                          of the cpu */
-       /* 64 bits, bytes 0-7 */
-       unsigned short  sending_cpu;    /* cpu that sent the message */
-       /* 16 bits, bytes 8-9 */
-       unsigned short  acknowledge_count; /* filled in by destination */
-       /* 16 bits, bytes 10-11 */
-       /* these next 3 bytes come from bits 58-81 of the message header */
-       unsigned short  replied_to:1;   /* sent as 0 by the source */
-       unsigned short  msg_type:3;     /* software message type */
-       unsigned short  canceled:1;     /* sent as 0 by the source */
-       unsigned short  unused1:3;      /* not currently using */
-       /* byte 12 */
-       unsigned char   unused2a;       /* not currently using */
-       /* byte 13 */
-       unsigned char   unused2;        /* not currently using */
-       /* byte 14 */
-       unsigned char   swack_vec;      /* filled in by the hardware */
-       /* byte 15 (bits 127:120) */
-       unsigned short  sequence;       /* message sequence number */
-       /* bytes 16-17 */
-       unsigned char   unused4[2];     /* not currently using bytes 18-19 */
-       /* bytes 18-19 */
-       int             number_of_cpus; /* filled in at destination */
-       /* 32 bits, bytes 20-23 (aligned) */
-       unsigned char   unused5[8];     /* not using */
-       /* bytes 24-31 */
-};
-
-struct msg_desc {
-       struct bau_pq_entry     *msg;
-       int                     msg_slot;
-       struct bau_pq_entry     *queue_first;
-       struct bau_pq_entry     *queue_last;
-};
-
-struct reset_args {
-       int                     sender;
-};
-
-/*
- * This structure is allocated per_cpu for UV TLB shootdown statistics.
- */
-struct ptc_stats {
-       /* sender statistics */
-       unsigned long   s_giveup;               /* number of fall backs to
-                                                  IPI-style flushes */
-       unsigned long   s_requestor;            /* number of shootdown
-                                                  requests */
-       unsigned long   s_stimeout;             /* source side timeouts */
-       unsigned long   s_dtimeout;             /* destination side timeouts */
-       unsigned long   s_strongnacks;          /* number of strong nack's */
-       unsigned long   s_time;                 /* time spent in sending side */
-       unsigned long   s_retriesok;            /* successful retries */
-       unsigned long   s_ntargcpu;             /* total number of cpu's
-                                                  targeted */
-       unsigned long   s_ntargself;            /* times the sending cpu was
-                                                  targeted */
-       unsigned long   s_ntarglocals;          /* targets of cpus on the local
-                                                  blade */
-       unsigned long   s_ntargremotes;         /* targets of cpus on remote
-                                                  blades */
-       unsigned long   s_ntarglocaluvhub;      /* targets of the local hub */
-       unsigned long   s_ntargremoteuvhub;     /* remotes hubs targeted */
-       unsigned long   s_ntarguvhub;           /* total number of uvhubs
-                                                  targeted */
-       unsigned long   s_ntarguvhub16;         /* number of times target
-                                                  hubs >= 16*/
-       unsigned long   s_ntarguvhub8;          /* number of times target
-                                                  hubs >= 8 */
-       unsigned long   s_ntarguvhub4;          /* number of times target
-                                                  hubs >= 4 */
-       unsigned long   s_ntarguvhub2;          /* number of times target
-                                                  hubs >= 2 */
-       unsigned long   s_ntarguvhub1;          /* number of times target
-                                                  hubs == 1 */
-       unsigned long   s_resets_plug;          /* ipi-style resets from plug
-                                                  state */
-       unsigned long   s_resets_timeout;       /* ipi-style resets from
-                                                  timeouts */
-       unsigned long   s_busy;                 /* status stayed busy past
-                                                  s/w timer */
-       unsigned long   s_throttles;            /* waits in throttle */
-       unsigned long   s_retry_messages;       /* retry broadcasts */
-       unsigned long   s_bau_reenabled;        /* for bau enable/disable */
-       unsigned long   s_bau_disabled;         /* for bau enable/disable */
-       unsigned long   s_uv2_wars;             /* uv2 workaround, perm. busy */
-       unsigned long   s_uv2_wars_hw;          /* uv2 workaround, hiwater */
-       unsigned long   s_uv2_war_waits;        /* uv2 workaround, long waits */
-       unsigned long   s_overipilimit;         /* over the ipi reset limit */
-       unsigned long   s_giveuplimit;          /* disables, over giveup limit*/
-       unsigned long   s_enters;               /* entries to the driver */
-       unsigned long   s_ipifordisabled;       /* fall back to IPI; disabled */
-       unsigned long   s_plugged;              /* plugged by h/w bug*/
-       unsigned long   s_congested;            /* giveup on long wait */
-       /* destination statistics */
-       unsigned long   d_alltlb;               /* times all tlb's on this
-                                                  cpu were flushed */
-       unsigned long   d_onetlb;               /* times just one tlb on this
-                                                  cpu was flushed */
-       unsigned long   d_multmsg;              /* interrupts with multiple
-                                                  messages */
-       unsigned long   d_nomsg;                /* interrupts with no message */
-       unsigned long   d_time;                 /* time spent on destination
-                                                  side */
-       unsigned long   d_requestee;            /* number of messages
-                                                  processed */
-       unsigned long   d_retries;              /* number of retry messages
-                                                  processed */
-       unsigned long   d_canceled;             /* number of messages canceled
-                                                  by retries */
-       unsigned long   d_nocanceled;           /* retries that found nothing
-                                                  to cancel */
-       unsigned long   d_resets;               /* number of ipi-style requests
-                                                  processed */
-       unsigned long   d_rcanceled;            /* number of messages canceled
-                                                  by resets */
-};
-
-struct tunables {
-       int                     *tunp;
-       int                     deflt;
-};
-
-struct hub_and_pnode {
-       short                   uvhub;
-       short                   pnode;
-};
-
-struct socket_desc {
-       short                   num_cpus;
-       short                   cpu_number[MAX_CPUS_PER_SOCKET];
-};
-
-struct uvhub_desc {
-       unsigned short          socket_mask;
-       short                   num_cpus;
-       short                   uvhub;
-       short                   pnode;
-       struct socket_desc      socket[2];
-};
-
-/**
- * struct bau_control
- * @status_mmr: location of status mmr, determined by uvhub_cpu
- * @status_index: index of ERR|BUSY bits in status mmr, determined by uvhub_cpu
- *
- * Per-cpu control struct containing CPU topology information and BAU tuneables.
- */
-struct bau_control {
-       struct bau_desc         *descriptor_base;
-       struct bau_pq_entry     *queue_first;
-       struct bau_pq_entry     *queue_last;
-       struct bau_pq_entry     *bau_msg_head;
-       struct bau_control      *uvhub_master;
-       struct bau_control      *socket_master;
-       struct ptc_stats        *statp;
-       cpumask_t               *cpumask;
-       unsigned long           timeout_interval;
-       unsigned long           set_bau_on_time;
-       atomic_t                active_descriptor_count;
-       int                     plugged_tries;
-       int                     timeout_tries;
-       int                     ipi_attempts;
-       int                     conseccompletes;
-       u64                     status_mmr;
-       int                     status_index;
-       bool                    nobau;
-       short                   baudisabled;
-       short                   cpu;
-       short                   osnode;
-       short                   uvhub_cpu;
-       short                   uvhub;
-       short                   uvhub_version;
-       short                   cpus_in_socket;
-       short                   cpus_in_uvhub;
-       short                   partition_base_pnode;
-       short                   busy;       /* all were busy (war) */
-       unsigned short          message_number;
-       unsigned short          uvhub_quiesce;
-       short                   socket_acknowledge_count[DEST_Q_SIZE];
-       cycles_t                send_message;
-       cycles_t                period_end;
-       cycles_t                period_time;
-       spinlock_t              uvhub_lock;
-       spinlock_t              queue_lock;
-       spinlock_t              disable_lock;
-       /* tunables */
-       int                     max_concurr;
-       int                     max_concurr_const;
-       int                     plugged_delay;
-       int                     plugsb4reset;
-       int                     timeoutsb4reset;
-       int                     ipi_reset_limit;
-       int                     complete_threshold;
-       int                     cong_response_us;
-       int                     cong_reps;
-       cycles_t                disabled_period;
-       int                     period_giveups;
-       int                     giveup_limit;
-       long                    period_requests;
-       struct hub_and_pnode    *thp;
-};
-
-/* Abstracted BAU functions */
-struct bau_operations {
-       unsigned long   (*read_l_sw_ack)(void);
-       unsigned long   (*read_g_sw_ack)(int pnode);
-       unsigned long   (*bau_gpa_to_offset)(unsigned long vaddr);
-       void            (*write_l_sw_ack)(unsigned long mmr);
-       void            (*write_g_sw_ack)(int pnode, unsigned long mmr);
-       void            (*write_payload_first)(int pnode, unsigned long mmr);
-       void            (*write_payload_last)(int pnode, unsigned long mmr);
-       int             (*wait_completion)(struct bau_desc*,
-                               struct bau_control*, long try);
-};
-
-static inline void write_mmr_data_broadcast(int pnode, unsigned long mmr_image)
-{
-       write_gmmr(pnode, UVH_BAU_DATA_BROADCAST, mmr_image);
-}
-
-static inline void write_mmr_descriptor_base(int pnode, unsigned long mmr_image)
-{
-       write_gmmr(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE, mmr_image);
-}
-
-static inline void write_mmr_activation(unsigned long index)
-{
-       write_lmmr(UVH_LB_BAU_SB_ACTIVATION_CONTROL, index);
-}
-
-static inline void write_gmmr_activation(int pnode, unsigned long mmr_image)
-{
-       write_gmmr(pnode, UVH_LB_BAU_SB_ACTIVATION_CONTROL, mmr_image);
-}
-
-static inline void write_mmr_proc_payload_first(int pnode, unsigned long mmr_image)
-{
-       write_gmmr(pnode, UV4H_LB_PROC_INTD_QUEUE_FIRST, mmr_image);
-}
-
-static inline void write_mmr_proc_payload_last(int pnode, unsigned long mmr_image)
-{
-       write_gmmr(pnode, UV4H_LB_PROC_INTD_QUEUE_LAST, mmr_image);
-}
-
-static inline void write_mmr_payload_first(int pnode, unsigned long mmr_image)
-{
-       write_gmmr(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST, mmr_image);
-}
-
-static inline void write_mmr_payload_tail(int pnode, unsigned long mmr_image)
-{
-       write_gmmr(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL, mmr_image);
-}
-
-static inline void write_mmr_payload_last(int pnode, unsigned long mmr_image)
-{
-       write_gmmr(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST, mmr_image);
-}
-
-static inline void write_mmr_misc_control(int pnode, unsigned long mmr_image)
-{
-       write_gmmr(pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
-}
-
-static inline unsigned long read_mmr_misc_control(int pnode)
-{
-       return read_gmmr(pnode, UVH_LB_BAU_MISC_CONTROL);
-}
-
-static inline void write_mmr_sw_ack(unsigned long mr)
-{
-       uv_write_local_mmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, mr);
-}
-
-static inline void write_gmmr_sw_ack(int pnode, unsigned long mr)
-{
-       write_gmmr(pnode, UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, mr);
-}
-
-static inline unsigned long read_mmr_sw_ack(void)
-{
-       return read_lmmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
-}
-
-static inline unsigned long read_gmmr_sw_ack(int pnode)
-{
-       return read_gmmr(pnode, UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
-}
-
-static inline void write_mmr_proc_sw_ack(unsigned long mr)
-{
-       uv_write_local_mmr(UV4H_LB_PROC_INTD_SOFT_ACK_CLEAR, mr);
-}
-
-static inline void write_gmmr_proc_sw_ack(int pnode, unsigned long mr)
-{
-       write_gmmr(pnode, UV4H_LB_PROC_INTD_SOFT_ACK_CLEAR, mr);
-}
-
-static inline unsigned long read_mmr_proc_sw_ack(void)
-{
-       return read_lmmr(UV4H_LB_PROC_INTD_SOFT_ACK_PENDING);
-}
-
-static inline unsigned long read_gmmr_proc_sw_ack(int pnode)
-{
-       return read_gmmr(pnode, UV4H_LB_PROC_INTD_SOFT_ACK_PENDING);
-}
-
-static inline void write_mmr_data_config(int pnode, unsigned long mr)
-{
-       uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG, mr);
-}
-
-static inline int bau_uvhub_isset(int uvhub, struct pnmask *dstp)
-{
-       return constant_test_bit(uvhub, &dstp->bits[0]);
-}
-static inline void bau_uvhub_set(int pnode, struct pnmask *dstp)
-{
-       __set_bit(pnode, &dstp->bits[0]);
-}
-static inline void bau_uvhubs_clear(struct pnmask *dstp,
-                                   int nbits)
-{
-       bitmap_zero(&dstp->bits[0], nbits);
-}
-static inline int bau_uvhub_weight(struct pnmask *dstp)
-{
-       return bitmap_weight((unsigned long *)&dstp->bits[0],
-                               UV_DISTRIBUTION_SIZE);
-}
-
-static inline void bau_cpubits_clear(struct bau_local_cpumask *dstp, int nbits)
-{
-       bitmap_zero(&dstp->bits, nbits);
-}
-
-struct atomic_short {
-       short counter;
-};
-
-/*
- * atomic_read_short - read a short atomic variable
- * @v: pointer of type atomic_short
- *
- * Atomically reads the value of @v.
- */
-static inline int atomic_read_short(const struct atomic_short *v)
-{
-       return v->counter;
-}
-
-/*
- * atom_asr - add and return a short int
- * @i: short value to add
- * @v: pointer of type atomic_short
- *
- * Atomically adds @i to @v and returns @i + @v
- */
-static inline int atom_asr(short i, struct atomic_short *v)
-{
-       short __i = i;
-       asm volatile(LOCK_PREFIX "xaddw %0, %1"
-                       : "+r" (i), "+m" (v->counter)
-                       : : "memory");
-       return i + __i;
-}
-
-/*
- * conditionally add 1 to *v, unless *v is >= u
- * return 0 if we cannot add 1 to *v because it is >= u
- * return 1 if we can add 1 to *v because it is < u
- * the add is atomic
- *
- * This is close to atomic_add_unless(), but this allows the 'u' value
- * to be lowered below the current 'v'.  atomic_add_unless can only stop
- * on equal.
- */
-static inline int atomic_inc_unless_ge(spinlock_t *lock, atomic_t *v, int u)
-{
-       spin_lock(lock);
-       if (atomic_read(v) >= u) {
-               spin_unlock(lock);
-               return 0;
-       }
-       atomic_inc(v);
-       spin_unlock(lock);
-       return 1;
-}
-
-void uv_bau_message_interrupt(struct pt_regs *regs);
-
-#endif /* _ASM_X86_UV_UV_BAU_H */
index 100d668..5002f52 100644 (file)
@@ -5,6 +5,7 @@
  *
  * SGI UV architectural definitions
  *
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 
  */
 #define UV_MAX_NASID_VALUE     (UV_MAX_NUMALINK_BLADES * 2)
 
-/* System Controller Interface Reg info */
-struct uv_scir_s {
-       struct timer_list timer;
-       unsigned long   offset;
-       unsigned long   last;
-       unsigned long   idle_on;
-       unsigned long   idle_off;
-       unsigned char   state;
-       unsigned char   enabled;
-};
-
 /* GAM (globally addressed memory) range table */
 struct uv_gam_range_s {
        u32     limit;          /* PA bits 56:26 (GAM_RANGE_SHFT) */
@@ -155,6 +145,8 @@ struct uv_gam_range_s {
  * available in the L3 cache on the cpu socket for the node.
  */
 struct uv_hub_info_s {
+       unsigned int            hub_type;
+       unsigned char           hub_revision;
        unsigned long           global_mmr_base;
        unsigned long           global_mmr_shift;
        unsigned long           gpa_mask;
@@ -167,9 +159,9 @@ struct uv_hub_info_s {
        unsigned char           m_val;
        unsigned char           n_val;
        unsigned char           gr_table_len;
-       unsigned char           hub_revision;
        unsigned char           apic_pnode_shift;
        unsigned char           gpa_shift;
+       unsigned char           nasid_shift;
        unsigned char           m_shift;
        unsigned char           n_lshift;
        unsigned int            gnode_extra;
@@ -191,16 +183,13 @@ struct uv_hub_info_s {
 struct uv_cpu_info_s {
        void                    *p_uv_hub_info;
        unsigned char           blade_cpu_id;
-       struct uv_scir_s        scir;
+       void                    *reserved;
 };
 DECLARE_PER_CPU(struct uv_cpu_info_s, __uv_cpu_info);
 
 #define uv_cpu_info            this_cpu_ptr(&__uv_cpu_info)
 #define uv_cpu_info_per(cpu)   (&per_cpu(__uv_cpu_info, cpu))
 
-#define        uv_scir_info            (&uv_cpu_info->scir)
-#define        uv_cpu_scir_info(cpu)   (&uv_cpu_info_per(cpu)->scir)
-
 /* Node specific hub common info struct */
 extern void **__uv_hub_info_list;
 static inline struct uv_hub_info_s *uv_hub_info_list(int node)
@@ -219,6 +208,17 @@ static inline struct uv_hub_info_s *uv_cpu_hub_info(int cpu)
        return (struct uv_hub_info_s *)uv_cpu_info_per(cpu)->p_uv_hub_info;
 }
 
+static inline int uv_hub_type(void)
+{
+       return uv_hub_info->hub_type;
+}
+
+static inline __init void uv_hub_type_set(int uvmask)
+{
+       uv_hub_info->hub_type = uvmask;
+}
+
+
 /*
  * HUB revision ranges for each UV HUB architecture.
  * This is a software convention - NOT the hardware revision numbers in
@@ -228,39 +228,31 @@ static inline struct uv_hub_info_s *uv_cpu_hub_info(int cpu)
 #define UV3_HUB_REVISION_BASE          5
 #define UV4_HUB_REVISION_BASE          7
 #define UV4A_HUB_REVISION_BASE         8       /* UV4 (fixed) rev 2 */
+#define UV5_HUB_REVISION_BASE          9
 
-static inline int is_uv2_hub(void)
-{
-       return is_uv_hubbed(uv(2));
-}
-
-static inline int is_uv3_hub(void)
-{
-       return is_uv_hubbed(uv(3));
-}
+static inline int is_uv(int uvmask) { return uv_hub_type() & uvmask; }
+static inline int is_uv1_hub(void) { return 0; }
+static inline int is_uv2_hub(void) { return is_uv(UV2); }
+static inline int is_uv3_hub(void) { return is_uv(UV3); }
+static inline int is_uv4a_hub(void) { return is_uv(UV4A); }
+static inline int is_uv4_hub(void) { return is_uv(UV4); }
+static inline int is_uv5_hub(void) { return is_uv(UV5); }
 
-/* First test "is UV4A", then "is UV4" */
-static inline int is_uv4a_hub(void)
-{
-       if (is_uv_hubbed(uv(4)))
-               return (uv_hub_info->hub_revision == UV4A_HUB_REVISION_BASE);
-       return 0;
-}
+/*
+ * UV4A is a revision of UV4.  So on UV4A, both is_uv4_hub() and
+ * is_uv4a_hub() return true, While on UV4, only is_uv4_hub()
+ * returns true.  So to get true results, first test if is UV4A,
+ * then test if is UV4.
+ */
 
-static inline int is_uv4_hub(void)
-{
-       return is_uv_hubbed(uv(4));
-}
+/* UVX class: UV2,3,4 */
+static inline int is_uvx_hub(void) { return is_uv(UVX); }
 
-static inline int is_uvx_hub(void)
-{
-       return (is_uv_hubbed(-2) >= uv(2));
-}
+/* UVY class: UV5,..? */
+static inline int is_uvy_hub(void) { return is_uv(UVY); }
 
-static inline int is_uv_hub(void)
-{
-       return is_uvx_hub();
-}
+/* Any UV Hubbed System */
+static inline int is_uv_hub(void) { return is_uv(UV_ANY); }
 
 union uvh_apicid {
     unsigned long       v;
@@ -282,9 +274,11 @@ union uvh_apicid {
  *             g -  GNODE (full 15-bit global nasid, right shifted 1)
  *             p -  PNODE (local part of nsids, right shifted 1)
  */
-#define UV_NASID_TO_PNODE(n)           (((n) >> 1) & uv_hub_info->pnode_mask)
+#define UV_NASID_TO_PNODE(n)           \
+               (((n) >> uv_hub_info->nasid_shift) & uv_hub_info->pnode_mask)
 #define UV_PNODE_TO_GNODE(p)           ((p) |uv_hub_info->gnode_extra)
-#define UV_PNODE_TO_NASID(p)           (UV_PNODE_TO_GNODE(p) << 1)
+#define UV_PNODE_TO_NASID(p)           \
+               (UV_PNODE_TO_GNODE(p) << uv_hub_info->nasid_shift)
 
 #define UV2_LOCAL_MMR_BASE             0xfa000000UL
 #define UV2_GLOBAL_MMR32_BASE          0xfc000000UL
@@ -297,29 +291,42 @@ union uvh_apicid {
 #define UV3_GLOBAL_MMR32_SIZE          (32UL * 1024 * 1024)
 
 #define UV4_LOCAL_MMR_BASE             0xfa000000UL
-#define UV4_GLOBAL_MMR32_BASE          0xfc000000UL
+#define UV4_GLOBAL_MMR32_BASE          0
 #define UV4_LOCAL_MMR_SIZE             (32UL * 1024 * 1024)
-#define UV4_GLOBAL_MMR32_SIZE          (16UL * 1024 * 1024)
+#define UV4_GLOBAL_MMR32_SIZE          0
+
+#define UV5_LOCAL_MMR_BASE             0xfa000000UL
+#define UV5_GLOBAL_MMR32_BASE          0
+#define UV5_LOCAL_MMR_SIZE             (32UL * 1024 * 1024)
+#define UV5_GLOBAL_MMR32_SIZE          0
 
 #define UV_LOCAL_MMR_BASE              (                               \
-                                       is_uv2_hub() ? UV2_LOCAL_MMR_BASE : \
-                                       is_uv3_hub() ? UV3_LOCAL_MMR_BASE : \
-                                       /*is_uv4_hub*/ UV4_LOCAL_MMR_BASE)
+                                       is_uv(UV2) ? UV2_LOCAL_MMR_BASE : \
+                                       is_uv(UV3) ? UV3_LOCAL_MMR_BASE : \
+                                       is_uv(UV4) ? UV4_LOCAL_MMR_BASE : \
+                                       is_uv(UV5) ? UV5_LOCAL_MMR_BASE : \
+                                       0)
 
 #define UV_GLOBAL_MMR32_BASE           (                               \
-                                       is_uv2_hub() ? UV2_GLOBAL_MMR32_BASE : \
-                                       is_uv3_hub() ? UV3_GLOBAL_MMR32_BASE : \
-                                       /*is_uv4_hub*/ UV4_GLOBAL_MMR32_BASE)
+                                       is_uv(UV2) ? UV2_GLOBAL_MMR32_BASE : \
+                                       is_uv(UV3) ? UV3_GLOBAL_MMR32_BASE : \
+                                       is_uv(UV4) ? UV4_GLOBAL_MMR32_BASE : \
+                                       is_uv(UV5) ? UV5_GLOBAL_MMR32_BASE : \
+                                       0)
 
 #define UV_LOCAL_MMR_SIZE              (                               \
-                                       is_uv2_hub() ? UV2_LOCAL_MMR_SIZE : \
-                                       is_uv3_hub() ? UV3_LOCAL_MMR_SIZE : \
-                                       /*is_uv4_hub*/ UV4_LOCAL_MMR_SIZE)
+                                       is_uv(UV2) ? UV2_LOCAL_MMR_SIZE : \
+                                       is_uv(UV3) ? UV3_LOCAL_MMR_SIZE : \
+                                       is_uv(UV4) ? UV4_LOCAL_MMR_SIZE : \
+                                       is_uv(UV5) ? UV5_LOCAL_MMR_SIZE : \
+                                       0)
 
 #define UV_GLOBAL_MMR32_SIZE           (                               \
-                                       is_uv2_hub() ? UV2_GLOBAL_MMR32_SIZE : \
-                                       is_uv3_hub() ? UV3_GLOBAL_MMR32_SIZE : \
-                                       /*is_uv4_hub*/ UV4_GLOBAL_MMR32_SIZE)
+                                       is_uv(UV2) ? UV2_GLOBAL_MMR32_SIZE : \
+                                       is_uv(UV3) ? UV3_GLOBAL_MMR32_SIZE : \
+                                       is_uv(UV4) ? UV4_GLOBAL_MMR32_SIZE : \
+                                       is_uv(UV5) ? UV5_GLOBAL_MMR32_SIZE : \
+                                       0)
 
 #define UV_GLOBAL_MMR64_BASE           (uv_hub_info->global_mmr_base)
 
@@ -720,7 +727,7 @@ extern void uv_nmi_setup_hubless(void);
 #define UVH_TSC_SYNC_SHIFT_UV2K        16      /* UV2/3k have different bits */
 #define UVH_TSC_SYNC_MASK      3       /* 0011 */
 #define UVH_TSC_SYNC_VALID     3       /* 0011 */
-#define UVH_TSC_SYNC_INVALID   2       /* 0010 */
+#define UVH_TSC_SYNC_UNKNOWN   0       /* 0000 */
 
 /* BMC sets a bit this MMR non-zero before sending an NMI */
 #define UVH_NMI_MMR            UVH_BIOS_KERNEL_MMR
@@ -728,19 +735,6 @@ extern void uv_nmi_setup_hubless(void);
 #define UVH_NMI_MMR_SHIFT      63
 #define UVH_NMI_MMR_TYPE       "SCRATCH5"
 
-/* Newer SMM NMI handler, not present in all systems */
-#define UVH_NMI_MMRX           UVH_EVENT_OCCURRED0
-#define UVH_NMI_MMRX_CLEAR     UVH_EVENT_OCCURRED0_ALIAS
-#define UVH_NMI_MMRX_SHIFT     UVH_EVENT_OCCURRED0_EXTIO_INT0_SHFT
-#define UVH_NMI_MMRX_TYPE      "EXTIO_INT0"
-
-/* Non-zero indicates newer SMM NMI handler present */
-#define UVH_NMI_MMRX_SUPPORTED UVH_EXTIO_INT0_BROADCAST
-
-/* Indicates to BIOS that we want to use the newer SMM NMI handler */
-#define UVH_NMI_MMRX_REQ       UVH_BIOS_KERNEL_MMR_ALIAS_2
-#define UVH_NMI_MMRX_REQ_SHIFT 62
-
 struct uv_hub_nmi_s {
        raw_spinlock_t  nmi_lock;
        atomic_t        in_nmi;         /* flag this node in UV NMI IRQ */
@@ -772,29 +766,6 @@ DECLARE_PER_CPU(struct uv_cpu_nmi_s, uv_cpu_nmi);
 #define        UV_NMI_STATE_DUMP               2
 #define        UV_NMI_STATE_DUMP_DONE          3
 
-/* Update SCIR state */
-static inline void uv_set_scir_bits(unsigned char value)
-{
-       if (uv_scir_info->state != value) {
-               uv_scir_info->state = value;
-               uv_write_local_mmr8(uv_scir_info->offset, value);
-       }
-}
-
-static inline unsigned long uv_scir_offset(int apicid)
-{
-       return SCIR_LOCAL_MMR_BASE | (apicid & 0x3f);
-}
-
-static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
-{
-       if (uv_cpu_scir_info(cpu)->state != value) {
-               uv_write_global_mmr8(uv_cpu_to_pnode(cpu),
-                               uv_cpu_scir_info(cpu)->offset, value);
-               uv_cpu_scir_info(cpu)->state = value;
-       }
-}
-
 /*
  * Get the minimum revision number of the hub chips within the partition.
  * (See UVx_HUB_REVISION_BASE above for specific values.)
index 775bf14..57fa673 100644 (file)
@@ -3,8 +3,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * SGI UV MMR definitions
+ * HPE UV MMR definitions
  *
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  * Copyright (C) 2007-2016 Silicon Graphics, Inc. All rights reserved.
  */
 
  * grouped by architecture types.
  *
  * UVH  - definitions common to all UV hub types.
- * UVXH - definitions common to all UV eXtended hub types (currently 2, 3, 4).
- * UV2H - definitions specific to UV type 2 hub.
- * UV3H - definitions specific to UV type 3 hub.
+ * UVXH - definitions common to UVX class (2, 3, 4).
+ * UVYH - definitions common to UVY class (5).
+ * UV5H - definitions specific to UV type 5 hub.
+ * UV4AH - definitions specific to UV type 4A hub.
  * UV4H - definitions specific to UV type 4 hub.
- *
- * So in general, MMR addresses and structures are identical on all hubs types.
- * These MMRs are identified as:
- *     #define UVH_xxx         <address>
- *     union uvh_xxx {
- *             unsigned long       v;
- *             struct uvh_int_cmpd_s {
- *             } s;
- *     };
+ * UV3H - definitions specific to UV type 3 hub.
+ * UV2H - definitions specific to UV type 2 hub.
  *
  * If the MMR exists on all hub types but have different addresses,
- * use a conditional operator to define the value at runtime.
- *     #define UV2Hxxx b
- *     #define UV3Hxxx c
- *     #define UV4Hxxx d
- *     #define UV4AHxxx e
- *     #define UVHxxx  (is_uv2_hub() ? UV2Hxxx :
- *                     (is_uv3_hub() ? UV3Hxxx :
- *                     (is_uv4a_hub() ? UV4AHxxx :
- *                                     UV4Hxxx))
+ * use a conditional operator to define the value at runtime.  Any
+ * that are not defined are blank.
+ *     (UV4A variations only generated if different from uv4)
+ *     #define UVHxxx (
+ *             is_uv(UV5) ? UV5Hxxx value :
+ *             is_uv(UV4A) ? UV4AHxxx value :
+ *             is_uv(UV4) ? UV4Hxxx value :
+ *             is_uv(UV3) ? UV3Hxxx value :
+ *             is_uv(UV2) ? UV2Hxxx value :
+ *             <ucv> or <undef value>)
+ *
+ * Class UVX has UVs (2|3|4|4A).
+ * Class UVY has UVs (5).
  *
  *     union uvh_xxx {
  *             unsigned long       v;
  *             struct uvh_xxx_s {       # Common fields only
  *             } s;
- *             struct uv2h_xxx_s {      # Full UV2 definition (*)
- *             } s2;
- *             struct uv3h_xxx_s {      # Full UV3 definition (*)
- *             } s3;
- *             (NOTE: No struct uv4ah_xxx_s members exist)
+ *             struct uv5h_xxx_s {      # Full UV5 definition (*)
+ *             } s5;
+ *             struct uv4ah_xxx_s {     # Full UV4A definition (*)
+ *             } s4a;
  *             struct uv4h_xxx_s {      # Full UV4 definition (*)
  *             } s4;
+ *             struct uv3h_xxx_s {      # Full UV3 definition (*)
+ *             } s3;
+ *             struct uv2h_xxx_s {      # Full UV2 definition (*)
+ *             } s2;
  *     };
  *             (* - if present and different than the common struct)
  *
  * if the contents is the same for all hubs, only the "s" structure is
  * generated.
  *
- * If the MMR exists on ONLY 1 type of hub, no generic definition is
- * generated:
- *     #define UVnH_xxx        <uvn address>
- *     union uvnh_xxx {
- *             unsigned long       v;
- *             struct uvh_int_cmpd_s {
- *             } sn;
- *     };
- *
- * (GEN Flags: mflags_opt= undefs=function UV234=UVXH)
+ * (GEN Flags: undefs=function)
  */
 
+ /* UV bit masks */
+#define        UV2     (1 << 0)
+#define        UV3     (1 << 1)
+#define        UV4     (1 << 2)
+#define        UV4A    (1 << 3)
+#define        UV5     (1 << 4)
+#define        UVX     (UV2|UV3|UV4)
+#define        UVY     (UV5)
+#define        UV_ANY  (~0)
+
+
+
+
 #define UV_MMR_ENABLE          (1UL << 63)
 
+#define UV1_HUB_PART_NUMBER    0x88a5
 #define UV2_HUB_PART_NUMBER    0x8eb8
 #define UV2_HUB_PART_NUMBER_X  0x1111
 #define UV3_HUB_PART_NUMBER    0x9578
 #define UV3_HUB_PART_NUMBER_X  0x4321
 #define UV4_HUB_PART_NUMBER    0x99a1
+#define UV5_HUB_PART_NUMBER    0xa171
 
 /* Error function to catch undefined references */
 extern unsigned long uv_undefined(char *str);
 
 /* ========================================================================= */
-/*                          UVH_BAU_DATA_BROADCAST                           */
-/* ========================================================================= */
-#define UVH_BAU_DATA_BROADCAST 0x61688UL
-
-#define UV2H_BAU_DATA_BROADCAST_32 0x440
-#define UV3H_BAU_DATA_BROADCAST_32 0x440
-#define UV4H_BAU_DATA_BROADCAST_32 0x360
-#define UVH_BAU_DATA_BROADCAST_32 (                                    \
-       is_uv2_hub() ? UV2H_BAU_DATA_BROADCAST_32 :                     \
-       is_uv3_hub() ? UV3H_BAU_DATA_BROADCAST_32 :                     \
-       /*is_uv4_hub*/ UV4H_BAU_DATA_BROADCAST_32)
-
-#define UVH_BAU_DATA_BROADCAST_ENABLE_SHFT             0
-#define UVH_BAU_DATA_BROADCAST_ENABLE_MASK             0x0000000000000001UL
-
-
-union uvh_bau_data_broadcast_u {
-       unsigned long   v;
-       struct uvh_bau_data_broadcast_s {
-               unsigned long   enable:1;                       /* RW */
-               unsigned long   rsvd_1_63:63;
-       } s;
-};
-
-/* ========================================================================= */
-/*                           UVH_BAU_DATA_CONFIG                             */
-/* ========================================================================= */
-#define UVH_BAU_DATA_CONFIG 0x61680UL
-
-#define UV2H_BAU_DATA_CONFIG_32 0x438
-#define UV3H_BAU_DATA_CONFIG_32 0x438
-#define UV4H_BAU_DATA_CONFIG_32 0x358
-#define UVH_BAU_DATA_CONFIG_32 (                                       \
-       is_uv2_hub() ? UV2H_BAU_DATA_CONFIG_32 :                        \
-       is_uv3_hub() ? UV3H_BAU_DATA_CONFIG_32 :                        \
-       /*is_uv4_hub*/ UV4H_BAU_DATA_CONFIG_32)
-
-#define UVH_BAU_DATA_CONFIG_VECTOR_SHFT                        0
-#define UVH_BAU_DATA_CONFIG_DM_SHFT                    8
-#define UVH_BAU_DATA_CONFIG_DESTMODE_SHFT              11
-#define UVH_BAU_DATA_CONFIG_STATUS_SHFT                        12
-#define UVH_BAU_DATA_CONFIG_P_SHFT                     13
-#define UVH_BAU_DATA_CONFIG_T_SHFT                     15
-#define UVH_BAU_DATA_CONFIG_M_SHFT                     16
-#define UVH_BAU_DATA_CONFIG_APIC_ID_SHFT               32
-#define UVH_BAU_DATA_CONFIG_VECTOR_MASK                        0x00000000000000ffUL
-#define UVH_BAU_DATA_CONFIG_DM_MASK                    0x0000000000000700UL
-#define UVH_BAU_DATA_CONFIG_DESTMODE_MASK              0x0000000000000800UL
-#define UVH_BAU_DATA_CONFIG_STATUS_MASK                        0x0000000000001000UL
-#define UVH_BAU_DATA_CONFIG_P_MASK                     0x0000000000002000UL
-#define UVH_BAU_DATA_CONFIG_T_MASK                     0x0000000000008000UL
-#define UVH_BAU_DATA_CONFIG_M_MASK                     0x0000000000010000UL
-#define UVH_BAU_DATA_CONFIG_APIC_ID_MASK               0xffffffff00000000UL
-
-
-union uvh_bau_data_config_u {
-       unsigned long   v;
-       struct uvh_bau_data_config_s {
-               unsigned long   vector_:8;                      /* RW */
-               unsigned long   dm:3;                           /* RW */
-               unsigned long   destmode:1;                     /* RW */
-               unsigned long   status:1;                       /* RO */
-               unsigned long   p:1;                            /* RO */
-               unsigned long   rsvd_14:1;
-               unsigned long   t:1;                            /* RO */
-               unsigned long   m:1;                            /* RW */
-               unsigned long   rsvd_17_31:15;
-               unsigned long   apic_id:32;                     /* RW */
-       } s;
-};
-
-/* ========================================================================= */
 /*                           UVH_EVENT_OCCURRED0                             */
 /* ========================================================================= */
 #define UVH_EVENT_OCCURRED0 0x70000UL
-#define UVH_EVENT_OCCURRED0_32 0x5e8
 
+/* UVH common defines*/
 #define UVH_EVENT_OCCURRED0_LB_HCERR_SHFT              0
-#define UVH_EVENT_OCCURRED0_RH_AOERR0_SHFT             11
 #define UVH_EVENT_OCCURRED0_LB_HCERR_MASK              0x0000000000000001UL
-#define UVH_EVENT_OCCURRED0_RH_AOERR0_MASK             0x0000000000000800UL
 
+/* UVXH common defines */
 #define UVXH_EVENT_OCCURRED0_RH_HCERR_SHFT             2
-#define UVXH_EVENT_OCCURRED0_LH0_HCERR_SHFT            3
-#define UVXH_EVENT_OCCURRED0_LH1_HCERR_SHFT            4
-#define UVXH_EVENT_OCCURRED0_GR0_HCERR_SHFT            5
-#define UVXH_EVENT_OCCURRED0_GR1_HCERR_SHFT            6
-#define UVXH_EVENT_OCCURRED0_NI0_HCERR_SHFT            7
-#define UVXH_EVENT_OCCURRED0_NI1_HCERR_SHFT            8
-#define UVXH_EVENT_OCCURRED0_LB_AOERR0_SHFT            9
-#define UVXH_EVENT_OCCURRED0_LH0_AOERR0_SHFT           12
-#define UVXH_EVENT_OCCURRED0_LH1_AOERR0_SHFT           13
-#define UVXH_EVENT_OCCURRED0_GR0_AOERR0_SHFT           14
-#define UVXH_EVENT_OCCURRED0_GR1_AOERR0_SHFT           15
-#define UVXH_EVENT_OCCURRED0_XB_AOERR0_SHFT            16
 #define UVXH_EVENT_OCCURRED0_RH_HCERR_MASK             0x0000000000000004UL
+#define UVXH_EVENT_OCCURRED0_LH0_HCERR_SHFT            3
 #define UVXH_EVENT_OCCURRED0_LH0_HCERR_MASK            0x0000000000000008UL
+#define UVXH_EVENT_OCCURRED0_LH1_HCERR_SHFT            4
 #define UVXH_EVENT_OCCURRED0_LH1_HCERR_MASK            0x0000000000000010UL
+#define UVXH_EVENT_OCCURRED0_GR0_HCERR_SHFT            5
 #define UVXH_EVENT_OCCURRED0_GR0_HCERR_MASK            0x0000000000000020UL
+#define UVXH_EVENT_OCCURRED0_GR1_HCERR_SHFT            6
 #define UVXH_EVENT_OCCURRED0_GR1_HCERR_MASK            0x0000000000000040UL
+#define UVXH_EVENT_OCCURRED0_NI0_HCERR_SHFT            7
 #define UVXH_EVENT_OCCURRED0_NI0_HCERR_MASK            0x0000000000000080UL
+#define UVXH_EVENT_OCCURRED0_NI1_HCERR_SHFT            8
 #define UVXH_EVENT_OCCURRED0_NI1_HCERR_MASK            0x0000000000000100UL
+#define UVXH_EVENT_OCCURRED0_LB_AOERR0_SHFT            9
 #define UVXH_EVENT_OCCURRED0_LB_AOERR0_MASK            0x0000000000000200UL
+#define UVXH_EVENT_OCCURRED0_RH_AOERR0_SHFT            11
+#define UVXH_EVENT_OCCURRED0_RH_AOERR0_MASK            0x0000000000000800UL
+#define UVXH_EVENT_OCCURRED0_LH0_AOERR0_SHFT           12
 #define UVXH_EVENT_OCCURRED0_LH0_AOERR0_MASK           0x0000000000001000UL
+#define UVXH_EVENT_OCCURRED0_LH1_AOERR0_SHFT           13
 #define UVXH_EVENT_OCCURRED0_LH1_AOERR0_MASK           0x0000000000002000UL
+#define UVXH_EVENT_OCCURRED0_GR0_AOERR0_SHFT           14
 #define UVXH_EVENT_OCCURRED0_GR0_AOERR0_MASK           0x0000000000004000UL
+#define UVXH_EVENT_OCCURRED0_GR1_AOERR0_SHFT           15
 #define UVXH_EVENT_OCCURRED0_GR1_AOERR0_MASK           0x0000000000008000UL
+#define UVXH_EVENT_OCCURRED0_XB_AOERR0_SHFT            16
 #define UVXH_EVENT_OCCURRED0_XB_AOERR0_MASK            0x0000000000010000UL
 
-#define UV2H_EVENT_OCCURRED0_QP_HCERR_SHFT             1
-#define UV2H_EVENT_OCCURRED0_QP_AOERR0_SHFT            10
-#define UV2H_EVENT_OCCURRED0_RT_AOERR0_SHFT            17
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_SHFT           18
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_SHFT           19
-#define UV2H_EVENT_OCCURRED0_LB_AOERR1_SHFT            20
-#define UV2H_EVENT_OCCURRED0_QP_AOERR1_SHFT            21
-#define UV2H_EVENT_OCCURRED0_RH_AOERR1_SHFT            22
-#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_SHFT           23
-#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_SHFT           24
-#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_SHFT           25
-#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_SHFT           26
-#define UV2H_EVENT_OCCURRED0_XB_AOERR1_SHFT            27
-#define UV2H_EVENT_OCCURRED0_RT_AOERR1_SHFT            28
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_SHFT           29
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_SHFT           30
-#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT  31
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT         32
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT         33
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT         34
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT         35
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT         36
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT         37
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT         38
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT         39
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT         40
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT         41
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT                42
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT                43
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT                44
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT                45
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT                46
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT                47
-#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_SHFT           48
-#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_SHFT           49
-#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT           50
-#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT           51
-#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT       52
-#define UV2H_EVENT_OCCURRED0_IPI_INT_SHFT              53
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_SHFT           54
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_SHFT           55
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_SHFT           56
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_SHFT           57
-#define UV2H_EVENT_OCCURRED0_PROFILE_INT_SHFT          58
-#define UV2H_EVENT_OCCURRED0_QP_HCERR_MASK             0x0000000000000002UL
-#define UV2H_EVENT_OCCURRED0_QP_AOERR0_MASK            0x0000000000000400UL
-#define UV2H_EVENT_OCCURRED0_RT_AOERR0_MASK            0x0000000000020000UL
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_MASK           0x0000000000040000UL
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_MASK           0x0000000000080000UL
-#define UV2H_EVENT_OCCURRED0_LB_AOERR1_MASK            0x0000000000100000UL
-#define UV2H_EVENT_OCCURRED0_QP_AOERR1_MASK            0x0000000000200000UL
-#define UV2H_EVENT_OCCURRED0_RH_AOERR1_MASK            0x0000000000400000UL
-#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_MASK           0x0000000000800000UL
-#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_MASK           0x0000000001000000UL
-#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_MASK           0x0000000002000000UL
-#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_MASK           0x0000000004000000UL
-#define UV2H_EVENT_OCCURRED0_XB_AOERR1_MASK            0x0000000008000000UL
-#define UV2H_EVENT_OCCURRED0_RT_AOERR1_MASK            0x0000000010000000UL
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_MASK           0x0000000020000000UL
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_MASK           0x0000000040000000UL
-#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK  0x0000000080000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK         0x0000000100000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK         0x0000000200000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK         0x0000000400000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK         0x0000000800000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK         0x0000001000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK         0x0000002000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK         0x0000004000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK         0x0000008000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK         0x0000010000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK         0x0000020000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK                0x0000040000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK                0x0000080000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK                0x0000100000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK                0x0000200000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK                0x0000400000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK                0x0000800000000000UL
-#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_MASK           0x0001000000000000UL
-#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_MASK           0x0002000000000000UL
-#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_MASK           0x0004000000000000UL
-#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_MASK           0x0008000000000000UL
-#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK       0x0010000000000000UL
-#define UV2H_EVENT_OCCURRED0_IPI_INT_MASK              0x0020000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_MASK           0x0040000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_MASK           0x0080000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_MASK           0x0100000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_MASK           0x0200000000000000UL
-#define UV2H_EVENT_OCCURRED0_PROFILE_INT_MASK          0x0400000000000000UL
-
-#define UV3H_EVENT_OCCURRED0_QP_HCERR_SHFT             1
-#define UV3H_EVENT_OCCURRED0_QP_AOERR0_SHFT            10
-#define UV3H_EVENT_OCCURRED0_RT_AOERR0_SHFT            17
-#define UV3H_EVENT_OCCURRED0_NI0_AOERR0_SHFT           18
-#define UV3H_EVENT_OCCURRED0_NI1_AOERR0_SHFT           19
-#define UV3H_EVENT_OCCURRED0_LB_AOERR1_SHFT            20
-#define UV3H_EVENT_OCCURRED0_QP_AOERR1_SHFT            21
-#define UV3H_EVENT_OCCURRED0_RH_AOERR1_SHFT            22
-#define UV3H_EVENT_OCCURRED0_LH0_AOERR1_SHFT           23
-#define UV3H_EVENT_OCCURRED0_LH1_AOERR1_SHFT           24
-#define UV3H_EVENT_OCCURRED0_GR0_AOERR1_SHFT           25
-#define UV3H_EVENT_OCCURRED0_GR1_AOERR1_SHFT           26
-#define UV3H_EVENT_OCCURRED0_XB_AOERR1_SHFT            27
-#define UV3H_EVENT_OCCURRED0_RT_AOERR1_SHFT            28
-#define UV3H_EVENT_OCCURRED0_NI0_AOERR1_SHFT           29
-#define UV3H_EVENT_OCCURRED0_NI1_AOERR1_SHFT           30
-#define UV3H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT  31
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT         32
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT         33
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT         34
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT         35
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT         36
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT         37
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT         38
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT         39
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT         40
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT         41
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT                42
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT                43
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT                44
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT                45
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT                46
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT                47
-#define UV3H_EVENT_OCCURRED0_L1_NMI_INT_SHFT           48
-#define UV3H_EVENT_OCCURRED0_STOP_CLOCK_SHFT           49
-#define UV3H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT           50
-#define UV3H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT           51
-#define UV3H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT       52
-#define UV3H_EVENT_OCCURRED0_IPI_INT_SHFT              53
-#define UV3H_EVENT_OCCURRED0_EXTIO_INT0_SHFT           54
-#define UV3H_EVENT_OCCURRED0_EXTIO_INT1_SHFT           55
-#define UV3H_EVENT_OCCURRED0_EXTIO_INT2_SHFT           56
-#define UV3H_EVENT_OCCURRED0_EXTIO_INT3_SHFT           57
-#define UV3H_EVENT_OCCURRED0_PROFILE_INT_SHFT          58
-#define UV3H_EVENT_OCCURRED0_QP_HCERR_MASK             0x0000000000000002UL
-#define UV3H_EVENT_OCCURRED0_QP_AOERR0_MASK            0x0000000000000400UL
-#define UV3H_EVENT_OCCURRED0_RT_AOERR0_MASK            0x0000000000020000UL
-#define UV3H_EVENT_OCCURRED0_NI0_AOERR0_MASK           0x0000000000040000UL
-#define UV3H_EVENT_OCCURRED0_NI1_AOERR0_MASK           0x0000000000080000UL
-#define UV3H_EVENT_OCCURRED0_LB_AOERR1_MASK            0x0000000000100000UL
-#define UV3H_EVENT_OCCURRED0_QP_AOERR1_MASK            0x0000000000200000UL
-#define UV3H_EVENT_OCCURRED0_RH_AOERR1_MASK            0x0000000000400000UL
-#define UV3H_EVENT_OCCURRED0_LH0_AOERR1_MASK           0x0000000000800000UL
-#define UV3H_EVENT_OCCURRED0_LH1_AOERR1_MASK           0x0000000001000000UL
-#define UV3H_EVENT_OCCURRED0_GR0_AOERR1_MASK           0x0000000002000000UL
-#define UV3H_EVENT_OCCURRED0_GR1_AOERR1_MASK           0x0000000004000000UL
-#define UV3H_EVENT_OCCURRED0_XB_AOERR1_MASK            0x0000000008000000UL
-#define UV3H_EVENT_OCCURRED0_RT_AOERR1_MASK            0x0000000010000000UL
-#define UV3H_EVENT_OCCURRED0_NI0_AOERR1_MASK           0x0000000020000000UL
-#define UV3H_EVENT_OCCURRED0_NI1_AOERR1_MASK           0x0000000040000000UL
-#define UV3H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK  0x0000000080000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK         0x0000000100000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK         0x0000000200000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK         0x0000000400000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK         0x0000000800000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK         0x0000001000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK         0x0000002000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK         0x0000004000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK         0x0000008000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK         0x0000010000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK         0x0000020000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK                0x0000040000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK                0x0000080000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK                0x0000100000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK                0x0000200000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK                0x0000400000000000UL
-#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK                0x0000800000000000UL
-#define UV3H_EVENT_OCCURRED0_L1_NMI_INT_MASK           0x0001000000000000UL
-#define UV3H_EVENT_OCCURRED0_STOP_CLOCK_MASK           0x0002000000000000UL
-#define UV3H_EVENT_OCCURRED0_ASIC_TO_L1_MASK           0x0004000000000000UL
-#define UV3H_EVENT_OCCURRED0_L1_TO_ASIC_MASK           0x0008000000000000UL
-#define UV3H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK       0x0010000000000000UL
-#define UV3H_EVENT_OCCURRED0_IPI_INT_MASK              0x0020000000000000UL
-#define UV3H_EVENT_OCCURRED0_EXTIO_INT0_MASK           0x0040000000000000UL
-#define UV3H_EVENT_OCCURRED0_EXTIO_INT1_MASK           0x0080000000000000UL
-#define UV3H_EVENT_OCCURRED0_EXTIO_INT2_MASK           0x0100000000000000UL
-#define UV3H_EVENT_OCCURRED0_EXTIO_INT3_MASK           0x0200000000000000UL
-#define UV3H_EVENT_OCCURRED0_PROFILE_INT_MASK          0x0400000000000000UL
-
+/* UVYH common defines */
+#define UVYH_EVENT_OCCURRED0_KT_HCERR_SHFT             1
+#define UVYH_EVENT_OCCURRED0_KT_HCERR_MASK             0x0000000000000002UL
+#define UVYH_EVENT_OCCURRED0_RH0_HCERR_SHFT            2
+#define UVYH_EVENT_OCCURRED0_RH0_HCERR_MASK            0x0000000000000004UL
+#define UVYH_EVENT_OCCURRED0_RH1_HCERR_SHFT            3
+#define UVYH_EVENT_OCCURRED0_RH1_HCERR_MASK            0x0000000000000008UL
+#define UVYH_EVENT_OCCURRED0_LH0_HCERR_SHFT            4
+#define UVYH_EVENT_OCCURRED0_LH0_HCERR_MASK            0x0000000000000010UL
+#define UVYH_EVENT_OCCURRED0_LH1_HCERR_SHFT            5
+#define UVYH_EVENT_OCCURRED0_LH1_HCERR_MASK            0x0000000000000020UL
+#define UVYH_EVENT_OCCURRED0_LH2_HCERR_SHFT            6
+#define UVYH_EVENT_OCCURRED0_LH2_HCERR_MASK            0x0000000000000040UL
+#define UVYH_EVENT_OCCURRED0_LH3_HCERR_SHFT            7
+#define UVYH_EVENT_OCCURRED0_LH3_HCERR_MASK            0x0000000000000080UL
+#define UVYH_EVENT_OCCURRED0_XB_HCERR_SHFT             8
+#define UVYH_EVENT_OCCURRED0_XB_HCERR_MASK             0x0000000000000100UL
+#define UVYH_EVENT_OCCURRED0_RDM_HCERR_SHFT            9
+#define UVYH_EVENT_OCCURRED0_RDM_HCERR_MASK            0x0000000000000200UL
+#define UVYH_EVENT_OCCURRED0_NI0_HCERR_SHFT            10
+#define UVYH_EVENT_OCCURRED0_NI0_HCERR_MASK            0x0000000000000400UL
+#define UVYH_EVENT_OCCURRED0_NI1_HCERR_SHFT            11
+#define UVYH_EVENT_OCCURRED0_NI1_HCERR_MASK            0x0000000000000800UL
+#define UVYH_EVENT_OCCURRED0_LB_AOERR0_SHFT            12
+#define UVYH_EVENT_OCCURRED0_LB_AOERR0_MASK            0x0000000000001000UL
+#define UVYH_EVENT_OCCURRED0_KT_AOERR0_SHFT            13
+#define UVYH_EVENT_OCCURRED0_KT_AOERR0_MASK            0x0000000000002000UL
+#define UVYH_EVENT_OCCURRED0_RH0_AOERR0_SHFT           14
+#define UVYH_EVENT_OCCURRED0_RH0_AOERR0_MASK           0x0000000000004000UL
+#define UVYH_EVENT_OCCURRED0_RH1_AOERR0_SHFT           15
+#define UVYH_EVENT_OCCURRED0_RH1_AOERR0_MASK           0x0000000000008000UL
+#define UVYH_EVENT_OCCURRED0_LH0_AOERR0_SHFT           16
+#define UVYH_EVENT_OCCURRED0_LH0_AOERR0_MASK           0x0000000000010000UL
+#define UVYH_EVENT_OCCURRED0_LH1_AOERR0_SHFT           17
+#define UVYH_EVENT_OCCURRED0_LH1_AOERR0_MASK           0x0000000000020000UL
+#define UVYH_EVENT_OCCURRED0_LH2_AOERR0_SHFT           18
+#define UVYH_EVENT_OCCURRED0_LH2_AOERR0_MASK           0x0000000000040000UL
+#define UVYH_EVENT_OCCURRED0_LH3_AOERR0_SHFT           19
+#define UVYH_EVENT_OCCURRED0_LH3_AOERR0_MASK           0x0000000000080000UL
+#define UVYH_EVENT_OCCURRED0_XB_AOERR0_SHFT            20
+#define UVYH_EVENT_OCCURRED0_XB_AOERR0_MASK            0x0000000000100000UL
+#define UVYH_EVENT_OCCURRED0_RDM_AOERR0_SHFT           21
+#define UVYH_EVENT_OCCURRED0_RDM_AOERR0_MASK           0x0000000000200000UL
+#define UVYH_EVENT_OCCURRED0_RT0_AOERR0_SHFT           22
+#define UVYH_EVENT_OCCURRED0_RT0_AOERR0_MASK           0x0000000000400000UL
+#define UVYH_EVENT_OCCURRED0_RT1_AOERR0_SHFT           23
+#define UVYH_EVENT_OCCURRED0_RT1_AOERR0_MASK           0x0000000000800000UL
+#define UVYH_EVENT_OCCURRED0_NI0_AOERR0_SHFT           24
+#define UVYH_EVENT_OCCURRED0_NI0_AOERR0_MASK           0x0000000001000000UL
+#define UVYH_EVENT_OCCURRED0_NI1_AOERR0_SHFT           25
+#define UVYH_EVENT_OCCURRED0_NI1_AOERR0_MASK           0x0000000002000000UL
+#define UVYH_EVENT_OCCURRED0_LB_AOERR1_SHFT            26
+#define UVYH_EVENT_OCCURRED0_LB_AOERR1_MASK            0x0000000004000000UL
+#define UVYH_EVENT_OCCURRED0_KT_AOERR1_SHFT            27
+#define UVYH_EVENT_OCCURRED0_KT_AOERR1_MASK            0x0000000008000000UL
+#define UVYH_EVENT_OCCURRED0_RH0_AOERR1_SHFT           28
+#define UVYH_EVENT_OCCURRED0_RH0_AOERR1_MASK           0x0000000010000000UL
+#define UVYH_EVENT_OCCURRED0_RH1_AOERR1_SHFT           29
+#define UVYH_EVENT_OCCURRED0_RH1_AOERR1_MASK           0x0000000020000000UL
+#define UVYH_EVENT_OCCURRED0_LH0_AOERR1_SHFT           30
+#define UVYH_EVENT_OCCURRED0_LH0_AOERR1_MASK           0x0000000040000000UL
+#define UVYH_EVENT_OCCURRED0_LH1_AOERR1_SHFT           31
+#define UVYH_EVENT_OCCURRED0_LH1_AOERR1_MASK           0x0000000080000000UL
+#define UVYH_EVENT_OCCURRED0_LH2_AOERR1_SHFT           32
+#define UVYH_EVENT_OCCURRED0_LH2_AOERR1_MASK           0x0000000100000000UL
+#define UVYH_EVENT_OCCURRED0_LH3_AOERR1_SHFT           33
+#define UVYH_EVENT_OCCURRED0_LH3_AOERR1_MASK           0x0000000200000000UL
+#define UVYH_EVENT_OCCURRED0_XB_AOERR1_SHFT            34
+#define UVYH_EVENT_OCCURRED0_XB_AOERR1_MASK            0x0000000400000000UL
+#define UVYH_EVENT_OCCURRED0_RDM_AOERR1_SHFT           35
+#define UVYH_EVENT_OCCURRED0_RDM_AOERR1_MASK           0x0000000800000000UL
+#define UVYH_EVENT_OCCURRED0_RT0_AOERR1_SHFT           36
+#define UVYH_EVENT_OCCURRED0_RT0_AOERR1_MASK           0x0000001000000000UL
+#define UVYH_EVENT_OCCURRED0_RT1_AOERR1_SHFT           37
+#define UVYH_EVENT_OCCURRED0_RT1_AOERR1_MASK           0x0000002000000000UL
+#define UVYH_EVENT_OCCURRED0_NI0_AOERR1_SHFT           38
+#define UVYH_EVENT_OCCURRED0_NI0_AOERR1_MASK           0x0000004000000000UL
+#define UVYH_EVENT_OCCURRED0_NI1_AOERR1_SHFT           39
+#define UVYH_EVENT_OCCURRED0_NI1_AOERR1_MASK           0x0000008000000000UL
+#define UVYH_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT  40
+#define UVYH_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK  0x0000010000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT         41
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK         0x0000020000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT         42
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK         0x0000040000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT         43
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK         0x0000080000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT         44
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK         0x0000100000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT         45
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK         0x0000200000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT         46
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK         0x0000400000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT         47
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK         0x0000800000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT         48
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK         0x0001000000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT         49
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK         0x0002000000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT         50
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK         0x0004000000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT                51
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK                0x0008000000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT                52
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK                0x0010000000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT                53
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK                0x0020000000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT                54
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK                0x0040000000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT                55
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK                0x0080000000000000UL
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT                56
+#define UVYH_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK                0x0100000000000000UL
+#define UVYH_EVENT_OCCURRED0_L1_NMI_INT_SHFT           57
+#define UVYH_EVENT_OCCURRED0_L1_NMI_INT_MASK           0x0200000000000000UL
+#define UVYH_EVENT_OCCURRED0_STOP_CLOCK_SHFT           58
+#define UVYH_EVENT_OCCURRED0_STOP_CLOCK_MASK           0x0400000000000000UL
+#define UVYH_EVENT_OCCURRED0_ASIC_TO_L1_SHFT           59
+#define UVYH_EVENT_OCCURRED0_ASIC_TO_L1_MASK           0x0800000000000000UL
+#define UVYH_EVENT_OCCURRED0_L1_TO_ASIC_SHFT           60
+#define UVYH_EVENT_OCCURRED0_L1_TO_ASIC_MASK           0x1000000000000000UL
+#define UVYH_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT       61
+#define UVYH_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK       0x2000000000000000UL
+
+/* UV4 unique defines */
 #define UV4H_EVENT_OCCURRED0_KT_HCERR_SHFT             1
+#define UV4H_EVENT_OCCURRED0_KT_HCERR_MASK             0x0000000000000002UL
 #define UV4H_EVENT_OCCURRED0_KT_AOERR0_SHFT            10
-#define UV4H_EVENT_OCCURRED0_RTQ0_AOERR0_SHFT          17
-#define UV4H_EVENT_OCCURRED0_RTQ1_AOERR0_SHFT          18
-#define UV4H_EVENT_OCCURRED0_RTQ2_AOERR0_SHFT          19
-#define UV4H_EVENT_OCCURRED0_RTQ3_AOERR0_SHFT          20
-#define UV4H_EVENT_OCCURRED0_NI0_AOERR0_SHFT           21
-#define UV4H_EVENT_OCCURRED0_NI1_AOERR0_SHFT           22
-#define UV4H_EVENT_OCCURRED0_LB_AOERR1_SHFT            23
-#define UV4H_EVENT_OCCURRED0_KT_AOERR1_SHFT            24
-#define UV4H_EVENT_OCCURRED0_RH_AOERR1_SHFT            25
-#define UV4H_EVENT_OCCURRED0_LH0_AOERR1_SHFT           26
-#define UV4H_EVENT_OCCURRED0_LH1_AOERR1_SHFT           27
-#define UV4H_EVENT_OCCURRED0_GR0_AOERR1_SHFT           28
-#define UV4H_EVENT_OCCURRED0_GR1_AOERR1_SHFT           29
-#define UV4H_EVENT_OCCURRED0_XB_AOERR1_SHFT            30
-#define UV4H_EVENT_OCCURRED0_RTQ0_AOERR1_SHFT          31
-#define UV4H_EVENT_OCCURRED0_RTQ1_AOERR1_SHFT          32
-#define UV4H_EVENT_OCCURRED0_RTQ2_AOERR1_SHFT          33
-#define UV4H_EVENT_OCCURRED0_RTQ3_AOERR1_SHFT          34
-#define UV4H_EVENT_OCCURRED0_NI0_AOERR1_SHFT           35
-#define UV4H_EVENT_OCCURRED0_NI1_AOERR1_SHFT           36
-#define UV4H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT  37
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT         38
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT         39
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT         40
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT         41
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT         42
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT         43
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT         44
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT         45
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT         46
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT         47
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT                48
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT                49
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT                50
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT                51
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT                52
-#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT                53
-#define UV4H_EVENT_OCCURRED0_L1_NMI_INT_SHFT           54
-#define UV4H_EVENT_OCCURRED0_STOP_CLOCK_SHFT           55
-#define UV4H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT           56
-#define UV4H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT           57
-#define UV4H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT       58
-#define UV4H_EVENT_OCCURRED0_IPI_INT_SHFT              59
-#define UV4H_EVENT_OCCURRED0_EXTIO_INT0_SHFT           60
-#define UV4H_EVENT_OCCURRED0_EXTIO_INT1_SHFT           61
-#define UV4H_EVENT_OCCURRED0_EXTIO_INT2_SHFT           62
-#define UV4H_EVENT_OCCURRED0_EXTIO_INT3_SHFT           63
-#define UV4H_EVENT_OCCURRED0_KT_HCERR_MASK             0x0000000000000002UL
 #define UV4H_EVENT_OCCURRED0_KT_AOERR0_MASK            0x0000000000000400UL
+#define UV4H_EVENT_OCCURRED0_RTQ0_AOERR0_SHFT          17
 #define UV4H_EVENT_OCCURRED0_RTQ0_AOERR0_MASK          0x0000000000020000UL
+#define UV4H_EVENT_OCCURRED0_RTQ1_AOERR0_SHFT          18
 #define UV4H_EVENT_OCCURRED0_RTQ1_AOERR0_MASK          0x0000000000040000UL
+#define UV4H_EVENT_OCCURRED0_RTQ2_AOERR0_SHFT          19
 #define UV4H_EVENT_OCCURRED0_RTQ2_AOERR0_MASK          0x0000000000080000UL
+#define UV4H_EVENT_OCCURRED0_RTQ3_AOERR0_SHFT          20
 #define UV4H_EVENT_OCCURRED0_RTQ3_AOERR0_MASK          0x0000000000100000UL
+#define UV4H_EVENT_OCCURRED0_NI0_AOERR0_SHFT           21
 #define UV4H_EVENT_OCCURRED0_NI0_AOERR0_MASK           0x0000000000200000UL
+#define UV4H_EVENT_OCCURRED0_NI1_AOERR0_SHFT           22
 #define UV4H_EVENT_OCCURRED0_NI1_AOERR0_MASK           0x0000000000400000UL
+#define UV4H_EVENT_OCCURRED0_LB_AOERR1_SHFT            23
 #define UV4H_EVENT_OCCURRED0_LB_AOERR1_MASK            0x0000000000800000UL
+#define UV4H_EVENT_OCCURRED0_KT_AOERR1_SHFT            24
 #define UV4H_EVENT_OCCURRED0_KT_AOERR1_MASK            0x0000000001000000UL
+#define UV4H_EVENT_OCCURRED0_RH_AOERR1_SHFT            25
 #define UV4H_EVENT_OCCURRED0_RH_AOERR1_MASK            0x0000000002000000UL
+#define UV4H_EVENT_OCCURRED0_LH0_AOERR1_SHFT           26
 #define UV4H_EVENT_OCCURRED0_LH0_AOERR1_MASK           0x0000000004000000UL
+#define UV4H_EVENT_OCCURRED0_LH1_AOERR1_SHFT           27
 #define UV4H_EVENT_OCCURRED0_LH1_AOERR1_MASK           0x0000000008000000UL
+#define UV4H_EVENT_OCCURRED0_GR0_AOERR1_SHFT           28
 #define UV4H_EVENT_OCCURRED0_GR0_AOERR1_MASK           0x0000000010000000UL
+#define UV4H_EVENT_OCCURRED0_GR1_AOERR1_SHFT           29
 #define UV4H_EVENT_OCCURRED0_GR1_AOERR1_MASK           0x0000000020000000UL
+#define UV4H_EVENT_OCCURRED0_XB_AOERR1_SHFT            30
 #define UV4H_EVENT_OCCURRED0_XB_AOERR1_MASK            0x0000000040000000UL
+#define UV4H_EVENT_OCCURRED0_RTQ0_AOERR1_SHFT          31
 #define UV4H_EVENT_OCCURRED0_RTQ0_AOERR1_MASK          0x0000000080000000UL
+#define UV4H_EVENT_OCCURRED0_RTQ1_AOERR1_SHFT          32
 #define UV4H_EVENT_OCCURRED0_RTQ1_AOERR1_MASK          0x0000000100000000UL
+#define UV4H_EVENT_OCCURRED0_RTQ2_AOERR1_SHFT          33
 #define UV4H_EVENT_OCCURRED0_RTQ2_AOERR1_MASK          0x0000000200000000UL
+#define UV4H_EVENT_OCCURRED0_RTQ3_AOERR1_SHFT          34
 #define UV4H_EVENT_OCCURRED0_RTQ3_AOERR1_MASK          0x0000000400000000UL
+#define UV4H_EVENT_OCCURRED0_NI0_AOERR1_SHFT           35
 #define UV4H_EVENT_OCCURRED0_NI0_AOERR1_MASK           0x0000000800000000UL
+#define UV4H_EVENT_OCCURRED0_NI1_AOERR1_SHFT           36
 #define UV4H_EVENT_OCCURRED0_NI1_AOERR1_MASK           0x0000001000000000UL
+#define UV4H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT  37
 #define UV4H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK  0x0000002000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT         38
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK         0x0000004000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT         39
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK         0x0000008000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT         40
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK         0x0000010000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT         41
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK         0x0000020000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT         42
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK         0x0000040000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT         43
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK         0x0000080000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT         44
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK         0x0000100000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT         45
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK         0x0000200000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT         46
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK         0x0000400000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT         47
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK         0x0000800000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT                48
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK                0x0001000000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT                49
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK                0x0002000000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT                50
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK                0x0004000000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT                51
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK                0x0008000000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT                52
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK                0x0010000000000000UL
+#define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT                53
 #define UV4H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK                0x0020000000000000UL
+#define UV4H_EVENT_OCCURRED0_L1_NMI_INT_SHFT           54
 #define UV4H_EVENT_OCCURRED0_L1_NMI_INT_MASK           0x0040000000000000UL
+#define UV4H_EVENT_OCCURRED0_STOP_CLOCK_SHFT           55
 #define UV4H_EVENT_OCCURRED0_STOP_CLOCK_MASK           0x0080000000000000UL
+#define UV4H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT           56
 #define UV4H_EVENT_OCCURRED0_ASIC_TO_L1_MASK           0x0100000000000000UL
+#define UV4H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT           57
 #define UV4H_EVENT_OCCURRED0_L1_TO_ASIC_MASK           0x0200000000000000UL
+#define UV4H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT       58
 #define UV4H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK       0x0400000000000000UL
+#define UV4H_EVENT_OCCURRED0_IPI_INT_SHFT              59
 #define UV4H_EVENT_OCCURRED0_IPI_INT_MASK              0x0800000000000000UL
+#define UV4H_EVENT_OCCURRED0_EXTIO_INT0_SHFT           60
 #define UV4H_EVENT_OCCURRED0_EXTIO_INT0_MASK           0x1000000000000000UL
+#define UV4H_EVENT_OCCURRED0_EXTIO_INT1_SHFT           61
 #define UV4H_EVENT_OCCURRED0_EXTIO_INT1_MASK           0x2000000000000000UL
+#define UV4H_EVENT_OCCURRED0_EXTIO_INT2_SHFT           62
 #define UV4H_EVENT_OCCURRED0_EXTIO_INT2_MASK           0x4000000000000000UL
+#define UV4H_EVENT_OCCURRED0_EXTIO_INT3_SHFT           63
 #define UV4H_EVENT_OCCURRED0_EXTIO_INT3_MASK           0x8000000000000000UL
 
-#define UVH_EVENT_OCCURRED0_EXTIO_INT0_SHFT (                          \
-       is_uv2_hub() ? UV2H_EVENT_OCCURRED0_EXTIO_INT0_SHFT :           \
-       is_uv3_hub() ? UV3H_EVENT_OCCURRED0_EXTIO_INT0_SHFT :           \
-       /*is_uv4_hub*/ UV4H_EVENT_OCCURRED0_EXTIO_INT0_SHFT)
+/* UV3 unique defines */
+#define UV3H_EVENT_OCCURRED0_QP_HCERR_SHFT             1
+#define UV3H_EVENT_OCCURRED0_QP_HCERR_MASK             0x0000000000000002UL
+#define UV3H_EVENT_OCCURRED0_QP_AOERR0_SHFT            10
+#define UV3H_EVENT_OCCURRED0_QP_AOERR0_MASK            0x0000000000000400UL
+#define UV3H_EVENT_OCCURRED0_RT_AOERR0_SHFT            17
+#define UV3H_EVENT_OCCURRED0_RT_AOERR0_MASK            0x0000000000020000UL
+#define UV3H_EVENT_OCCURRED0_NI0_AOERR0_SHFT           18
+#define UV3H_EVENT_OCCURRED0_NI0_AOERR0_MASK           0x0000000000040000UL
+#define UV3H_EVENT_OCCURRED0_NI1_AOERR0_SHFT           19
+#define UV3H_EVENT_OCCURRED0_NI1_AOERR0_MASK           0x0000000000080000UL
+#define UV3H_EVENT_OCCURRED0_LB_AOERR1_SHFT            20
+#define UV3H_EVENT_OCCURRED0_LB_AOERR1_MASK            0x0000000000100000UL
+#define UV3H_EVENT_OCCURRED0_QP_AOERR1_SHFT            21
+#define UV3H_EVENT_OCCURRED0_QP_AOERR1_MASK            0x0000000000200000UL
+#define UV3H_EVENT_OCCURRED0_RH_AOERR1_SHFT            22
+#define UV3H_EVENT_OCCURRED0_RH_AOERR1_MASK            0x0000000000400000UL
+#define UV3H_EVENT_OCCURRED0_LH0_AOERR1_SHFT           23
+#define UV3H_EVENT_OCCURRED0_LH0_AOERR1_MASK           0x0000000000800000UL
+#define UV3H_EVENT_OCCURRED0_LH1_AOERR1_SHFT           24
+#define UV3H_EVENT_OCCURRED0_LH1_AOERR1_MASK           0x0000000001000000UL
+#define UV3H_EVENT_OCCURRED0_GR0_AOERR1_SHFT           25
+#define UV3H_EVENT_OCCURRED0_GR0_AOERR1_MASK           0x0000000002000000UL
+#define UV3H_EVENT_OCCURRED0_GR1_AOERR1_SHFT           26
+#define UV3H_EVENT_OCCURRED0_GR1_AOERR1_MASK           0x0000000004000000UL
+#define UV3H_EVENT_OCCURRED0_XB_AOERR1_SHFT            27
+#define UV3H_EVENT_OCCURRED0_XB_AOERR1_MASK            0x0000000008000000UL
+#define UV3H_EVENT_OCCURRED0_RT_AOERR1_SHFT            28
+#define UV3H_EVENT_OCCURRED0_RT_AOERR1_MASK            0x0000000010000000UL
+#define UV3H_EVENT_OCCURRED0_NI0_AOERR1_SHFT           29
+#define UV3H_EVENT_OCCURRED0_NI0_AOERR1_MASK           0x0000000020000000UL
+#define UV3H_EVENT_OCCURRED0_NI1_AOERR1_SHFT           30
+#define UV3H_EVENT_OCCURRED0_NI1_AOERR1_MASK           0x0000000040000000UL
+#define UV3H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT  31
+#define UV3H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK  0x0000000080000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT         32
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK         0x0000000100000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT         33
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK         0x0000000200000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT         34
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK         0x0000000400000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT         35
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK         0x0000000800000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT         36
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK         0x0000001000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT         37
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK         0x0000002000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT         38
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK         0x0000004000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT         39
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK         0x0000008000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT         40
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK         0x0000010000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT         41
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK         0x0000020000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT                42
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK                0x0000040000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT                43
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK                0x0000080000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT                44
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK                0x0000100000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT                45
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK                0x0000200000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT                46
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK                0x0000400000000000UL
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT                47
+#define UV3H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK                0x0000800000000000UL
+#define UV3H_EVENT_OCCURRED0_L1_NMI_INT_SHFT           48
+#define UV3H_EVENT_OCCURRED0_L1_NMI_INT_MASK           0x0001000000000000UL
+#define UV3H_EVENT_OCCURRED0_STOP_CLOCK_SHFT           49
+#define UV3H_EVENT_OCCURRED0_STOP_CLOCK_MASK           0x0002000000000000UL
+#define UV3H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT           50
+#define UV3H_EVENT_OCCURRED0_ASIC_TO_L1_MASK           0x0004000000000000UL
+#define UV3H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT           51
+#define UV3H_EVENT_OCCURRED0_L1_TO_ASIC_MASK           0x0008000000000000UL
+#define UV3H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT       52
+#define UV3H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK       0x0010000000000000UL
+#define UV3H_EVENT_OCCURRED0_IPI_INT_SHFT              53
+#define UV3H_EVENT_OCCURRED0_IPI_INT_MASK              0x0020000000000000UL
+#define UV3H_EVENT_OCCURRED0_EXTIO_INT0_SHFT           54
+#define UV3H_EVENT_OCCURRED0_EXTIO_INT0_MASK           0x0040000000000000UL
+#define UV3H_EVENT_OCCURRED0_EXTIO_INT1_SHFT           55
+#define UV3H_EVENT_OCCURRED0_EXTIO_INT1_MASK           0x0080000000000000UL
+#define UV3H_EVENT_OCCURRED0_EXTIO_INT2_SHFT           56
+#define UV3H_EVENT_OCCURRED0_EXTIO_INT2_MASK           0x0100000000000000UL
+#define UV3H_EVENT_OCCURRED0_EXTIO_INT3_SHFT           57
+#define UV3H_EVENT_OCCURRED0_EXTIO_INT3_MASK           0x0200000000000000UL
+#define UV3H_EVENT_OCCURRED0_PROFILE_INT_SHFT          58
+#define UV3H_EVENT_OCCURRED0_PROFILE_INT_MASK          0x0400000000000000UL
 
-union uvh_event_occurred0_u {
-       unsigned long   v;
-       struct uvh_event_occurred0_s {
-               unsigned long   lb_hcerr:1;                     /* RW, W1C */
-               unsigned long   rsvd_1_10:10;
-               unsigned long   rh_aoerr0:1;                    /* RW, W1C */
-               unsigned long   rsvd_12_63:52;
-       } s;
-       struct uvxh_event_occurred0_s {
-               unsigned long   lb_hcerr:1;                     /* RW */
-               unsigned long   rsvd_1:1;
-               unsigned long   rh_hcerr:1;                     /* RW */
-               unsigned long   lh0_hcerr:1;                    /* RW */
-               unsigned long   lh1_hcerr:1;                    /* RW */
-               unsigned long   gr0_hcerr:1;                    /* RW */
-               unsigned long   gr1_hcerr:1;                    /* RW */
-               unsigned long   ni0_hcerr:1;                    /* RW */
-               unsigned long   ni1_hcerr:1;                    /* RW */
-               unsigned long   lb_aoerr0:1;                    /* RW */
-               unsigned long   rsvd_10:1;
-               unsigned long   rh_aoerr0:1;                    /* RW */
-               unsigned long   lh0_aoerr0:1;                   /* RW */
-               unsigned long   lh1_aoerr0:1;                   /* RW */
-               unsigned long   gr0_aoerr0:1;                   /* RW */
-               unsigned long   gr1_aoerr0:1;                   /* RW */
-               unsigned long   xb_aoerr0:1;                    /* RW */
-               unsigned long   rsvd_17_63:47;
-       } sx;
-       struct uv4h_event_occurred0_s {
-               unsigned long   lb_hcerr:1;                     /* RW */
-               unsigned long   kt_hcerr:1;                     /* RW */
-               unsigned long   rh_hcerr:1;                     /* RW */
-               unsigned long   lh0_hcerr:1;                    /* RW */
-               unsigned long   lh1_hcerr:1;                    /* RW */
-               unsigned long   gr0_hcerr:1;                    /* RW */
-               unsigned long   gr1_hcerr:1;                    /* RW */
-               unsigned long   ni0_hcerr:1;                    /* RW */
-               unsigned long   ni1_hcerr:1;                    /* RW */
-               unsigned long   lb_aoerr0:1;                    /* RW */
-               unsigned long   kt_aoerr0:1;                    /* RW */
-               unsigned long   rh_aoerr0:1;                    /* RW */
-               unsigned long   lh0_aoerr0:1;                   /* RW */
-               unsigned long   lh1_aoerr0:1;                   /* RW */
-               unsigned long   gr0_aoerr0:1;                   /* RW */
-               unsigned long   gr1_aoerr0:1;                   /* RW */
-               unsigned long   xb_aoerr0:1;                    /* RW */
-               unsigned long   rtq0_aoerr0:1;                  /* RW */
-               unsigned long   rtq1_aoerr0:1;                  /* RW */
-               unsigned long   rtq2_aoerr0:1;                  /* RW */
-               unsigned long   rtq3_aoerr0:1;                  /* RW */
-               unsigned long   ni0_aoerr0:1;                   /* RW */
-               unsigned long   ni1_aoerr0:1;                   /* RW */
-               unsigned long   lb_aoerr1:1;                    /* RW */
-               unsigned long   kt_aoerr1:1;                    /* RW */
-               unsigned long   rh_aoerr1:1;                    /* RW */
-               unsigned long   lh0_aoerr1:1;                   /* RW */
-               unsigned long   lh1_aoerr1:1;                   /* RW */
-               unsigned long   gr0_aoerr1:1;                   /* RW */
-               unsigned long   gr1_aoerr1:1;                   /* RW */
-               unsigned long   xb_aoerr1:1;                    /* RW */
-               unsigned long   rtq0_aoerr1:1;                  /* RW */
-               unsigned long   rtq1_aoerr1:1;                  /* RW */
-               unsigned long   rtq2_aoerr1:1;                  /* RW */
-               unsigned long   rtq3_aoerr1:1;                  /* RW */
-               unsigned long   ni0_aoerr1:1;                   /* RW */
-               unsigned long   ni1_aoerr1:1;                   /* RW */
-               unsigned long   system_shutdown_int:1;          /* RW */
-               unsigned long   lb_irq_int_0:1;                 /* RW */
-               unsigned long   lb_irq_int_1:1;                 /* RW */
-               unsigned long   lb_irq_int_2:1;                 /* RW */
-               unsigned long   lb_irq_int_3:1;                 /* RW */
-               unsigned long   lb_irq_int_4:1;                 /* RW */
-               unsigned long   lb_irq_int_5:1;                 /* RW */
-               unsigned long   lb_irq_int_6:1;                 /* RW */
-               unsigned long   lb_irq_int_7:1;                 /* RW */
+/* UV2 unique defines */
+#define UV2H_EVENT_OCCURRED0_QP_HCERR_SHFT             1
+#define UV2H_EVENT_OCCURRED0_QP_HCERR_MASK             0x0000000000000002UL
+#define UV2H_EVENT_OCCURRED0_QP_AOERR0_SHFT            10
+#define UV2H_EVENT_OCCURRED0_QP_AOERR0_MASK            0x0000000000000400UL
+#define UV2H_EVENT_OCCURRED0_RT_AOERR0_SHFT            17
+#define UV2H_EVENT_OCCURRED0_RT_AOERR0_MASK            0x0000000000020000UL
+#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_SHFT           18
+#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_MASK           0x0000000000040000UL
+#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_SHFT           19
+#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_MASK           0x0000000000080000UL
+#define UV2H_EVENT_OCCURRED0_LB_AOERR1_SHFT            20
+#define UV2H_EVENT_OCCURRED0_LB_AOERR1_MASK            0x0000000000100000UL
+#define UV2H_EVENT_OCCURRED0_QP_AOERR1_SHFT            21
+#define UV2H_EVENT_OCCURRED0_QP_AOERR1_MASK            0x0000000000200000UL
+#define UV2H_EVENT_OCCURRED0_RH_AOERR1_SHFT            22
+#define UV2H_EVENT_OCCURRED0_RH_AOERR1_MASK            0x0000000000400000UL
+#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_SHFT           23
+#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_MASK           0x0000000000800000UL
+#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_SHFT           24
+#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_MASK           0x0000000001000000UL
+#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_SHFT           25
+#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_MASK           0x0000000002000000UL
+#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_SHFT           26
+#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_MASK           0x0000000004000000UL
+#define UV2H_EVENT_OCCURRED0_XB_AOERR1_SHFT            27
+#define UV2H_EVENT_OCCURRED0_XB_AOERR1_MASK            0x0000000008000000UL
+#define UV2H_EVENT_OCCURRED0_RT_AOERR1_SHFT            28
+#define UV2H_EVENT_OCCURRED0_RT_AOERR1_MASK            0x0000000010000000UL
+#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_SHFT           29
+#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_MASK           0x0000000020000000UL
+#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_SHFT           30
+#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_MASK           0x0000000040000000UL
+#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT  31
+#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK  0x0000000080000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT         32
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK         0x0000000100000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT         33
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK         0x0000000200000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT         34
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK         0x0000000400000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT         35
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK         0x0000000800000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT         36
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK         0x0000001000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT         37
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK         0x0000002000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT         38
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK         0x0000004000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT         39
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK         0x0000008000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT         40
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK         0x0000010000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT         41
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK         0x0000020000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT                42
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK                0x0000040000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT                43
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK                0x0000080000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT                44
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK                0x0000100000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT                45
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK                0x0000200000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT                46
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK                0x0000400000000000UL
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT                47
+#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK                0x0000800000000000UL
+#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_SHFT           48
+#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_MASK           0x0001000000000000UL
+#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_SHFT           49
+#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_MASK           0x0002000000000000UL
+#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT           50
+#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_MASK           0x0004000000000000UL
+#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT           51
+#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_MASK           0x0008000000000000UL
+#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT       52
+#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK       0x0010000000000000UL
+#define UV2H_EVENT_OCCURRED0_IPI_INT_SHFT              53
+#define UV2H_EVENT_OCCURRED0_IPI_INT_MASK              0x0020000000000000UL
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_SHFT           54
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_MASK           0x0040000000000000UL
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_SHFT           55
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_MASK           0x0080000000000000UL
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_SHFT           56
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_MASK           0x0100000000000000UL
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_SHFT           57
+#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_MASK           0x0200000000000000UL
+#define UV2H_EVENT_OCCURRED0_PROFILE_INT_SHFT          58
+#define UV2H_EVENT_OCCURRED0_PROFILE_INT_MASK          0x0400000000000000UL
+
+#define UVH_EVENT_OCCURRED0_EXTIO_INT0_MASK (                          \
+       is_uv(UV4) ? 0x1000000000000000UL :                             \
+       is_uv(UV3) ? 0x0040000000000000UL :                             \
+       is_uv(UV2) ? 0x0040000000000000UL :                             \
+       0)
+#define UVH_EVENT_OCCURRED0_EXTIO_INT0_SHFT (                          \
+       is_uv(UV4) ? 60 :                                               \
+       is_uv(UV3) ? 54 :                                               \
+       is_uv(UV2) ? 54 :                                               \
+       -1)
+
+union uvh_event_occurred0_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_event_occurred0_s {
+               unsigned long   lb_hcerr:1;                     /* RW */
+               unsigned long   rsvd_1_63:63;
+       } s;
+
+       /* UVXH common struct */
+       struct uvxh_event_occurred0_s {
+               unsigned long   lb_hcerr:1;                     /* RW */
+               unsigned long   rsvd_1:1;
+               unsigned long   rh_hcerr:1;                     /* RW */
+               unsigned long   lh0_hcerr:1;                    /* RW */
+               unsigned long   lh1_hcerr:1;                    /* RW */
+               unsigned long   gr0_hcerr:1;                    /* RW */
+               unsigned long   gr1_hcerr:1;                    /* RW */
+               unsigned long   ni0_hcerr:1;                    /* RW */
+               unsigned long   ni1_hcerr:1;                    /* RW */
+               unsigned long   lb_aoerr0:1;                    /* RW */
+               unsigned long   rsvd_10:1;
+               unsigned long   rh_aoerr0:1;                    /* RW */
+               unsigned long   lh0_aoerr0:1;                   /* RW */
+               unsigned long   lh1_aoerr0:1;                   /* RW */
+               unsigned long   gr0_aoerr0:1;                   /* RW */
+               unsigned long   gr1_aoerr0:1;                   /* RW */
+               unsigned long   xb_aoerr0:1;                    /* RW */
+               unsigned long   rsvd_17_63:47;
+       } sx;
+
+       /* UVYH common struct */
+       struct uvyh_event_occurred0_s {
+               unsigned long   lb_hcerr:1;                     /* RW */
+               unsigned long   kt_hcerr:1;                     /* RW */
+               unsigned long   rh0_hcerr:1;                    /* RW */
+               unsigned long   rh1_hcerr:1;                    /* RW */
+               unsigned long   lh0_hcerr:1;                    /* RW */
+               unsigned long   lh1_hcerr:1;                    /* RW */
+               unsigned long   lh2_hcerr:1;                    /* RW */
+               unsigned long   lh3_hcerr:1;                    /* RW */
+               unsigned long   xb_hcerr:1;                     /* RW */
+               unsigned long   rdm_hcerr:1;                    /* RW */
+               unsigned long   ni0_hcerr:1;                    /* RW */
+               unsigned long   ni1_hcerr:1;                    /* RW */
+               unsigned long   lb_aoerr0:1;                    /* RW */
+               unsigned long   kt_aoerr0:1;                    /* RW */
+               unsigned long   rh0_aoerr0:1;                   /* RW */
+               unsigned long   rh1_aoerr0:1;                   /* RW */
+               unsigned long   lh0_aoerr0:1;                   /* RW */
+               unsigned long   lh1_aoerr0:1;                   /* RW */
+               unsigned long   lh2_aoerr0:1;                   /* RW */
+               unsigned long   lh3_aoerr0:1;                   /* RW */
+               unsigned long   xb_aoerr0:1;                    /* RW */
+               unsigned long   rdm_aoerr0:1;                   /* RW */
+               unsigned long   rt0_aoerr0:1;                   /* RW */
+               unsigned long   rt1_aoerr0:1;                   /* RW */
+               unsigned long   ni0_aoerr0:1;                   /* RW */
+               unsigned long   ni1_aoerr0:1;                   /* RW */
+               unsigned long   lb_aoerr1:1;                    /* RW */
+               unsigned long   kt_aoerr1:1;                    /* RW */
+               unsigned long   rh0_aoerr1:1;                   /* RW */
+               unsigned long   rh1_aoerr1:1;                   /* RW */
+               unsigned long   lh0_aoerr1:1;                   /* RW */
+               unsigned long   lh1_aoerr1:1;                   /* RW */
+               unsigned long   lh2_aoerr1:1;                   /* RW */
+               unsigned long   lh3_aoerr1:1;                   /* RW */
+               unsigned long   xb_aoerr1:1;                    /* RW */
+               unsigned long   rdm_aoerr1:1;                   /* RW */
+               unsigned long   rt0_aoerr1:1;                   /* RW */
+               unsigned long   rt1_aoerr1:1;                   /* RW */
+               unsigned long   ni0_aoerr1:1;                   /* RW */
+               unsigned long   ni1_aoerr1:1;                   /* RW */
+               unsigned long   system_shutdown_int:1;          /* RW */
+               unsigned long   lb_irq_int_0:1;                 /* RW */
+               unsigned long   lb_irq_int_1:1;                 /* RW */
+               unsigned long   lb_irq_int_2:1;                 /* RW */
+               unsigned long   lb_irq_int_3:1;                 /* RW */
+               unsigned long   lb_irq_int_4:1;                 /* RW */
+               unsigned long   lb_irq_int_5:1;                 /* RW */
+               unsigned long   lb_irq_int_6:1;                 /* RW */
+               unsigned long   lb_irq_int_7:1;                 /* RW */
+               unsigned long   lb_irq_int_8:1;                 /* RW */
+               unsigned long   lb_irq_int_9:1;                 /* RW */
+               unsigned long   lb_irq_int_10:1;                /* RW */
+               unsigned long   lb_irq_int_11:1;                /* RW */
+               unsigned long   lb_irq_int_12:1;                /* RW */
+               unsigned long   lb_irq_int_13:1;                /* RW */
+               unsigned long   lb_irq_int_14:1;                /* RW */
+               unsigned long   lb_irq_int_15:1;                /* RW */
+               unsigned long   l1_nmi_int:1;                   /* RW */
+               unsigned long   stop_clock:1;                   /* RW */
+               unsigned long   asic_to_l1:1;                   /* RW */
+               unsigned long   l1_to_asic:1;                   /* RW */
+               unsigned long   la_seq_trigger:1;               /* RW */
+               unsigned long   rsvd_62_63:2;
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_event_occurred0_s {
+               unsigned long   lb_hcerr:1;                     /* RW */
+               unsigned long   kt_hcerr:1;                     /* RW */
+               unsigned long   rh0_hcerr:1;                    /* RW */
+               unsigned long   rh1_hcerr:1;                    /* RW */
+               unsigned long   lh0_hcerr:1;                    /* RW */
+               unsigned long   lh1_hcerr:1;                    /* RW */
+               unsigned long   lh2_hcerr:1;                    /* RW */
+               unsigned long   lh3_hcerr:1;                    /* RW */
+               unsigned long   xb_hcerr:1;                     /* RW */
+               unsigned long   rdm_hcerr:1;                    /* RW */
+               unsigned long   ni0_hcerr:1;                    /* RW */
+               unsigned long   ni1_hcerr:1;                    /* RW */
+               unsigned long   lb_aoerr0:1;                    /* RW */
+               unsigned long   kt_aoerr0:1;                    /* RW */
+               unsigned long   rh0_aoerr0:1;                   /* RW */
+               unsigned long   rh1_aoerr0:1;                   /* RW */
+               unsigned long   lh0_aoerr0:1;                   /* RW */
+               unsigned long   lh1_aoerr0:1;                   /* RW */
+               unsigned long   lh2_aoerr0:1;                   /* RW */
+               unsigned long   lh3_aoerr0:1;                   /* RW */
+               unsigned long   xb_aoerr0:1;                    /* RW */
+               unsigned long   rdm_aoerr0:1;                   /* RW */
+               unsigned long   rt0_aoerr0:1;                   /* RW */
+               unsigned long   rt1_aoerr0:1;                   /* RW */
+               unsigned long   ni0_aoerr0:1;                   /* RW */
+               unsigned long   ni1_aoerr0:1;                   /* RW */
+               unsigned long   lb_aoerr1:1;                    /* RW */
+               unsigned long   kt_aoerr1:1;                    /* RW */
+               unsigned long   rh0_aoerr1:1;                   /* RW */
+               unsigned long   rh1_aoerr1:1;                   /* RW */
+               unsigned long   lh0_aoerr1:1;                   /* RW */
+               unsigned long   lh1_aoerr1:1;                   /* RW */
+               unsigned long   lh2_aoerr1:1;                   /* RW */
+               unsigned long   lh3_aoerr1:1;                   /* RW */
+               unsigned long   xb_aoerr1:1;                    /* RW */
+               unsigned long   rdm_aoerr1:1;                   /* RW */
+               unsigned long   rt0_aoerr1:1;                   /* RW */
+               unsigned long   rt1_aoerr1:1;                   /* RW */
+               unsigned long   ni0_aoerr1:1;                   /* RW */
+               unsigned long   ni1_aoerr1:1;                   /* RW */
+               unsigned long   system_shutdown_int:1;          /* RW */
+               unsigned long   lb_irq_int_0:1;                 /* RW */
+               unsigned long   lb_irq_int_1:1;                 /* RW */
+               unsigned long   lb_irq_int_2:1;                 /* RW */
+               unsigned long   lb_irq_int_3:1;                 /* RW */
+               unsigned long   lb_irq_int_4:1;                 /* RW */
+               unsigned long   lb_irq_int_5:1;                 /* RW */
+               unsigned long   lb_irq_int_6:1;                 /* RW */
+               unsigned long   lb_irq_int_7:1;                 /* RW */
+               unsigned long   lb_irq_int_8:1;                 /* RW */
+               unsigned long   lb_irq_int_9:1;                 /* RW */
+               unsigned long   lb_irq_int_10:1;                /* RW */
+               unsigned long   lb_irq_int_11:1;                /* RW */
+               unsigned long   lb_irq_int_12:1;                /* RW */
+               unsigned long   lb_irq_int_13:1;                /* RW */
+               unsigned long   lb_irq_int_14:1;                /* RW */
+               unsigned long   lb_irq_int_15:1;                /* RW */
+               unsigned long   l1_nmi_int:1;                   /* RW */
+               unsigned long   stop_clock:1;                   /* RW */
+               unsigned long   asic_to_l1:1;                   /* RW */
+               unsigned long   l1_to_asic:1;                   /* RW */
+               unsigned long   la_seq_trigger:1;               /* RW */
+               unsigned long   rsvd_62_63:2;
+       } s5;
+
+       /* UV4 unique struct */
+       struct uv4h_event_occurred0_s {
+               unsigned long   lb_hcerr:1;                     /* RW */
+               unsigned long   kt_hcerr:1;                     /* RW */
+               unsigned long   rh_hcerr:1;                     /* RW */
+               unsigned long   lh0_hcerr:1;                    /* RW */
+               unsigned long   lh1_hcerr:1;                    /* RW */
+               unsigned long   gr0_hcerr:1;                    /* RW */
+               unsigned long   gr1_hcerr:1;                    /* RW */
+               unsigned long   ni0_hcerr:1;                    /* RW */
+               unsigned long   ni1_hcerr:1;                    /* RW */
+               unsigned long   lb_aoerr0:1;                    /* RW */
+               unsigned long   kt_aoerr0:1;                    /* RW */
+               unsigned long   rh_aoerr0:1;                    /* RW */
+               unsigned long   lh0_aoerr0:1;                   /* RW */
+               unsigned long   lh1_aoerr0:1;                   /* RW */
+               unsigned long   gr0_aoerr0:1;                   /* RW */
+               unsigned long   gr1_aoerr0:1;                   /* RW */
+               unsigned long   xb_aoerr0:1;                    /* RW */
+               unsigned long   rtq0_aoerr0:1;                  /* RW */
+               unsigned long   rtq1_aoerr0:1;                  /* RW */
+               unsigned long   rtq2_aoerr0:1;                  /* RW */
+               unsigned long   rtq3_aoerr0:1;                  /* RW */
+               unsigned long   ni0_aoerr0:1;                   /* RW */
+               unsigned long   ni1_aoerr0:1;                   /* RW */
+               unsigned long   lb_aoerr1:1;                    /* RW */
+               unsigned long   kt_aoerr1:1;                    /* RW */
+               unsigned long   rh_aoerr1:1;                    /* RW */
+               unsigned long   lh0_aoerr1:1;                   /* RW */
+               unsigned long   lh1_aoerr1:1;                   /* RW */
+               unsigned long   gr0_aoerr1:1;                   /* RW */
+               unsigned long   gr1_aoerr1:1;                   /* RW */
+               unsigned long   xb_aoerr1:1;                    /* RW */
+               unsigned long   rtq0_aoerr1:1;                  /* RW */
+               unsigned long   rtq1_aoerr1:1;                  /* RW */
+               unsigned long   rtq2_aoerr1:1;                  /* RW */
+               unsigned long   rtq3_aoerr1:1;                  /* RW */
+               unsigned long   ni0_aoerr1:1;                   /* RW */
+               unsigned long   ni1_aoerr1:1;                   /* RW */
+               unsigned long   system_shutdown_int:1;          /* RW */
+               unsigned long   lb_irq_int_0:1;                 /* RW */
+               unsigned long   lb_irq_int_1:1;                 /* RW */
+               unsigned long   lb_irq_int_2:1;                 /* RW */
+               unsigned long   lb_irq_int_3:1;                 /* RW */
+               unsigned long   lb_irq_int_4:1;                 /* RW */
+               unsigned long   lb_irq_int_5:1;                 /* RW */
+               unsigned long   lb_irq_int_6:1;                 /* RW */
+               unsigned long   lb_irq_int_7:1;                 /* RW */
                unsigned long   lb_irq_int_8:1;                 /* RW */
                unsigned long   lb_irq_int_9:1;                 /* RW */
                unsigned long   lb_irq_int_10:1;                /* RW */
@@ -571,538 +779,1650 @@ union uvh_event_occurred0_u {
                unsigned long   extio_int2:1;                   /* RW */
                unsigned long   extio_int3:1;                   /* RW */
        } s4;
-};
-
-/* ========================================================================= */
-/*                        UVH_EVENT_OCCURRED0_ALIAS                          */
-/* ========================================================================= */
-#define UVH_EVENT_OCCURRED0_ALIAS 0x70008UL
-#define UVH_EVENT_OCCURRED0_ALIAS_32 0x5f0
-
-
-/* ========================================================================= */
-/*                         UVH_EXTIO_INT0_BROADCAST                          */
-/* ========================================================================= */
-#define UVH_EXTIO_INT0_BROADCAST 0x61448UL
-
-#define UV2H_EXTIO_INT0_BROADCAST_32 0x3f0
-#define UV3H_EXTIO_INT0_BROADCAST_32 0x3f0
-#define UV4H_EXTIO_INT0_BROADCAST_32 0x310
-#define UVH_EXTIO_INT0_BROADCAST_32 (                                  \
-       is_uv2_hub() ? UV2H_EXTIO_INT0_BROADCAST_32 :                   \
-       is_uv3_hub() ? UV3H_EXTIO_INT0_BROADCAST_32 :                   \
-       /*is_uv4_hub*/ UV4H_EXTIO_INT0_BROADCAST_32)
-
-#define UVH_EXTIO_INT0_BROADCAST_ENABLE_SHFT           0
-#define UVH_EXTIO_INT0_BROADCAST_ENABLE_MASK           0x0000000000000001UL
 
+       /* UV3 unique struct */
+       struct uv3h_event_occurred0_s {
+               unsigned long   lb_hcerr:1;                     /* RW */
+               unsigned long   qp_hcerr:1;                     /* RW */
+               unsigned long   rh_hcerr:1;                     /* RW */
+               unsigned long   lh0_hcerr:1;                    /* RW */
+               unsigned long   lh1_hcerr:1;                    /* RW */
+               unsigned long   gr0_hcerr:1;                    /* RW */
+               unsigned long   gr1_hcerr:1;                    /* RW */
+               unsigned long   ni0_hcerr:1;                    /* RW */
+               unsigned long   ni1_hcerr:1;                    /* RW */
+               unsigned long   lb_aoerr0:1;                    /* RW */
+               unsigned long   qp_aoerr0:1;                    /* RW */
+               unsigned long   rh_aoerr0:1;                    /* RW */
+               unsigned long   lh0_aoerr0:1;                   /* RW */
+               unsigned long   lh1_aoerr0:1;                   /* RW */
+               unsigned long   gr0_aoerr0:1;                   /* RW */
+               unsigned long   gr1_aoerr0:1;                   /* RW */
+               unsigned long   xb_aoerr0:1;                    /* RW */
+               unsigned long   rt_aoerr0:1;                    /* RW */
+               unsigned long   ni0_aoerr0:1;                   /* RW */
+               unsigned long   ni1_aoerr0:1;                   /* RW */
+               unsigned long   lb_aoerr1:1;                    /* RW */
+               unsigned long   qp_aoerr1:1;                    /* RW */
+               unsigned long   rh_aoerr1:1;                    /* RW */
+               unsigned long   lh0_aoerr1:1;                   /* RW */
+               unsigned long   lh1_aoerr1:1;                   /* RW */
+               unsigned long   gr0_aoerr1:1;                   /* RW */
+               unsigned long   gr1_aoerr1:1;                   /* RW */
+               unsigned long   xb_aoerr1:1;                    /* RW */
+               unsigned long   rt_aoerr1:1;                    /* RW */
+               unsigned long   ni0_aoerr1:1;                   /* RW */
+               unsigned long   ni1_aoerr1:1;                   /* RW */
+               unsigned long   system_shutdown_int:1;          /* RW */
+               unsigned long   lb_irq_int_0:1;                 /* RW */
+               unsigned long   lb_irq_int_1:1;                 /* RW */
+               unsigned long   lb_irq_int_2:1;                 /* RW */
+               unsigned long   lb_irq_int_3:1;                 /* RW */
+               unsigned long   lb_irq_int_4:1;                 /* RW */
+               unsigned long   lb_irq_int_5:1;                 /* RW */
+               unsigned long   lb_irq_int_6:1;                 /* RW */
+               unsigned long   lb_irq_int_7:1;                 /* RW */
+               unsigned long   lb_irq_int_8:1;                 /* RW */
+               unsigned long   lb_irq_int_9:1;                 /* RW */
+               unsigned long   lb_irq_int_10:1;                /* RW */
+               unsigned long   lb_irq_int_11:1;                /* RW */
+               unsigned long   lb_irq_int_12:1;                /* RW */
+               unsigned long   lb_irq_int_13:1;                /* RW */
+               unsigned long   lb_irq_int_14:1;                /* RW */
+               unsigned long   lb_irq_int_15:1;                /* RW */
+               unsigned long   l1_nmi_int:1;                   /* RW */
+               unsigned long   stop_clock:1;                   /* RW */
+               unsigned long   asic_to_l1:1;                   /* RW */
+               unsigned long   l1_to_asic:1;                   /* RW */
+               unsigned long   la_seq_trigger:1;               /* RW */
+               unsigned long   ipi_int:1;                      /* RW */
+               unsigned long   extio_int0:1;                   /* RW */
+               unsigned long   extio_int1:1;                   /* RW */
+               unsigned long   extio_int2:1;                   /* RW */
+               unsigned long   extio_int3:1;                   /* RW */
+               unsigned long   profile_int:1;                  /* RW */
+               unsigned long   rsvd_59_63:5;
+       } s3;
 
-union uvh_extio_int0_broadcast_u {
-       unsigned long   v;
-       struct uvh_extio_int0_broadcast_s {
-               unsigned long   enable:1;                       /* RW */
-               unsigned long   rsvd_1_63:63;
-       } s;
+       /* UV2 unique struct */
+       struct uv2h_event_occurred0_s {
+               unsigned long   lb_hcerr:1;                     /* RW */
+               unsigned long   qp_hcerr:1;                     /* RW */
+               unsigned long   rh_hcerr:1;                     /* RW */
+               unsigned long   lh0_hcerr:1;                    /* RW */
+               unsigned long   lh1_hcerr:1;                    /* RW */
+               unsigned long   gr0_hcerr:1;                    /* RW */
+               unsigned long   gr1_hcerr:1;                    /* RW */
+               unsigned long   ni0_hcerr:1;                    /* RW */
+               unsigned long   ni1_hcerr:1;                    /* RW */
+               unsigned long   lb_aoerr0:1;                    /* RW */
+               unsigned long   qp_aoerr0:1;                    /* RW */
+               unsigned long   rh_aoerr0:1;                    /* RW */
+               unsigned long   lh0_aoerr0:1;                   /* RW */
+               unsigned long   lh1_aoerr0:1;                   /* RW */
+               unsigned long   gr0_aoerr0:1;                   /* RW */
+               unsigned long   gr1_aoerr0:1;                   /* RW */
+               unsigned long   xb_aoerr0:1;                    /* RW */
+               unsigned long   rt_aoerr0:1;                    /* RW */
+               unsigned long   ni0_aoerr0:1;                   /* RW */
+               unsigned long   ni1_aoerr0:1;                   /* RW */
+               unsigned long   lb_aoerr1:1;                    /* RW */
+               unsigned long   qp_aoerr1:1;                    /* RW */
+               unsigned long   rh_aoerr1:1;                    /* RW */
+               unsigned long   lh0_aoerr1:1;                   /* RW */
+               unsigned long   lh1_aoerr1:1;                   /* RW */
+               unsigned long   gr0_aoerr1:1;                   /* RW */
+               unsigned long   gr1_aoerr1:1;                   /* RW */
+               unsigned long   xb_aoerr1:1;                    /* RW */
+               unsigned long   rt_aoerr1:1;                    /* RW */
+               unsigned long   ni0_aoerr1:1;                   /* RW */
+               unsigned long   ni1_aoerr1:1;                   /* RW */
+               unsigned long   system_shutdown_int:1;          /* RW */
+               unsigned long   lb_irq_int_0:1;                 /* RW */
+               unsigned long   lb_irq_int_1:1;                 /* RW */
+               unsigned long   lb_irq_int_2:1;                 /* RW */
+               unsigned long   lb_irq_int_3:1;                 /* RW */
+               unsigned long   lb_irq_int_4:1;                 /* RW */
+               unsigned long   lb_irq_int_5:1;                 /* RW */
+               unsigned long   lb_irq_int_6:1;                 /* RW */
+               unsigned long   lb_irq_int_7:1;                 /* RW */
+               unsigned long   lb_irq_int_8:1;                 /* RW */
+               unsigned long   lb_irq_int_9:1;                 /* RW */
+               unsigned long   lb_irq_int_10:1;                /* RW */
+               unsigned long   lb_irq_int_11:1;                /* RW */
+               unsigned long   lb_irq_int_12:1;                /* RW */
+               unsigned long   lb_irq_int_13:1;                /* RW */
+               unsigned long   lb_irq_int_14:1;                /* RW */
+               unsigned long   lb_irq_int_15:1;                /* RW */
+               unsigned long   l1_nmi_int:1;                   /* RW */
+               unsigned long   stop_clock:1;                   /* RW */
+               unsigned long   asic_to_l1:1;                   /* RW */
+               unsigned long   l1_to_asic:1;                   /* RW */
+               unsigned long   la_seq_trigger:1;               /* RW */
+               unsigned long   ipi_int:1;                      /* RW */
+               unsigned long   extio_int0:1;                   /* RW */
+               unsigned long   extio_int1:1;                   /* RW */
+               unsigned long   extio_int2:1;                   /* RW */
+               unsigned long   extio_int3:1;                   /* RW */
+               unsigned long   profile_int:1;                  /* RW */
+               unsigned long   rsvd_59_63:5;
+       } s2;
 };
 
 /* ========================================================================= */
-/*                         UVH_GR0_TLB_INT0_CONFIG                           */
+/*                        UVH_EVENT_OCCURRED0_ALIAS                          */
 /* ========================================================================= */
-#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL
-
-#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT            0
-#define UVH_GR0_TLB_INT0_CONFIG_DM_SHFT                        8
-#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_SHFT          11
-#define UVH_GR0_TLB_INT0_CONFIG_STATUS_SHFT            12
-#define UVH_GR0_TLB_INT0_CONFIG_P_SHFT                 13
-#define UVH_GR0_TLB_INT0_CONFIG_T_SHFT                 15
-#define UVH_GR0_TLB_INT0_CONFIG_M_SHFT                 16
-#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_SHFT           32
-#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_MASK            0x00000000000000ffUL
-#define UVH_GR0_TLB_INT0_CONFIG_DM_MASK                        0x0000000000000700UL
-#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_MASK          0x0000000000000800UL
-#define UVH_GR0_TLB_INT0_CONFIG_STATUS_MASK            0x0000000000001000UL
-#define UVH_GR0_TLB_INT0_CONFIG_P_MASK                 0x0000000000002000UL
-#define UVH_GR0_TLB_INT0_CONFIG_T_MASK                 0x0000000000008000UL
-#define UVH_GR0_TLB_INT0_CONFIG_M_MASK                 0x0000000000010000UL
-#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_MASK           0xffffffff00000000UL
-
+#define UVH_EVENT_OCCURRED0_ALIAS 0x70008UL
 
-union uvh_gr0_tlb_int0_config_u {
-       unsigned long   v;
-       struct uvh_gr0_tlb_int0_config_s {
-               unsigned long   vector_:8;                      /* RW */
-               unsigned long   dm:3;                           /* RW */
-               unsigned long   destmode:1;                     /* RW */
-               unsigned long   status:1;                       /* RO */
-               unsigned long   p:1;                            /* RO */
-               unsigned long   rsvd_14:1;
-               unsigned long   t:1;                            /* RO */
-               unsigned long   m:1;                            /* RW */
-               unsigned long   rsvd_17_31:15;
-               unsigned long   apic_id:32;                     /* RW */
-       } s;
-};
 
 /* ========================================================================= */
-/*                         UVH_GR0_TLB_INT1_CONFIG                           */
+/*                           UVH_EVENT_OCCURRED1                             */
 /* ========================================================================= */
-#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL
-
-#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT            0
-#define UVH_GR0_TLB_INT1_CONFIG_DM_SHFT                        8
-#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_SHFT          11
-#define UVH_GR0_TLB_INT1_CONFIG_STATUS_SHFT            12
-#define UVH_GR0_TLB_INT1_CONFIG_P_SHFT                 13
-#define UVH_GR0_TLB_INT1_CONFIG_T_SHFT                 15
-#define UVH_GR0_TLB_INT1_CONFIG_M_SHFT                 16
-#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_SHFT           32
-#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_MASK            0x00000000000000ffUL
-#define UVH_GR0_TLB_INT1_CONFIG_DM_MASK                        0x0000000000000700UL
-#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_MASK          0x0000000000000800UL
-#define UVH_GR0_TLB_INT1_CONFIG_STATUS_MASK            0x0000000000001000UL
-#define UVH_GR0_TLB_INT1_CONFIG_P_MASK                 0x0000000000002000UL
-#define UVH_GR0_TLB_INT1_CONFIG_T_MASK                 0x0000000000008000UL
-#define UVH_GR0_TLB_INT1_CONFIG_M_MASK                 0x0000000000010000UL
-#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_MASK           0xffffffff00000000UL
-
-
-union uvh_gr0_tlb_int1_config_u {
+#define UVH_EVENT_OCCURRED1 0x70080UL
+
+
+
+/* UVYH common defines */
+#define UVYH_EVENT_OCCURRED1_IPI_INT_SHFT              0
+#define UVYH_EVENT_OCCURRED1_IPI_INT_MASK              0x0000000000000001UL
+#define UVYH_EVENT_OCCURRED1_EXTIO_INT0_SHFT           1
+#define UVYH_EVENT_OCCURRED1_EXTIO_INT0_MASK           0x0000000000000002UL
+#define UVYH_EVENT_OCCURRED1_EXTIO_INT1_SHFT           2
+#define UVYH_EVENT_OCCURRED1_EXTIO_INT1_MASK           0x0000000000000004UL
+#define UVYH_EVENT_OCCURRED1_EXTIO_INT2_SHFT           3
+#define UVYH_EVENT_OCCURRED1_EXTIO_INT2_MASK           0x0000000000000008UL
+#define UVYH_EVENT_OCCURRED1_EXTIO_INT3_SHFT           4
+#define UVYH_EVENT_OCCURRED1_EXTIO_INT3_MASK           0x0000000000000010UL
+#define UVYH_EVENT_OCCURRED1_PROFILE_INT_SHFT          5
+#define UVYH_EVENT_OCCURRED1_PROFILE_INT_MASK          0x0000000000000020UL
+#define UVYH_EVENT_OCCURRED1_BAU_DATA_SHFT             6
+#define UVYH_EVENT_OCCURRED1_BAU_DATA_MASK             0x0000000000000040UL
+#define UVYH_EVENT_OCCURRED1_PROC_GENERAL_SHFT         7
+#define UVYH_EVENT_OCCURRED1_PROC_GENERAL_MASK         0x0000000000000080UL
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT0_SHFT          8
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT0_MASK          0x0000000000000100UL
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT1_SHFT          9
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT1_MASK          0x0000000000000200UL
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT2_SHFT          10
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT2_MASK          0x0000000000000400UL
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT3_SHFT          11
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT3_MASK          0x0000000000000800UL
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT4_SHFT          12
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT4_MASK          0x0000000000001000UL
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT5_SHFT          13
+#define UVYH_EVENT_OCCURRED1_XH_TLB_INT5_MASK          0x0000000000002000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT0_SHFT         14
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT0_MASK         0x0000000000004000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT1_SHFT         15
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT1_MASK         0x0000000000008000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT2_SHFT         16
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT2_MASK         0x0000000000010000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT3_SHFT         17
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT3_MASK         0x0000000000020000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT4_SHFT         18
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT4_MASK         0x0000000000040000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT5_SHFT         19
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT5_MASK         0x0000000000080000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT6_SHFT         20
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT6_MASK         0x0000000000100000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT7_SHFT         21
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT7_MASK         0x0000000000200000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT8_SHFT         22
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT8_MASK         0x0000000000400000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT9_SHFT         23
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT9_MASK         0x0000000000800000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT10_SHFT                24
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT10_MASK                0x0000000001000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT11_SHFT                25
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT11_MASK                0x0000000002000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT12_SHFT                26
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT12_MASK                0x0000000004000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT13_SHFT                27
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT13_MASK                0x0000000008000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT14_SHFT                28
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT14_MASK                0x0000000010000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT15_SHFT                29
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT15_MASK                0x0000000020000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT16_SHFT                30
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT16_MASK                0x0000000040000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT17_SHFT                31
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT17_MASK                0x0000000080000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT18_SHFT                32
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT18_MASK                0x0000000100000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT19_SHFT                33
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT19_MASK                0x0000000200000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT20_SHFT                34
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT20_MASK                0x0000000400000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT21_SHFT                35
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT21_MASK                0x0000000800000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT22_SHFT                36
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT22_MASK                0x0000001000000000UL
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT23_SHFT                37
+#define UVYH_EVENT_OCCURRED1_RDM_TLB_INT23_MASK                0x0000002000000000UL
+
+/* UV4 unique defines */
+#define UV4H_EVENT_OCCURRED1_PROFILE_INT_SHFT          0
+#define UV4H_EVENT_OCCURRED1_PROFILE_INT_MASK          0x0000000000000001UL
+#define UV4H_EVENT_OCCURRED1_BAU_DATA_SHFT             1
+#define UV4H_EVENT_OCCURRED1_BAU_DATA_MASK             0x0000000000000002UL
+#define UV4H_EVENT_OCCURRED1_PROC_GENERAL_SHFT         2
+#define UV4H_EVENT_OCCURRED1_PROC_GENERAL_MASK         0x0000000000000004UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT0_SHFT         3
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT0_MASK         0x0000000000000008UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT1_SHFT         4
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT1_MASK         0x0000000000000010UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT2_SHFT         5
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT2_MASK         0x0000000000000020UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT3_SHFT         6
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT3_MASK         0x0000000000000040UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT4_SHFT         7
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT4_MASK         0x0000000000000080UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT5_SHFT         8
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT5_MASK         0x0000000000000100UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT6_SHFT         9
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT6_MASK         0x0000000000000200UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT7_SHFT         10
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT7_MASK         0x0000000000000400UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT8_SHFT         11
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT8_MASK         0x0000000000000800UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT9_SHFT         12
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT9_MASK         0x0000000000001000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT10_SHFT                13
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT10_MASK                0x0000000000002000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT11_SHFT                14
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT11_MASK                0x0000000000004000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT12_SHFT                15
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT12_MASK                0x0000000000008000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT13_SHFT                16
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT13_MASK                0x0000000000010000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT14_SHFT                17
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT14_MASK                0x0000000000020000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT15_SHFT                18
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT15_MASK                0x0000000000040000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT16_SHFT                19
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT16_MASK                0x0000000000080000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT17_SHFT                20
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT17_MASK                0x0000000000100000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT18_SHFT                21
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT18_MASK                0x0000000000200000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT19_SHFT                22
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT19_MASK                0x0000000000400000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT20_SHFT                23
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT20_MASK                0x0000000000800000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT21_SHFT                24
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT21_MASK                0x0000000001000000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT22_SHFT                25
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT22_MASK                0x0000000002000000UL
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT23_SHFT                26
+#define UV4H_EVENT_OCCURRED1_GR0_TLB_INT23_MASK                0x0000000004000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT0_SHFT         27
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT0_MASK         0x0000000008000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT1_SHFT         28
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT1_MASK         0x0000000010000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT2_SHFT         29
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT2_MASK         0x0000000020000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT3_SHFT         30
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT3_MASK         0x0000000040000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT4_SHFT         31
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT4_MASK         0x0000000080000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT5_SHFT         32
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT5_MASK         0x0000000100000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT6_SHFT         33
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT6_MASK         0x0000000200000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT7_SHFT         34
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT7_MASK         0x0000000400000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT8_SHFT         35
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT8_MASK         0x0000000800000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT9_SHFT         36
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT9_MASK         0x0000001000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT10_SHFT                37
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT10_MASK                0x0000002000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT11_SHFT                38
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT11_MASK                0x0000004000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT12_SHFT                39
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT12_MASK                0x0000008000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT13_SHFT                40
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT13_MASK                0x0000010000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT14_SHFT                41
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT14_MASK                0x0000020000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT15_SHFT                42
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT15_MASK                0x0000040000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT16_SHFT                43
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT16_MASK                0x0000080000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT17_SHFT                44
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT17_MASK                0x0000100000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT18_SHFT                45
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT18_MASK                0x0000200000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT19_SHFT                46
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT19_MASK                0x0000400000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT20_SHFT                47
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT20_MASK                0x0000800000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT21_SHFT                48
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT21_MASK                0x0001000000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT22_SHFT                49
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT22_MASK                0x0002000000000000UL
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT23_SHFT                50
+#define UV4H_EVENT_OCCURRED1_GR1_TLB_INT23_MASK                0x0004000000000000UL
+
+/* UV3 unique defines */
+#define UV3H_EVENT_OCCURRED1_BAU_DATA_SHFT             0
+#define UV3H_EVENT_OCCURRED1_BAU_DATA_MASK             0x0000000000000001UL
+#define UV3H_EVENT_OCCURRED1_POWER_MANAGEMENT_REQ_SHFT 1
+#define UV3H_EVENT_OCCURRED1_POWER_MANAGEMENT_REQ_MASK 0x0000000000000002UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT0_SHFT 2
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT0_MASK 0x0000000000000004UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT1_SHFT 3
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT1_MASK 0x0000000000000008UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT2_SHFT 4
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT2_MASK 0x0000000000000010UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT3_SHFT 5
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT3_MASK 0x0000000000000020UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT4_SHFT 6
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT4_MASK 0x0000000000000040UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT5_SHFT 7
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT5_MASK 0x0000000000000080UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT6_SHFT 8
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT6_MASK 0x0000000000000100UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT7_SHFT 9
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT7_MASK 0x0000000000000200UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT8_SHFT 10
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT8_MASK 0x0000000000000400UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT9_SHFT 11
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT9_MASK 0x0000000000000800UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT10_SHFT 12
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT10_MASK 0x0000000000001000UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT11_SHFT 13
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT11_MASK 0x0000000000002000UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT12_SHFT 14
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT12_MASK 0x0000000000004000UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT13_SHFT 15
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT13_MASK 0x0000000000008000UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT14_SHFT 16
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT14_MASK 0x0000000000010000UL
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT15_SHFT 17
+#define UV3H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT15_MASK 0x0000000000020000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT0_SHFT         18
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT0_MASK         0x0000000000040000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT1_SHFT         19
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT1_MASK         0x0000000000080000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT2_SHFT         20
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT2_MASK         0x0000000000100000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT3_SHFT         21
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT3_MASK         0x0000000000200000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT4_SHFT         22
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT4_MASK         0x0000000000400000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT5_SHFT         23
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT5_MASK         0x0000000000800000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT6_SHFT         24
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT6_MASK         0x0000000001000000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT7_SHFT         25
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT7_MASK         0x0000000002000000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT8_SHFT         26
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT8_MASK         0x0000000004000000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT9_SHFT         27
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT9_MASK         0x0000000008000000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT10_SHFT                28
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT10_MASK                0x0000000010000000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT11_SHFT                29
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT11_MASK                0x0000000020000000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT12_SHFT                30
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT12_MASK                0x0000000040000000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT13_SHFT                31
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT13_MASK                0x0000000080000000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT14_SHFT                32
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT14_MASK                0x0000000100000000UL
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT15_SHFT                33
+#define UV3H_EVENT_OCCURRED1_GR0_TLB_INT15_MASK                0x0000000200000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT0_SHFT         34
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT0_MASK         0x0000000400000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT1_SHFT         35
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT1_MASK         0x0000000800000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT2_SHFT         36
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT2_MASK         0x0000001000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT3_SHFT         37
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT3_MASK         0x0000002000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT4_SHFT         38
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT4_MASK         0x0000004000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT5_SHFT         39
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT5_MASK         0x0000008000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT6_SHFT         40
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT6_MASK         0x0000010000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT7_SHFT         41
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT7_MASK         0x0000020000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT8_SHFT         42
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT8_MASK         0x0000040000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT9_SHFT         43
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT9_MASK         0x0000080000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT10_SHFT                44
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT10_MASK                0x0000100000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT11_SHFT                45
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT11_MASK                0x0000200000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT12_SHFT                46
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT12_MASK                0x0000400000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT13_SHFT                47
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT13_MASK                0x0000800000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT14_SHFT                48
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT14_MASK                0x0001000000000000UL
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT15_SHFT                49
+#define UV3H_EVENT_OCCURRED1_GR1_TLB_INT15_MASK                0x0002000000000000UL
+#define UV3H_EVENT_OCCURRED1_RTC_INTERVAL_INT_SHFT     50
+#define UV3H_EVENT_OCCURRED1_RTC_INTERVAL_INT_MASK     0x0004000000000000UL
+#define UV3H_EVENT_OCCURRED1_BAU_DASHBOARD_INT_SHFT    51
+#define UV3H_EVENT_OCCURRED1_BAU_DASHBOARD_INT_MASK    0x0008000000000000UL
+
+/* UV2 unique defines */
+#define UV2H_EVENT_OCCURRED1_BAU_DATA_SHFT             0
+#define UV2H_EVENT_OCCURRED1_BAU_DATA_MASK             0x0000000000000001UL
+#define UV2H_EVENT_OCCURRED1_POWER_MANAGEMENT_REQ_SHFT 1
+#define UV2H_EVENT_OCCURRED1_POWER_MANAGEMENT_REQ_MASK 0x0000000000000002UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT0_SHFT 2
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT0_MASK 0x0000000000000004UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT1_SHFT 3
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT1_MASK 0x0000000000000008UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT2_SHFT 4
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT2_MASK 0x0000000000000010UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT3_SHFT 5
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT3_MASK 0x0000000000000020UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT4_SHFT 6
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT4_MASK 0x0000000000000040UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT5_SHFT 7
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT5_MASK 0x0000000000000080UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT6_SHFT 8
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT6_MASK 0x0000000000000100UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT7_SHFT 9
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT7_MASK 0x0000000000000200UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT8_SHFT 10
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT8_MASK 0x0000000000000400UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT9_SHFT 11
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT9_MASK 0x0000000000000800UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT10_SHFT 12
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT10_MASK 0x0000000000001000UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT11_SHFT 13
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT11_MASK 0x0000000000002000UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT12_SHFT 14
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT12_MASK 0x0000000000004000UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT13_SHFT 15
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT13_MASK 0x0000000000008000UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT14_SHFT 16
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT14_MASK 0x0000000000010000UL
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT15_SHFT 17
+#define UV2H_EVENT_OCCURRED1_MESSAGE_ACCELERATOR_INT15_MASK 0x0000000000020000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT0_SHFT         18
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT0_MASK         0x0000000000040000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT1_SHFT         19
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT1_MASK         0x0000000000080000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT2_SHFT         20
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT2_MASK         0x0000000000100000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT3_SHFT         21
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT3_MASK         0x0000000000200000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT4_SHFT         22
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT4_MASK         0x0000000000400000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT5_SHFT         23
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT5_MASK         0x0000000000800000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT6_SHFT         24
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT6_MASK         0x0000000001000000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT7_SHFT         25
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT7_MASK         0x0000000002000000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT8_SHFT         26
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT8_MASK         0x0000000004000000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT9_SHFT         27
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT9_MASK         0x0000000008000000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT10_SHFT                28
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT10_MASK                0x0000000010000000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT11_SHFT                29
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT11_MASK                0x0000000020000000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT12_SHFT                30
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT12_MASK                0x0000000040000000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT13_SHFT                31
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT13_MASK                0x0000000080000000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT14_SHFT                32
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT14_MASK                0x0000000100000000UL
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT15_SHFT                33
+#define UV2H_EVENT_OCCURRED1_GR0_TLB_INT15_MASK                0x0000000200000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT0_SHFT         34
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT0_MASK         0x0000000400000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT1_SHFT         35
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT1_MASK         0x0000000800000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT2_SHFT         36
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT2_MASK         0x0000001000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT3_SHFT         37
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT3_MASK         0x0000002000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT4_SHFT         38
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT4_MASK         0x0000004000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT5_SHFT         39
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT5_MASK         0x0000008000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT6_SHFT         40
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT6_MASK         0x0000010000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT7_SHFT         41
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT7_MASK         0x0000020000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT8_SHFT         42
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT8_MASK         0x0000040000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT9_SHFT         43
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT9_MASK         0x0000080000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT10_SHFT                44
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT10_MASK                0x0000100000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT11_SHFT                45
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT11_MASK                0x0000200000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT12_SHFT                46
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT12_MASK                0x0000400000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT13_SHFT                47
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT13_MASK                0x0000800000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT14_SHFT                48
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT14_MASK                0x0001000000000000UL
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT15_SHFT                49
+#define UV2H_EVENT_OCCURRED1_GR1_TLB_INT15_MASK                0x0002000000000000UL
+#define UV2H_EVENT_OCCURRED1_RTC_INTERVAL_INT_SHFT     50
+#define UV2H_EVENT_OCCURRED1_RTC_INTERVAL_INT_MASK     0x0004000000000000UL
+#define UV2H_EVENT_OCCURRED1_BAU_DASHBOARD_INT_SHFT    51
+#define UV2H_EVENT_OCCURRED1_BAU_DASHBOARD_INT_MASK    0x0008000000000000UL
+
+#define UVH_EVENT_OCCURRED1_EXTIO_INT0_MASK (                          \
+       is_uv(UV5) ? 0x0000000000000002UL :                             \
+       0)
+#define UVH_EVENT_OCCURRED1_EXTIO_INT0_SHFT (                          \
+       is_uv(UV5) ? 1 :                                                \
+       -1)
+
+union uvyh_event_occurred1_u {
        unsigned long   v;
-       struct uvh_gr0_tlb_int1_config_s {
-               unsigned long   vector_:8;                      /* RW */
-               unsigned long   dm:3;                           /* RW */
-               unsigned long   destmode:1;                     /* RW */
-               unsigned long   status:1;                       /* RO */
-               unsigned long   p:1;                            /* RO */
-               unsigned long   rsvd_14:1;
-               unsigned long   t:1;                            /* RO */
-               unsigned long   m:1;                            /* RW */
-               unsigned long   rsvd_17_31:15;
-               unsigned long   apic_id:32;                     /* RW */
-       } s;
-};
 
-/* ========================================================================= */
-/*                         UVH_GR0_TLB_MMR_CONTROL                           */
-/* ========================================================================= */
-#define UV2H_GR0_TLB_MMR_CONTROL 0xc01080UL
-#define UV3H_GR0_TLB_MMR_CONTROL 0xc01080UL
-#define UV4H_GR0_TLB_MMR_CONTROL 0x601080UL
-#define UVH_GR0_TLB_MMR_CONTROL (                                      \
-       is_uv2_hub() ? UV2H_GR0_TLB_MMR_CONTROL :                       \
-       is_uv3_hub() ? UV3H_GR0_TLB_MMR_CONTROL :                       \
-       /*is_uv4_hub*/ UV4H_GR0_TLB_MMR_CONTROL)
-
-#define UVH_GR0_TLB_MMR_CONTROL_INDEX_SHFT             0
-#define UVH_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT     16
-#define UVH_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20
-#define UVH_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT         30
-#define UVH_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT          31
-#define UVH_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK     0x0000000000010000UL
-#define UVH_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL
-#define UVH_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK         0x0000000040000000UL
-#define UVH_GR0_TLB_MMR_CONTROL_MMR_READ_MASK          0x0000000080000000UL
-
-#define UVXH_GR0_TLB_MMR_CONTROL_INDEX_SHFT            0
-#define UVXH_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
-#define UVXH_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
-#define UVXH_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
-#define UVXH_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT         31
-#define UVXH_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
-#define UVXH_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
-#define UVXH_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
-#define UVXH_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
-#define UVXH_GR0_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
-#define UVXH_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
-
-#define UV2H_GR0_TLB_MMR_CONTROL_INDEX_SHFT            0
-#define UV2H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT          12
-#define UV2H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT         31
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_CON_SHFT      48
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_SHFT   52
-#define UV2H_GR0_TLB_MMR_CONTROL_INDEX_MASK            0x0000000000000fffUL
-#define UV2H_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK          0x0000000000003000UL
-#define UV2H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_CON_MASK      0x0001000000000000UL
-#define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_MASK   0x0010000000000000UL
-
-#define UV3H_GR0_TLB_MMR_CONTROL_INDEX_SHFT            0
-#define UV3H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT          12
-#define UV3H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
-#define UV3H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
-#define UV3H_GR0_TLB_MMR_CONTROL_ECC_SEL_SHFT          21
-#define UV3H_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
-#define UV3H_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT         31
-#define UV3H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
-#define UV3H_GR0_TLB_MMR_CONTROL_INDEX_MASK            0x0000000000000fffUL
-#define UV3H_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK          0x0000000000003000UL
-#define UV3H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
-#define UV3H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
-#define UV3H_GR0_TLB_MMR_CONTROL_ECC_SEL_MASK          0x0000000000200000UL
-#define UV3H_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
-#define UV3H_GR0_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
-#define UV3H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
-
-#define UV4H_GR0_TLB_MMR_CONTROL_INDEX_SHFT            0
-#define UV4H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT          13
-#define UV4H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
-#define UV4H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
-#define UV4H_GR0_TLB_MMR_CONTROL_ECC_SEL_SHFT          21
-#define UV4H_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
-#define UV4H_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT         31
-#define UV4H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
-#define UV4H_GR0_TLB_MMR_CONTROL_PAGE_SIZE_SHFT                59
-#define UV4H_GR0_TLB_MMR_CONTROL_INDEX_MASK            0x0000000000001fffUL
-#define UV4H_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK          0x0000000000006000UL
-#define UV4H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
-#define UV4H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
-#define UV4H_GR0_TLB_MMR_CONTROL_ECC_SEL_MASK          0x0000000000200000UL
-#define UV4H_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
-#define UV4H_GR0_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
-#define UV4H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
-#define UV4H_GR0_TLB_MMR_CONTROL_PAGE_SIZE_MASK                0xf800000000000000UL
-
-#define UVH_GR0_TLB_MMR_CONTROL_INDEX_MASK (                           \
-       is_uv2_hub() ? UV2H_GR0_TLB_MMR_CONTROL_INDEX_MASK :            \
-       is_uv3_hub() ? UV3H_GR0_TLB_MMR_CONTROL_INDEX_MASK :            \
-       /*is_uv4_hub*/ UV4H_GR0_TLB_MMR_CONTROL_INDEX_MASK)
-#define UVH_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK (                         \
-       is_uv2_hub() ? UV2H_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK :          \
-       is_uv3_hub() ? UV3H_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK :          \
-       /*is_uv4_hub*/ UV4H_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK)
-#define UVH_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT (                         \
-       is_uv2_hub() ? UV2H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT :          \
-       is_uv3_hub() ? UV3H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT :          \
-       /*is_uv4_hub*/ UV4H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT)
-
-union uvh_gr0_tlb_mmr_control_u {
-       unsigned long   v;
-       struct uvh_gr0_tlb_mmr_control_s {
-               unsigned long   rsvd_0_15:16;
-               unsigned long   auto_valid_en:1;                /* RW */
-               unsigned long   rsvd_17_19:3;
-               unsigned long   mmr_hash_index_en:1;            /* RW */
-               unsigned long   rsvd_21_29:9;
-               unsigned long   mmr_write:1;                    /* WP */
-               unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   rsvd_32_48:17;
-               unsigned long   rsvd_49_51:3;
-               unsigned long   rsvd_52_63:12;
-       } s;
-       struct uvxh_gr0_tlb_mmr_control_s {
-               unsigned long   rsvd_0_15:16;
-               unsigned long   auto_valid_en:1;                /* RW */
-               unsigned long   rsvd_17_19:3;
-               unsigned long   mmr_hash_index_en:1;            /* RW */
-               unsigned long   rsvd_21_29:9;
-               unsigned long   mmr_write:1;                    /* WP */
-               unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   mmr_op_done:1;                  /* RW */
-               unsigned long   rsvd_33_47:15;
-               unsigned long   rsvd_48:1;
-               unsigned long   rsvd_49_51:3;
-               unsigned long   rsvd_52_63:12;
-       } sx;
-       struct uv2h_gr0_tlb_mmr_control_s {
-               unsigned long   index:12;                       /* RW */
-               unsigned long   mem_sel:2;                      /* RW */
-               unsigned long   rsvd_14_15:2;
-               unsigned long   auto_valid_en:1;                /* RW */
-               unsigned long   rsvd_17_19:3;
-               unsigned long   mmr_hash_index_en:1;            /* RW */
-               unsigned long   rsvd_21_29:9;
-               unsigned long   mmr_write:1;                    /* WP */
-               unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   mmr_op_done:1;                  /* RW */
-               unsigned long   rsvd_33_47:15;
-               unsigned long   mmr_inj_con:1;                  /* RW */
-               unsigned long   rsvd_49_51:3;
-               unsigned long   mmr_inj_tlbram:1;               /* RW */
-               unsigned long   rsvd_53_63:11;
-       } s2;
-       struct uv3h_gr0_tlb_mmr_control_s {
-               unsigned long   index:12;                       /* RW */
-               unsigned long   mem_sel:2;                      /* RW */
-               unsigned long   rsvd_14_15:2;
-               unsigned long   auto_valid_en:1;                /* RW */
-               unsigned long   rsvd_17_19:3;
-               unsigned long   mmr_hash_index_en:1;            /* RW */
-               unsigned long   ecc_sel:1;                      /* RW */
-               unsigned long   rsvd_22_29:8;
-               unsigned long   mmr_write:1;                    /* WP */
-               unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   mmr_op_done:1;                  /* RW */
-               unsigned long   rsvd_33_47:15;
-               unsigned long   undef_48:1;                     /* Undefined */
-               unsigned long   rsvd_49_51:3;
-               unsigned long   undef_52:1;                     /* Undefined */
-               unsigned long   rsvd_53_63:11;
-       } s3;
-       struct uv4h_gr0_tlb_mmr_control_s {
-               unsigned long   index:13;                       /* RW */
-               unsigned long   mem_sel:2;                      /* RW */
-               unsigned long   rsvd_15:1;
-               unsigned long   auto_valid_en:1;                /* RW */
-               unsigned long   rsvd_17_19:3;
-               unsigned long   mmr_hash_index_en:1;            /* RW */
-               unsigned long   ecc_sel:1;                      /* RW */
-               unsigned long   rsvd_22_29:8;
-               unsigned long   mmr_write:1;                    /* WP */
-               unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   mmr_op_done:1;                  /* RW */
-               unsigned long   rsvd_33_47:15;
-               unsigned long   undef_48:1;                     /* Undefined */
-               unsigned long   rsvd_49_51:3;
-               unsigned long   rsvd_52_58:7;
-               unsigned long   page_size:5;                    /* RW */
+       /* UVYH common struct */
+       struct uvyh_event_occurred1_s {
+               unsigned long   ipi_int:1;                      /* RW */
+               unsigned long   extio_int0:1;                   /* RW */
+               unsigned long   extio_int1:1;                   /* RW */
+               unsigned long   extio_int2:1;                   /* RW */
+               unsigned long   extio_int3:1;                   /* RW */
+               unsigned long   profile_int:1;                  /* RW */
+               unsigned long   bau_data:1;                     /* RW */
+               unsigned long   proc_general:1;                 /* RW */
+               unsigned long   xh_tlb_int0:1;                  /* RW */
+               unsigned long   xh_tlb_int1:1;                  /* RW */
+               unsigned long   xh_tlb_int2:1;                  /* RW */
+               unsigned long   xh_tlb_int3:1;                  /* RW */
+               unsigned long   xh_tlb_int4:1;                  /* RW */
+               unsigned long   xh_tlb_int5:1;                  /* RW */
+               unsigned long   rdm_tlb_int0:1;                 /* RW */
+               unsigned long   rdm_tlb_int1:1;                 /* RW */
+               unsigned long   rdm_tlb_int2:1;                 /* RW */
+               unsigned long   rdm_tlb_int3:1;                 /* RW */
+               unsigned long   rdm_tlb_int4:1;                 /* RW */
+               unsigned long   rdm_tlb_int5:1;                 /* RW */
+               unsigned long   rdm_tlb_int6:1;                 /* RW */
+               unsigned long   rdm_tlb_int7:1;                 /* RW */
+               unsigned long   rdm_tlb_int8:1;                 /* RW */
+               unsigned long   rdm_tlb_int9:1;                 /* RW */
+               unsigned long   rdm_tlb_int10:1;                /* RW */
+               unsigned long   rdm_tlb_int11:1;                /* RW */
+               unsigned long   rdm_tlb_int12:1;                /* RW */
+               unsigned long   rdm_tlb_int13:1;                /* RW */
+               unsigned long   rdm_tlb_int14:1;                /* RW */
+               unsigned long   rdm_tlb_int15:1;                /* RW */
+               unsigned long   rdm_tlb_int16:1;                /* RW */
+               unsigned long   rdm_tlb_int17:1;                /* RW */
+               unsigned long   rdm_tlb_int18:1;                /* RW */
+               unsigned long   rdm_tlb_int19:1;                /* RW */
+               unsigned long   rdm_tlb_int20:1;                /* RW */
+               unsigned long   rdm_tlb_int21:1;                /* RW */
+               unsigned long   rdm_tlb_int22:1;                /* RW */
+               unsigned long   rdm_tlb_int23:1;                /* RW */
+               unsigned long   rsvd_38_63:26;
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_event_occurred1_s {
+               unsigned long   ipi_int:1;                      /* RW */
+               unsigned long   extio_int0:1;                   /* RW */
+               unsigned long   extio_int1:1;                   /* RW */
+               unsigned long   extio_int2:1;                   /* RW */
+               unsigned long   extio_int3:1;                   /* RW */
+               unsigned long   profile_int:1;                  /* RW */
+               unsigned long   bau_data:1;                     /* RW */
+               unsigned long   proc_general:1;                 /* RW */
+               unsigned long   xh_tlb_int0:1;                  /* RW */
+               unsigned long   xh_tlb_int1:1;                  /* RW */
+               unsigned long   xh_tlb_int2:1;                  /* RW */
+               unsigned long   xh_tlb_int3:1;                  /* RW */
+               unsigned long   xh_tlb_int4:1;                  /* RW */
+               unsigned long   xh_tlb_int5:1;                  /* RW */
+               unsigned long   rdm_tlb_int0:1;                 /* RW */
+               unsigned long   rdm_tlb_int1:1;                 /* RW */
+               unsigned long   rdm_tlb_int2:1;                 /* RW */
+               unsigned long   rdm_tlb_int3:1;                 /* RW */
+               unsigned long   rdm_tlb_int4:1;                 /* RW */
+               unsigned long   rdm_tlb_int5:1;                 /* RW */
+               unsigned long   rdm_tlb_int6:1;                 /* RW */
+               unsigned long   rdm_tlb_int7:1;                 /* RW */
+               unsigned long   rdm_tlb_int8:1;                 /* RW */
+               unsigned long   rdm_tlb_int9:1;                 /* RW */
+               unsigned long   rdm_tlb_int10:1;                /* RW */
+               unsigned long   rdm_tlb_int11:1;                /* RW */
+               unsigned long   rdm_tlb_int12:1;                /* RW */
+               unsigned long   rdm_tlb_int13:1;                /* RW */
+               unsigned long   rdm_tlb_int14:1;                /* RW */
+               unsigned long   rdm_tlb_int15:1;                /* RW */
+               unsigned long   rdm_tlb_int16:1;                /* RW */
+               unsigned long   rdm_tlb_int17:1;                /* RW */
+               unsigned long   rdm_tlb_int18:1;                /* RW */
+               unsigned long   rdm_tlb_int19:1;                /* RW */
+               unsigned long   rdm_tlb_int20:1;                /* RW */
+               unsigned long   rdm_tlb_int21:1;                /* RW */
+               unsigned long   rdm_tlb_int22:1;                /* RW */
+               unsigned long   rdm_tlb_int23:1;                /* RW */
+               unsigned long   rsvd_38_63:26;
+       } s5;
+
+       /* UV4 unique struct */
+       struct uv4h_event_occurred1_s {
+               unsigned long   profile_int:1;                  /* RW */
+               unsigned long   bau_data:1;                     /* RW */
+               unsigned long   proc_general:1;                 /* RW */
+               unsigned long   gr0_tlb_int0:1;                 /* RW */
+               unsigned long   gr0_tlb_int1:1;                 /* RW */
+               unsigned long   gr0_tlb_int2:1;                 /* RW */
+               unsigned long   gr0_tlb_int3:1;                 /* RW */
+               unsigned long   gr0_tlb_int4:1;                 /* RW */
+               unsigned long   gr0_tlb_int5:1;                 /* RW */
+               unsigned long   gr0_tlb_int6:1;                 /* RW */
+               unsigned long   gr0_tlb_int7:1;                 /* RW */
+               unsigned long   gr0_tlb_int8:1;                 /* RW */
+               unsigned long   gr0_tlb_int9:1;                 /* RW */
+               unsigned long   gr0_tlb_int10:1;                /* RW */
+               unsigned long   gr0_tlb_int11:1;                /* RW */
+               unsigned long   gr0_tlb_int12:1;                /* RW */
+               unsigned long   gr0_tlb_int13:1;                /* RW */
+               unsigned long   gr0_tlb_int14:1;                /* RW */
+               unsigned long   gr0_tlb_int15:1;                /* RW */
+               unsigned long   gr0_tlb_int16:1;                /* RW */
+               unsigned long   gr0_tlb_int17:1;                /* RW */
+               unsigned long   gr0_tlb_int18:1;                /* RW */
+               unsigned long   gr0_tlb_int19:1;                /* RW */
+               unsigned long   gr0_tlb_int20:1;                /* RW */
+               unsigned long   gr0_tlb_int21:1;                /* RW */
+               unsigned long   gr0_tlb_int22:1;                /* RW */
+               unsigned long   gr0_tlb_int23:1;                /* RW */
+               unsigned long   gr1_tlb_int0:1;                 /* RW */
+               unsigned long   gr1_tlb_int1:1;                 /* RW */
+               unsigned long   gr1_tlb_int2:1;                 /* RW */
+               unsigned long   gr1_tlb_int3:1;                 /* RW */
+               unsigned long   gr1_tlb_int4:1;                 /* RW */
+               unsigned long   gr1_tlb_int5:1;                 /* RW */
+               unsigned long   gr1_tlb_int6:1;                 /* RW */
+               unsigned long   gr1_tlb_int7:1;                 /* RW */
+               unsigned long   gr1_tlb_int8:1;                 /* RW */
+               unsigned long   gr1_tlb_int9:1;                 /* RW */
+               unsigned long   gr1_tlb_int10:1;                /* RW */
+               unsigned long   gr1_tlb_int11:1;                /* RW */
+               unsigned long   gr1_tlb_int12:1;                /* RW */
+               unsigned long   gr1_tlb_int13:1;                /* RW */
+               unsigned long   gr1_tlb_int14:1;                /* RW */
+               unsigned long   gr1_tlb_int15:1;                /* RW */
+               unsigned long   gr1_tlb_int16:1;                /* RW */
+               unsigned long   gr1_tlb_int17:1;                /* RW */
+               unsigned long   gr1_tlb_int18:1;                /* RW */
+               unsigned long   gr1_tlb_int19:1;                /* RW */
+               unsigned long   gr1_tlb_int20:1;                /* RW */
+               unsigned long   gr1_tlb_int21:1;                /* RW */
+               unsigned long   gr1_tlb_int22:1;                /* RW */
+               unsigned long   gr1_tlb_int23:1;                /* RW */
+               unsigned long   rsvd_51_63:13;
        } s4;
-};
 
-/* ========================================================================= */
-/*                       UVH_GR0_TLB_MMR_READ_DATA_HI                        */
-/* ========================================================================= */
-#define UV2H_GR0_TLB_MMR_READ_DATA_HI 0xc010a0UL
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI 0xc010a0UL
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI 0x6010a0UL
-#define UVH_GR0_TLB_MMR_READ_DATA_HI (                                 \
-       is_uv2_hub() ? UV2H_GR0_TLB_MMR_READ_DATA_HI :                  \
-       is_uv3_hub() ? UV3H_GR0_TLB_MMR_READ_DATA_HI :                  \
-       /*is_uv4_hub*/ UV4H_GR0_TLB_MMR_READ_DATA_HI)
-
-#define UVH_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT          0
-
-#define UVXH_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
-
-#define UV2H_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
-#define UV2H_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
-#define UV2H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
-#define UV2H_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
-#define UV2H_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
-#define UV2H_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
-#define UV2H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
-#define UV2H_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
-
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_AA_EXT_SHFT      45
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_WAY_ECC_SHFT     55
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_AA_EXT_MASK      0x0000200000000000UL
-#define UV3H_GR0_TLB_MMR_READ_DATA_HI_WAY_ECC_MASK     0xff80000000000000UL
-
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_PNID_SHFT                34
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT         49
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       51
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT      52
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_AA_EXT_SHFT      53
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_WAY_ECC_SHFT     55
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK         0x00000003ffffffffUL
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_PNID_MASK                0x0001fffc00000000UL
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0006000000000000UL
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0008000000000000UL
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0010000000000000UL
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_AA_EXT_MASK      0x0020000000000000UL
-#define UV4H_GR0_TLB_MMR_READ_DATA_HI_WAY_ECC_MASK     0xff80000000000000UL
-
-
-union uvh_gr0_tlb_mmr_read_data_hi_u {
-       unsigned long   v;
-       struct uv2h_gr0_tlb_mmr_read_data_hi_s {
-               unsigned long   pfn:41;                         /* RO */
-               unsigned long   gaa:2;                          /* RO */
-               unsigned long   dirty:1;                        /* RO */
-               unsigned long   larger:1;                       /* RO */
-               unsigned long   rsvd_45_63:19;
-       } s2;
-       struct uv3h_gr0_tlb_mmr_read_data_hi_s {
-               unsigned long   pfn:41;                         /* RO */
-               unsigned long   gaa:2;                          /* RO */
-               unsigned long   dirty:1;                        /* RO */
-               unsigned long   larger:1;                       /* RO */
-               unsigned long   aa_ext:1;                       /* RO */
-               unsigned long   undef_46_54:9;                  /* Undefined */
-               unsigned long   way_ecc:9;                      /* RO */
+       /* UV3 unique struct */
+       struct uv3h_event_occurred1_s {
+               unsigned long   bau_data:1;                     /* RW */
+               unsigned long   power_management_req:1;         /* RW */
+               unsigned long   message_accelerator_int0:1;     /* RW */
+               unsigned long   message_accelerator_int1:1;     /* RW */
+               unsigned long   message_accelerator_int2:1;     /* RW */
+               unsigned long   message_accelerator_int3:1;     /* RW */
+               unsigned long   message_accelerator_int4:1;     /* RW */
+               unsigned long   message_accelerator_int5:1;     /* RW */
+               unsigned long   message_accelerator_int6:1;     /* RW */
+               unsigned long   message_accelerator_int7:1;     /* RW */
+               unsigned long   message_accelerator_int8:1;     /* RW */
+               unsigned long   message_accelerator_int9:1;     /* RW */
+               unsigned long   message_accelerator_int10:1;    /* RW */
+               unsigned long   message_accelerator_int11:1;    /* RW */
+               unsigned long   message_accelerator_int12:1;    /* RW */
+               unsigned long   message_accelerator_int13:1;    /* RW */
+               unsigned long   message_accelerator_int14:1;    /* RW */
+               unsigned long   message_accelerator_int15:1;    /* RW */
+               unsigned long   gr0_tlb_int0:1;                 /* RW */
+               unsigned long   gr0_tlb_int1:1;                 /* RW */
+               unsigned long   gr0_tlb_int2:1;                 /* RW */
+               unsigned long   gr0_tlb_int3:1;                 /* RW */
+               unsigned long   gr0_tlb_int4:1;                 /* RW */
+               unsigned long   gr0_tlb_int5:1;                 /* RW */
+               unsigned long   gr0_tlb_int6:1;                 /* RW */
+               unsigned long   gr0_tlb_int7:1;                 /* RW */
+               unsigned long   gr0_tlb_int8:1;                 /* RW */
+               unsigned long   gr0_tlb_int9:1;                 /* RW */
+               unsigned long   gr0_tlb_int10:1;                /* RW */
+               unsigned long   gr0_tlb_int11:1;                /* RW */
+               unsigned long   gr0_tlb_int12:1;                /* RW */
+               unsigned long   gr0_tlb_int13:1;                /* RW */
+               unsigned long   gr0_tlb_int14:1;                /* RW */
+               unsigned long   gr0_tlb_int15:1;                /* RW */
+               unsigned long   gr1_tlb_int0:1;                 /* RW */
+               unsigned long   gr1_tlb_int1:1;                 /* RW */
+               unsigned long   gr1_tlb_int2:1;                 /* RW */
+               unsigned long   gr1_tlb_int3:1;                 /* RW */
+               unsigned long   gr1_tlb_int4:1;                 /* RW */
+               unsigned long   gr1_tlb_int5:1;                 /* RW */
+               unsigned long   gr1_tlb_int6:1;                 /* RW */
+               unsigned long   gr1_tlb_int7:1;                 /* RW */
+               unsigned long   gr1_tlb_int8:1;                 /* RW */
+               unsigned long   gr1_tlb_int9:1;                 /* RW */
+               unsigned long   gr1_tlb_int10:1;                /* RW */
+               unsigned long   gr1_tlb_int11:1;                /* RW */
+               unsigned long   gr1_tlb_int12:1;                /* RW */
+               unsigned long   gr1_tlb_int13:1;                /* RW */
+               unsigned long   gr1_tlb_int14:1;                /* RW */
+               unsigned long   gr1_tlb_int15:1;                /* RW */
+               unsigned long   rtc_interval_int:1;             /* RW */
+               unsigned long   bau_dashboard_int:1;            /* RW */
+               unsigned long   rsvd_52_63:12;
        } s3;
-       struct uv4h_gr0_tlb_mmr_read_data_hi_s {
-               unsigned long   pfn:34;                         /* RO */
-               unsigned long   pnid:15;                        /* RO */
-               unsigned long   gaa:2;                          /* RO */
-               unsigned long   dirty:1;                        /* RO */
-               unsigned long   larger:1;                       /* RO */
-               unsigned long   aa_ext:1;                       /* RO */
-               unsigned long   undef_54:1;                     /* Undefined */
-               unsigned long   way_ecc:9;                      /* RO */
-       } s4;
-};
 
-/* ========================================================================= */
-/*                       UVH_GR0_TLB_MMR_READ_DATA_LO                        */
-/* ========================================================================= */
-#define UV2H_GR0_TLB_MMR_READ_DATA_LO 0xc010a8UL
-#define UV3H_GR0_TLB_MMR_READ_DATA_LO 0xc010a8UL
-#define UV4H_GR0_TLB_MMR_READ_DATA_LO 0x6010a8UL
-#define UVH_GR0_TLB_MMR_READ_DATA_LO (                                 \
-       is_uv2_hub() ? UV2H_GR0_TLB_MMR_READ_DATA_LO :                  \
-       is_uv3_hub() ? UV3H_GR0_TLB_MMR_READ_DATA_LO :                  \
-       /*is_uv4_hub*/ UV4H_GR0_TLB_MMR_READ_DATA_LO)
-
-#define UVH_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT          0
-#define UVH_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT         39
-#define UVH_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT                63
-#define UVH_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK          0x0000007fffffffffUL
-#define UVH_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK         0x7fffff8000000000UL
-#define UVH_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK                0x8000000000000000UL
-
-#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
-#define UVXH_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
-#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
-#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
-#define UVXH_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
-#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
-
-#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
-#define UV2H_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
-#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
-#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
-#define UV2H_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
-#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
-
-#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
-#define UV3H_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
-#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
-#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
-#define UV3H_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
-#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
-
-#define UV4H_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
-#define UV4H_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
-#define UV4H_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
-#define UV4H_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
-#define UV4H_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
-#define UV4H_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
-
-
-union uvh_gr0_tlb_mmr_read_data_lo_u {
-       unsigned long   v;
-       struct uvh_gr0_tlb_mmr_read_data_lo_s {
-               unsigned long   vpn:39;                         /* RO */
-               unsigned long   asid:24;                        /* RO */
-               unsigned long   valid:1;                        /* RO */
-       } s;
-       struct uvxh_gr0_tlb_mmr_read_data_lo_s {
-               unsigned long   vpn:39;                         /* RO */
-               unsigned long   asid:24;                        /* RO */
-               unsigned long   valid:1;                        /* RO */
-       } sx;
-       struct uv2h_gr0_tlb_mmr_read_data_lo_s {
-               unsigned long   vpn:39;                         /* RO */
-               unsigned long   asid:24;                        /* RO */
-               unsigned long   valid:1;                        /* RO */
+       /* UV2 unique struct */
+       struct uv2h_event_occurred1_s {
+               unsigned long   bau_data:1;                     /* RW */
+               unsigned long   power_management_req:1;         /* RW */
+               unsigned long   message_accelerator_int0:1;     /* RW */
+               unsigned long   message_accelerator_int1:1;     /* RW */
+               unsigned long   message_accelerator_int2:1;     /* RW */
+               unsigned long   message_accelerator_int3:1;     /* RW */
+               unsigned long   message_accelerator_int4:1;     /* RW */
+               unsigned long   message_accelerator_int5:1;     /* RW */
+               unsigned long   message_accelerator_int6:1;     /* RW */
+               unsigned long   message_accelerator_int7:1;     /* RW */
+               unsigned long   message_accelerator_int8:1;     /* RW */
+               unsigned long   message_accelerator_int9:1;     /* RW */
+               unsigned long   message_accelerator_int10:1;    /* RW */
+               unsigned long   message_accelerator_int11:1;    /* RW */
+               unsigned long   message_accelerator_int12:1;    /* RW */
+               unsigned long   message_accelerator_int13:1;    /* RW */
+               unsigned long   message_accelerator_int14:1;    /* RW */
+               unsigned long   message_accelerator_int15:1;    /* RW */
+               unsigned long   gr0_tlb_int0:1;                 /* RW */
+               unsigned long   gr0_tlb_int1:1;                 /* RW */
+               unsigned long   gr0_tlb_int2:1;                 /* RW */
+               unsigned long   gr0_tlb_int3:1;                 /* RW */
+               unsigned long   gr0_tlb_int4:1;                 /* RW */
+               unsigned long   gr0_tlb_int5:1;                 /* RW */
+               unsigned long   gr0_tlb_int6:1;                 /* RW */
+               unsigned long   gr0_tlb_int7:1;                 /* RW */
+               unsigned long   gr0_tlb_int8:1;                 /* RW */
+               unsigned long   gr0_tlb_int9:1;                 /* RW */
+               unsigned long   gr0_tlb_int10:1;                /* RW */
+               unsigned long   gr0_tlb_int11:1;                /* RW */
+               unsigned long   gr0_tlb_int12:1;                /* RW */
+               unsigned long   gr0_tlb_int13:1;                /* RW */
+               unsigned long   gr0_tlb_int14:1;                /* RW */
+               unsigned long   gr0_tlb_int15:1;                /* RW */
+               unsigned long   gr1_tlb_int0:1;                 /* RW */
+               unsigned long   gr1_tlb_int1:1;                 /* RW */
+               unsigned long   gr1_tlb_int2:1;                 /* RW */
+               unsigned long   gr1_tlb_int3:1;                 /* RW */
+               unsigned long   gr1_tlb_int4:1;                 /* RW */
+               unsigned long   gr1_tlb_int5:1;                 /* RW */
+               unsigned long   gr1_tlb_int6:1;                 /* RW */
+               unsigned long   gr1_tlb_int7:1;                 /* RW */
+               unsigned long   gr1_tlb_int8:1;                 /* RW */
+               unsigned long   gr1_tlb_int9:1;                 /* RW */
+               unsigned long   gr1_tlb_int10:1;                /* RW */
+               unsigned long   gr1_tlb_int11:1;                /* RW */
+               unsigned long   gr1_tlb_int12:1;                /* RW */
+               unsigned long   gr1_tlb_int13:1;                /* RW */
+               unsigned long   gr1_tlb_int14:1;                /* RW */
+               unsigned long   gr1_tlb_int15:1;                /* RW */
+               unsigned long   rtc_interval_int:1;             /* RW */
+               unsigned long   bau_dashboard_int:1;            /* RW */
+               unsigned long   rsvd_52_63:12;
        } s2;
-       struct uv3h_gr0_tlb_mmr_read_data_lo_s {
-               unsigned long   vpn:39;                         /* RO */
-               unsigned long   asid:24;                        /* RO */
-               unsigned long   valid:1;                        /* RO */
-       } s3;
-       struct uv4h_gr0_tlb_mmr_read_data_lo_s {
-               unsigned long   vpn:39;                         /* RO */
-               unsigned long   asid:24;                        /* RO */
-               unsigned long   valid:1;                        /* RO */
-       } s4;
 };
 
 /* ========================================================================= */
-/*                         UVH_GR1_TLB_INT0_CONFIG                           */
+/*                        UVH_EVENT_OCCURRED1_ALIAS                          */
 /* ========================================================================= */
-#define UV2H_GR1_TLB_INT0_CONFIG 0x61f00UL
-#define UV3H_GR1_TLB_INT0_CONFIG 0x61f00UL
-#define UV4H_GR1_TLB_INT0_CONFIG 0x62100UL
-#define UVH_GR1_TLB_INT0_CONFIG (                                      \
-       is_uv2_hub() ? UV2H_GR1_TLB_INT0_CONFIG :                       \
-       is_uv3_hub() ? UV3H_GR1_TLB_INT0_CONFIG :                       \
-       /*is_uv4_hub*/ UV4H_GR1_TLB_INT0_CONFIG)
-
-#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT            0
-#define UVH_GR1_TLB_INT0_CONFIG_DM_SHFT                        8
-#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_SHFT          11
-#define UVH_GR1_TLB_INT0_CONFIG_STATUS_SHFT            12
-#define UVH_GR1_TLB_INT0_CONFIG_P_SHFT                 13
-#define UVH_GR1_TLB_INT0_CONFIG_T_SHFT                 15
-#define UVH_GR1_TLB_INT0_CONFIG_M_SHFT                 16
-#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_SHFT           32
-#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_MASK            0x00000000000000ffUL
-#define UVH_GR1_TLB_INT0_CONFIG_DM_MASK                        0x0000000000000700UL
-#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_MASK          0x0000000000000800UL
-#define UVH_GR1_TLB_INT0_CONFIG_STATUS_MASK            0x0000000000001000UL
-#define UVH_GR1_TLB_INT0_CONFIG_P_MASK                 0x0000000000002000UL
-#define UVH_GR1_TLB_INT0_CONFIG_T_MASK                 0x0000000000008000UL
-#define UVH_GR1_TLB_INT0_CONFIG_M_MASK                 0x0000000000010000UL
-#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_MASK           0xffffffff00000000UL
+#define UVH_EVENT_OCCURRED1_ALIAS 0x70088UL
 
 
-union uvh_gr1_tlb_int0_config_u {
-       unsigned long   v;
-       struct uvh_gr1_tlb_int0_config_s {
-               unsigned long   vector_:8;                      /* RW */
-               unsigned long   dm:3;                           /* RW */
-               unsigned long   destmode:1;                     /* RW */
-               unsigned long   status:1;                       /* RO */
-               unsigned long   p:1;                            /* RO */
-               unsigned long   rsvd_14:1;
-               unsigned long   t:1;                            /* RO */
-               unsigned long   m:1;                            /* RW */
-               unsigned long   rsvd_17_31:15;
-               unsigned long   apic_id:32;                     /* RW */
-       } s;
-};
-
 /* ========================================================================= */
-/*                         UVH_GR1_TLB_INT1_CONFIG                           */
+/*                           UVH_EVENT_OCCURRED2                             */
 /* ========================================================================= */
-#define UV2H_GR1_TLB_INT1_CONFIG 0x61f40UL
-#define UV3H_GR1_TLB_INT1_CONFIG 0x61f40UL
-#define UV4H_GR1_TLB_INT1_CONFIG 0x62140UL
-#define UVH_GR1_TLB_INT1_CONFIG (                                      \
-       is_uv2_hub() ? UV2H_GR1_TLB_INT1_CONFIG :                       \
-       is_uv3_hub() ? UV3H_GR1_TLB_INT1_CONFIG :                       \
-       /*is_uv4_hub*/ UV4H_GR1_TLB_INT1_CONFIG)
-
-#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT            0
-#define UVH_GR1_TLB_INT1_CONFIG_DM_SHFT                        8
-#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_SHFT          11
-#define UVH_GR1_TLB_INT1_CONFIG_STATUS_SHFT            12
-#define UVH_GR1_TLB_INT1_CONFIG_P_SHFT                 13
-#define UVH_GR1_TLB_INT1_CONFIG_T_SHFT                 15
-#define UVH_GR1_TLB_INT1_CONFIG_M_SHFT                 16
-#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_SHFT           32
-#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_MASK            0x00000000000000ffUL
-#define UVH_GR1_TLB_INT1_CONFIG_DM_MASK                        0x0000000000000700UL
-#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_MASK          0x0000000000000800UL
-#define UVH_GR1_TLB_INT1_CONFIG_STATUS_MASK            0x0000000000001000UL
-#define UVH_GR1_TLB_INT1_CONFIG_P_MASK                 0x0000000000002000UL
-#define UVH_GR1_TLB_INT1_CONFIG_T_MASK                 0x0000000000008000UL
-#define UVH_GR1_TLB_INT1_CONFIG_M_MASK                 0x0000000000010000UL
-#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_MASK           0xffffffff00000000UL
+#define UVH_EVENT_OCCURRED2 0x70100UL
+
+
+
+/* UVYH common defines */
+#define UVYH_EVENT_OCCURRED2_RTC_INTERVAL_INT_SHFT     0
+#define UVYH_EVENT_OCCURRED2_RTC_INTERVAL_INT_MASK     0x0000000000000001UL
+#define UVYH_EVENT_OCCURRED2_BAU_DASHBOARD_INT_SHFT    1
+#define UVYH_EVENT_OCCURRED2_BAU_DASHBOARD_INT_MASK    0x0000000000000002UL
+#define UVYH_EVENT_OCCURRED2_RTC_0_SHFT                        2
+#define UVYH_EVENT_OCCURRED2_RTC_0_MASK                        0x0000000000000004UL
+#define UVYH_EVENT_OCCURRED2_RTC_1_SHFT                        3
+#define UVYH_EVENT_OCCURRED2_RTC_1_MASK                        0x0000000000000008UL
+#define UVYH_EVENT_OCCURRED2_RTC_2_SHFT                        4
+#define UVYH_EVENT_OCCURRED2_RTC_2_MASK                        0x0000000000000010UL
+#define UVYH_EVENT_OCCURRED2_RTC_3_SHFT                        5
+#define UVYH_EVENT_OCCURRED2_RTC_3_MASK                        0x0000000000000020UL
+#define UVYH_EVENT_OCCURRED2_RTC_4_SHFT                        6
+#define UVYH_EVENT_OCCURRED2_RTC_4_MASK                        0x0000000000000040UL
+#define UVYH_EVENT_OCCURRED2_RTC_5_SHFT                        7
+#define UVYH_EVENT_OCCURRED2_RTC_5_MASK                        0x0000000000000080UL
+#define UVYH_EVENT_OCCURRED2_RTC_6_SHFT                        8
+#define UVYH_EVENT_OCCURRED2_RTC_6_MASK                        0x0000000000000100UL
+#define UVYH_EVENT_OCCURRED2_RTC_7_SHFT                        9
+#define UVYH_EVENT_OCCURRED2_RTC_7_MASK                        0x0000000000000200UL
+#define UVYH_EVENT_OCCURRED2_RTC_8_SHFT                        10
+#define UVYH_EVENT_OCCURRED2_RTC_8_MASK                        0x0000000000000400UL
+#define UVYH_EVENT_OCCURRED2_RTC_9_SHFT                        11
+#define UVYH_EVENT_OCCURRED2_RTC_9_MASK                        0x0000000000000800UL
+#define UVYH_EVENT_OCCURRED2_RTC_10_SHFT               12
+#define UVYH_EVENT_OCCURRED2_RTC_10_MASK               0x0000000000001000UL
+#define UVYH_EVENT_OCCURRED2_RTC_11_SHFT               13
+#define UVYH_EVENT_OCCURRED2_RTC_11_MASK               0x0000000000002000UL
+#define UVYH_EVENT_OCCURRED2_RTC_12_SHFT               14
+#define UVYH_EVENT_OCCURRED2_RTC_12_MASK               0x0000000000004000UL
+#define UVYH_EVENT_OCCURRED2_RTC_13_SHFT               15
+#define UVYH_EVENT_OCCURRED2_RTC_13_MASK               0x0000000000008000UL
+#define UVYH_EVENT_OCCURRED2_RTC_14_SHFT               16
+#define UVYH_EVENT_OCCURRED2_RTC_14_MASK               0x0000000000010000UL
+#define UVYH_EVENT_OCCURRED2_RTC_15_SHFT               17
+#define UVYH_EVENT_OCCURRED2_RTC_15_MASK               0x0000000000020000UL
+#define UVYH_EVENT_OCCURRED2_RTC_16_SHFT               18
+#define UVYH_EVENT_OCCURRED2_RTC_16_MASK               0x0000000000040000UL
+#define UVYH_EVENT_OCCURRED2_RTC_17_SHFT               19
+#define UVYH_EVENT_OCCURRED2_RTC_17_MASK               0x0000000000080000UL
+#define UVYH_EVENT_OCCURRED2_RTC_18_SHFT               20
+#define UVYH_EVENT_OCCURRED2_RTC_18_MASK               0x0000000000100000UL
+#define UVYH_EVENT_OCCURRED2_RTC_19_SHFT               21
+#define UVYH_EVENT_OCCURRED2_RTC_19_MASK               0x0000000000200000UL
+#define UVYH_EVENT_OCCURRED2_RTC_20_SHFT               22
+#define UVYH_EVENT_OCCURRED2_RTC_20_MASK               0x0000000000400000UL
+#define UVYH_EVENT_OCCURRED2_RTC_21_SHFT               23
+#define UVYH_EVENT_OCCURRED2_RTC_21_MASK               0x0000000000800000UL
+#define UVYH_EVENT_OCCURRED2_RTC_22_SHFT               24
+#define UVYH_EVENT_OCCURRED2_RTC_22_MASK               0x0000000001000000UL
+#define UVYH_EVENT_OCCURRED2_RTC_23_SHFT               25
+#define UVYH_EVENT_OCCURRED2_RTC_23_MASK               0x0000000002000000UL
+#define UVYH_EVENT_OCCURRED2_RTC_24_SHFT               26
+#define UVYH_EVENT_OCCURRED2_RTC_24_MASK               0x0000000004000000UL
+#define UVYH_EVENT_OCCURRED2_RTC_25_SHFT               27
+#define UVYH_EVENT_OCCURRED2_RTC_25_MASK               0x0000000008000000UL
+#define UVYH_EVENT_OCCURRED2_RTC_26_SHFT               28
+#define UVYH_EVENT_OCCURRED2_RTC_26_MASK               0x0000000010000000UL
+#define UVYH_EVENT_OCCURRED2_RTC_27_SHFT               29
+#define UVYH_EVENT_OCCURRED2_RTC_27_MASK               0x0000000020000000UL
+#define UVYH_EVENT_OCCURRED2_RTC_28_SHFT               30
+#define UVYH_EVENT_OCCURRED2_RTC_28_MASK               0x0000000040000000UL
+#define UVYH_EVENT_OCCURRED2_RTC_29_SHFT               31
+#define UVYH_EVENT_OCCURRED2_RTC_29_MASK               0x0000000080000000UL
+#define UVYH_EVENT_OCCURRED2_RTC_30_SHFT               32
+#define UVYH_EVENT_OCCURRED2_RTC_30_MASK               0x0000000100000000UL
+#define UVYH_EVENT_OCCURRED2_RTC_31_SHFT               33
+#define UVYH_EVENT_OCCURRED2_RTC_31_MASK               0x0000000200000000UL
+
+/* UV4 unique defines */
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT0_SHFT 0
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT0_MASK 0x0000000000000001UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT1_SHFT 1
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT1_MASK 0x0000000000000002UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT2_SHFT 2
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT2_MASK 0x0000000000000004UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT3_SHFT 3
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT3_MASK 0x0000000000000008UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT4_SHFT 4
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT4_MASK 0x0000000000000010UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT5_SHFT 5
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT5_MASK 0x0000000000000020UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT6_SHFT 6
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT6_MASK 0x0000000000000040UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT7_SHFT 7
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT7_MASK 0x0000000000000080UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT8_SHFT 8
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT8_MASK 0x0000000000000100UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT9_SHFT 9
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT9_MASK 0x0000000000000200UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT10_SHFT 10
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT10_MASK 0x0000000000000400UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT11_SHFT 11
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT11_MASK 0x0000000000000800UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT12_SHFT 12
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT12_MASK 0x0000000000001000UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT13_SHFT 13
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT13_MASK 0x0000000000002000UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT14_SHFT 14
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT14_MASK 0x0000000000004000UL
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT15_SHFT 15
+#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT15_MASK 0x0000000000008000UL
+#define UV4H_EVENT_OCCURRED2_RTC_INTERVAL_INT_SHFT     16
+#define UV4H_EVENT_OCCURRED2_RTC_INTERVAL_INT_MASK     0x0000000000010000UL
+#define UV4H_EVENT_OCCURRED2_BAU_DASHBOARD_INT_SHFT    17
+#define UV4H_EVENT_OCCURRED2_BAU_DASHBOARD_INT_MASK    0x0000000000020000UL
+#define UV4H_EVENT_OCCURRED2_RTC_0_SHFT                        18
+#define UV4H_EVENT_OCCURRED2_RTC_0_MASK                        0x0000000000040000UL
+#define UV4H_EVENT_OCCURRED2_RTC_1_SHFT                        19
+#define UV4H_EVENT_OCCURRED2_RTC_1_MASK                        0x0000000000080000UL
+#define UV4H_EVENT_OCCURRED2_RTC_2_SHFT                        20
+#define UV4H_EVENT_OCCURRED2_RTC_2_MASK                        0x0000000000100000UL
+#define UV4H_EVENT_OCCURRED2_RTC_3_SHFT                        21
+#define UV4H_EVENT_OCCURRED2_RTC_3_MASK                        0x0000000000200000UL
+#define UV4H_EVENT_OCCURRED2_RTC_4_SHFT                        22
+#define UV4H_EVENT_OCCURRED2_RTC_4_MASK                        0x0000000000400000UL
+#define UV4H_EVENT_OCCURRED2_RTC_5_SHFT                        23
+#define UV4H_EVENT_OCCURRED2_RTC_5_MASK                        0x0000000000800000UL
+#define UV4H_EVENT_OCCURRED2_RTC_6_SHFT                        24
+#define UV4H_EVENT_OCCURRED2_RTC_6_MASK                        0x0000000001000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_7_SHFT                        25
+#define UV4H_EVENT_OCCURRED2_RTC_7_MASK                        0x0000000002000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_8_SHFT                        26
+#define UV4H_EVENT_OCCURRED2_RTC_8_MASK                        0x0000000004000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_9_SHFT                        27
+#define UV4H_EVENT_OCCURRED2_RTC_9_MASK                        0x0000000008000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_10_SHFT               28
+#define UV4H_EVENT_OCCURRED2_RTC_10_MASK               0x0000000010000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_11_SHFT               29
+#define UV4H_EVENT_OCCURRED2_RTC_11_MASK               0x0000000020000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_12_SHFT               30
+#define UV4H_EVENT_OCCURRED2_RTC_12_MASK               0x0000000040000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_13_SHFT               31
+#define UV4H_EVENT_OCCURRED2_RTC_13_MASK               0x0000000080000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_14_SHFT               32
+#define UV4H_EVENT_OCCURRED2_RTC_14_MASK               0x0000000100000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_15_SHFT               33
+#define UV4H_EVENT_OCCURRED2_RTC_15_MASK               0x0000000200000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_16_SHFT               34
+#define UV4H_EVENT_OCCURRED2_RTC_16_MASK               0x0000000400000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_17_SHFT               35
+#define UV4H_EVENT_OCCURRED2_RTC_17_MASK               0x0000000800000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_18_SHFT               36
+#define UV4H_EVENT_OCCURRED2_RTC_18_MASK               0x0000001000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_19_SHFT               37
+#define UV4H_EVENT_OCCURRED2_RTC_19_MASK               0x0000002000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_20_SHFT               38
+#define UV4H_EVENT_OCCURRED2_RTC_20_MASK               0x0000004000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_21_SHFT               39
+#define UV4H_EVENT_OCCURRED2_RTC_21_MASK               0x0000008000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_22_SHFT               40
+#define UV4H_EVENT_OCCURRED2_RTC_22_MASK               0x0000010000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_23_SHFT               41
+#define UV4H_EVENT_OCCURRED2_RTC_23_MASK               0x0000020000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_24_SHFT               42
+#define UV4H_EVENT_OCCURRED2_RTC_24_MASK               0x0000040000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_25_SHFT               43
+#define UV4H_EVENT_OCCURRED2_RTC_25_MASK               0x0000080000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_26_SHFT               44
+#define UV4H_EVENT_OCCURRED2_RTC_26_MASK               0x0000100000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_27_SHFT               45
+#define UV4H_EVENT_OCCURRED2_RTC_27_MASK               0x0000200000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_28_SHFT               46
+#define UV4H_EVENT_OCCURRED2_RTC_28_MASK               0x0000400000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_29_SHFT               47
+#define UV4H_EVENT_OCCURRED2_RTC_29_MASK               0x0000800000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_30_SHFT               48
+#define UV4H_EVENT_OCCURRED2_RTC_30_MASK               0x0001000000000000UL
+#define UV4H_EVENT_OCCURRED2_RTC_31_SHFT               49
+#define UV4H_EVENT_OCCURRED2_RTC_31_MASK               0x0002000000000000UL
+
+/* UV3 unique defines */
+#define UV3H_EVENT_OCCURRED2_RTC_0_SHFT                        0
+#define UV3H_EVENT_OCCURRED2_RTC_0_MASK                        0x0000000000000001UL
+#define UV3H_EVENT_OCCURRED2_RTC_1_SHFT                        1
+#define UV3H_EVENT_OCCURRED2_RTC_1_MASK                        0x0000000000000002UL
+#define UV3H_EVENT_OCCURRED2_RTC_2_SHFT                        2
+#define UV3H_EVENT_OCCURRED2_RTC_2_MASK                        0x0000000000000004UL
+#define UV3H_EVENT_OCCURRED2_RTC_3_SHFT                        3
+#define UV3H_EVENT_OCCURRED2_RTC_3_MASK                        0x0000000000000008UL
+#define UV3H_EVENT_OCCURRED2_RTC_4_SHFT                        4
+#define UV3H_EVENT_OCCURRED2_RTC_4_MASK                        0x0000000000000010UL
+#define UV3H_EVENT_OCCURRED2_RTC_5_SHFT                        5
+#define UV3H_EVENT_OCCURRED2_RTC_5_MASK                        0x0000000000000020UL
+#define UV3H_EVENT_OCCURRED2_RTC_6_SHFT                        6
+#define UV3H_EVENT_OCCURRED2_RTC_6_MASK                        0x0000000000000040UL
+#define UV3H_EVENT_OCCURRED2_RTC_7_SHFT                        7
+#define UV3H_EVENT_OCCURRED2_RTC_7_MASK                        0x0000000000000080UL
+#define UV3H_EVENT_OCCURRED2_RTC_8_SHFT                        8
+#define UV3H_EVENT_OCCURRED2_RTC_8_MASK                        0x0000000000000100UL
+#define UV3H_EVENT_OCCURRED2_RTC_9_SHFT                        9
+#define UV3H_EVENT_OCCURRED2_RTC_9_MASK                        0x0000000000000200UL
+#define UV3H_EVENT_OCCURRED2_RTC_10_SHFT               10
+#define UV3H_EVENT_OCCURRED2_RTC_10_MASK               0x0000000000000400UL
+#define UV3H_EVENT_OCCURRED2_RTC_11_SHFT               11
+#define UV3H_EVENT_OCCURRED2_RTC_11_MASK               0x0000000000000800UL
+#define UV3H_EVENT_OCCURRED2_RTC_12_SHFT               12
+#define UV3H_EVENT_OCCURRED2_RTC_12_MASK               0x0000000000001000UL
+#define UV3H_EVENT_OCCURRED2_RTC_13_SHFT               13
+#define UV3H_EVENT_OCCURRED2_RTC_13_MASK               0x0000000000002000UL
+#define UV3H_EVENT_OCCURRED2_RTC_14_SHFT               14
+#define UV3H_EVENT_OCCURRED2_RTC_14_MASK               0x0000000000004000UL
+#define UV3H_EVENT_OCCURRED2_RTC_15_SHFT               15
+#define UV3H_EVENT_OCCURRED2_RTC_15_MASK               0x0000000000008000UL
+#define UV3H_EVENT_OCCURRED2_RTC_16_SHFT               16
+#define UV3H_EVENT_OCCURRED2_RTC_16_MASK               0x0000000000010000UL
+#define UV3H_EVENT_OCCURRED2_RTC_17_SHFT               17
+#define UV3H_EVENT_OCCURRED2_RTC_17_MASK               0x0000000000020000UL
+#define UV3H_EVENT_OCCURRED2_RTC_18_SHFT               18
+#define UV3H_EVENT_OCCURRED2_RTC_18_MASK               0x0000000000040000UL
+#define UV3H_EVENT_OCCURRED2_RTC_19_SHFT               19
+#define UV3H_EVENT_OCCURRED2_RTC_19_MASK               0x0000000000080000UL
+#define UV3H_EVENT_OCCURRED2_RTC_20_SHFT               20
+#define UV3H_EVENT_OCCURRED2_RTC_20_MASK               0x0000000000100000UL
+#define UV3H_EVENT_OCCURRED2_RTC_21_SHFT               21
+#define UV3H_EVENT_OCCURRED2_RTC_21_MASK               0x0000000000200000UL
+#define UV3H_EVENT_OCCURRED2_RTC_22_SHFT               22
+#define UV3H_EVENT_OCCURRED2_RTC_22_MASK               0x0000000000400000UL
+#define UV3H_EVENT_OCCURRED2_RTC_23_SHFT               23
+#define UV3H_EVENT_OCCURRED2_RTC_23_MASK               0x0000000000800000UL
+#define UV3H_EVENT_OCCURRED2_RTC_24_SHFT               24
+#define UV3H_EVENT_OCCURRED2_RTC_24_MASK               0x0000000001000000UL
+#define UV3H_EVENT_OCCURRED2_RTC_25_SHFT               25
+#define UV3H_EVENT_OCCURRED2_RTC_25_MASK               0x0000000002000000UL
+#define UV3H_EVENT_OCCURRED2_RTC_26_SHFT               26
+#define UV3H_EVENT_OCCURRED2_RTC_26_MASK               0x0000000004000000UL
+#define UV3H_EVENT_OCCURRED2_RTC_27_SHFT               27
+#define UV3H_EVENT_OCCURRED2_RTC_27_MASK               0x0000000008000000UL
+#define UV3H_EVENT_OCCURRED2_RTC_28_SHFT               28
+#define UV3H_EVENT_OCCURRED2_RTC_28_MASK               0x0000000010000000UL
+#define UV3H_EVENT_OCCURRED2_RTC_29_SHFT               29
+#define UV3H_EVENT_OCCURRED2_RTC_29_MASK               0x0000000020000000UL
+#define UV3H_EVENT_OCCURRED2_RTC_30_SHFT               30
+#define UV3H_EVENT_OCCURRED2_RTC_30_MASK               0x0000000040000000UL
+#define UV3H_EVENT_OCCURRED2_RTC_31_SHFT               31
+#define UV3H_EVENT_OCCURRED2_RTC_31_MASK               0x0000000080000000UL
+
+/* UV2 unique defines */
+#define UV2H_EVENT_OCCURRED2_RTC_0_SHFT                        0
+#define UV2H_EVENT_OCCURRED2_RTC_0_MASK                        0x0000000000000001UL
+#define UV2H_EVENT_OCCURRED2_RTC_1_SHFT                        1
+#define UV2H_EVENT_OCCURRED2_RTC_1_MASK                        0x0000000000000002UL
+#define UV2H_EVENT_OCCURRED2_RTC_2_SHFT                        2
+#define UV2H_EVENT_OCCURRED2_RTC_2_MASK                        0x0000000000000004UL
+#define UV2H_EVENT_OCCURRED2_RTC_3_SHFT                        3
+#define UV2H_EVENT_OCCURRED2_RTC_3_MASK                        0x0000000000000008UL
+#define UV2H_EVENT_OCCURRED2_RTC_4_SHFT                        4
+#define UV2H_EVENT_OCCURRED2_RTC_4_MASK                        0x0000000000000010UL
+#define UV2H_EVENT_OCCURRED2_RTC_5_SHFT                        5
+#define UV2H_EVENT_OCCURRED2_RTC_5_MASK                        0x0000000000000020UL
+#define UV2H_EVENT_OCCURRED2_RTC_6_SHFT                        6
+#define UV2H_EVENT_OCCURRED2_RTC_6_MASK                        0x0000000000000040UL
+#define UV2H_EVENT_OCCURRED2_RTC_7_SHFT                        7
+#define UV2H_EVENT_OCCURRED2_RTC_7_MASK                        0x0000000000000080UL
+#define UV2H_EVENT_OCCURRED2_RTC_8_SHFT                        8
+#define UV2H_EVENT_OCCURRED2_RTC_8_MASK                        0x0000000000000100UL
+#define UV2H_EVENT_OCCURRED2_RTC_9_SHFT                        9
+#define UV2H_EVENT_OCCURRED2_RTC_9_MASK                        0x0000000000000200UL
+#define UV2H_EVENT_OCCURRED2_RTC_10_SHFT               10
+#define UV2H_EVENT_OCCURRED2_RTC_10_MASK               0x0000000000000400UL
+#define UV2H_EVENT_OCCURRED2_RTC_11_SHFT               11
+#define UV2H_EVENT_OCCURRED2_RTC_11_MASK               0x0000000000000800UL
+#define UV2H_EVENT_OCCURRED2_RTC_12_SHFT               12
+#define UV2H_EVENT_OCCURRED2_RTC_12_MASK               0x0000000000001000UL
+#define UV2H_EVENT_OCCURRED2_RTC_13_SHFT               13
+#define UV2H_EVENT_OCCURRED2_RTC_13_MASK               0x0000000000002000UL
+#define UV2H_EVENT_OCCURRED2_RTC_14_SHFT               14
+#define UV2H_EVENT_OCCURRED2_RTC_14_MASK               0x0000000000004000UL
+#define UV2H_EVENT_OCCURRED2_RTC_15_SHFT               15
+#define UV2H_EVENT_OCCURRED2_RTC_15_MASK               0x0000000000008000UL
+#define UV2H_EVENT_OCCURRED2_RTC_16_SHFT               16
+#define UV2H_EVENT_OCCURRED2_RTC_16_MASK               0x0000000000010000UL
+#define UV2H_EVENT_OCCURRED2_RTC_17_SHFT               17
+#define UV2H_EVENT_OCCURRED2_RTC_17_MASK               0x0000000000020000UL
+#define UV2H_EVENT_OCCURRED2_RTC_18_SHFT               18
+#define UV2H_EVENT_OCCURRED2_RTC_18_MASK               0x0000000000040000UL
+#define UV2H_EVENT_OCCURRED2_RTC_19_SHFT               19
+#define UV2H_EVENT_OCCURRED2_RTC_19_MASK               0x0000000000080000UL
+#define UV2H_EVENT_OCCURRED2_RTC_20_SHFT               20
+#define UV2H_EVENT_OCCURRED2_RTC_20_MASK               0x0000000000100000UL
+#define UV2H_EVENT_OCCURRED2_RTC_21_SHFT               21
+#define UV2H_EVENT_OCCURRED2_RTC_21_MASK               0x0000000000200000UL
+#define UV2H_EVENT_OCCURRED2_RTC_22_SHFT               22
+#define UV2H_EVENT_OCCURRED2_RTC_22_MASK               0x0000000000400000UL
+#define UV2H_EVENT_OCCURRED2_RTC_23_SHFT               23
+#define UV2H_EVENT_OCCURRED2_RTC_23_MASK               0x0000000000800000UL
+#define UV2H_EVENT_OCCURRED2_RTC_24_SHFT               24
+#define UV2H_EVENT_OCCURRED2_RTC_24_MASK               0x0000000001000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_25_SHFT               25
+#define UV2H_EVENT_OCCURRED2_RTC_25_MASK               0x0000000002000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_26_SHFT               26
+#define UV2H_EVENT_OCCURRED2_RTC_26_MASK               0x0000000004000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_27_SHFT               27
+#define UV2H_EVENT_OCCURRED2_RTC_27_MASK               0x0000000008000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_28_SHFT               28
+#define UV2H_EVENT_OCCURRED2_RTC_28_MASK               0x0000000010000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_29_SHFT               29
+#define UV2H_EVENT_OCCURRED2_RTC_29_MASK               0x0000000020000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_30_SHFT               30
+#define UV2H_EVENT_OCCURRED2_RTC_30_MASK               0x0000000040000000UL
+#define UV2H_EVENT_OCCURRED2_RTC_31_SHFT               31
+#define UV2H_EVENT_OCCURRED2_RTC_31_MASK               0x0000000080000000UL
+
+#define UVH_EVENT_OCCURRED2_RTC_1_MASK (                               \
+       is_uv(UV5) ? 0x0000000000000008UL :                             \
+       is_uv(UV4) ? 0x0000000000080000UL :                             \
+       is_uv(UV3) ? 0x0000000000000002UL :                             \
+       is_uv(UV2) ? 0x0000000000000002UL :                             \
+       0)
+#define UVH_EVENT_OCCURRED2_RTC_1_SHFT (                               \
+       is_uv(UV5) ? 3 :                                                \
+       is_uv(UV4) ? 19 :                                               \
+       is_uv(UV3) ? 1 :                                                \
+       is_uv(UV2) ? 1 :                                                \
+       -1)
+
+union uvyh_event_occurred2_u {
+       unsigned long   v;
+
+       /* UVYH common struct */
+       struct uvyh_event_occurred2_s {
+               unsigned long   rtc_interval_int:1;             /* RW */
+               unsigned long   bau_dashboard_int:1;            /* RW */
+               unsigned long   rtc_0:1;                        /* RW */
+               unsigned long   rtc_1:1;                        /* RW */
+               unsigned long   rtc_2:1;                        /* RW */
+               unsigned long   rtc_3:1;                        /* RW */
+               unsigned long   rtc_4:1;                        /* RW */
+               unsigned long   rtc_5:1;                        /* RW */
+               unsigned long   rtc_6:1;                        /* RW */
+               unsigned long   rtc_7:1;                        /* RW */
+               unsigned long   rtc_8:1;                        /* RW */
+               unsigned long   rtc_9:1;                        /* RW */
+               unsigned long   rtc_10:1;                       /* RW */
+               unsigned long   rtc_11:1;                       /* RW */
+               unsigned long   rtc_12:1;                       /* RW */
+               unsigned long   rtc_13:1;                       /* RW */
+               unsigned long   rtc_14:1;                       /* RW */
+               unsigned long   rtc_15:1;                       /* RW */
+               unsigned long   rtc_16:1;                       /* RW */
+               unsigned long   rtc_17:1;                       /* RW */
+               unsigned long   rtc_18:1;                       /* RW */
+               unsigned long   rtc_19:1;                       /* RW */
+               unsigned long   rtc_20:1;                       /* RW */
+               unsigned long   rtc_21:1;                       /* RW */
+               unsigned long   rtc_22:1;                       /* RW */
+               unsigned long   rtc_23:1;                       /* RW */
+               unsigned long   rtc_24:1;                       /* RW */
+               unsigned long   rtc_25:1;                       /* RW */
+               unsigned long   rtc_26:1;                       /* RW */
+               unsigned long   rtc_27:1;                       /* RW */
+               unsigned long   rtc_28:1;                       /* RW */
+               unsigned long   rtc_29:1;                       /* RW */
+               unsigned long   rtc_30:1;                       /* RW */
+               unsigned long   rtc_31:1;                       /* RW */
+               unsigned long   rsvd_34_63:30;
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_event_occurred2_s {
+               unsigned long   rtc_interval_int:1;             /* RW */
+               unsigned long   bau_dashboard_int:1;            /* RW */
+               unsigned long   rtc_0:1;                        /* RW */
+               unsigned long   rtc_1:1;                        /* RW */
+               unsigned long   rtc_2:1;                        /* RW */
+               unsigned long   rtc_3:1;                        /* RW */
+               unsigned long   rtc_4:1;                        /* RW */
+               unsigned long   rtc_5:1;                        /* RW */
+               unsigned long   rtc_6:1;                        /* RW */
+               unsigned long   rtc_7:1;                        /* RW */
+               unsigned long   rtc_8:1;                        /* RW */
+               unsigned long   rtc_9:1;                        /* RW */
+               unsigned long   rtc_10:1;                       /* RW */
+               unsigned long   rtc_11:1;                       /* RW */
+               unsigned long   rtc_12:1;                       /* RW */
+               unsigned long   rtc_13:1;                       /* RW */
+               unsigned long   rtc_14:1;                       /* RW */
+               unsigned long   rtc_15:1;                       /* RW */
+               unsigned long   rtc_16:1;                       /* RW */
+               unsigned long   rtc_17:1;                       /* RW */
+               unsigned long   rtc_18:1;                       /* RW */
+               unsigned long   rtc_19:1;                       /* RW */
+               unsigned long   rtc_20:1;                       /* RW */
+               unsigned long   rtc_21:1;                       /* RW */
+               unsigned long   rtc_22:1;                       /* RW */
+               unsigned long   rtc_23:1;                       /* RW */
+               unsigned long   rtc_24:1;                       /* RW */
+               unsigned long   rtc_25:1;                       /* RW */
+               unsigned long   rtc_26:1;                       /* RW */
+               unsigned long   rtc_27:1;                       /* RW */
+               unsigned long   rtc_28:1;                       /* RW */
+               unsigned long   rtc_29:1;                       /* RW */
+               unsigned long   rtc_30:1;                       /* RW */
+               unsigned long   rtc_31:1;                       /* RW */
+               unsigned long   rsvd_34_63:30;
+       } s5;
+
+       /* UV4 unique struct */
+       struct uv4h_event_occurred2_s {
+               unsigned long   message_accelerator_int0:1;     /* RW */
+               unsigned long   message_accelerator_int1:1;     /* RW */
+               unsigned long   message_accelerator_int2:1;     /* RW */
+               unsigned long   message_accelerator_int3:1;     /* RW */
+               unsigned long   message_accelerator_int4:1;     /* RW */
+               unsigned long   message_accelerator_int5:1;     /* RW */
+               unsigned long   message_accelerator_int6:1;     /* RW */
+               unsigned long   message_accelerator_int7:1;     /* RW */
+               unsigned long   message_accelerator_int8:1;     /* RW */
+               unsigned long   message_accelerator_int9:1;     /* RW */
+               unsigned long   message_accelerator_int10:1;    /* RW */
+               unsigned long   message_accelerator_int11:1;    /* RW */
+               unsigned long   message_accelerator_int12:1;    /* RW */
+               unsigned long   message_accelerator_int13:1;    /* RW */
+               unsigned long   message_accelerator_int14:1;    /* RW */
+               unsigned long   message_accelerator_int15:1;    /* RW */
+               unsigned long   rtc_interval_int:1;             /* RW */
+               unsigned long   bau_dashboard_int:1;            /* RW */
+               unsigned long   rtc_0:1;                        /* RW */
+               unsigned long   rtc_1:1;                        /* RW */
+               unsigned long   rtc_2:1;                        /* RW */
+               unsigned long   rtc_3:1;                        /* RW */
+               unsigned long   rtc_4:1;                        /* RW */
+               unsigned long   rtc_5:1;                        /* RW */
+               unsigned long   rtc_6:1;                        /* RW */
+               unsigned long   rtc_7:1;                        /* RW */
+               unsigned long   rtc_8:1;                        /* RW */
+               unsigned long   rtc_9:1;                        /* RW */
+               unsigned long   rtc_10:1;                       /* RW */
+               unsigned long   rtc_11:1;                       /* RW */
+               unsigned long   rtc_12:1;                       /* RW */
+               unsigned long   rtc_13:1;                       /* RW */
+               unsigned long   rtc_14:1;                       /* RW */
+               unsigned long   rtc_15:1;                       /* RW */
+               unsigned long   rtc_16:1;                       /* RW */
+               unsigned long   rtc_17:1;                       /* RW */
+               unsigned long   rtc_18:1;                       /* RW */
+               unsigned long   rtc_19:1;                       /* RW */
+               unsigned long   rtc_20:1;                       /* RW */
+               unsigned long   rtc_21:1;                       /* RW */
+               unsigned long   rtc_22:1;                       /* RW */
+               unsigned long   rtc_23:1;                       /* RW */
+               unsigned long   rtc_24:1;                       /* RW */
+               unsigned long   rtc_25:1;                       /* RW */
+               unsigned long   rtc_26:1;                       /* RW */
+               unsigned long   rtc_27:1;                       /* RW */
+               unsigned long   rtc_28:1;                       /* RW */
+               unsigned long   rtc_29:1;                       /* RW */
+               unsigned long   rtc_30:1;                       /* RW */
+               unsigned long   rtc_31:1;                       /* RW */
+               unsigned long   rsvd_50_63:14;
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_event_occurred2_s {
+               unsigned long   rtc_0:1;                        /* RW */
+               unsigned long   rtc_1:1;                        /* RW */
+               unsigned long   rtc_2:1;                        /* RW */
+               unsigned long   rtc_3:1;                        /* RW */
+               unsigned long   rtc_4:1;                        /* RW */
+               unsigned long   rtc_5:1;                        /* RW */
+               unsigned long   rtc_6:1;                        /* RW */
+               unsigned long   rtc_7:1;                        /* RW */
+               unsigned long   rtc_8:1;                        /* RW */
+               unsigned long   rtc_9:1;                        /* RW */
+               unsigned long   rtc_10:1;                       /* RW */
+               unsigned long   rtc_11:1;                       /* RW */
+               unsigned long   rtc_12:1;                       /* RW */
+               unsigned long   rtc_13:1;                       /* RW */
+               unsigned long   rtc_14:1;                       /* RW */
+               unsigned long   rtc_15:1;                       /* RW */
+               unsigned long   rtc_16:1;                       /* RW */
+               unsigned long   rtc_17:1;                       /* RW */
+               unsigned long   rtc_18:1;                       /* RW */
+               unsigned long   rtc_19:1;                       /* RW */
+               unsigned long   rtc_20:1;                       /* RW */
+               unsigned long   rtc_21:1;                       /* RW */
+               unsigned long   rtc_22:1;                       /* RW */
+               unsigned long   rtc_23:1;                       /* RW */
+               unsigned long   rtc_24:1;                       /* RW */
+               unsigned long   rtc_25:1;                       /* RW */
+               unsigned long   rtc_26:1;                       /* RW */
+               unsigned long   rtc_27:1;                       /* RW */
+               unsigned long   rtc_28:1;                       /* RW */
+               unsigned long   rtc_29:1;                       /* RW */
+               unsigned long   rtc_30:1;                       /* RW */
+               unsigned long   rtc_31:1;                       /* RW */
+               unsigned long   rsvd_32_63:32;
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_event_occurred2_s {
+               unsigned long   rtc_0:1;                        /* RW */
+               unsigned long   rtc_1:1;                        /* RW */
+               unsigned long   rtc_2:1;                        /* RW */
+               unsigned long   rtc_3:1;                        /* RW */
+               unsigned long   rtc_4:1;                        /* RW */
+               unsigned long   rtc_5:1;                        /* RW */
+               unsigned long   rtc_6:1;                        /* RW */
+               unsigned long   rtc_7:1;                        /* RW */
+               unsigned long   rtc_8:1;                        /* RW */
+               unsigned long   rtc_9:1;                        /* RW */
+               unsigned long   rtc_10:1;                       /* RW */
+               unsigned long   rtc_11:1;                       /* RW */
+               unsigned long   rtc_12:1;                       /* RW */
+               unsigned long   rtc_13:1;                       /* RW */
+               unsigned long   rtc_14:1;                       /* RW */
+               unsigned long   rtc_15:1;                       /* RW */
+               unsigned long   rtc_16:1;                       /* RW */
+               unsigned long   rtc_17:1;                       /* RW */
+               unsigned long   rtc_18:1;                       /* RW */
+               unsigned long   rtc_19:1;                       /* RW */
+               unsigned long   rtc_20:1;                       /* RW */
+               unsigned long   rtc_21:1;                       /* RW */
+               unsigned long   rtc_22:1;                       /* RW */
+               unsigned long   rtc_23:1;                       /* RW */
+               unsigned long   rtc_24:1;                       /* RW */
+               unsigned long   rtc_25:1;                       /* RW */
+               unsigned long   rtc_26:1;                       /* RW */
+               unsigned long   rtc_27:1;                       /* RW */
+               unsigned long   rtc_28:1;                       /* RW */
+               unsigned long   rtc_29:1;                       /* RW */
+               unsigned long   rtc_30:1;                       /* RW */
+               unsigned long   rtc_31:1;                       /* RW */
+               unsigned long   rsvd_32_63:32;
+       } s2;
+};
+
+/* ========================================================================= */
+/*                        UVH_EVENT_OCCURRED2_ALIAS                          */
+/* ========================================================================= */
+#define UVH_EVENT_OCCURRED2_ALIAS 0x70108UL
+
+
+/* ========================================================================= */
+/*                         UVH_EXTIO_INT0_BROADCAST                          */
+/* ========================================================================= */
+#define UVH_EXTIO_INT0_BROADCAST 0x61448UL
+
+/* UVH common defines*/
+#define UVH_EXTIO_INT0_BROADCAST_ENABLE_SHFT           0
+#define UVH_EXTIO_INT0_BROADCAST_ENABLE_MASK           0x0000000000000001UL
+
+
+union uvh_extio_int0_broadcast_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_extio_int0_broadcast_s {
+               unsigned long   enable:1;                       /* RW */
+               unsigned long   rsvd_1_63:63;
+       } s;
+
+       /* UV5 unique struct */
+       struct uv5h_extio_int0_broadcast_s {
+               unsigned long   enable:1;                       /* RW */
+               unsigned long   rsvd_1_63:63;
+       } s5;
+
+       /* UV4 unique struct */
+       struct uv4h_extio_int0_broadcast_s {
+               unsigned long   enable:1;                       /* RW */
+               unsigned long   rsvd_1_63:63;
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_extio_int0_broadcast_s {
+               unsigned long   enable:1;                       /* RW */
+               unsigned long   rsvd_1_63:63;
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_extio_int0_broadcast_s {
+               unsigned long   enable:1;                       /* RW */
+               unsigned long   rsvd_1_63:63;
+       } s2;
+};
+
+/* ========================================================================= */
+/*                          UVH_GR0_GAM_GR_CONFIG                            */
+/* ========================================================================= */
+#define UVH_GR0_GAM_GR_CONFIG (                                                \
+       is_uv(UV5) ? 0x600028UL :                                       \
+       is_uv(UV4) ? 0x600028UL :                                       \
+       is_uv(UV3) ? 0xc00028UL :                                       \
+       is_uv(UV2) ? 0xc00028UL :                                       \
+       0)
+
+
+
+/* UVYH common defines */
+#define UVYH_GR0_GAM_GR_CONFIG_SUBSPACE_SHFT           10
+#define UVYH_GR0_GAM_GR_CONFIG_SUBSPACE_MASK           0x0000000000000400UL
+
+/* UV4 unique defines */
+#define UV4H_GR0_GAM_GR_CONFIG_SUBSPACE_SHFT           10
+#define UV4H_GR0_GAM_GR_CONFIG_SUBSPACE_MASK           0x0000000000000400UL
+
+/* UV3 unique defines */
+#define UV3H_GR0_GAM_GR_CONFIG_M_SKT_SHFT              0
+#define UV3H_GR0_GAM_GR_CONFIG_M_SKT_MASK              0x000000000000003fUL
+#define UV3H_GR0_GAM_GR_CONFIG_SUBSPACE_SHFT           10
+#define UV3H_GR0_GAM_GR_CONFIG_SUBSPACE_MASK           0x0000000000000400UL
+
+/* UV2 unique defines */
+#define UV2H_GR0_GAM_GR_CONFIG_N_GR_SHFT               0
+#define UV2H_GR0_GAM_GR_CONFIG_N_GR_MASK               0x000000000000000fUL
+
+
+union uvyh_gr0_gam_gr_config_u {
+       unsigned long   v;
 
+       /* UVYH common struct */
+       struct uvyh_gr0_gam_gr_config_s {
+               unsigned long   rsvd_0_9:10;
+               unsigned long   subspace:1;                     /* RW */
+               unsigned long   rsvd_11_63:53;
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_gr0_gam_gr_config_s {
+               unsigned long   rsvd_0_9:10;
+               unsigned long   subspace:1;                     /* RW */
+               unsigned long   rsvd_11_63:53;
+       } s5;
+
+       /* UV4 unique struct */
+       struct uv4h_gr0_gam_gr_config_s {
+               unsigned long   rsvd_0_9:10;
+               unsigned long   subspace:1;                     /* RW */
+               unsigned long   rsvd_11_63:53;
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_gr0_gam_gr_config_s {
+               unsigned long   m_skt:6;                        /* RW */
+               unsigned long   undef_6_9:4;                    /* Undefined */
+               unsigned long   subspace:1;                     /* RW */
+               unsigned long   reserved:53;
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_gr0_gam_gr_config_s {
+               unsigned long   n_gr:4;                         /* RW */
+               unsigned long   reserved:60;
+       } s2;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR0_TLB_INT0_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR0_TLB_INT0_CONFIG (                                      \
+       is_uv(UV4) ? 0x61b00UL :                                        \
+       is_uv(UV3) ? 0x61b00UL :                                        \
+       is_uv(UV2) ? 0x61b00UL :                                        \
+       uv_undefined("UVH_GR0_TLB_INT0_CONFIG"))
+
+
+/* UVXH common defines */
+#define UVXH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT           0
+#define UVXH_GR0_TLB_INT0_CONFIG_VECTOR_MASK           0x00000000000000ffUL
+#define UVXH_GR0_TLB_INT0_CONFIG_DM_SHFT               8
+#define UVXH_GR0_TLB_INT0_CONFIG_DM_MASK               0x0000000000000700UL
+#define UVXH_GR0_TLB_INT0_CONFIG_DESTMODE_SHFT         11
+#define UVXH_GR0_TLB_INT0_CONFIG_DESTMODE_MASK         0x0000000000000800UL
+#define UVXH_GR0_TLB_INT0_CONFIG_STATUS_SHFT           12
+#define UVXH_GR0_TLB_INT0_CONFIG_STATUS_MASK           0x0000000000001000UL
+#define UVXH_GR0_TLB_INT0_CONFIG_P_SHFT                        13
+#define UVXH_GR0_TLB_INT0_CONFIG_P_MASK                        0x0000000000002000UL
+#define UVXH_GR0_TLB_INT0_CONFIG_T_SHFT                        15
+#define UVXH_GR0_TLB_INT0_CONFIG_T_MASK                        0x0000000000008000UL
+#define UVXH_GR0_TLB_INT0_CONFIG_M_SHFT                        16
+#define UVXH_GR0_TLB_INT0_CONFIG_M_MASK                        0x0000000000010000UL
+#define UVXH_GR0_TLB_INT0_CONFIG_APIC_ID_SHFT          32
+#define UVXH_GR0_TLB_INT0_CONFIG_APIC_ID_MASK          0xffffffff00000000UL
+
+
+union uvh_gr0_tlb_int0_config_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_gr0_tlb_int0_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s;
+
+       /* UVXH common struct */
+       struct uvxh_gr0_tlb_int0_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } sx;
+
+       /* UV4 unique struct */
+       struct uv4h_gr0_tlb_int0_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_gr0_tlb_int0_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_gr0_tlb_int0_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s2;
+};
+
+/* ========================================================================= */
+/*                         UVH_GR0_TLB_INT1_CONFIG                           */
+/* ========================================================================= */
+#define UVH_GR0_TLB_INT1_CONFIG (                                      \
+       is_uv(UV4) ? 0x61b40UL :                                        \
+       is_uv(UV3) ? 0x61b40UL :                                        \
+       is_uv(UV2) ? 0x61b40UL :                                        \
+       uv_undefined("UVH_GR0_TLB_INT1_CONFIG"))
+
+
+/* UVXH common defines */
+#define UVXH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT           0
+#define UVXH_GR0_TLB_INT1_CONFIG_VECTOR_MASK           0x00000000000000ffUL
+#define UVXH_GR0_TLB_INT1_CONFIG_DM_SHFT               8
+#define UVXH_GR0_TLB_INT1_CONFIG_DM_MASK               0x0000000000000700UL
+#define UVXH_GR0_TLB_INT1_CONFIG_DESTMODE_SHFT         11
+#define UVXH_GR0_TLB_INT1_CONFIG_DESTMODE_MASK         0x0000000000000800UL
+#define UVXH_GR0_TLB_INT1_CONFIG_STATUS_SHFT           12
+#define UVXH_GR0_TLB_INT1_CONFIG_STATUS_MASK           0x0000000000001000UL
+#define UVXH_GR0_TLB_INT1_CONFIG_P_SHFT                        13
+#define UVXH_GR0_TLB_INT1_CONFIG_P_MASK                        0x0000000000002000UL
+#define UVXH_GR0_TLB_INT1_CONFIG_T_SHFT                        15
+#define UVXH_GR0_TLB_INT1_CONFIG_T_MASK                        0x0000000000008000UL
+#define UVXH_GR0_TLB_INT1_CONFIG_M_SHFT                        16
+#define UVXH_GR0_TLB_INT1_CONFIG_M_MASK                        0x0000000000010000UL
+#define UVXH_GR0_TLB_INT1_CONFIG_APIC_ID_SHFT          32
+#define UVXH_GR0_TLB_INT1_CONFIG_APIC_ID_MASK          0xffffffff00000000UL
+
+
+union uvh_gr0_tlb_int1_config_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_gr0_tlb_int1_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s;
+
+       /* UVXH common struct */
+       struct uvxh_gr0_tlb_int1_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } sx;
+
+       /* UV4 unique struct */
+       struct uv4h_gr0_tlb_int1_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s4;
 
-union uvh_gr1_tlb_int1_config_u {
-       unsigned long   v;
-       struct uvh_gr1_tlb_int1_config_s {
+       /* UV3 unique struct */
+       struct uv3h_gr0_tlb_int1_config_s {
                unsigned long   vector_:8;                      /* RW */
                unsigned long   dm:3;                           /* RW */
                unsigned long   destmode:1;                     /* RW */
@@ -1113,1326 +2433,403 @@ union uvh_gr1_tlb_int1_config_u {
                unsigned long   m:1;                            /* RW */
                unsigned long   rsvd_17_31:15;
                unsigned long   apic_id:32;                     /* RW */
-       } s;
-};
-
-/* ========================================================================= */
-/*                         UVH_GR1_TLB_MMR_CONTROL                           */
-/* ========================================================================= */
-#define UV2H_GR1_TLB_MMR_CONTROL 0x1001080UL
-#define UV3H_GR1_TLB_MMR_CONTROL 0x1001080UL
-#define UV4H_GR1_TLB_MMR_CONTROL 0x701080UL
-#define UVH_GR1_TLB_MMR_CONTROL (                                      \
-       is_uv2_hub() ? UV2H_GR1_TLB_MMR_CONTROL :                       \
-       is_uv3_hub() ? UV3H_GR1_TLB_MMR_CONTROL :                       \
-       /*is_uv4_hub*/ UV4H_GR1_TLB_MMR_CONTROL)
-
-#define UVH_GR1_TLB_MMR_CONTROL_INDEX_SHFT             0
-#define UVH_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT     16
-#define UVH_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20
-#define UVH_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT         30
-#define UVH_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT          31
-#define UVH_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK     0x0000000000010000UL
-#define UVH_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL
-#define UVH_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK         0x0000000040000000UL
-#define UVH_GR1_TLB_MMR_CONTROL_MMR_READ_MASK          0x0000000080000000UL
-
-#define UVXH_GR1_TLB_MMR_CONTROL_INDEX_SHFT            0
-#define UVXH_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
-#define UVXH_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
-#define UVXH_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
-#define UVXH_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT         31
-#define UVXH_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
-#define UVXH_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
-#define UVXH_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
-#define UVXH_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
-#define UVXH_GR1_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
-#define UVXH_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
-
-#define UV2H_GR1_TLB_MMR_CONTROL_INDEX_SHFT            0
-#define UV2H_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT          12
-#define UV2H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT         31
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_CON_SHFT      48
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_SHFT   52
-#define UV2H_GR1_TLB_MMR_CONTROL_INDEX_MASK            0x0000000000000fffUL
-#define UV2H_GR1_TLB_MMR_CONTROL_MEM_SEL_MASK          0x0000000000003000UL
-#define UV2H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_CON_MASK      0x0001000000000000UL
-#define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_MASK   0x0010000000000000UL
-
-#define UV3H_GR1_TLB_MMR_CONTROL_INDEX_SHFT            0
-#define UV3H_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT          12
-#define UV3H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
-#define UV3H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
-#define UV3H_GR1_TLB_MMR_CONTROL_ECC_SEL_SHFT          21
-#define UV3H_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
-#define UV3H_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT         31
-#define UV3H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
-#define UV3H_GR1_TLB_MMR_CONTROL_INDEX_MASK            0x0000000000000fffUL
-#define UV3H_GR1_TLB_MMR_CONTROL_MEM_SEL_MASK          0x0000000000003000UL
-#define UV3H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
-#define UV3H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
-#define UV3H_GR1_TLB_MMR_CONTROL_ECC_SEL_MASK          0x0000000000200000UL
-#define UV3H_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
-#define UV3H_GR1_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
-#define UV3H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
-
-#define UV4H_GR1_TLB_MMR_CONTROL_INDEX_SHFT            0
-#define UV4H_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT          13
-#define UV4H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
-#define UV4H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
-#define UV4H_GR1_TLB_MMR_CONTROL_ECC_SEL_SHFT          21
-#define UV4H_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
-#define UV4H_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT         31
-#define UV4H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
-#define UV4H_GR1_TLB_MMR_CONTROL_PAGE_SIZE_SHFT                59
-#define UV4H_GR1_TLB_MMR_CONTROL_INDEX_MASK            0x0000000000001fffUL
-#define UV4H_GR1_TLB_MMR_CONTROL_MEM_SEL_MASK          0x0000000000006000UL
-#define UV4H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
-#define UV4H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
-#define UV4H_GR1_TLB_MMR_CONTROL_ECC_SEL_MASK          0x0000000000200000UL
-#define UV4H_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
-#define UV4H_GR1_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
-#define UV4H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
-#define UV4H_GR1_TLB_MMR_CONTROL_PAGE_SIZE_MASK                0xf800000000000000UL
-
-
-union uvh_gr1_tlb_mmr_control_u {
-       unsigned long   v;
-       struct uvh_gr1_tlb_mmr_control_s {
-               unsigned long   rsvd_0_15:16;
-               unsigned long   auto_valid_en:1;                /* RW */
-               unsigned long   rsvd_17_19:3;
-               unsigned long   mmr_hash_index_en:1;            /* RW */
-               unsigned long   rsvd_21_29:9;
-               unsigned long   mmr_write:1;                    /* WP */
-               unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   rsvd_32_48:17;
-               unsigned long   rsvd_49_51:3;
-               unsigned long   rsvd_52_63:12;
-       } s;
-       struct uvxh_gr1_tlb_mmr_control_s {
-               unsigned long   rsvd_0_15:16;
-               unsigned long   auto_valid_en:1;                /* RW */
-               unsigned long   rsvd_17_19:3;
-               unsigned long   mmr_hash_index_en:1;            /* RW */
-               unsigned long   rsvd_21_29:9;
-               unsigned long   mmr_write:1;                    /* WP */
-               unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   mmr_op_done:1;                  /* RW */
-               unsigned long   rsvd_33_47:15;
-               unsigned long   rsvd_48:1;
-               unsigned long   rsvd_49_51:3;
-               unsigned long   rsvd_52_63:12;
-       } sx;
-       struct uv2h_gr1_tlb_mmr_control_s {
-               unsigned long   index:12;                       /* RW */
-               unsigned long   mem_sel:2;                      /* RW */
-               unsigned long   rsvd_14_15:2;
-               unsigned long   auto_valid_en:1;                /* RW */
-               unsigned long   rsvd_17_19:3;
-               unsigned long   mmr_hash_index_en:1;            /* RW */
-               unsigned long   rsvd_21_29:9;
-               unsigned long   mmr_write:1;                    /* WP */
-               unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   mmr_op_done:1;                  /* RW */
-               unsigned long   rsvd_33_47:15;
-               unsigned long   mmr_inj_con:1;                  /* RW */
-               unsigned long   rsvd_49_51:3;
-               unsigned long   mmr_inj_tlbram:1;               /* RW */
-               unsigned long   rsvd_53_63:11;
-       } s2;
-       struct uv3h_gr1_tlb_mmr_control_s {
-               unsigned long   index:12;                       /* RW */
-               unsigned long   mem_sel:2;                      /* RW */
-               unsigned long   rsvd_14_15:2;
-               unsigned long   auto_valid_en:1;                /* RW */
-               unsigned long   rsvd_17_19:3;
-               unsigned long   mmr_hash_index_en:1;            /* RW */
-               unsigned long   ecc_sel:1;                      /* RW */
-               unsigned long   rsvd_22_29:8;
-               unsigned long   mmr_write:1;                    /* WP */
-               unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   mmr_op_done:1;                  /* RW */
-               unsigned long   rsvd_33_47:15;
-               unsigned long   undef_48:1;                     /* Undefined */
-               unsigned long   rsvd_49_51:3;
-               unsigned long   undef_52:1;                     /* Undefined */
-               unsigned long   rsvd_53_63:11;
-       } s3;
-       struct uv4h_gr1_tlb_mmr_control_s {
-               unsigned long   index:13;                       /* RW */
-               unsigned long   mem_sel:2;                      /* RW */
-               unsigned long   rsvd_15:1;
-               unsigned long   auto_valid_en:1;                /* RW */
-               unsigned long   rsvd_17_19:3;
-               unsigned long   mmr_hash_index_en:1;            /* RW */
-               unsigned long   ecc_sel:1;                      /* RW */
-               unsigned long   rsvd_22_29:8;
-               unsigned long   mmr_write:1;                    /* WP */
-               unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   mmr_op_done:1;                  /* RW */
-               unsigned long   rsvd_33_47:15;
-               unsigned long   undef_48:1;                     /* Undefined */
-               unsigned long   rsvd_49_51:3;
-               unsigned long   rsvd_52_58:7;
-               unsigned long   page_size:5;                    /* RW */
-       } s4;
-};
-
-/* ========================================================================= */
-/*                       UVH_GR1_TLB_MMR_READ_DATA_HI                        */
-/* ========================================================================= */
-#define UV2H_GR1_TLB_MMR_READ_DATA_HI 0x10010a0UL
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI 0x10010a0UL
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI 0x7010a0UL
-#define UVH_GR1_TLB_MMR_READ_DATA_HI (                                 \
-       is_uv2_hub() ? UV2H_GR1_TLB_MMR_READ_DATA_HI :                  \
-       is_uv3_hub() ? UV3H_GR1_TLB_MMR_READ_DATA_HI :                  \
-       /*is_uv4_hub*/ UV4H_GR1_TLB_MMR_READ_DATA_HI)
-
-#define UVH_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT          0
-
-#define UVXH_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
-
-#define UV2H_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
-#define UV2H_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
-#define UV2H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
-#define UV2H_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
-#define UV2H_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
-#define UV2H_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
-#define UV2H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
-#define UV2H_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
-
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_AA_EXT_SHFT      45
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_WAY_ECC_SHFT     55
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_AA_EXT_MASK      0x0000200000000000UL
-#define UV3H_GR1_TLB_MMR_READ_DATA_HI_WAY_ECC_MASK     0xff80000000000000UL
-
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_PNID_SHFT                34
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT         49
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       51
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT      52
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_AA_EXT_SHFT      53
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_WAY_ECC_SHFT     55
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK         0x00000003ffffffffUL
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_PNID_MASK                0x0001fffc00000000UL
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0006000000000000UL
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0008000000000000UL
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0010000000000000UL
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_AA_EXT_MASK      0x0020000000000000UL
-#define UV4H_GR1_TLB_MMR_READ_DATA_HI_WAY_ECC_MASK     0xff80000000000000UL
-
-
-union uvh_gr1_tlb_mmr_read_data_hi_u {
-       unsigned long   v;
-       struct uv2h_gr1_tlb_mmr_read_data_hi_s {
-               unsigned long   pfn:41;                         /* RO */
-               unsigned long   gaa:2;                          /* RO */
-               unsigned long   dirty:1;                        /* RO */
-               unsigned long   larger:1;                       /* RO */
-               unsigned long   rsvd_45_63:19;
-       } s2;
-       struct uv3h_gr1_tlb_mmr_read_data_hi_s {
-               unsigned long   pfn:41;                         /* RO */
-               unsigned long   gaa:2;                          /* RO */
-               unsigned long   dirty:1;                        /* RO */
-               unsigned long   larger:1;                       /* RO */
-               unsigned long   aa_ext:1;                       /* RO */
-               unsigned long   undef_46_54:9;                  /* Undefined */
-               unsigned long   way_ecc:9;                      /* RO */
        } s3;
-       struct uv4h_gr1_tlb_mmr_read_data_hi_s {
-               unsigned long   pfn:34;                         /* RO */
-               unsigned long   pnid:15;                        /* RO */
-               unsigned long   gaa:2;                          /* RO */
-               unsigned long   dirty:1;                        /* RO */
-               unsigned long   larger:1;                       /* RO */
-               unsigned long   aa_ext:1;                       /* RO */
-               unsigned long   undef_54:1;                     /* Undefined */
-               unsigned long   way_ecc:9;                      /* RO */
-       } s4;
-};
 
-/* ========================================================================= */
-/*                       UVH_GR1_TLB_MMR_READ_DATA_LO                        */
-/* ========================================================================= */
-#define UV2H_GR1_TLB_MMR_READ_DATA_LO 0x10010a8UL
-#define UV3H_GR1_TLB_MMR_READ_DATA_LO 0x10010a8UL
-#define UV4H_GR1_TLB_MMR_READ_DATA_LO 0x7010a8UL
-#define UVH_GR1_TLB_MMR_READ_DATA_LO (                                 \
-       is_uv2_hub() ? UV2H_GR1_TLB_MMR_READ_DATA_LO :                  \
-       is_uv3_hub() ? UV3H_GR1_TLB_MMR_READ_DATA_LO :                  \
-       /*is_uv4_hub*/ UV4H_GR1_TLB_MMR_READ_DATA_LO)
-
-#define UVH_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT          0
-#define UVH_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT         39
-#define UVH_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT                63
-#define UVH_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK          0x0000007fffffffffUL
-#define UVH_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK         0x7fffff8000000000UL
-#define UVH_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK                0x8000000000000000UL
-
-#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
-#define UVXH_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
-#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
-#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
-#define UVXH_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
-#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
-
-#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
-#define UV2H_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
-#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
-#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
-#define UV2H_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
-#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
-
-#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
-#define UV3H_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
-#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
-#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
-#define UV3H_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
-#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
-
-#define UV4H_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
-#define UV4H_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
-#define UV4H_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
-#define UV4H_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
-#define UV4H_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
-#define UV4H_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
-
-
-union uvh_gr1_tlb_mmr_read_data_lo_u {
-       unsigned long   v;
-       struct uvh_gr1_tlb_mmr_read_data_lo_s {
-               unsigned long   vpn:39;                         /* RO */
-               unsigned long   asid:24;                        /* RO */
-               unsigned long   valid:1;                        /* RO */
-       } s;
-       struct uvxh_gr1_tlb_mmr_read_data_lo_s {
-               unsigned long   vpn:39;                         /* RO */
-               unsigned long   asid:24;                        /* RO */
-               unsigned long   valid:1;                        /* RO */
-       } sx;
-       struct uv2h_gr1_tlb_mmr_read_data_lo_s {
-               unsigned long   vpn:39;                         /* RO */
-               unsigned long   asid:24;                        /* RO */
-               unsigned long   valid:1;                        /* RO */
+       /* UV2 unique struct */
+       struct uv2h_gr0_tlb_int1_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
        } s2;
-       struct uv3h_gr1_tlb_mmr_read_data_lo_s {
-               unsigned long   vpn:39;                         /* RO */
-               unsigned long   asid:24;                        /* RO */
-               unsigned long   valid:1;                        /* RO */
-       } s3;
-       struct uv4h_gr1_tlb_mmr_read_data_lo_s {
-               unsigned long   vpn:39;                         /* RO */
-               unsigned long   asid:24;                        /* RO */
-               unsigned long   valid:1;                        /* RO */
-       } s4;
 };
 
 /* ========================================================================= */
-/*                               UVH_INT_CMPB                                */
+/*                         UVH_GR1_TLB_INT0_CONFIG                           */
 /* ========================================================================= */
-#define UVH_INT_CMPB 0x22080UL
-
-#define UVH_INT_CMPB_REAL_TIME_CMPB_SHFT               0
-#define UVH_INT_CMPB_REAL_TIME_CMPB_MASK               0x00ffffffffffffffUL
+#define UVH_GR1_TLB_INT0_CONFIG (                                      \
+       is_uv(UV4) ? 0x62100UL :                                        \
+       is_uv(UV3) ? 0x61f00UL :                                        \
+       is_uv(UV2) ? 0x61f00UL :                                        \
+       uv_undefined("UVH_GR1_TLB_INT0_CONFIG"))
+
+
+/* UVXH common defines */
+#define UVXH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT           0
+#define UVXH_GR1_TLB_INT0_CONFIG_VECTOR_MASK           0x00000000000000ffUL
+#define UVXH_GR1_TLB_INT0_CONFIG_DM_SHFT               8
+#define UVXH_GR1_TLB_INT0_CONFIG_DM_MASK               0x0000000000000700UL
+#define UVXH_GR1_TLB_INT0_CONFIG_DESTMODE_SHFT         11
+#define UVXH_GR1_TLB_INT0_CONFIG_DESTMODE_MASK         0x0000000000000800UL
+#define UVXH_GR1_TLB_INT0_CONFIG_STATUS_SHFT           12
+#define UVXH_GR1_TLB_INT0_CONFIG_STATUS_MASK           0x0000000000001000UL
+#define UVXH_GR1_TLB_INT0_CONFIG_P_SHFT                        13
+#define UVXH_GR1_TLB_INT0_CONFIG_P_MASK                        0x0000000000002000UL
+#define UVXH_GR1_TLB_INT0_CONFIG_T_SHFT                        15
+#define UVXH_GR1_TLB_INT0_CONFIG_T_MASK                        0x0000000000008000UL
+#define UVXH_GR1_TLB_INT0_CONFIG_M_SHFT                        16
+#define UVXH_GR1_TLB_INT0_CONFIG_M_MASK                        0x0000000000010000UL
+#define UVXH_GR1_TLB_INT0_CONFIG_APIC_ID_SHFT          32
+#define UVXH_GR1_TLB_INT0_CONFIG_APIC_ID_MASK          0xffffffff00000000UL
 
 
-union uvh_int_cmpb_u {
+union uvh_gr1_tlb_int0_config_u {
        unsigned long   v;
-       struct uvh_int_cmpb_s {
-               unsigned long   real_time_cmpb:56;              /* RW */
-               unsigned long   rsvd_56_63:8;
-       } s;
-};
-
-/* ========================================================================= */
-/*                               UVH_INT_CMPC                                */
-/* ========================================================================= */
-#define UVH_INT_CMPC 0x22100UL
-
-
-#define UVXH_INT_CMPC_REAL_TIME_CMP_2_SHFT             0
-#define UVXH_INT_CMPC_REAL_TIME_CMP_2_MASK             0x00ffffffffffffffUL
-
 
-union uvh_int_cmpc_u {
-       unsigned long   v;
-       struct uvh_int_cmpc_s {
-               unsigned long   real_time_cmpc:56;              /* RW */
-               unsigned long   rsvd_56_63:8;
+       /* UVH common struct */
+       struct uvh_gr1_tlb_int0_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
        } s;
-};
-
-/* ========================================================================= */
-/*                               UVH_INT_CMPD                                */
-/* ========================================================================= */
-#define UVH_INT_CMPD 0x22180UL
 
+       /* UVXH common struct */
+       struct uvxh_gr1_tlb_int0_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } sx;
 
-#define UVXH_INT_CMPD_REAL_TIME_CMP_3_SHFT             0
-#define UVXH_INT_CMPD_REAL_TIME_CMP_3_MASK             0x00ffffffffffffffUL
+       /* UV4 unique struct */
+       struct uv4h_gr1_tlb_int0_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s4;
 
+       /* UV3 unique struct */
+       struct uv3h_gr1_tlb_int0_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s3;
 
-union uvh_int_cmpd_u {
-       unsigned long   v;
-       struct uvh_int_cmpd_s {
-               unsigned long   real_time_cmpd:56;              /* RW */
-               unsigned long   rsvd_56_63:8;
-       } s;
+       /* UV2 unique struct */
+       struct uv2h_gr1_tlb_int0_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s2;
 };
 
 /* ========================================================================= */
-/*                               UVH_IPI_INT                                 */
+/*                         UVH_GR1_TLB_INT1_CONFIG                           */
 /* ========================================================================= */
-#define UVH_IPI_INT 0x60500UL
-
-#define UV2H_IPI_INT_32 0x348
-#define UV3H_IPI_INT_32 0x348
-#define UV4H_IPI_INT_32 0x268
-#define UVH_IPI_INT_32 (                                               \
-       is_uv2_hub() ? UV2H_IPI_INT_32 :                                \
-       is_uv3_hub() ? UV3H_IPI_INT_32 :                                \
-       /*is_uv4_hub*/ UV4H_IPI_INT_32)
-
-#define UVH_IPI_INT_VECTOR_SHFT                                0
-#define UVH_IPI_INT_DELIVERY_MODE_SHFT                 8
-#define UVH_IPI_INT_DESTMODE_SHFT                      11
-#define UVH_IPI_INT_APIC_ID_SHFT                       16
-#define UVH_IPI_INT_SEND_SHFT                          63
-#define UVH_IPI_INT_VECTOR_MASK                                0x00000000000000ffUL
-#define UVH_IPI_INT_DELIVERY_MODE_MASK                 0x0000000000000700UL
-#define UVH_IPI_INT_DESTMODE_MASK                      0x0000000000000800UL
-#define UVH_IPI_INT_APIC_ID_MASK                       0x0000ffffffff0000UL
-#define UVH_IPI_INT_SEND_MASK                          0x8000000000000000UL
+#define UVH_GR1_TLB_INT1_CONFIG (                                      \
+       is_uv(UV4) ? 0x62140UL :                                        \
+       is_uv(UV3) ? 0x61f40UL :                                        \
+       is_uv(UV2) ? 0x61f40UL :                                        \
+       uv_undefined("UVH_GR1_TLB_INT1_CONFIG"))
+
+
+/* UVXH common defines */
+#define UVXH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT           0
+#define UVXH_GR1_TLB_INT1_CONFIG_VECTOR_MASK           0x00000000000000ffUL
+#define UVXH_GR1_TLB_INT1_CONFIG_DM_SHFT               8
+#define UVXH_GR1_TLB_INT1_CONFIG_DM_MASK               0x0000000000000700UL
+#define UVXH_GR1_TLB_INT1_CONFIG_DESTMODE_SHFT         11
+#define UVXH_GR1_TLB_INT1_CONFIG_DESTMODE_MASK         0x0000000000000800UL
+#define UVXH_GR1_TLB_INT1_CONFIG_STATUS_SHFT           12
+#define UVXH_GR1_TLB_INT1_CONFIG_STATUS_MASK           0x0000000000001000UL
+#define UVXH_GR1_TLB_INT1_CONFIG_P_SHFT                        13
+#define UVXH_GR1_TLB_INT1_CONFIG_P_MASK                        0x0000000000002000UL
+#define UVXH_GR1_TLB_INT1_CONFIG_T_SHFT                        15
+#define UVXH_GR1_TLB_INT1_CONFIG_T_MASK                        0x0000000000008000UL
+#define UVXH_GR1_TLB_INT1_CONFIG_M_SHFT                        16
+#define UVXH_GR1_TLB_INT1_CONFIG_M_MASK                        0x0000000000010000UL
+#define UVXH_GR1_TLB_INT1_CONFIG_APIC_ID_SHFT          32
+#define UVXH_GR1_TLB_INT1_CONFIG_APIC_ID_MASK          0xffffffff00000000UL
 
 
-union uvh_ipi_int_u {
+union uvh_gr1_tlb_int1_config_u {
        unsigned long   v;
-       struct uvh_ipi_int_s {
+
+       /* UVH common struct */
+       struct uvh_gr1_tlb_int1_config_s {
                unsigned long   vector_:8;                      /* RW */
-               unsigned long   delivery_mode:3;                /* RW */
+               unsigned long   dm:3;                           /* RW */
                unsigned long   destmode:1;                     /* RW */
-               unsigned long   rsvd_12_15:4;
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
                unsigned long   apic_id:32;                     /* RW */
-               unsigned long   rsvd_48_62:15;
-               unsigned long   send:1;                         /* WP */
        } s;
-};
-
-/* ========================================================================= */
-/*                   UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST                     */
-/* ========================================================================= */
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST 0x320050UL
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST 0x320050UL
-#define UV4H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST uv_undefined("UV4H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST")
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST (                          \
-       is_uv2_hub() ? UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST :           \
-       is_uv3_hub() ? UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST :           \
-       /*is_uv4_hub*/ UV4H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST)
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32 0x9c0
 
+       /* UVXH common struct */
+       struct uvxh_gr1_tlb_int1_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } sx;
 
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_SHFT 4
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_NODE_ID_SHFT 49
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_MASK 0x000007fffffffff0UL
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_NODE_ID_MASK 0x7ffe000000000000UL
-
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_SHFT 4
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_NODE_ID_SHFT 49
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_MASK 0x000007fffffffff0UL
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_NODE_ID_MASK 0x7ffe000000000000UL
+       /* UV4 unique struct */
+       struct uv4h_gr1_tlb_int1_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s4;
 
+       /* UV3 unique struct */
+       struct uv3h_gr1_tlb_int1_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s3;
 
-union uvh_lb_bau_intd_payload_queue_first_u {
-       unsigned long   v;
-       struct uv2h_lb_bau_intd_payload_queue_first_s {
-               unsigned long   rsvd_0_3:4;
-               unsigned long   address:39;                     /* RW */
-               unsigned long   rsvd_43_48:6;
-               unsigned long   node_id:14;                     /* RW */
-               unsigned long   rsvd_63:1;
+       /* UV2 unique struct */
+       struct uv2h_gr1_tlb_int1_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
        } s2;
-       struct uv3h_lb_bau_intd_payload_queue_first_s {
-               unsigned long   rsvd_0_3:4;
-               unsigned long   address:39;                     /* RW */
-               unsigned long   rsvd_43_48:6;
-               unsigned long   node_id:14;                     /* RW */
-               unsigned long   rsvd_63:1;
-       } s3;
 };
 
 /* ========================================================================= */
-/*                    UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST                     */
+/*                               UVH_INT_CMPB                                */
 /* ========================================================================= */
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST 0x320060UL
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST 0x320060UL
-#define UV4H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST uv_undefined("UV4H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST")
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST (                           \
-       is_uv2_hub() ? UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST :            \
-       is_uv3_hub() ? UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST :            \
-       /*is_uv4_hub*/ UV4H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST)
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32 0x9c8
-
-
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_SHFT 4
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_MASK 0x000007fffffffff0UL
+#define UVH_INT_CMPB 0x22080UL
 
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_SHFT 4
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_MASK 0x000007fffffffff0UL
+/* UVH common defines*/
+#define UVH_INT_CMPB_REAL_TIME_CMPB_SHFT               0
+#define UVH_INT_CMPB_REAL_TIME_CMPB_MASK               0x00ffffffffffffffUL
 
 
-union uvh_lb_bau_intd_payload_queue_last_u {
+union uvh_int_cmpb_u {
        unsigned long   v;
-       struct uv2h_lb_bau_intd_payload_queue_last_s {
-               unsigned long   rsvd_0_3:4;
-               unsigned long   address:39;                     /* RW */
-               unsigned long   rsvd_43_63:21;
-       } s2;
-       struct uv3h_lb_bau_intd_payload_queue_last_s {
-               unsigned long   rsvd_0_3:4;
-               unsigned long   address:39;                     /* RW */
-               unsigned long   rsvd_43_63:21;
-       } s3;
-};
-
-/* ========================================================================= */
-/*                    UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL                     */
-/* ========================================================================= */
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL 0x320070UL
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL 0x320070UL
-#define UV4H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL uv_undefined("UV4H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL")
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL (                           \
-       is_uv2_hub() ? UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL :            \
-       is_uv3_hub() ? UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL :            \
-       /*is_uv4_hub*/ UV4H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL)
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32 0x9d0
-
 
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_SHFT 4
-#define UV2H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_MASK 0x000007fffffffff0UL
-
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_SHFT 4
-#define UV3H_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_MASK 0x000007fffffffff0UL
+       /* UVH common struct */
+       struct uvh_int_cmpb_s {
+               unsigned long   real_time_cmpb:56;              /* RW */
+               unsigned long   rsvd_56_63:8;
+       } s;
 
+       /* UV5 unique struct */
+       struct uv5h_int_cmpb_s {
+               unsigned long   real_time_cmpb:56;              /* RW */
+               unsigned long   rsvd_56_63:8;
+       } s5;
 
-union uvh_lb_bau_intd_payload_queue_tail_u {
-       unsigned long   v;
-       struct uv2h_lb_bau_intd_payload_queue_tail_s {
-               unsigned long   rsvd_0_3:4;
-               unsigned long   address:39;                     /* RW */
-               unsigned long   rsvd_43_63:21;
-       } s2;
-       struct uv3h_lb_bau_intd_payload_queue_tail_s {
-               unsigned long   rsvd_0_3:4;
-               unsigned long   address:39;                     /* RW */
-               unsigned long   rsvd_43_63:21;
-       } s3;
-};
+       /* UV4 unique struct */
+       struct uv4h_int_cmpb_s {
+               unsigned long   real_time_cmpb:56;              /* RW */
+               unsigned long   rsvd_56_63:8;
+       } s4;
 
-/* ========================================================================= */
-/*                   UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE                    */
-/* ========================================================================= */
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE 0x320080UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE 0x320080UL
-#define UV4H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE uv_undefined("UV4H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE")
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE (                         \
-       is_uv2_hub() ? UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE :          \
-       is_uv3_hub() ? UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE :          \
-       /*is_uv4_hub*/ UV4H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE)
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_32 0xa68
-
-
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_SHFT 0
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_1_SHFT 1
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_2_SHFT 2
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_3_SHFT 3
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_4_SHFT 4
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_5_SHFT 5
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_6_SHFT 6
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_7_SHFT 7
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_0_SHFT 8
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_1_SHFT 9
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_2_SHFT 10
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_3_SHFT 11
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_4_SHFT 12
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_5_SHFT 13
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_6_SHFT 14
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_7_SHFT 15
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_MASK 0x0000000000000001UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_1_MASK 0x0000000000000002UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_2_MASK 0x0000000000000004UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_3_MASK 0x0000000000000008UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_4_MASK 0x0000000000000010UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_5_MASK 0x0000000000000020UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_6_MASK 0x0000000000000040UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_7_MASK 0x0000000000000080UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_0_MASK 0x0000000000000100UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_1_MASK 0x0000000000000200UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_2_MASK 0x0000000000000400UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_3_MASK 0x0000000000000800UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_4_MASK 0x0000000000001000UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_5_MASK 0x0000000000002000UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_6_MASK 0x0000000000004000UL
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_7_MASK 0x0000000000008000UL
-
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_SHFT 0
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_1_SHFT 1
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_2_SHFT 2
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_3_SHFT 3
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_4_SHFT 4
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_5_SHFT 5
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_6_SHFT 6
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_7_SHFT 7
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_0_SHFT 8
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_1_SHFT 9
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_2_SHFT 10
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_3_SHFT 11
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_4_SHFT 12
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_5_SHFT 13
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_6_SHFT 14
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_7_SHFT 15
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_MASK 0x0000000000000001UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_1_MASK 0x0000000000000002UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_2_MASK 0x0000000000000004UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_3_MASK 0x0000000000000008UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_4_MASK 0x0000000000000010UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_5_MASK 0x0000000000000020UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_6_MASK 0x0000000000000040UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_7_MASK 0x0000000000000080UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_0_MASK 0x0000000000000100UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_1_MASK 0x0000000000000200UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_2_MASK 0x0000000000000400UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_3_MASK 0x0000000000000800UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_4_MASK 0x0000000000001000UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_5_MASK 0x0000000000002000UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_6_MASK 0x0000000000004000UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_TIMEOUT_7_MASK 0x0000000000008000UL
-
-
-union uvh_lb_bau_intd_software_acknowledge_u {
-       unsigned long   v;
-       struct uv2h_lb_bau_intd_software_acknowledge_s {
-               unsigned long   pending_0:1;                    /* RW */
-               unsigned long   pending_1:1;                    /* RW */
-               unsigned long   pending_2:1;                    /* RW */
-               unsigned long   pending_3:1;                    /* RW */
-               unsigned long   pending_4:1;                    /* RW */
-               unsigned long   pending_5:1;                    /* RW */
-               unsigned long   pending_6:1;                    /* RW */
-               unsigned long   pending_7:1;                    /* RW */
-               unsigned long   timeout_0:1;                    /* RW */
-               unsigned long   timeout_1:1;                    /* RW */
-               unsigned long   timeout_2:1;                    /* RW */
-               unsigned long   timeout_3:1;                    /* RW */
-               unsigned long   timeout_4:1;                    /* RW */
-               unsigned long   timeout_5:1;                    /* RW */
-               unsigned long   timeout_6:1;                    /* RW */
-               unsigned long   timeout_7:1;                    /* RW */
-               unsigned long   rsvd_16_63:48;
-       } s2;
-       struct uv3h_lb_bau_intd_software_acknowledge_s {
-               unsigned long   pending_0:1;                    /* RW */
-               unsigned long   pending_1:1;                    /* RW */
-               unsigned long   pending_2:1;                    /* RW */
-               unsigned long   pending_3:1;                    /* RW */
-               unsigned long   pending_4:1;                    /* RW */
-               unsigned long   pending_5:1;                    /* RW */
-               unsigned long   pending_6:1;                    /* RW */
-               unsigned long   pending_7:1;                    /* RW */
-               unsigned long   timeout_0:1;                    /* RW */
-               unsigned long   timeout_1:1;                    /* RW */
-               unsigned long   timeout_2:1;                    /* RW */
-               unsigned long   timeout_3:1;                    /* RW */
-               unsigned long   timeout_4:1;                    /* RW */
-               unsigned long   timeout_5:1;                    /* RW */
-               unsigned long   timeout_6:1;                    /* RW */
-               unsigned long   timeout_7:1;                    /* RW */
-               unsigned long   rsvd_16_63:48;
+       /* UV3 unique struct */
+       struct uv3h_int_cmpb_s {
+               unsigned long   real_time_cmpb:56;              /* RW */
+               unsigned long   rsvd_56_63:8;
        } s3;
-};
-
-/* ========================================================================= */
-/*                UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS                 */
-/* ========================================================================= */
-#define UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS 0x320088UL
-#define UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS 0x320088UL
-#define UV4H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS uv_undefined("UV4H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS")
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS (                   \
-       is_uv2_hub() ? UV2H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS :    \
-       is_uv3_hub() ? UV3H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS :    \
-       /*is_uv4_hub*/ UV4H_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS)
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS_32 0xa70
 
-
-/* ========================================================================= */
-/*                         UVH_LB_BAU_MISC_CONTROL                           */
-/* ========================================================================= */
-#define UV2H_LB_BAU_MISC_CONTROL 0x320170UL
-#define UV3H_LB_BAU_MISC_CONTROL 0x320170UL
-#define UV4H_LB_BAU_MISC_CONTROL 0xc8170UL
-#define UVH_LB_BAU_MISC_CONTROL (                                      \
-       is_uv2_hub() ? UV2H_LB_BAU_MISC_CONTROL :                       \
-       is_uv3_hub() ? UV3H_LB_BAU_MISC_CONTROL :                       \
-       /*is_uv4_hub*/ UV4H_LB_BAU_MISC_CONTROL)
-
-#define UV2H_LB_BAU_MISC_CONTROL_32 0xa10
-#define UV3H_LB_BAU_MISC_CONTROL_32 0xa10
-#define UV4H_LB_BAU_MISC_CONTROL_32 0xa18
-#define UVH_LB_BAU_MISC_CONTROL_32 (                                   \
-       is_uv2_hub() ? UV2H_LB_BAU_MISC_CONTROL_32 :                    \
-       is_uv3_hub() ? UV3H_LB_BAU_MISC_CONTROL_32 :                    \
-       /*is_uv4_hub*/ UV4H_LB_BAU_MISC_CONTROL_32)
-
-#define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT   0
-#define UVH_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT         8
-#define UVH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT   9
-#define UVH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT    10
-#define UVH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
-#define UVH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
-#define UVH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
-#define UVH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
-#define UVH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
-#define UVH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
-#define UVH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
-#define UVH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
-#define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
-#define UVH_LB_BAU_MISC_CONTROL_FUN_SHFT               48
-#define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK   0x00000000000000ffUL
-#define UVH_LB_BAU_MISC_CONTROL_APIC_MODE_MASK         0x0000000000000100UL
-#define UVH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK   0x0000000000000200UL
-#define UVH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK    0x0000000000000400UL
-#define UVH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
-#define UVH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
-#define UVH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
-#define UVH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
-#define UVH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
-#define UVH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
-#define UVH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
-#define UVH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
-#define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
-#define UVH_LB_BAU_MISC_CONTROL_FUN_MASK               0xffff000000000000UL
-
-#define UVXH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT  0
-#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT                8
-#define UVXH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT  9
-#define UVXH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT   10
-#define UVXH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
-#define UVXH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
-#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
-#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
-#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
-#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
-#define UVXH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
-#define UVXH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
-#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
-#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29
-#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30
-#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31
-#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32
-#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33
-#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34
-#define UVXH_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35
-#define UVXH_LB_BAU_MISC_CONTROL_FUN_SHFT              48
-#define UVXH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK  0x00000000000000ffUL
-#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_MASK                0x0000000000000100UL
-#define UVXH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK  0x0000000000000200UL
-#define UVXH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK   0x0000000000000400UL
-#define UVXH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
-#define UVXH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
-#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
-#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
-#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
-#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
-#define UVXH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
-#define UVXH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
-#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
-#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_MASK 0x0000000020000000UL
-#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL
-#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_MASK 0x0000000080000000UL
-#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_MASK 0x0000000100000000UL
-#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_MASK 0x0000000200000000UL
-#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_MASK 0x0000000400000000UL
-#define UVXH_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
-#define UVXH_LB_BAU_MISC_CONTROL_FUN_MASK              0xffff000000000000UL
-
-#define UV2H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT  0
-#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT                8
-#define UV2H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT  9
-#define UV2H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT   10
-#define UV2H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
-#define UV2H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15
-#define UV2H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
-#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
-#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
-#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
-#define UV2H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
-#define UV2H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29
-#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30
-#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33
-#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34
-#define UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35
-#define UV2H_LB_BAU_MISC_CONTROL_FUN_SHFT              48
-#define UV2H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK  0x00000000000000ffUL
-#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK                0x0000000000000100UL
-#define UV2H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK  0x0000000000000200UL
-#define UV2H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK   0x0000000000000400UL
-#define UV2H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
-#define UV2H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL
-#define UV2H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
-#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
-#define UV2H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
-#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
-#define UV2H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
-#define UV2H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_MASK 0x0000000020000000UL
-#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL
-#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_MASK 0x0000000080000000UL
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_MASK 0x0000000100000000UL
-#define UV2H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_MASK 0x0000000200000000UL
-#define UV2H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_MASK 0x0000000400000000UL
-#define UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
-#define UV2H_LB_BAU_MISC_CONTROL_FUN_MASK              0xffff000000000000UL
-
-#define UV3H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT  0
-#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT                8
-#define UV3H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT  9
-#define UV3H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT   10
-#define UV3H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
-#define UV3H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15
-#define UV3H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
-#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
-#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
-#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
-#define UV3H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
-#define UV3H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29
-#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30
-#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33
-#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34
-#define UV3H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35
-#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_QUIESCE_MSGS_TO_QPI_SHFT 36
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_PREFETCH_HINT_SHFT 37
-#define UV3H_LB_BAU_MISC_CONTROL_THREAD_KILL_TIMEBASE_SHFT 38
-#define UV3H_LB_BAU_MISC_CONTROL_FUN_SHFT              48
-#define UV3H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK  0x00000000000000ffUL
-#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK                0x0000000000000100UL
-#define UV3H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK  0x0000000000000200UL
-#define UV3H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK   0x0000000000000400UL
-#define UV3H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
-#define UV3H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL
-#define UV3H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
-#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
-#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
-#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
-#define UV3H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_MASK 0x0000000020000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_MASK 0x0000000080000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_MASK 0x0000000100000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_MASK 0x0000000200000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_MASK 0x0000000400000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_QUIESCE_MSGS_TO_QPI_MASK 0x0000001000000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_PREFETCH_HINT_MASK 0x0000002000000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_THREAD_KILL_TIMEBASE_MASK 0x00003fc000000000UL
-#define UV3H_LB_BAU_MISC_CONTROL_FUN_MASK              0xffff000000000000UL
-
-#define UV4H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT  0
-#define UV4H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT                8
-#define UV4H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT  9
-#define UV4H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT   10
-#define UV4H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
-#define UV4H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
-#define UV4H_LB_BAU_MISC_CONTROL_RESERVED_15_19_SHFT   15
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
-#define UV4H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
-#define UV4H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
-#define UV4H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
-#define UV4H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
-#define UV4H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29
-#define UV4H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30
-#define UV4H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33
-#define UV4H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34
-#define UV4H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35
-#define UV4H_LB_BAU_MISC_CONTROL_SUPPRESS_QUIESCE_MSGS_TO_QPI_SHFT 36
-#define UV4H_LB_BAU_MISC_CONTROL_RESERVED_37_SHFT      37
-#define UV4H_LB_BAU_MISC_CONTROL_THREAD_KILL_TIMEBASE_SHFT 38
-#define UV4H_LB_BAU_MISC_CONTROL_ADDRESS_INTERLEAVE_SELECT_SHFT 46
-#define UV4H_LB_BAU_MISC_CONTROL_FUN_SHFT              48
-#define UV4H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK  0x00000000000000ffUL
-#define UV4H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK                0x0000000000000100UL
-#define UV4H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK  0x0000000000000200UL
-#define UV4H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK   0x0000000000000400UL
-#define UV4H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
-#define UV4H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
-#define UV4H_LB_BAU_MISC_CONTROL_RESERVED_15_19_MASK   0x00000000000f8000UL
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
-#define UV4H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
-#define UV4H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
-#define UV4H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
-#define UV4H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_MASK 0x0000000020000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_MASK 0x0000000080000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_MASK 0x0000000100000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_MASK 0x0000000200000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_MASK 0x0000000400000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_SUPPRESS_QUIESCE_MSGS_TO_QPI_MASK 0x0000001000000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_RESERVED_37_MASK      0x0000002000000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_THREAD_KILL_TIMEBASE_MASK 0x00003fc000000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_ADDRESS_INTERLEAVE_SELECT_MASK 0x0000400000000000UL
-#define UV4H_LB_BAU_MISC_CONTROL_FUN_MASK              0xffff000000000000UL
-
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK        \
-       uv_undefined("UV4H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK")
-#define UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK (       \
-       is_uv2_hub() ? UV2H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK : \
-       is_uv3_hub() ? UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK : \
-       /*is_uv4_hub*/ UV4H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK)
-#define UV4H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT        \
-       uv_undefined("UV4H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT")
-#define UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT (       \
-       is_uv2_hub() ? UV2H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT : \
-       is_uv3_hub() ? UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT : \
-       /*is_uv4_hub*/ UV4H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT)
-#define UV4H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK     \
-       uv_undefined("UV4H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK")
-#define UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK (    \
-       is_uv2_hub() ? UV2H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK : \
-       is_uv3_hub() ? UV3H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK : \
-       /*is_uv4_hub*/ UV4H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK)
-#define UV4H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT     \
-       uv_undefined("UV4H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT")
-#define UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT (    \
-       is_uv2_hub() ? UV2H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT : \
-       is_uv3_hub() ? UV3H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT : \
-       /*is_uv4_hub*/ UV4H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT)
-
-union uvh_lb_bau_misc_control_u {
-       unsigned long   v;
-       struct uvh_lb_bau_misc_control_s {
-               unsigned long   rejection_delay:8;              /* RW */
-               unsigned long   apic_mode:1;                    /* RW */
-               unsigned long   force_broadcast:1;              /* RW */
-               unsigned long   force_lock_nop:1;               /* RW */
-               unsigned long   qpi_agent_presence_vector:3;    /* RW */
-               unsigned long   descriptor_fetch_mode:1;        /* RW */
-               unsigned long   rsvd_15_19:5;
-               unsigned long   enable_dual_mapping_mode:1;     /* RW */
-               unsigned long   vga_io_port_decode_enable:1;    /* RW */
-               unsigned long   vga_io_port_16_bit_decode:1;    /* RW */
-               unsigned long   suppress_dest_registration:1;   /* RW */
-               unsigned long   programmed_initial_priority:3;  /* RW */
-               unsigned long   use_incoming_priority:1;        /* RW */
-               unsigned long   enable_programmed_initial_priority:1;/* RW */
-               unsigned long   rsvd_29_47:19;
-               unsigned long   fun:16;                         /* RW */
-       } s;
-       struct uvxh_lb_bau_misc_control_s {
-               unsigned long   rejection_delay:8;              /* RW */
-               unsigned long   apic_mode:1;                    /* RW */
-               unsigned long   force_broadcast:1;              /* RW */
-               unsigned long   force_lock_nop:1;               /* RW */
-               unsigned long   qpi_agent_presence_vector:3;    /* RW */
-               unsigned long   descriptor_fetch_mode:1;        /* RW */
-               unsigned long   rsvd_15_19:5;
-               unsigned long   enable_dual_mapping_mode:1;     /* RW */
-               unsigned long   vga_io_port_decode_enable:1;    /* RW */
-               unsigned long   vga_io_port_16_bit_decode:1;    /* RW */
-               unsigned long   suppress_dest_registration:1;   /* RW */
-               unsigned long   programmed_initial_priority:3;  /* RW */
-               unsigned long   use_incoming_priority:1;        /* RW */
-               unsigned long   enable_programmed_initial_priority:1;/* RW */
-               unsigned long   enable_automatic_apic_mode_selection:1;/* RW */
-               unsigned long   apic_mode_status:1;             /* RO */
-               unsigned long   suppress_interrupts_to_self:1;  /* RW */
-               unsigned long   enable_lock_based_system_flush:1;/* RW */
-               unsigned long   enable_extended_sb_status:1;    /* RW */
-               unsigned long   suppress_int_prio_udt_to_self:1;/* RW */
-               unsigned long   use_legacy_descriptor_formats:1;/* RW */
-               unsigned long   rsvd_36_47:12;
-               unsigned long   fun:16;                         /* RW */
-       } sx;
-       struct uv2h_lb_bau_misc_control_s {
-               unsigned long   rejection_delay:8;              /* RW */
-               unsigned long   apic_mode:1;                    /* RW */
-               unsigned long   force_broadcast:1;              /* RW */
-               unsigned long   force_lock_nop:1;               /* RW */
-               unsigned long   qpi_agent_presence_vector:3;    /* RW */
-               unsigned long   descriptor_fetch_mode:1;        /* RW */
-               unsigned long   enable_intd_soft_ack_mode:1;    /* RW */
-               unsigned long   intd_soft_ack_timeout_period:4; /* RW */
-               unsigned long   enable_dual_mapping_mode:1;     /* RW */
-               unsigned long   vga_io_port_decode_enable:1;    /* RW */
-               unsigned long   vga_io_port_16_bit_decode:1;    /* RW */
-               unsigned long   suppress_dest_registration:1;   /* RW */
-               unsigned long   programmed_initial_priority:3;  /* RW */
-               unsigned long   use_incoming_priority:1;        /* RW */
-               unsigned long   enable_programmed_initial_priority:1;/* RW */
-               unsigned long   enable_automatic_apic_mode_selection:1;/* RW */
-               unsigned long   apic_mode_status:1;             /* RO */
-               unsigned long   suppress_interrupts_to_self:1;  /* RW */
-               unsigned long   enable_lock_based_system_flush:1;/* RW */
-               unsigned long   enable_extended_sb_status:1;    /* RW */
-               unsigned long   suppress_int_prio_udt_to_self:1;/* RW */
-               unsigned long   use_legacy_descriptor_formats:1;/* RW */
-               unsigned long   rsvd_36_47:12;
-               unsigned long   fun:16;                         /* RW */
+       /* UV2 unique struct */
+       struct uv2h_int_cmpb_s {
+               unsigned long   real_time_cmpb:56;              /* RW */
+               unsigned long   rsvd_56_63:8;
        } s2;
-       struct uv3h_lb_bau_misc_control_s {
-               unsigned long   rejection_delay:8;              /* RW */
-               unsigned long   apic_mode:1;                    /* RW */
-               unsigned long   force_broadcast:1;              /* RW */
-               unsigned long   force_lock_nop:1;               /* RW */
-               unsigned long   qpi_agent_presence_vector:3;    /* RW */
-               unsigned long   descriptor_fetch_mode:1;        /* RW */
-               unsigned long   enable_intd_soft_ack_mode:1;    /* RW */
-               unsigned long   intd_soft_ack_timeout_period:4; /* RW */
-               unsigned long   enable_dual_mapping_mode:1;     /* RW */
-               unsigned long   vga_io_port_decode_enable:1;    /* RW */
-               unsigned long   vga_io_port_16_bit_decode:1;    /* RW */
-               unsigned long   suppress_dest_registration:1;   /* RW */
-               unsigned long   programmed_initial_priority:3;  /* RW */
-               unsigned long   use_incoming_priority:1;        /* RW */
-               unsigned long   enable_programmed_initial_priority:1;/* RW */
-               unsigned long   enable_automatic_apic_mode_selection:1;/* RW */
-               unsigned long   apic_mode_status:1;             /* RO */
-               unsigned long   suppress_interrupts_to_self:1;  /* RW */
-               unsigned long   enable_lock_based_system_flush:1;/* RW */
-               unsigned long   enable_extended_sb_status:1;    /* RW */
-               unsigned long   suppress_int_prio_udt_to_self:1;/* RW */
-               unsigned long   use_legacy_descriptor_formats:1;/* RW */
-               unsigned long   suppress_quiesce_msgs_to_qpi:1; /* RW */
-               unsigned long   enable_intd_prefetch_hint:1;    /* RW */
-               unsigned long   thread_kill_timebase:8;         /* RW */
-               unsigned long   rsvd_46_47:2;
-               unsigned long   fun:16;                         /* RW */
-       } s3;
-       struct uv4h_lb_bau_misc_control_s {
-               unsigned long   rejection_delay:8;              /* RW */
-               unsigned long   apic_mode:1;                    /* RW */
-               unsigned long   force_broadcast:1;              /* RW */
-               unsigned long   force_lock_nop:1;               /* RW */
-               unsigned long   qpi_agent_presence_vector:3;    /* RW */
-               unsigned long   descriptor_fetch_mode:1;        /* RW */
-               unsigned long   rsvd_15_19:5;
-               unsigned long   enable_dual_mapping_mode:1;     /* RW */
-               unsigned long   vga_io_port_decode_enable:1;    /* RW */
-               unsigned long   vga_io_port_16_bit_decode:1;    /* RW */
-               unsigned long   suppress_dest_registration:1;   /* RW */
-               unsigned long   programmed_initial_priority:3;  /* RW */
-               unsigned long   use_incoming_priority:1;        /* RW */
-               unsigned long   enable_programmed_initial_priority:1;/* RW */
-               unsigned long   enable_automatic_apic_mode_selection:1;/* RW */
-               unsigned long   apic_mode_status:1;             /* RO */
-               unsigned long   suppress_interrupts_to_self:1;  /* RW */
-               unsigned long   enable_lock_based_system_flush:1;/* RW */
-               unsigned long   enable_extended_sb_status:1;    /* RW */
-               unsigned long   suppress_int_prio_udt_to_self:1;/* RW */
-               unsigned long   use_legacy_descriptor_formats:1;/* RW */
-               unsigned long   suppress_quiesce_msgs_to_qpi:1; /* RW */
-               unsigned long   rsvd_37:1;
-               unsigned long   thread_kill_timebase:8;         /* RW */
-               unsigned long   address_interleave_select:1;    /* RW */
-               unsigned long   rsvd_47:1;
-               unsigned long   fun:16;                         /* RW */
-       } s4;
 };
 
 /* ========================================================================= */
-/*                     UVH_LB_BAU_SB_ACTIVATION_CONTROL                      */
+/*                               UVH_IPI_INT                                 */
 /* ========================================================================= */
-#define UV2H_LB_BAU_SB_ACTIVATION_CONTROL 0x320020UL
-#define UV3H_LB_BAU_SB_ACTIVATION_CONTROL 0x320020UL
-#define UV4H_LB_BAU_SB_ACTIVATION_CONTROL 0xc8020UL
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL (                             \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_ACTIVATION_CONTROL :              \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_ACTIVATION_CONTROL :              \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_ACTIVATION_CONTROL)
-
-#define UV2H_LB_BAU_SB_ACTIVATION_CONTROL_32 0x9a8
-#define UV3H_LB_BAU_SB_ACTIVATION_CONTROL_32 0x9a8
-#define UV4H_LB_BAU_SB_ACTIVATION_CONTROL_32 0x9c8
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32 (                          \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_ACTIVATION_CONTROL_32 :           \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_ACTIVATION_CONTROL_32 :           \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_ACTIVATION_CONTROL_32)
-
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_SHFT    0
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT     62
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INIT_SHFT     63
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_MASK    0x000000000000003fUL
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_MASK     0x4000000000000000UL
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INIT_MASK     0x8000000000000000UL
-
-
-union uvh_lb_bau_sb_activation_control_u {
-       unsigned long   v;
-       struct uvh_lb_bau_sb_activation_control_s {
-               unsigned long   index:6;                        /* RW */
-               unsigned long   rsvd_6_61:56;
-               unsigned long   push:1;                         /* WP */
-               unsigned long   init:1;                         /* WP */
-       } s;
-};
+#define UVH_IPI_INT 0x60500UL
 
-/* ========================================================================= */
-/*                    UVH_LB_BAU_SB_ACTIVATION_STATUS_0                      */
-/* ========================================================================= */
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_0 0x320030UL
-#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_0 0x320030UL
-#define UV4H_LB_BAU_SB_ACTIVATION_STATUS_0 0xc8030UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0 (                            \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_ACTIVATION_STATUS_0 :             \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_ACTIVATION_STATUS_0 :             \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_ACTIVATION_STATUS_0)
-
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x9b0
-#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x9b0
-#define UV4H_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x9d0
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32 (                         \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_ACTIVATION_STATUS_0_32 :          \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_ACTIVATION_STATUS_0_32 :          \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_ACTIVATION_STATUS_0_32)
-
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_SHFT  0
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_MASK  0xffffffffffffffffUL
-
-
-union uvh_lb_bau_sb_activation_status_0_u {
-       unsigned long   v;
-       struct uvh_lb_bau_sb_activation_status_0_s {
-               unsigned long   status:64;                      /* RW */
-       } s;
-};
+/* UVH common defines*/
+#define UVH_IPI_INT_VECTOR_SHFT                                0
+#define UVH_IPI_INT_VECTOR_MASK                                0x00000000000000ffUL
+#define UVH_IPI_INT_DELIVERY_MODE_SHFT                 8
+#define UVH_IPI_INT_DELIVERY_MODE_MASK                 0x0000000000000700UL
+#define UVH_IPI_INT_DESTMODE_SHFT                      11
+#define UVH_IPI_INT_DESTMODE_MASK                      0x0000000000000800UL
+#define UVH_IPI_INT_APIC_ID_SHFT                       16
+#define UVH_IPI_INT_APIC_ID_MASK                       0x0000ffffffff0000UL
+#define UVH_IPI_INT_SEND_SHFT                          63
+#define UVH_IPI_INT_SEND_MASK                          0x8000000000000000UL
 
-/* ========================================================================= */
-/*                    UVH_LB_BAU_SB_ACTIVATION_STATUS_1                      */
-/* ========================================================================= */
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_1 0x320040UL
-#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_1 0x320040UL
-#define UV4H_LB_BAU_SB_ACTIVATION_STATUS_1 0xc8040UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1 (                            \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_ACTIVATION_STATUS_1 :             \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_ACTIVATION_STATUS_1 :             \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_ACTIVATION_STATUS_1)
-
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x9b8
-#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x9b8
-#define UV4H_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x9d8
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32 (                         \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_ACTIVATION_STATUS_1_32 :          \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_ACTIVATION_STATUS_1_32 :          \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_ACTIVATION_STATUS_1_32)
-
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_SHFT  0
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_MASK  0xffffffffffffffffUL
-
-
-union uvh_lb_bau_sb_activation_status_1_u {
+
+union uvh_ipi_int_u {
        unsigned long   v;
-       struct uvh_lb_bau_sb_activation_status_1_s {
-               unsigned long   status:64;                      /* RW */
+
+       /* UVH common struct */
+       struct uvh_ipi_int_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   delivery_mode:3;                /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   rsvd_12_15:4;
+               unsigned long   apic_id:32;                     /* RW */
+               unsigned long   rsvd_48_62:15;
+               unsigned long   send:1;                         /* WP */
        } s;
-};
 
-/* ========================================================================= */
-/*                      UVH_LB_BAU_SB_DESCRIPTOR_BASE                        */
-/* ========================================================================= */
-#define UV2H_LB_BAU_SB_DESCRIPTOR_BASE 0x320010UL
-#define UV3H_LB_BAU_SB_DESCRIPTOR_BASE 0x320010UL
-#define UV4H_LB_BAU_SB_DESCRIPTOR_BASE 0xc8010UL
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE (                                        \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_DESCRIPTOR_BASE :                 \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_DESCRIPTOR_BASE :                 \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_DESCRIPTOR_BASE)
-
-#define UV2H_LB_BAU_SB_DESCRIPTOR_BASE_32 0x9a0
-#define UV3H_LB_BAU_SB_DESCRIPTOR_BASE_32 0x9a0
-#define UV4H_LB_BAU_SB_DESCRIPTOR_BASE_32 0x9c0
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32 (                             \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_DESCRIPTOR_BASE_32 :              \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_DESCRIPTOR_BASE_32 :              \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_DESCRIPTOR_BASE_32)
-
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_SHFT        12
-
-#define UV2H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT    49
-#define UV2H_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_MASK 0x000007fffffff000UL
-#define UV2H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK    0x7ffe000000000000UL
-
-#define UV3H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT    49
-#define UV3H_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_MASK 0x000007fffffff000UL
-#define UV3H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK    0x7ffe000000000000UL
-
-#define UV4H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT    49
-#define UV4H_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_MASK 0x00003ffffffff000UL
-#define UV4H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK    0x7ffe000000000000UL
-
-#define UV4AH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT   53
-#define UV4AH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_MASK 0x000ffffffffff000UL
-#define UV4AH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK   0xffe0000000000000UL
-
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT (                   \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT :    \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT :    \
-       is_uv4a_hub() ? UV4AH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT :  \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT)
-
-#define UVH_LB_BAU_SB_DESCRIPTOR_PAGE_ADDRESS_MASK (                   \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_DESCRIPTOR_PAGE_ADDRESS_MASK :    \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_DESCRIPTOR_PAGE_ADDRESS_MASK :    \
-       is_uv4a_hub() ? UV4AH_LB_BAU_SB_DESCRIPTOR_PAGE_ADDRESS_MASK :  \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_DESCRIPTOR_PAGE_ADDRESS_MASK)
-
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK (                   \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK :    \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK :    \
-       is_uv4a_hub() ? UV4AH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK :  \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_MASK)
+       /* UV5 unique struct */
+       struct uv5h_ipi_int_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   delivery_mode:3;                /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   rsvd_12_15:4;
+               unsigned long   apic_id:32;                     /* RW */
+               unsigned long   rsvd_48_62:15;
+               unsigned long   send:1;                         /* WP */
+       } s5;
+
+       /* UV4 unique struct */
+       struct uv4h_ipi_int_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   delivery_mode:3;                /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   rsvd_12_15:4;
+               unsigned long   apic_id:32;                     /* RW */
+               unsigned long   rsvd_48_62:15;
+               unsigned long   send:1;                         /* WP */
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_ipi_int_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   delivery_mode:3;                /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   rsvd_12_15:4;
+               unsigned long   apic_id:32;                     /* RW */
+               unsigned long   rsvd_48_62:15;
+               unsigned long   send:1;                         /* WP */
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_ipi_int_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   delivery_mode:3;                /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   rsvd_12_15:4;
+               unsigned long   apic_id:32;                     /* RW */
+               unsigned long   rsvd_48_62:15;
+               unsigned long   send:1;                         /* WP */
+       } s2;
+};
 
 /* ========================================================================= */
 /*                               UVH_NODE_ID                                 */
 /* ========================================================================= */
 #define UVH_NODE_ID 0x0UL
-#define UV2H_NODE_ID 0x0UL
-#define UV3H_NODE_ID 0x0UL
-#define UV4H_NODE_ID 0x0UL
 
+/* UVH common defines*/
 #define UVH_NODE_ID_FORCE1_SHFT                                0
-#define UVH_NODE_ID_MANUFACTURER_SHFT                  1
-#define UVH_NODE_ID_PART_NUMBER_SHFT                   12
-#define UVH_NODE_ID_REVISION_SHFT                      28
-#define UVH_NODE_ID_NODE_ID_SHFT                       32
 #define UVH_NODE_ID_FORCE1_MASK                                0x0000000000000001UL
+#define UVH_NODE_ID_MANUFACTURER_SHFT                  1
 #define UVH_NODE_ID_MANUFACTURER_MASK                  0x0000000000000ffeUL
+#define UVH_NODE_ID_PART_NUMBER_SHFT                   12
 #define UVH_NODE_ID_PART_NUMBER_MASK                   0x000000000ffff000UL
+#define UVH_NODE_ID_REVISION_SHFT                      28
 #define UVH_NODE_ID_REVISION_MASK                      0x00000000f0000000UL
-#define UVH_NODE_ID_NODE_ID_MASK                       0x00007fff00000000UL
+#define UVH_NODE_ID_NODE_ID_SHFT                       32
+#define UVH_NODE_ID_NI_PORT_SHFT                       57
 
-#define UVXH_NODE_ID_FORCE1_SHFT                       0
-#define UVXH_NODE_ID_MANUFACTURER_SHFT                 1
-#define UVXH_NODE_ID_PART_NUMBER_SHFT                  12
-#define UVXH_NODE_ID_REVISION_SHFT                     28
-#define UVXH_NODE_ID_NODE_ID_SHFT                      32
-#define UVXH_NODE_ID_NODES_PER_BIT_SHFT                        50
-#define UVXH_NODE_ID_NI_PORT_SHFT                      57
-#define UVXH_NODE_ID_FORCE1_MASK                       0x0000000000000001UL
-#define UVXH_NODE_ID_MANUFACTURER_MASK                 0x0000000000000ffeUL
-#define UVXH_NODE_ID_PART_NUMBER_MASK                  0x000000000ffff000UL
-#define UVXH_NODE_ID_REVISION_MASK                     0x00000000f0000000UL
+/* UVXH common defines */
 #define UVXH_NODE_ID_NODE_ID_MASK                      0x00007fff00000000UL
+#define UVXH_NODE_ID_NODES_PER_BIT_SHFT                        50
 #define UVXH_NODE_ID_NODES_PER_BIT_MASK                        0x01fc000000000000UL
 #define UVXH_NODE_ID_NI_PORT_MASK                      0x3e00000000000000UL
 
-#define UV2H_NODE_ID_FORCE1_SHFT                       0
-#define UV2H_NODE_ID_MANUFACTURER_SHFT                 1
-#define UV2H_NODE_ID_PART_NUMBER_SHFT                  12
-#define UV2H_NODE_ID_REVISION_SHFT                     28
-#define UV2H_NODE_ID_NODE_ID_SHFT                      32
-#define UV2H_NODE_ID_NODES_PER_BIT_SHFT                        50
-#define UV2H_NODE_ID_NI_PORT_SHFT                      57
-#define UV2H_NODE_ID_FORCE1_MASK                       0x0000000000000001UL
-#define UV2H_NODE_ID_MANUFACTURER_MASK                 0x0000000000000ffeUL
-#define UV2H_NODE_ID_PART_NUMBER_MASK                  0x000000000ffff000UL
-#define UV2H_NODE_ID_REVISION_MASK                     0x00000000f0000000UL
-#define UV2H_NODE_ID_NODE_ID_MASK                      0x00007fff00000000UL
-#define UV2H_NODE_ID_NODES_PER_BIT_MASK                        0x01fc000000000000UL
-#define UV2H_NODE_ID_NI_PORT_MASK                      0x3e00000000000000UL
-
-#define UV3H_NODE_ID_FORCE1_SHFT                       0
-#define UV3H_NODE_ID_MANUFACTURER_SHFT                 1
-#define UV3H_NODE_ID_PART_NUMBER_SHFT                  12
-#define UV3H_NODE_ID_REVISION_SHFT                     28
-#define UV3H_NODE_ID_NODE_ID_SHFT                      32
-#define UV3H_NODE_ID_ROUTER_SELECT_SHFT                        48
-#define UV3H_NODE_ID_RESERVED_2_SHFT                   49
-#define UV3H_NODE_ID_NODES_PER_BIT_SHFT                        50
-#define UV3H_NODE_ID_NI_PORT_SHFT                      57
-#define UV3H_NODE_ID_FORCE1_MASK                       0x0000000000000001UL
-#define UV3H_NODE_ID_MANUFACTURER_MASK                 0x0000000000000ffeUL
-#define UV3H_NODE_ID_PART_NUMBER_MASK                  0x000000000ffff000UL
-#define UV3H_NODE_ID_REVISION_MASK                     0x00000000f0000000UL
-#define UV3H_NODE_ID_NODE_ID_MASK                      0x00007fff00000000UL
-#define UV3H_NODE_ID_ROUTER_SELECT_MASK                        0x0001000000000000UL
-#define UV3H_NODE_ID_RESERVED_2_MASK                   0x0002000000000000UL
-#define UV3H_NODE_ID_NODES_PER_BIT_MASK                        0x01fc000000000000UL
-#define UV3H_NODE_ID_NI_PORT_MASK                      0x3e00000000000000UL
-
-#define UV4H_NODE_ID_FORCE1_SHFT                       0
-#define UV4H_NODE_ID_MANUFACTURER_SHFT                 1
-#define UV4H_NODE_ID_PART_NUMBER_SHFT                  12
-#define UV4H_NODE_ID_REVISION_SHFT                     28
-#define UV4H_NODE_ID_NODE_ID_SHFT                      32
+/* UVYH common defines */
+#define UVYH_NODE_ID_NODE_ID_MASK                      0x0000007f00000000UL
+#define UVYH_NODE_ID_NI_PORT_MASK                      0x7e00000000000000UL
+
+/* UV4 unique defines */
 #define UV4H_NODE_ID_ROUTER_SELECT_SHFT                        48
-#define UV4H_NODE_ID_RESERVED_2_SHFT                   49
-#define UV4H_NODE_ID_NODES_PER_BIT_SHFT                        50
-#define UV4H_NODE_ID_NI_PORT_SHFT                      57
-#define UV4H_NODE_ID_FORCE1_MASK                       0x0000000000000001UL
-#define UV4H_NODE_ID_MANUFACTURER_MASK                 0x0000000000000ffeUL
-#define UV4H_NODE_ID_PART_NUMBER_MASK                  0x000000000ffff000UL
-#define UV4H_NODE_ID_REVISION_MASK                     0x00000000f0000000UL
-#define UV4H_NODE_ID_NODE_ID_MASK                      0x00007fff00000000UL
 #define UV4H_NODE_ID_ROUTER_SELECT_MASK                        0x0001000000000000UL
+#define UV4H_NODE_ID_RESERVED_2_SHFT                   49
 #define UV4H_NODE_ID_RESERVED_2_MASK                   0x0002000000000000UL
-#define UV4H_NODE_ID_NODES_PER_BIT_MASK                        0x01fc000000000000UL
-#define UV4H_NODE_ID_NI_PORT_MASK                      0x3e00000000000000UL
+
+/* UV3 unique defines */
+#define UV3H_NODE_ID_ROUTER_SELECT_SHFT                        48
+#define UV3H_NODE_ID_ROUTER_SELECT_MASK                        0x0001000000000000UL
+#define UV3H_NODE_ID_RESERVED_2_SHFT                   49
+#define UV3H_NODE_ID_RESERVED_2_MASK                   0x0002000000000000UL
 
 
 union uvh_node_id_u {
        unsigned long   v;
+
+       /* UVH common struct */
        struct uvh_node_id_s {
                unsigned long   force1:1;                       /* RO */
                unsigned long   manufacturer:11;                /* RO */
                unsigned long   part_number:16;                 /* RO */
                unsigned long   revision:4;                     /* RO */
-               unsigned long   node_id:15;                     /* RW */
-               unsigned long   rsvd_47_63:17;
+               unsigned long   rsvd_32_63:32;
        } s;
+
+       /* UVXH common struct */
        struct uvxh_node_id_s {
                unsigned long   force1:1;                       /* RO */
                unsigned long   manufacturer:11;                /* RO */
@@ -2444,17 +2841,47 @@ union uvh_node_id_u {
                unsigned long   ni_port:5;                      /* RO */
                unsigned long   rsvd_62_63:2;
        } sx;
-       struct uv2h_node_id_s {
+
+       /* UVYH common struct */
+       struct uvyh_node_id_s {
+               unsigned long   force1:1;                       /* RO */
+               unsigned long   manufacturer:11;                /* RO */
+               unsigned long   part_number:16;                 /* RO */
+               unsigned long   revision:4;                     /* RO */
+               unsigned long   node_id:7;                      /* RW */
+               unsigned long   rsvd_39_56:18;
+               unsigned long   ni_port:6;                      /* RO */
+               unsigned long   rsvd_63:1;
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_node_id_s {
+               unsigned long   force1:1;                       /* RO */
+               unsigned long   manufacturer:11;                /* RO */
+               unsigned long   part_number:16;                 /* RO */
+               unsigned long   revision:4;                     /* RO */
+               unsigned long   node_id:7;                      /* RW */
+               unsigned long   rsvd_39_56:18;
+               unsigned long   ni_port:6;                      /* RO */
+               unsigned long   rsvd_63:1;
+       } s5;
+
+       /* UV4 unique struct */
+       struct uv4h_node_id_s {
                unsigned long   force1:1;                       /* RO */
                unsigned long   manufacturer:11;                /* RO */
                unsigned long   part_number:16;                 /* RO */
                unsigned long   revision:4;                     /* RO */
                unsigned long   node_id:15;                     /* RW */
-               unsigned long   rsvd_47_49:3;
+               unsigned long   rsvd_47:1;
+               unsigned long   router_select:1;                /* RO */
+               unsigned long   rsvd_49:1;
                unsigned long   nodes_per_bit:7;                /* RO */
                unsigned long   ni_port:5;                      /* RO */
                unsigned long   rsvd_62_63:2;
-       } s2;
+       } s4;
+
+       /* UV3 unique struct */
        struct uv3h_node_id_s {
                unsigned long   force1:1;                       /* RO */
                unsigned long   manufacturer:11;                /* RO */
@@ -2468,1642 +2895,1743 @@ union uvh_node_id_u {
                unsigned long   ni_port:5;                      /* RO */
                unsigned long   rsvd_62_63:2;
        } s3;
-       struct uv4h_node_id_s {
+
+       /* UV2 unique struct */
+       struct uv2h_node_id_s {
                unsigned long   force1:1;                       /* RO */
                unsigned long   manufacturer:11;                /* RO */
                unsigned long   part_number:16;                 /* RO */
                unsigned long   revision:4;                     /* RO */
                unsigned long   node_id:15;                     /* RW */
-               unsigned long   rsvd_47:1;
-               unsigned long   router_select:1;                /* RO */
-               unsigned long   rsvd_49:1;
+               unsigned long   rsvd_47_49:3;
                unsigned long   nodes_per_bit:7;                /* RO */
                unsigned long   ni_port:5;                      /* RO */
                unsigned long   rsvd_62_63:2;
-       } s4;
+       } s2;
+};
+
+/* ========================================================================= */
+/*                            UVH_NODE_PRESENT_0                             */
+/* ========================================================================= */
+#define UVH_NODE_PRESENT_0 (                                           \
+       is_uv(UV5) ? 0x1400UL :                                         \
+       0)
+
+
+/* UVYH common defines */
+#define UVYH_NODE_PRESENT_0_NODES_SHFT                 0
+#define UVYH_NODE_PRESENT_0_NODES_MASK                 0xffffffffffffffffUL
+
+
+union uvh_node_present_0_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_node_present_0_s {
+               unsigned long   nodes:64;                       /* RW */
+       } s;
+
+       /* UVYH common struct */
+       struct uvyh_node_present_0_s {
+               unsigned long   nodes:64;                       /* RW */
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_node_present_0_s {
+               unsigned long   nodes:64;                       /* RW */
+       } s5;
+};
+
+/* ========================================================================= */
+/*                            UVH_NODE_PRESENT_1                             */
+/* ========================================================================= */
+#define UVH_NODE_PRESENT_1 (                                           \
+       is_uv(UV5) ? 0x1408UL :                                         \
+       0)
+
+
+/* UVYH common defines */
+#define UVYH_NODE_PRESENT_1_NODES_SHFT                 0
+#define UVYH_NODE_PRESENT_1_NODES_MASK                 0xffffffffffffffffUL
+
+
+union uvh_node_present_1_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_node_present_1_s {
+               unsigned long   nodes:64;                       /* RW */
+       } s;
+
+       /* UVYH common struct */
+       struct uvyh_node_present_1_s {
+               unsigned long   nodes:64;                       /* RW */
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_node_present_1_s {
+               unsigned long   nodes:64;                       /* RW */
+       } s5;
 };
 
 /* ========================================================================= */
 /*                          UVH_NODE_PRESENT_TABLE                           */
 /* ========================================================================= */
-#define UVH_NODE_PRESENT_TABLE 0x1400UL
+#define UVH_NODE_PRESENT_TABLE (                                       \
+       is_uv(UV4) ? 0x1400UL :                                         \
+       is_uv(UV3) ? 0x1400UL :                                         \
+       is_uv(UV2) ? 0x1400UL :                                         \
+       0)
 
-#define UV2H_NODE_PRESENT_TABLE_DEPTH 16
-#define UV3H_NODE_PRESENT_TABLE_DEPTH 16
-#define UV4H_NODE_PRESENT_TABLE_DEPTH 4
 #define UVH_NODE_PRESENT_TABLE_DEPTH (                                 \
-       is_uv2_hub() ? UV2H_NODE_PRESENT_TABLE_DEPTH :                  \
-       is_uv3_hub() ? UV3H_NODE_PRESENT_TABLE_DEPTH :                  \
-       /*is_uv4_hub*/ UV4H_NODE_PRESENT_TABLE_DEPTH)
+       is_uv(UV4) ? 4 :                                                \
+       is_uv(UV3) ? 16 :                                               \
+       is_uv(UV2) ? 16 :                                               \
+       0)
+
 
-#define UVH_NODE_PRESENT_TABLE_NODES_SHFT              0
-#define UVH_NODE_PRESENT_TABLE_NODES_MASK              0xffffffffffffffffUL
+/* UVXH common defines */
+#define UVXH_NODE_PRESENT_TABLE_NODES_SHFT             0
+#define UVXH_NODE_PRESENT_TABLE_NODES_MASK             0xffffffffffffffffUL
 
 
 union uvh_node_present_table_u {
        unsigned long   v;
+
+       /* UVH common struct */
        struct uvh_node_present_table_s {
                unsigned long   nodes:64;                       /* RW */
        } s;
+
+       /* UVXH common struct */
+       struct uvxh_node_present_table_s {
+               unsigned long   nodes:64;                       /* RW */
+       } sx;
+
+       /* UV4 unique struct */
+       struct uv4h_node_present_table_s {
+               unsigned long   nodes:64;                       /* RW */
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_node_present_table_s {
+               unsigned long   nodes:64;                       /* RW */
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_node_present_table_s {
+               unsigned long   nodes:64;                       /* RW */
+       } s2;
 };
 
 /* ========================================================================= */
-/*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR                  */
+/*                       UVH_RH10_GAM_ADDR_MAP_CONFIG                        */
 /* ========================================================================= */
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR 0x16000c8UL
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR 0x16000c8UL
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR 0x4800c8UL
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR (                     \
-       is_uv2_hub() ? UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR :      \
-       is_uv3_hub() ? UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR :      \
-       /*is_uv4_hub*/ UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR)
-
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_SHFT 24
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_SHFT 63
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_MASK 0x00000000ff000000UL
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_SHFT 24
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_SHFT 63
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_MASK 0x00000000ff000000UL
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_SHFT 24
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_SHFT 63
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_MASK 0x00000000ff000000UL
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_SHFT 24
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_SHFT 63
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_MASK 0x00000000ff000000UL
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_SHFT 24
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_SHFT 63
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_MASK 0x00000000ff000000UL
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_MASK 0x8000000000000000UL
-
-
-union uvh_rh_gam_alias210_overlay_config_0_mmr_u {
+#define UVH_RH10_GAM_ADDR_MAP_CONFIG (                                 \
+       is_uv(UV5) ? 0x470000UL :                                       \
+       0)
+
+
+/* UVYH common defines */
+#define UVYH_RH10_GAM_ADDR_MAP_CONFIG_N_SKT_SHFT       6
+#define UVYH_RH10_GAM_ADDR_MAP_CONFIG_N_SKT_MASK       0x00000000000001c0UL
+#define UVYH_RH10_GAM_ADDR_MAP_CONFIG_LS_ENABLE_SHFT   12
+#define UVYH_RH10_GAM_ADDR_MAP_CONFIG_LS_ENABLE_MASK   0x0000000000001000UL
+#define UVYH_RH10_GAM_ADDR_MAP_CONFIG_MK_TME_KEYID_BITS_SHFT 16
+#define UVYH_RH10_GAM_ADDR_MAP_CONFIG_MK_TME_KEYID_BITS_MASK 0x00000000000f0000UL
+
+
+union uvh_rh10_gam_addr_map_config_u {
        unsigned long   v;
-       struct uvh_rh_gam_alias210_overlay_config_0_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
+
+       /* UVH common struct */
+       struct uvh_rh10_gam_addr_map_config_s {
+               unsigned long   undef_0_5:6;                    /* Undefined */
+               unsigned long   n_skt:3;                        /* RW */
+               unsigned long   undef_9_11:3;                   /* Undefined */
+               unsigned long   ls_enable:1;                    /* RW */
+               unsigned long   undef_13_15:3;                  /* Undefined */
+               unsigned long   mk_tme_keyid_bits:4;            /* RW */
+               unsigned long   rsvd_20_63:44;
        } s;
-       struct uvxh_rh_gam_alias210_overlay_config_0_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
-       } sx;
-       struct uv2h_rh_gam_alias210_overlay_config_0_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
-       } s2;
-       struct uv3h_rh_gam_alias210_overlay_config_0_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
-       } s3;
-       struct uv4h_rh_gam_alias210_overlay_config_0_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
-       } s4;
+
+       /* UVYH common struct */
+       struct uvyh_rh10_gam_addr_map_config_s {
+               unsigned long   undef_0_5:6;                    /* Undefined */
+               unsigned long   n_skt:3;                        /* RW */
+               unsigned long   undef_9_11:3;                   /* Undefined */
+               unsigned long   ls_enable:1;                    /* RW */
+               unsigned long   undef_13_15:3;                  /* Undefined */
+               unsigned long   mk_tme_keyid_bits:4;            /* RW */
+               unsigned long   rsvd_20_63:44;
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_rh10_gam_addr_map_config_s {
+               unsigned long   undef_0_5:6;                    /* Undefined */
+               unsigned long   n_skt:3;                        /* RW */
+               unsigned long   undef_9_11:3;                   /* Undefined */
+               unsigned long   ls_enable:1;                    /* RW */
+               unsigned long   undef_13_15:3;                  /* Undefined */
+               unsigned long   mk_tme_keyid_bits:4;            /* RW */
+       } s5;
 };
 
 /* ========================================================================= */
-/*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR                  */
+/*                     UVH_RH10_GAM_GRU_OVERLAY_CONFIG                       */
 /* ========================================================================= */
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR 0x16000d8UL
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR 0x16000d8UL
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR 0x4800d8UL
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR (                     \
-       is_uv2_hub() ? UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR :      \
-       is_uv3_hub() ? UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR :      \
-       /*is_uv4_hub*/ UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR)
-
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_SHFT 24
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_SHFT 63
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_MASK 0x00000000ff000000UL
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_SHFT 24
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_SHFT 63
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_MASK 0x00000000ff000000UL
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_SHFT 24
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_SHFT 63
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_MASK 0x00000000ff000000UL
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_SHFT 24
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_SHFT 63
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_MASK 0x00000000ff000000UL
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_SHFT 24
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_SHFT 63
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_MASK 0x00000000ff000000UL
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_MASK 0x8000000000000000UL
-
-
-union uvh_rh_gam_alias210_overlay_config_1_mmr_u {
+#define UVH_RH10_GAM_GRU_OVERLAY_CONFIG (                              \
+       is_uv(UV5) ? 0x4700b0UL :                                       \
+       0)
+
+
+/* UVYH common defines */
+#define UVYH_RH10_GAM_GRU_OVERLAY_CONFIG_BASE_SHFT     25
+#define UVYH_RH10_GAM_GRU_OVERLAY_CONFIG_BASE_MASK     0x000ffffffe000000UL
+#define UVYH_RH10_GAM_GRU_OVERLAY_CONFIG_N_GRU_SHFT    52
+#define UVYH_RH10_GAM_GRU_OVERLAY_CONFIG_N_GRU_MASK    0x0070000000000000UL
+#define UVYH_RH10_GAM_GRU_OVERLAY_CONFIG_ENABLE_SHFT   63
+#define UVYH_RH10_GAM_GRU_OVERLAY_CONFIG_ENABLE_MASK   0x8000000000000000UL
+
+#define UVH_RH10_GAM_GRU_OVERLAY_CONFIG_BASE_MASK (                    \
+       is_uv(UV5) ? 0x000ffffffe000000UL :                             \
+       0)
+#define UVH_RH10_GAM_GRU_OVERLAY_CONFIG_BASE_SHFT (                    \
+       is_uv(UV5) ? 25 :                                               \
+       -1)
+
+union uvh_rh10_gam_gru_overlay_config_u {
        unsigned long   v;
-       struct uvh_rh_gam_alias210_overlay_config_1_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
-       } s;
-       struct uvxh_rh_gam_alias210_overlay_config_1_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
-       } sx;
-       struct uv2h_rh_gam_alias210_overlay_config_1_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
-       } s2;
-       struct uv3h_rh_gam_alias210_overlay_config_1_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
-       } s3;
-       struct uv4h_rh_gam_alias210_overlay_config_1_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
+
+       /* UVH common struct */
+       struct uvh_rh10_gam_gru_overlay_config_s {
+               unsigned long   undef_0_24:25;                  /* Undefined */
+               unsigned long   base:27;                        /* RW */
+               unsigned long   n_gru:3;                        /* RW */
+               unsigned long   undef_55_62:8;                  /* Undefined */
                unsigned long   enable:1;                       /* RW */
-       } s4;
+       } s;
+
+       /* UVYH common struct */
+       struct uvyh_rh10_gam_gru_overlay_config_s {
+               unsigned long   undef_0_24:25;                  /* Undefined */
+               unsigned long   base:27;                        /* RW */
+               unsigned long   n_gru:3;                        /* RW */
+               unsigned long   undef_55_62:8;                  /* Undefined */
+               unsigned long   enable:1;                       /* RW */
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_rh10_gam_gru_overlay_config_s {
+               unsigned long   undef_0_24:25;                  /* Undefined */
+               unsigned long   base:27;                        /* RW */
+               unsigned long   n_gru:3;                        /* RW */
+               unsigned long   undef_55_62:8;                  /* Undefined */
+               unsigned long   enable:1;                       /* RW */
+       } s5;
 };
 
 /* ========================================================================= */
-/*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR                  */
+/*                    UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0                     */
 /* ========================================================================= */
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR 0x16000e8UL
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR 0x16000e8UL
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR 0x4800e8UL
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR (                     \
-       is_uv2_hub() ? UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR :      \
-       is_uv3_hub() ? UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR :      \
-       /*is_uv4_hub*/ UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR)
-
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_SHFT 24
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_SHFT 63
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_MASK 0x00000000ff000000UL
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_SHFT 24
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_SHFT 63
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_MASK 0x00000000ff000000UL
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UVXH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_SHFT 24
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_SHFT 63
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_MASK 0x00000000ff000000UL
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UV2H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_SHFT 24
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_SHFT 63
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_MASK 0x00000000ff000000UL
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UV3H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_SHFT 24
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_SHFT 63
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_MASK 0x00000000ff000000UL
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_MASK 0x001f000000000000UL
-#define UV4H_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_MASK 0x8000000000000000UL
-
-
-union uvh_rh_gam_alias210_overlay_config_2_mmr_u {
+#define UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0 (                           \
+       is_uv(UV5) ? 0x473000UL :                                       \
+       0)
+
+
+/* UVYH common defines */
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_BASE_SHFT  26
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK  0x000ffffffc000000UL
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_SHFT  52
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_MASK  0x03f0000000000000UL
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_ENABLE_SHFT        63
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_ENABLE_MASK        0x8000000000000000UL
+
+#define UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK (                 \
+       is_uv(UV5) ? 0x000ffffffc000000UL :                             \
+       0)
+#define UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_BASE_SHFT (                 \
+       is_uv(UV5) ? 26 :                                               \
+       -1)
+
+union uvh_rh10_gam_mmioh_overlay_config0_u {
        unsigned long   v;
-       struct uvh_rh_gam_alias210_overlay_config_2_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
+
+       /* UVH common struct */
+       struct uvh_rh10_gam_mmioh_overlay_config0_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:26;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   undef_62:1;                     /* Undefined */
                unsigned long   enable:1;                       /* RW */
        } s;
-       struct uvxh_rh_gam_alias210_overlay_config_2_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
-       } sx;
-       struct uv2h_rh_gam_alias210_overlay_config_2_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
-               unsigned long   enable:1;                       /* RW */
-       } s2;
-       struct uv3h_rh_gam_alias210_overlay_config_2_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
+
+       /* UVYH common struct */
+       struct uvyh_rh10_gam_mmioh_overlay_config0_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:26;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   undef_62:1;                     /* Undefined */
                unsigned long   enable:1;                       /* RW */
-       } s3;
-       struct uv4h_rh_gam_alias210_overlay_config_2_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   base:8;                         /* RW */
-               unsigned long   rsvd_32_47:16;
-               unsigned long   m_alias:5;                      /* RW */
-               unsigned long   rsvd_53_62:10;
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_rh10_gam_mmioh_overlay_config0_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:26;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   undef_62:1;                     /* Undefined */
                unsigned long   enable:1;                       /* RW */
-       } s4;
+       } s5;
 };
 
 /* ========================================================================= */
-/*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR                  */
+/*                    UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1                     */
 /* ========================================================================= */
-#define UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR 0x16000d0UL
-#define UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR 0x16000d0UL
-#define UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR 0x4800d0UL
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR (                    \
-       is_uv2_hub() ? UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR :     \
-       is_uv3_hub() ? UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR :     \
-       /*is_uv4_hub*/ UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR)
+#define UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1 (                           \
+       is_uv(UV5) ? 0x474000UL :                                       \
+       0)
+
+
+/* UVYH common defines */
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_BASE_SHFT  26
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK  0x000ffffffc000000UL
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_SHFT  52
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_MASK  0x03f0000000000000UL
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_ENABLE_SHFT        63
+#define UVYH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_ENABLE_MASK        0x8000000000000000UL
+
+#define UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK (                 \
+       is_uv(UV5) ? 0x000ffffffc000000UL :                             \
+       0)
+#define UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_BASE_SHFT (                 \
+       is_uv(UV5) ? 26 :                                               \
+       -1)
+
+union uvh_rh10_gam_mmioh_overlay_config1_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_rh10_gam_mmioh_overlay_config1_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:26;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   undef_62:1;                     /* Undefined */
+               unsigned long   enable:1;                       /* RW */
+       } s;
+
+       /* UVYH common struct */
+       struct uvyh_rh10_gam_mmioh_overlay_config1_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:26;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   undef_62:1;                     /* Undefined */
+               unsigned long   enable:1;                       /* RW */
+       } sy;
 
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT 24
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+       /* UV5 unique struct */
+       struct uv5h_rh10_gam_mmioh_overlay_config1_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:26;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   undef_62:1;                     /* Undefined */
+               unsigned long   enable:1;                       /* RW */
+       } s5;
+};
 
-#define UVXH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT 24
-#define UVXH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+/* ========================================================================= */
+/*                   UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0                     */
+/* ========================================================================= */
+#define UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0 (                          \
+       is_uv(UV5) ? 0x473800UL :                                       \
+       0)
 
-#define UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT 24
-#define UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+#define UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH (                    \
+       is_uv(UV5) ? 128 :                                              \
+       0)
 
-#define UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT 24
-#define UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_MASK 0x00003fffff000000UL
 
-#define UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT 24
-#define UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+/* UVYH common defines */
+#define UVYH_RH10_GAM_MMIOH_REDIRECT_CONFIG0_NASID_SHFT        0
+#define UVYH_RH10_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK        0x000000000000007fUL
 
 
-union uvh_rh_gam_alias210_redirect_config_0_mmr_u {
+union uvh_rh10_gam_mmioh_redirect_config0_u {
        unsigned long   v;
-       struct uvh_rh_gam_alias210_redirect_config_0_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
+
+       /* UVH common struct */
+       struct uvh_rh10_gam_mmioh_redirect_config0_s {
+               unsigned long   nasid:7;                        /* RW */
+               unsigned long   rsvd_7_63:57;
        } s;
-       struct uvxh_rh_gam_alias210_redirect_config_0_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } sx;
-       struct uv2h_rh_gam_alias210_redirect_config_0_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } s2;
-       struct uv3h_rh_gam_alias210_redirect_config_0_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } s3;
-       struct uv4h_rh_gam_alias210_redirect_config_0_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } s4;
+
+       /* UVYH common struct */
+       struct uvyh_rh10_gam_mmioh_redirect_config0_s {
+               unsigned long   nasid:7;                        /* RW */
+               unsigned long   rsvd_7_63:57;
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_rh10_gam_mmioh_redirect_config0_s {
+               unsigned long   nasid:7;                        /* RW */
+               unsigned long   rsvd_7_63:57;
+       } s5;
 };
 
 /* ========================================================================= */
-/*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR                  */
+/*                   UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1                     */
 /* ========================================================================= */
-#define UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR 0x16000e0UL
-#define UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR 0x16000e0UL
-#define UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR 0x4800e0UL
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR (                    \
-       is_uv2_hub() ? UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR :     \
-       is_uv3_hub() ? UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR :     \
-       /*is_uv4_hub*/ UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR)
+#define UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1 (                          \
+       is_uv(UV5) ? 0x474800UL :                                       \
+       0)
 
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_SHFT 24
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+#define UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH (                    \
+       is_uv(UV5) ? 128 :                                              \
+       0)
 
-#define UVXH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_SHFT 24
-#define UVXH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_MASK 0x00003fffff000000UL
 
-#define UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_SHFT 24
-#define UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+/* UVYH common defines */
+#define UVYH_RH10_GAM_MMIOH_REDIRECT_CONFIG1_NASID_SHFT        0
+#define UVYH_RH10_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK        0x000000000000007fUL
 
-#define UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_SHFT 24
-#define UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_MASK 0x00003fffff000000UL
 
-#define UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_SHFT 24
-#define UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_MASK 0x00003fffff000000UL
-
-
-union uvh_rh_gam_alias210_redirect_config_1_mmr_u {
+union uvh_rh10_gam_mmioh_redirect_config1_u {
        unsigned long   v;
-       struct uvh_rh_gam_alias210_redirect_config_1_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
+
+       /* UVH common struct */
+       struct uvh_rh10_gam_mmioh_redirect_config1_s {
+               unsigned long   nasid:7;                        /* RW */
+               unsigned long   rsvd_7_63:57;
        } s;
-       struct uvxh_rh_gam_alias210_redirect_config_1_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } sx;
-       struct uv2h_rh_gam_alias210_redirect_config_1_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } s2;
-       struct uv3h_rh_gam_alias210_redirect_config_1_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } s3;
-       struct uv4h_rh_gam_alias210_redirect_config_1_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } s4;
+
+       /* UVYH common struct */
+       struct uvyh_rh10_gam_mmioh_redirect_config1_s {
+               unsigned long   nasid:7;                        /* RW */
+               unsigned long   rsvd_7_63:57;
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_rh10_gam_mmioh_redirect_config1_s {
+               unsigned long   nasid:7;                        /* RW */
+               unsigned long   rsvd_7_63:57;
+       } s5;
 };
 
 /* ========================================================================= */
-/*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR                  */
+/*                     UVH_RH10_GAM_MMR_OVERLAY_CONFIG                       */
 /* ========================================================================= */
-#define UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR 0x16000f0UL
-#define UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR 0x16000f0UL
-#define UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR 0x4800f0UL
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR (                    \
-       is_uv2_hub() ? UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR :     \
-       is_uv3_hub() ? UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR :     \
-       /*is_uv4_hub*/ UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR)
+#define UVH_RH10_GAM_MMR_OVERLAY_CONFIG (                              \
+       is_uv(UV5) ? 0x470090UL :                                       \
+       0)
 
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_SHFT 24
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_MASK 0x00003fffff000000UL
 
-#define UVXH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_SHFT 24
-#define UVXH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+/* UVYH common defines */
+#define UVYH_RH10_GAM_MMR_OVERLAY_CONFIG_BASE_SHFT     25
+#define UVYH_RH10_GAM_MMR_OVERLAY_CONFIG_BASE_MASK     0x000ffffffe000000UL
+#define UVYH_RH10_GAM_MMR_OVERLAY_CONFIG_ENABLE_SHFT   63
+#define UVYH_RH10_GAM_MMR_OVERLAY_CONFIG_ENABLE_MASK   0x8000000000000000UL
 
-#define UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_SHFT 24
-#define UV2H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+#define UVH_RH10_GAM_MMR_OVERLAY_CONFIG_BASE_MASK (                    \
+       is_uv(UV5) ? 0x000ffffffe000000UL :                             \
+       0)
+#define UVH_RH10_GAM_MMR_OVERLAY_CONFIG_BASE_SHFT (                    \
+       is_uv(UV5) ? 25 :                                               \
+       -1)
 
-#define UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_SHFT 24
-#define UV3H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+union uvh_rh10_gam_mmr_overlay_config_u {
+       unsigned long   v;
 
-#define UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_SHFT 24
-#define UV4H_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+       /* UVH common struct */
+       struct uvh_rh10_gam_mmr_overlay_config_s {
+               unsigned long   undef_0_24:25;                  /* Undefined */
+               unsigned long   base:27;                        /* RW */
+               unsigned long   undef_52_62:11;                 /* Undefined */
+               unsigned long   enable:1;                       /* RW */
+       } s;
 
+       /* UVYH common struct */
+       struct uvyh_rh10_gam_mmr_overlay_config_s {
+               unsigned long   undef_0_24:25;                  /* Undefined */
+               unsigned long   base:27;                        /* RW */
+               unsigned long   undef_52_62:11;                 /* Undefined */
+               unsigned long   enable:1;                       /* RW */
+       } sy;
 
-union uvh_rh_gam_alias210_redirect_config_2_mmr_u {
-       unsigned long   v;
-       struct uvh_rh_gam_alias210_redirect_config_2_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } s;
-       struct uvxh_rh_gam_alias210_redirect_config_2_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } sx;
-       struct uv2h_rh_gam_alias210_redirect_config_2_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } s2;
-       struct uv3h_rh_gam_alias210_redirect_config_2_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } s3;
-       struct uv4h_rh_gam_alias210_redirect_config_2_mmr_s {
-               unsigned long   rsvd_0_23:24;
-               unsigned long   dest_base:22;                   /* RW */
-               unsigned long   rsvd_46_63:18;
-       } s4;
+       /* UV5 unique struct */
+       struct uv5h_rh10_gam_mmr_overlay_config_s {
+               unsigned long   undef_0_24:25;                  /* Undefined */
+               unsigned long   base:27;                        /* RW */
+               unsigned long   undef_52_62:11;                 /* Undefined */
+               unsigned long   enable:1;                       /* RW */
+       } s5;
 };
 
 /* ========================================================================= */
-/*                          UVH_RH_GAM_CONFIG_MMR                            */
+/*                        UVH_RH_GAM_ADDR_MAP_CONFIG                         */
 /* ========================================================================= */
-#define UV2H_RH_GAM_CONFIG_MMR 0x1600000UL
-#define UV3H_RH_GAM_CONFIG_MMR 0x1600000UL
-#define UV4H_RH_GAM_CONFIG_MMR 0x480000UL
-#define UVH_RH_GAM_CONFIG_MMR (                                                \
-       is_uv2_hub() ? UV2H_RH_GAM_CONFIG_MMR :                         \
-       is_uv3_hub() ? UV3H_RH_GAM_CONFIG_MMR :                         \
-       /*is_uv4_hub*/ UV4H_RH_GAM_CONFIG_MMR)
-
-#define UVH_RH_GAM_CONFIG_MMR_N_SKT_SHFT               6
-#define UVH_RH_GAM_CONFIG_MMR_N_SKT_MASK               0x00000000000003c0UL
+#define UVH_RH_GAM_ADDR_MAP_CONFIG (                                   \
+       is_uv(UV4) ? 0x480000UL :                                       \
+       is_uv(UV3) ? 0x1600000UL :                                      \
+       is_uv(UV2) ? 0x1600000UL :                                      \
+       0)
 
-#define UVXH_RH_GAM_CONFIG_MMR_N_SKT_SHFT              6
-#define UVXH_RH_GAM_CONFIG_MMR_N_SKT_MASK              0x00000000000003c0UL
 
-#define UV2H_RH_GAM_CONFIG_MMR_M_SKT_SHFT              0
-#define UV2H_RH_GAM_CONFIG_MMR_N_SKT_SHFT              6
-#define UV2H_RH_GAM_CONFIG_MMR_M_SKT_MASK              0x000000000000003fUL
-#define UV2H_RH_GAM_CONFIG_MMR_N_SKT_MASK              0x00000000000003c0UL
+/* UVXH common defines */
+#define UVXH_RH_GAM_ADDR_MAP_CONFIG_N_SKT_SHFT         6
+#define UVXH_RH_GAM_ADDR_MAP_CONFIG_N_SKT_MASK         0x00000000000003c0UL
 
-#define UV3H_RH_GAM_CONFIG_MMR_M_SKT_SHFT              0
-#define UV3H_RH_GAM_CONFIG_MMR_N_SKT_SHFT              6
-#define UV3H_RH_GAM_CONFIG_MMR_M_SKT_MASK              0x000000000000003fUL
-#define UV3H_RH_GAM_CONFIG_MMR_N_SKT_MASK              0x00000000000003c0UL
+/* UV3 unique defines */
+#define UV3H_RH_GAM_ADDR_MAP_CONFIG_M_SKT_SHFT         0
+#define UV3H_RH_GAM_ADDR_MAP_CONFIG_M_SKT_MASK         0x000000000000003fUL
 
-#define UV4H_RH_GAM_CONFIG_MMR_N_SKT_SHFT              6
-#define UV4H_RH_GAM_CONFIG_MMR_N_SKT_MASK              0x00000000000003c0UL
+/* UV2 unique defines */
+#define UV2H_RH_GAM_ADDR_MAP_CONFIG_M_SKT_SHFT         0
+#define UV2H_RH_GAM_ADDR_MAP_CONFIG_M_SKT_MASK         0x000000000000003fUL
 
 
-union uvh_rh_gam_config_mmr_u {
+union uvh_rh_gam_addr_map_config_u {
        unsigned long   v;
-       struct uvh_rh_gam_config_mmr_s {
+
+       /* UVH common struct */
+       struct uvh_rh_gam_addr_map_config_s {
                unsigned long   rsvd_0_5:6;
                unsigned long   n_skt:4;                        /* RW */
                unsigned long   rsvd_10_63:54;
        } s;
-       struct uvxh_rh_gam_config_mmr_s {
+
+       /* UVXH common struct */
+       struct uvxh_rh_gam_addr_map_config_s {
                unsigned long   rsvd_0_5:6;
                unsigned long   n_skt:4;                        /* RW */
                unsigned long   rsvd_10_63:54;
        } sx;
-       struct uv2h_rh_gam_config_mmr_s {
-               unsigned long   m_skt:6;                        /* RW */
+
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_addr_map_config_s {
+               unsigned long   rsvd_0_5:6;
                unsigned long   n_skt:4;                        /* RW */
                unsigned long   rsvd_10_63:54;
-       } s2;
-       struct uv3h_rh_gam_config_mmr_s {
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_addr_map_config_s {
                unsigned long   m_skt:6;                        /* RW */
                unsigned long   n_skt:4;                        /* RW */
                unsigned long   rsvd_10_63:54;
        } s3;
-       struct uv4h_rh_gam_config_mmr_s {
-               unsigned long   rsvd_0_5:6;
+
+       /* UV2 unique struct */
+       struct uv2h_rh_gam_addr_map_config_s {
+               unsigned long   m_skt:6;                        /* RW */
                unsigned long   n_skt:4;                        /* RW */
                unsigned long   rsvd_10_63:54;
-       } s4;
+       } s2;
 };
 
 /* ========================================================================= */
-/*                    UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR                      */
+/*                    UVH_RH_GAM_ALIAS_0_OVERLAY_CONFIG                      */
 /* ========================================================================= */
-#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
-#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
-#define UV4H_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x480010UL
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR (                            \
-       is_uv2_hub() ? UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR :             \
-       is_uv3_hub() ? UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR :             \
-       /*is_uv4_hub*/ UV4H_RH_GAM_GRU_OVERLAY_CONFIG_MMR)
-
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT   52
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT  63
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK   0x00f0000000000000UL
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK  0x8000000000000000UL
-
-#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT  52
-#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK  0x00f0000000000000UL
-#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT   28
-#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT  52
-#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffff0000000UL
-#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK  0x00f0000000000000UL
-#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT   28
-#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT  52
-#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_MODE_SHFT   62
-#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffff0000000UL
-#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK  0x00f0000000000000UL
-#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_MODE_MASK   0x4000000000000000UL
-#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV4H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT   26
-#define UV4H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT  52
-#define UV4H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UV4H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffffc000000UL
-#define UV4H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK  0x00f0000000000000UL
-#define UV4H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK (                  \
-       is_uv2_hub() ? UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK :   \
-       is_uv3_hub() ? UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK :   \
-       /*is_uv4_hub*/ UV4H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK)
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT (                  \
-       is_uv2_hub() ? UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT :   \
-       is_uv3_hub() ? UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT :   \
-       /*is_uv4_hub*/ UV4H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT)
-
-union uvh_rh_gam_gru_overlay_config_mmr_u {
+#define UVH_RH_GAM_ALIAS_0_OVERLAY_CONFIG (                            \
+       is_uv(UV4) ? 0x4800c8UL :                                       \
+       is_uv(UV3) ? 0x16000c8UL :                                      \
+       is_uv(UV2) ? 0x16000c8UL :                                      \
+       0)
+
+
+/* UVXH common defines */
+#define UVXH_RH_GAM_ALIAS_0_OVERLAY_CONFIG_BASE_SHFT   24
+#define UVXH_RH_GAM_ALIAS_0_OVERLAY_CONFIG_BASE_MASK   0x00000000ff000000UL
+#define UVXH_RH_GAM_ALIAS_0_OVERLAY_CONFIG_M_ALIAS_SHFT        48
+#define UVXH_RH_GAM_ALIAS_0_OVERLAY_CONFIG_M_ALIAS_MASK        0x001f000000000000UL
+#define UVXH_RH_GAM_ALIAS_0_OVERLAY_CONFIG_ENABLE_SHFT 63
+#define UVXH_RH_GAM_ALIAS_0_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
+
+
+union uvh_rh_gam_alias_0_overlay_config_u {
        unsigned long   v;
-       struct uvh_rh_gam_gru_overlay_config_mmr_s {
-               unsigned long   rsvd_0_51:52;
-               unsigned long   n_gru:4;                        /* RW */
-               unsigned long   rsvd_56_62:7;
+
+       /* UVH common struct */
+       struct uvh_rh_gam_alias_0_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
                unsigned long   enable:1;                       /* RW */
        } s;
-       struct uvxh_rh_gam_gru_overlay_config_mmr_s {
-               unsigned long   rsvd_0_45:46;
-               unsigned long   rsvd_46_51:6;
-               unsigned long   n_gru:4;                        /* RW */
-               unsigned long   rsvd_56_62:7;
-               unsigned long   enable:1;                       /* RW */
-       } sx;
-       struct uv2h_rh_gam_gru_overlay_config_mmr_s {
-               unsigned long   rsvd_0_27:28;
-               unsigned long   base:18;                        /* RW */
-               unsigned long   rsvd_46_51:6;
-               unsigned long   n_gru:4;                        /* RW */
-               unsigned long   rsvd_56_62:7;
-               unsigned long   enable:1;                       /* RW */
-       } s2;
-       struct uv3h_rh_gam_gru_overlay_config_mmr_s {
-               unsigned long   rsvd_0_27:28;
-               unsigned long   base:18;                        /* RW */
-               unsigned long   rsvd_46_51:6;
-               unsigned long   n_gru:4;                        /* RW */
-               unsigned long   rsvd_56_61:6;
-               unsigned long   mode:1;                         /* RW */
-               unsigned long   enable:1;                       /* RW */
-       } s3;
-       struct uv4h_rh_gam_gru_overlay_config_mmr_s {
-               unsigned long   rsvd_0_24:25;
-               unsigned long   undef_25:1;                     /* Undefined */
-               unsigned long   base:20;                        /* RW */
-               unsigned long   rsvd_46_51:6;
-               unsigned long   n_gru:4;                        /* RW */
-               unsigned long   rsvd_56_62:7;
-               unsigned long   enable:1;                       /* RW */
-       } s4;
-};
 
-/* ========================================================================= */
-/*                   UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR                    */
-/* ========================================================================= */
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR uv_undefined("UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR")
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR 0x1603000UL
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR 0x483000UL
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR (                         \
-       is_uv2_hub() ? UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR :          \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR :          \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR)
-
-
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_SHFT        26
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT        46
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_SHFT 63
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_MASK        0x00003ffffc000000UL
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_MASK        0x000fc00000000000UL
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_SHFT        26
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT        46
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_SHFT 63
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_MASK        0x00003ffffc000000UL
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_MASK        0x000fc00000000000UL
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT 52
-#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_MASK 0x000ffffffc000000UL
-#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_MASK 0x03f0000000000000UL
-#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT (               \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT : \
-       is_uv4a_hub() ? UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT : \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT)
-
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_MASK (               \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_MASK : \
-       is_uv4a_hub() ? UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_MASK : \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_MASK)
-
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_MASK (               \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_MASK : \
-       is_uv4a_hub() ? UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_MASK : \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_MASK)
-
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_MASK (             \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_MASK : \
-       is_uv4a_hub() ? UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_MASK : \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_MASK)
-
-union uvh_rh_gam_mmioh_overlay_config0_mmr_u {
-       unsigned long   v;
-       struct uv3h_rh_gam_mmioh_overlay_config0_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:20;                        /* RW */
-               unsigned long   m_io:6;                         /* RW */
-               unsigned long   n_io:4;
-               unsigned long   rsvd_56_62:7;
-               unsigned long   enable:1;                       /* RW */
-       } s3;
-       struct uv4h_rh_gam_mmioh_overlay_config0_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:20;                        /* RW */
-               unsigned long   m_io:6;                         /* RW */
-               unsigned long   n_io:4;
-               unsigned long   rsvd_56_62:7;
-               unsigned long   enable:1;                       /* RW */
-       } s4;
-       struct uv4ah_rh_gam_mmioh_overlay_config0_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:26;                        /* RW */
-               unsigned long   m_io:6;                         /* RW */
-               unsigned long   n_io:4;
-               unsigned long   undef_62:1;                     /* Undefined */
+       /* UVXH common struct */
+       struct uvxh_rh_gam_alias_0_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
                unsigned long   enable:1;                       /* RW */
-       } s4a;
-};
+       } sx;
 
-/* ========================================================================= */
-/*                   UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR                    */
-/* ========================================================================= */
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR uv_undefined("UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR")
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR 0x1603000UL
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR 0x484000UL
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR (                         \
-       is_uv2_hub() ? UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR :          \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR :          \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR)
-
-
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_SHFT        26
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT        46
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_ENABLE_SHFT 63
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_MASK        0x00003ffffc000000UL
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_MASK        0x000fc00000000000UL
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_SHFT        26
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT        46
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_ENABLE_SHFT 63
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_MASK        0x00003ffffc000000UL
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_MASK        0x000fc00000000000UL
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT 52
-#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_MASK 0x000ffffffc000000UL
-#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_MASK 0x03f0000000000000UL
-
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT (               \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT : \
-       is_uv4a_hub() ? UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT : \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT)
-
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_MASK (               \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_MASK : \
-       is_uv4a_hub() ? UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_MASK : \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_MASK)
-
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_MASK (               \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_MASK : \
-       is_uv4a_hub() ? UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_MASK : \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_MASK)
-
-union uvh_rh_gam_mmioh_overlay_config1_mmr_u {
-       unsigned long   v;
-       struct uv3h_rh_gam_mmioh_overlay_config1_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:20;                        /* RW */
-               unsigned long   m_io:6;                         /* RW */
-               unsigned long   n_io:4;
-               unsigned long   rsvd_56_62:7;
-               unsigned long   enable:1;                       /* RW */
-       } s3;
-       struct uv4h_rh_gam_mmioh_overlay_config1_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:20;                        /* RW */
-               unsigned long   m_io:6;                         /* RW */
-               unsigned long   n_io:4;
-               unsigned long   rsvd_56_62:7;
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_alias_0_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
                unsigned long   enable:1;                       /* RW */
        } s4;
-       struct uv4ah_rh_gam_mmioh_overlay_config1_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:26;                        /* RW */
-               unsigned long   m_io:6;                         /* RW */
-               unsigned long   n_io:4;
-               unsigned long   undef_62:1;                     /* Undefined */
+
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_alias_0_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
                unsigned long   enable:1;                       /* RW */
-       } s4a;
-};
+       } s3;
 
-/* ========================================================================= */
-/*                   UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR                     */
-/* ========================================================================= */
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR 0x1600030UL
-#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR uv_undefined("UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR")
-#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR uv_undefined("UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR")
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR (                          \
-       is_uv2_hub() ? UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR :           \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR :           \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR)
-
-
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 27
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_SHFT 52
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff8000000UL
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_MASK 0x000fc00000000000UL
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_MASK 0x00f0000000000000UL
-#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
-
-
-union uvh_rh_gam_mmioh_overlay_config_mmr_u {
-       unsigned long   v;
-       struct uv2h_rh_gam_mmioh_overlay_config_mmr_s {
-               unsigned long   rsvd_0_26:27;
-               unsigned long   base:19;                        /* RW */
-               unsigned long   m_io:6;                         /* RW */
-               unsigned long   n_io:4;                         /* RW */
-               unsigned long   rsvd_56_62:7;
+       /* UV2 unique struct */
+       struct uv2h_rh_gam_alias_0_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
                unsigned long   enable:1;                       /* RW */
        } s2;
 };
 
 /* ========================================================================= */
-/*                  UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR                    */
+/*                    UVH_RH_GAM_ALIAS_0_REDIRECT_CONFIG                     */
 /* ========================================================================= */
-#define UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR uv_undefined("UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR")
-#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR 0x1603800UL
-#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR 0x483800UL
-#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR (                                \
-       is_uv2_hub() ? UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR :         \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR :         \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR)
+#define UVH_RH_GAM_ALIAS_0_REDIRECT_CONFIG (                           \
+       is_uv(UV4) ? 0x4800d0UL :                                       \
+       is_uv(UV3) ? 0x16000d0UL :                                      \
+       is_uv(UV2) ? 0x16000d0UL :                                      \
+       0)
 
-#define UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH uv_undefined("UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH")
-#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH 128
-#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH 128
-#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH (                  \
-       is_uv2_hub() ? UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH :   \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH :   \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH)
 
+/* UVXH common defines */
+#define UVXH_RH_GAM_ALIAS_0_REDIRECT_CONFIG_DEST_BASE_SHFT 24
+#define UVXH_RH_GAM_ALIAS_0_REDIRECT_CONFIG_DEST_BASE_MASK 0x00003fffff000000UL
 
-#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_SHFT 0
-#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_MASK 0x0000000000007fffUL
 
-#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_SHFT 0
-#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_MASK 0x0000000000007fffUL
+union uvh_rh_gam_alias_0_redirect_config_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_rh_gam_alias_0_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } s;
 
-#define UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_MASK 0x0000000000000fffUL
+       /* UVXH common struct */
+       struct uvxh_rh_gam_alias_0_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } sx;
 
-#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_MASK (             \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_MASK : \
-       is_uv4a_hub() ? UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_MASK : \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_MASK)
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_alias_0_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } s4;
 
-union uvh_rh_gam_mmioh_redirect_config0_mmr_u {
-       unsigned long   v;
-       struct uv3h_rh_gam_mmioh_redirect_config0_mmr_s {
-               unsigned long   nasid:15;                       /* RW */
-               unsigned long   rsvd_15_63:49;
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_alias_0_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
        } s3;
-       struct uv4h_rh_gam_mmioh_redirect_config0_mmr_s {
-               unsigned long   nasid:15;                       /* RW */
-               unsigned long   rsvd_15_63:49;
-       } s4;
-       struct uv4ah_rh_gam_mmioh_redirect_config0_mmr_s {
-               unsigned long   nasid:12;                       /* RW */
-               unsigned long   rsvd_12_63:52;
-       } s4a;
+
+       /* UV2 unique struct */
+       struct uv2h_rh_gam_alias_0_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } s2;
 };
 
 /* ========================================================================= */
-/*                  UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR                    */
+/*                    UVH_RH_GAM_ALIAS_1_OVERLAY_CONFIG                      */
 /* ========================================================================= */
-#define UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR uv_undefined("UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR")
-#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR 0x1604800UL
-#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR 0x484800UL
-#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR (                                \
-       is_uv2_hub() ? UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR :         \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR :         \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR)
-
-#define UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH uv_undefined("UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH")
-#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH 128
-#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH 128
-#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH (                  \
-       is_uv2_hub() ? UV2H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH :   \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH :   \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH)
+#define UVH_RH_GAM_ALIAS_1_OVERLAY_CONFIG (                            \
+       is_uv(UV4) ? 0x4800d8UL :                                       \
+       is_uv(UV3) ? 0x16000d8UL :                                      \
+       is_uv(UV2) ? 0x16000d8UL :                                      \
+       0)
 
 
-#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_SHFT 0
-#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_MASK 0x0000000000007fffUL
+/* UVXH common defines */
+#define UVXH_RH_GAM_ALIAS_1_OVERLAY_CONFIG_BASE_SHFT   24
+#define UVXH_RH_GAM_ALIAS_1_OVERLAY_CONFIG_BASE_MASK   0x00000000ff000000UL
+#define UVXH_RH_GAM_ALIAS_1_OVERLAY_CONFIG_M_ALIAS_SHFT        48
+#define UVXH_RH_GAM_ALIAS_1_OVERLAY_CONFIG_M_ALIAS_MASK        0x001f000000000000UL
+#define UVXH_RH_GAM_ALIAS_1_OVERLAY_CONFIG_ENABLE_SHFT 63
+#define UVXH_RH_GAM_ALIAS_1_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
 
-#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_SHFT 0
-#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_MASK 0x0000000000007fffUL
 
-#define UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_MASK 0x0000000000000fffUL
-
-#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_MASK (             \
-       is_uv3_hub() ? UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_MASK : \
-       is_uv4a_hub() ? UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_MASK : \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_MASK)
-
-union uvh_rh_gam_mmioh_redirect_config1_mmr_u {
+union uvh_rh_gam_alias_1_overlay_config_u {
        unsigned long   v;
-       struct uv3h_rh_gam_mmioh_redirect_config1_mmr_s {
-               unsigned long   nasid:15;                       /* RW */
-               unsigned long   rsvd_15_63:49;
-       } s3;
-       struct uv4h_rh_gam_mmioh_redirect_config1_mmr_s {
-               unsigned long   nasid:15;                       /* RW */
-               unsigned long   rsvd_15_63:49;
-       } s4;
-       struct uv4ah_rh_gam_mmioh_redirect_config1_mmr_s {
-               unsigned long   nasid:12;                       /* RW */
-               unsigned long   rsvd_12_63:52;
-       } s4a;
-};
 
-/* ========================================================================= */
-/*                    UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR                      */
-/* ========================================================================= */
-#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
-#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
-#define UV4H_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x480028UL
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR (                            \
-       is_uv2_hub() ? UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR :             \
-       is_uv3_hub() ? UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR :             \
-       /*is_uv4_hub*/ UV4H_RH_GAM_MMR_OVERLAY_CONFIG_MMR)
-
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT    26
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT  63
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK    0x00003ffffc000000UL
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK  0x8000000000000000UL
-
-#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT   26
-#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffffc000000UL
-#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT   26
-#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffffc000000UL
-#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT   26
-#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffffc000000UL
-#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
-
-#define UV4H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT   26
-#define UV4H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
-#define UV4H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffffc000000UL
-#define UV4H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
-
-
-union uvh_rh_gam_mmr_overlay_config_mmr_u {
-       unsigned long   v;
-       struct uvh_rh_gam_mmr_overlay_config_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:20;                        /* RW */
-               unsigned long   rsvd_46_62:17;
+       /* UVH common struct */
+       struct uvh_rh_gam_alias_1_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
                unsigned long   enable:1;                       /* RW */
        } s;
-       struct uvxh_rh_gam_mmr_overlay_config_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:20;                        /* RW */
-               unsigned long   rsvd_46_62:17;
+
+       /* UVXH common struct */
+       struct uvxh_rh_gam_alias_1_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
                unsigned long   enable:1;                       /* RW */
        } sx;
-       struct uv2h_rh_gam_mmr_overlay_config_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:20;                        /* RW */
-               unsigned long   rsvd_46_62:17;
+
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_alias_1_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
                unsigned long   enable:1;                       /* RW */
-       } s2;
-       struct uv3h_rh_gam_mmr_overlay_config_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:20;                        /* RW */
-               unsigned long   rsvd_46_62:17;
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_alias_1_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
                unsigned long   enable:1;                       /* RW */
        } s3;
-       struct uv4h_rh_gam_mmr_overlay_config_mmr_s {
-               unsigned long   rsvd_0_25:26;
-               unsigned long   base:20;                        /* RW */
-               unsigned long   rsvd_46_62:17;
+
+       /* UV2 unique struct */
+       struct uv2h_rh_gam_alias_1_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
                unsigned long   enable:1;                       /* RW */
-       } s4;
+       } s2;
 };
 
 /* ========================================================================= */
-/*                                 UVH_RTC                                   */
+/*                    UVH_RH_GAM_ALIAS_1_REDIRECT_CONFIG                     */
 /* ========================================================================= */
-#define UV2H_RTC 0x340000UL
-#define UV3H_RTC 0x340000UL
-#define UV4H_RTC 0xe0000UL
-#define UVH_RTC (                                                      \
-       is_uv2_hub() ? UV2H_RTC :                                       \
-       is_uv3_hub() ? UV3H_RTC :                                       \
-       /*is_uv4_hub*/ UV4H_RTC)
+#define UVH_RH_GAM_ALIAS_1_REDIRECT_CONFIG (                           \
+       is_uv(UV4) ? 0x4800e0UL :                                       \
+       is_uv(UV3) ? 0x16000e0UL :                                      \
+       is_uv(UV2) ? 0x16000e0UL :                                      \
+       0)
 
-#define UVH_RTC_REAL_TIME_CLOCK_SHFT                   0
-#define UVH_RTC_REAL_TIME_CLOCK_MASK                   0x00ffffffffffffffUL
 
+/* UVXH common defines */
+#define UVXH_RH_GAM_ALIAS_1_REDIRECT_CONFIG_DEST_BASE_SHFT 24
+#define UVXH_RH_GAM_ALIAS_1_REDIRECT_CONFIG_DEST_BASE_MASK 0x00003fffff000000UL
 
-union uvh_rtc_u {
+
+union uvh_rh_gam_alias_1_redirect_config_u {
        unsigned long   v;
-       struct uvh_rtc_s {
-               unsigned long   real_time_clock:56;             /* RW */
-               unsigned long   rsvd_56_63:8;
+
+       /* UVH common struct */
+       struct uvh_rh_gam_alias_1_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
        } s;
+
+       /* UVXH common struct */
+       struct uvxh_rh_gam_alias_1_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } sx;
+
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_alias_1_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_alias_1_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_rh_gam_alias_1_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } s2;
 };
 
 /* ========================================================================= */
-/*                           UVH_RTC1_INT_CONFIG                             */
+/*                    UVH_RH_GAM_ALIAS_2_OVERLAY_CONFIG                      */
 /* ========================================================================= */
-#define UVH_RTC1_INT_CONFIG 0x615c0UL
+#define UVH_RH_GAM_ALIAS_2_OVERLAY_CONFIG (                            \
+       is_uv(UV4) ? 0x4800e8UL :                                       \
+       is_uv(UV3) ? 0x16000e8UL :                                      \
+       is_uv(UV2) ? 0x16000e8UL :                                      \
+       0)
 
-#define UVH_RTC1_INT_CONFIG_VECTOR_SHFT                        0
-#define UVH_RTC1_INT_CONFIG_DM_SHFT                    8
-#define UVH_RTC1_INT_CONFIG_DESTMODE_SHFT              11
-#define UVH_RTC1_INT_CONFIG_STATUS_SHFT                        12
-#define UVH_RTC1_INT_CONFIG_P_SHFT                     13
-#define UVH_RTC1_INT_CONFIG_T_SHFT                     15
-#define UVH_RTC1_INT_CONFIG_M_SHFT                     16
-#define UVH_RTC1_INT_CONFIG_APIC_ID_SHFT               32
-#define UVH_RTC1_INT_CONFIG_VECTOR_MASK                        0x00000000000000ffUL
-#define UVH_RTC1_INT_CONFIG_DM_MASK                    0x0000000000000700UL
-#define UVH_RTC1_INT_CONFIG_DESTMODE_MASK              0x0000000000000800UL
-#define UVH_RTC1_INT_CONFIG_STATUS_MASK                        0x0000000000001000UL
-#define UVH_RTC1_INT_CONFIG_P_MASK                     0x0000000000002000UL
-#define UVH_RTC1_INT_CONFIG_T_MASK                     0x0000000000008000UL
-#define UVH_RTC1_INT_CONFIG_M_MASK                     0x0000000000010000UL
-#define UVH_RTC1_INT_CONFIG_APIC_ID_MASK               0xffffffff00000000UL
 
+/* UVXH common defines */
+#define UVXH_RH_GAM_ALIAS_2_OVERLAY_CONFIG_BASE_SHFT   24
+#define UVXH_RH_GAM_ALIAS_2_OVERLAY_CONFIG_BASE_MASK   0x00000000ff000000UL
+#define UVXH_RH_GAM_ALIAS_2_OVERLAY_CONFIG_M_ALIAS_SHFT        48
+#define UVXH_RH_GAM_ALIAS_2_OVERLAY_CONFIG_M_ALIAS_MASK        0x001f000000000000UL
+#define UVXH_RH_GAM_ALIAS_2_OVERLAY_CONFIG_ENABLE_SHFT 63
+#define UVXH_RH_GAM_ALIAS_2_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
 
-union uvh_rtc1_int_config_u {
+
+union uvh_rh_gam_alias_2_overlay_config_u {
        unsigned long   v;
-       struct uvh_rtc1_int_config_s {
-               unsigned long   vector_:8;                      /* RW */
-               unsigned long   dm:3;                           /* RW */
-               unsigned long   destmode:1;                     /* RW */
-               unsigned long   status:1;                       /* RO */
-               unsigned long   p:1;                            /* RO */
-               unsigned long   rsvd_14:1;
-               unsigned long   t:1;                            /* RO */
-               unsigned long   m:1;                            /* RW */
-               unsigned long   rsvd_17_31:15;
-               unsigned long   apic_id:32;                     /* RW */
+
+       /* UVH common struct */
+       struct uvh_rh_gam_alias_2_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
+               unsigned long   enable:1;                       /* RW */
        } s;
+
+       /* UVXH common struct */
+       struct uvxh_rh_gam_alias_2_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
+               unsigned long   enable:1;                       /* RW */
+       } sx;
+
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_alias_2_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
+               unsigned long   enable:1;                       /* RW */
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_alias_2_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
+               unsigned long   enable:1;                       /* RW */
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_rh_gam_alias_2_overlay_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   base:8;                         /* RW */
+               unsigned long   rsvd_32_47:16;
+               unsigned long   m_alias:5;                      /* RW */
+               unsigned long   rsvd_53_62:10;
+               unsigned long   enable:1;                       /* RW */
+       } s2;
 };
 
 /* ========================================================================= */
-/*                               UVH_SCRATCH5                                */
+/*                    UVH_RH_GAM_ALIAS_2_REDIRECT_CONFIG                     */
 /* ========================================================================= */
-#define UV2H_SCRATCH5 0x2d0200UL
-#define UV3H_SCRATCH5 0x2d0200UL
-#define UV4H_SCRATCH5 0xb0200UL
-#define UVH_SCRATCH5 (                                                 \
-       is_uv2_hub() ? UV2H_SCRATCH5 :                                  \
-       is_uv3_hub() ? UV3H_SCRATCH5 :                                  \
-       /*is_uv4_hub*/ UV4H_SCRATCH5)
-
-#define UV2H_SCRATCH5_32 0x778
-#define UV3H_SCRATCH5_32 0x778
-#define UV4H_SCRATCH5_32 0x798
-#define UVH_SCRATCH5_32 (                                              \
-       is_uv2_hub() ? UV2H_SCRATCH5_32 :                               \
-       is_uv3_hub() ? UV3H_SCRATCH5_32 :                               \
-       /*is_uv4_hub*/ UV4H_SCRATCH5_32)
+#define UVH_RH_GAM_ALIAS_2_REDIRECT_CONFIG (                           \
+       is_uv(UV4) ? 0x4800f0UL :                                       \
+       is_uv(UV3) ? 0x16000f0UL :                                      \
+       is_uv(UV2) ? 0x16000f0UL :                                      \
+       0)
 
-#define UVH_SCRATCH5_SCRATCH5_SHFT                     0
-#define UVH_SCRATCH5_SCRATCH5_MASK                     0xffffffffffffffffUL
 
+/* UVXH common defines */
+#define UVXH_RH_GAM_ALIAS_2_REDIRECT_CONFIG_DEST_BASE_SHFT 24
+#define UVXH_RH_GAM_ALIAS_2_REDIRECT_CONFIG_DEST_BASE_MASK 0x00003fffff000000UL
 
-union uvh_scratch5_u {
+
+union uvh_rh_gam_alias_2_redirect_config_u {
        unsigned long   v;
-       struct uvh_scratch5_s {
-               unsigned long   scratch5:64;                    /* RW, W1CS */
-       } s;
-};
 
-/* ========================================================================= */
-/*                            UVH_SCRATCH5_ALIAS                             */
-/* ========================================================================= */
-#define UV2H_SCRATCH5_ALIAS 0x2d0208UL
-#define UV3H_SCRATCH5_ALIAS 0x2d0208UL
-#define UV4H_SCRATCH5_ALIAS 0xb0208UL
-#define UVH_SCRATCH5_ALIAS (                                           \
-       is_uv2_hub() ? UV2H_SCRATCH5_ALIAS :                            \
-       is_uv3_hub() ? UV3H_SCRATCH5_ALIAS :                            \
-       /*is_uv4_hub*/ UV4H_SCRATCH5_ALIAS)
+       /* UVH common struct */
+       struct uvh_rh_gam_alias_2_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } s;
 
-#define UV2H_SCRATCH5_ALIAS_32 0x780
-#define UV3H_SCRATCH5_ALIAS_32 0x780
-#define UV4H_SCRATCH5_ALIAS_32 0x7a0
-#define UVH_SCRATCH5_ALIAS_32 (                                                \
-       is_uv2_hub() ? UV2H_SCRATCH5_ALIAS_32 :                         \
-       is_uv3_hub() ? UV3H_SCRATCH5_ALIAS_32 :                         \
-       /*is_uv4_hub*/ UV4H_SCRATCH5_ALIAS_32)
+       /* UVXH common struct */
+       struct uvxh_rh_gam_alias_2_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } sx;
 
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_alias_2_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } s4;
 
-/* ========================================================================= */
-/*                           UVH_SCRATCH5_ALIAS_2                            */
-/* ========================================================================= */
-#define UV2H_SCRATCH5_ALIAS_2 0x2d0210UL
-#define UV3H_SCRATCH5_ALIAS_2 0x2d0210UL
-#define UV4H_SCRATCH5_ALIAS_2 0xb0210UL
-#define UVH_SCRATCH5_ALIAS_2 (                                         \
-       is_uv2_hub() ? UV2H_SCRATCH5_ALIAS_2 :                          \
-       is_uv3_hub() ? UV3H_SCRATCH5_ALIAS_2 :                          \
-       /*is_uv4_hub*/ UV4H_SCRATCH5_ALIAS_2)
-#define UVH_SCRATCH5_ALIAS_2_32 0x788
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_alias_2_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } s3;
 
+       /* UV2 unique struct */
+       struct uv2h_rh_gam_alias_2_redirect_config_s {
+               unsigned long   rsvd_0_23:24;
+               unsigned long   dest_base:22;                   /* RW */
+               unsigned long   rsvd_46_63:18;
+       } s2;
+};
 
 /* ========================================================================= */
-/*                          UVXH_EVENT_OCCURRED2                             */
+/*                      UVH_RH_GAM_GRU_OVERLAY_CONFIG                        */
 /* ========================================================================= */
-#define UVXH_EVENT_OCCURRED2 0x70100UL
-
-#define UV2H_EVENT_OCCURRED2_32 0xb68
-#define UV3H_EVENT_OCCURRED2_32 0xb68
-#define UV4H_EVENT_OCCURRED2_32 0x608
-#define UVH_EVENT_OCCURRED2_32 (                                       \
-       is_uv2_hub() ? UV2H_EVENT_OCCURRED2_32 :                        \
-       is_uv3_hub() ? UV3H_EVENT_OCCURRED2_32 :                        \
-       /*is_uv4_hub*/ UV4H_EVENT_OCCURRED2_32)
-
-
-#define UV2H_EVENT_OCCURRED2_RTC_0_SHFT                        0
-#define UV2H_EVENT_OCCURRED2_RTC_1_SHFT                        1
-#define UV2H_EVENT_OCCURRED2_RTC_2_SHFT                        2
-#define UV2H_EVENT_OCCURRED2_RTC_3_SHFT                        3
-#define UV2H_EVENT_OCCURRED2_RTC_4_SHFT                        4
-#define UV2H_EVENT_OCCURRED2_RTC_5_SHFT                        5
-#define UV2H_EVENT_OCCURRED2_RTC_6_SHFT                        6
-#define UV2H_EVENT_OCCURRED2_RTC_7_SHFT                        7
-#define UV2H_EVENT_OCCURRED2_RTC_8_SHFT                        8
-#define UV2H_EVENT_OCCURRED2_RTC_9_SHFT                        9
-#define UV2H_EVENT_OCCURRED2_RTC_10_SHFT               10
-#define UV2H_EVENT_OCCURRED2_RTC_11_SHFT               11
-#define UV2H_EVENT_OCCURRED2_RTC_12_SHFT               12
-#define UV2H_EVENT_OCCURRED2_RTC_13_SHFT               13
-#define UV2H_EVENT_OCCURRED2_RTC_14_SHFT               14
-#define UV2H_EVENT_OCCURRED2_RTC_15_SHFT               15
-#define UV2H_EVENT_OCCURRED2_RTC_16_SHFT               16
-#define UV2H_EVENT_OCCURRED2_RTC_17_SHFT               17
-#define UV2H_EVENT_OCCURRED2_RTC_18_SHFT               18
-#define UV2H_EVENT_OCCURRED2_RTC_19_SHFT               19
-#define UV2H_EVENT_OCCURRED2_RTC_20_SHFT               20
-#define UV2H_EVENT_OCCURRED2_RTC_21_SHFT               21
-#define UV2H_EVENT_OCCURRED2_RTC_22_SHFT               22
-#define UV2H_EVENT_OCCURRED2_RTC_23_SHFT               23
-#define UV2H_EVENT_OCCURRED2_RTC_24_SHFT               24
-#define UV2H_EVENT_OCCURRED2_RTC_25_SHFT               25
-#define UV2H_EVENT_OCCURRED2_RTC_26_SHFT               26
-#define UV2H_EVENT_OCCURRED2_RTC_27_SHFT               27
-#define UV2H_EVENT_OCCURRED2_RTC_28_SHFT               28
-#define UV2H_EVENT_OCCURRED2_RTC_29_SHFT               29
-#define UV2H_EVENT_OCCURRED2_RTC_30_SHFT               30
-#define UV2H_EVENT_OCCURRED2_RTC_31_SHFT               31
-#define UV2H_EVENT_OCCURRED2_RTC_0_MASK                        0x0000000000000001UL
-#define UV2H_EVENT_OCCURRED2_RTC_1_MASK                        0x0000000000000002UL
-#define UV2H_EVENT_OCCURRED2_RTC_2_MASK                        0x0000000000000004UL
-#define UV2H_EVENT_OCCURRED2_RTC_3_MASK                        0x0000000000000008UL
-#define UV2H_EVENT_OCCURRED2_RTC_4_MASK                        0x0000000000000010UL
-#define UV2H_EVENT_OCCURRED2_RTC_5_MASK                        0x0000000000000020UL
-#define UV2H_EVENT_OCCURRED2_RTC_6_MASK                        0x0000000000000040UL
-#define UV2H_EVENT_OCCURRED2_RTC_7_MASK                        0x0000000000000080UL
-#define UV2H_EVENT_OCCURRED2_RTC_8_MASK                        0x0000000000000100UL
-#define UV2H_EVENT_OCCURRED2_RTC_9_MASK                        0x0000000000000200UL
-#define UV2H_EVENT_OCCURRED2_RTC_10_MASK               0x0000000000000400UL
-#define UV2H_EVENT_OCCURRED2_RTC_11_MASK               0x0000000000000800UL
-#define UV2H_EVENT_OCCURRED2_RTC_12_MASK               0x0000000000001000UL
-#define UV2H_EVENT_OCCURRED2_RTC_13_MASK               0x0000000000002000UL
-#define UV2H_EVENT_OCCURRED2_RTC_14_MASK               0x0000000000004000UL
-#define UV2H_EVENT_OCCURRED2_RTC_15_MASK               0x0000000000008000UL
-#define UV2H_EVENT_OCCURRED2_RTC_16_MASK               0x0000000000010000UL
-#define UV2H_EVENT_OCCURRED2_RTC_17_MASK               0x0000000000020000UL
-#define UV2H_EVENT_OCCURRED2_RTC_18_MASK               0x0000000000040000UL
-#define UV2H_EVENT_OCCURRED2_RTC_19_MASK               0x0000000000080000UL
-#define UV2H_EVENT_OCCURRED2_RTC_20_MASK               0x0000000000100000UL
-#define UV2H_EVENT_OCCURRED2_RTC_21_MASK               0x0000000000200000UL
-#define UV2H_EVENT_OCCURRED2_RTC_22_MASK               0x0000000000400000UL
-#define UV2H_EVENT_OCCURRED2_RTC_23_MASK               0x0000000000800000UL
-#define UV2H_EVENT_OCCURRED2_RTC_24_MASK               0x0000000001000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_25_MASK               0x0000000002000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_26_MASK               0x0000000004000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_27_MASK               0x0000000008000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_28_MASK               0x0000000010000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_29_MASK               0x0000000020000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_30_MASK               0x0000000040000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_31_MASK               0x0000000080000000UL
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG (                                        \
+       is_uv(UV4) ? 0x480010UL :                                       \
+       is_uv(UV3) ? 0x1600010UL :                                      \
+       is_uv(UV2) ? 0x1600010UL :                                      \
+       0)
+
+
+/* UVXH common defines */
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_N_GRU_SHFT      52
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_N_GRU_MASK      0x00f0000000000000UL
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_ENABLE_SHFT     63
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_ENABLE_MASK     0x8000000000000000UL
+
+/* UV4A unique defines */
+#define UV4AH_RH_GAM_GRU_OVERLAY_CONFIG_BASE_SHFT      26
+#define UV4AH_RH_GAM_GRU_OVERLAY_CONFIG_BASE_MASK      0x000ffffffc000000UL
+
+/* UV4 unique defines */
+#define UV4H_RH_GAM_GRU_OVERLAY_CONFIG_BASE_SHFT       26
+#define UV4H_RH_GAM_GRU_OVERLAY_CONFIG_BASE_MASK       0x00003ffffc000000UL
+
+/* UV3 unique defines */
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_BASE_SHFT       28
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_BASE_MASK       0x00003ffff0000000UL
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MODE_SHFT       62
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MODE_MASK       0x4000000000000000UL
+
+/* UV2 unique defines */
+#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_BASE_SHFT       28
+#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_BASE_MASK       0x00003ffff0000000UL
+
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_BASE_MASK (                      \
+       is_uv(UV4A) ? 0x000ffffffc000000UL :                            \
+       is_uv(UV4) ? 0x00003ffffc000000UL :                             \
+       is_uv(UV3) ? 0x00003ffff0000000UL :                             \
+       is_uv(UV2) ? 0x00003ffff0000000UL :                             \
+       0)
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_BASE_SHFT (                      \
+       is_uv(UV4) ? 26 :                                               \
+       is_uv(UV3) ? 28 :                                               \
+       is_uv(UV2) ? 28 :                                               \
+       -1)
+
+union uvh_rh_gam_gru_overlay_config_u {
+       unsigned long   v;
 
-#define UV3H_EVENT_OCCURRED2_RTC_0_SHFT                        0
-#define UV3H_EVENT_OCCURRED2_RTC_1_SHFT                        1
-#define UV3H_EVENT_OCCURRED2_RTC_2_SHFT                        2
-#define UV3H_EVENT_OCCURRED2_RTC_3_SHFT                        3
-#define UV3H_EVENT_OCCURRED2_RTC_4_SHFT                        4
-#define UV3H_EVENT_OCCURRED2_RTC_5_SHFT                        5
-#define UV3H_EVENT_OCCURRED2_RTC_6_SHFT                        6
-#define UV3H_EVENT_OCCURRED2_RTC_7_SHFT                        7
-#define UV3H_EVENT_OCCURRED2_RTC_8_SHFT                        8
-#define UV3H_EVENT_OCCURRED2_RTC_9_SHFT                        9
-#define UV3H_EVENT_OCCURRED2_RTC_10_SHFT               10
-#define UV3H_EVENT_OCCURRED2_RTC_11_SHFT               11
-#define UV3H_EVENT_OCCURRED2_RTC_12_SHFT               12
-#define UV3H_EVENT_OCCURRED2_RTC_13_SHFT               13
-#define UV3H_EVENT_OCCURRED2_RTC_14_SHFT               14
-#define UV3H_EVENT_OCCURRED2_RTC_15_SHFT               15
-#define UV3H_EVENT_OCCURRED2_RTC_16_SHFT               16
-#define UV3H_EVENT_OCCURRED2_RTC_17_SHFT               17
-#define UV3H_EVENT_OCCURRED2_RTC_18_SHFT               18
-#define UV3H_EVENT_OCCURRED2_RTC_19_SHFT               19
-#define UV3H_EVENT_OCCURRED2_RTC_20_SHFT               20
-#define UV3H_EVENT_OCCURRED2_RTC_21_SHFT               21
-#define UV3H_EVENT_OCCURRED2_RTC_22_SHFT               22
-#define UV3H_EVENT_OCCURRED2_RTC_23_SHFT               23
-#define UV3H_EVENT_OCCURRED2_RTC_24_SHFT               24
-#define UV3H_EVENT_OCCURRED2_RTC_25_SHFT               25
-#define UV3H_EVENT_OCCURRED2_RTC_26_SHFT               26
-#define UV3H_EVENT_OCCURRED2_RTC_27_SHFT               27
-#define UV3H_EVENT_OCCURRED2_RTC_28_SHFT               28
-#define UV3H_EVENT_OCCURRED2_RTC_29_SHFT               29
-#define UV3H_EVENT_OCCURRED2_RTC_30_SHFT               30
-#define UV3H_EVENT_OCCURRED2_RTC_31_SHFT               31
-#define UV3H_EVENT_OCCURRED2_RTC_0_MASK                        0x0000000000000001UL
-#define UV3H_EVENT_OCCURRED2_RTC_1_MASK                        0x0000000000000002UL
-#define UV3H_EVENT_OCCURRED2_RTC_2_MASK                        0x0000000000000004UL
-#define UV3H_EVENT_OCCURRED2_RTC_3_MASK                        0x0000000000000008UL
-#define UV3H_EVENT_OCCURRED2_RTC_4_MASK                        0x0000000000000010UL
-#define UV3H_EVENT_OCCURRED2_RTC_5_MASK                        0x0000000000000020UL
-#define UV3H_EVENT_OCCURRED2_RTC_6_MASK                        0x0000000000000040UL
-#define UV3H_EVENT_OCCURRED2_RTC_7_MASK                        0x0000000000000080UL
-#define UV3H_EVENT_OCCURRED2_RTC_8_MASK                        0x0000000000000100UL
-#define UV3H_EVENT_OCCURRED2_RTC_9_MASK                        0x0000000000000200UL
-#define UV3H_EVENT_OCCURRED2_RTC_10_MASK               0x0000000000000400UL
-#define UV3H_EVENT_OCCURRED2_RTC_11_MASK               0x0000000000000800UL
-#define UV3H_EVENT_OCCURRED2_RTC_12_MASK               0x0000000000001000UL
-#define UV3H_EVENT_OCCURRED2_RTC_13_MASK               0x0000000000002000UL
-#define UV3H_EVENT_OCCURRED2_RTC_14_MASK               0x0000000000004000UL
-#define UV3H_EVENT_OCCURRED2_RTC_15_MASK               0x0000000000008000UL
-#define UV3H_EVENT_OCCURRED2_RTC_16_MASK               0x0000000000010000UL
-#define UV3H_EVENT_OCCURRED2_RTC_17_MASK               0x0000000000020000UL
-#define UV3H_EVENT_OCCURRED2_RTC_18_MASK               0x0000000000040000UL
-#define UV3H_EVENT_OCCURRED2_RTC_19_MASK               0x0000000000080000UL
-#define UV3H_EVENT_OCCURRED2_RTC_20_MASK               0x0000000000100000UL
-#define UV3H_EVENT_OCCURRED2_RTC_21_MASK               0x0000000000200000UL
-#define UV3H_EVENT_OCCURRED2_RTC_22_MASK               0x0000000000400000UL
-#define UV3H_EVENT_OCCURRED2_RTC_23_MASK               0x0000000000800000UL
-#define UV3H_EVENT_OCCURRED2_RTC_24_MASK               0x0000000001000000UL
-#define UV3H_EVENT_OCCURRED2_RTC_25_MASK               0x0000000002000000UL
-#define UV3H_EVENT_OCCURRED2_RTC_26_MASK               0x0000000004000000UL
-#define UV3H_EVENT_OCCURRED2_RTC_27_MASK               0x0000000008000000UL
-#define UV3H_EVENT_OCCURRED2_RTC_28_MASK               0x0000000010000000UL
-#define UV3H_EVENT_OCCURRED2_RTC_29_MASK               0x0000000020000000UL
-#define UV3H_EVENT_OCCURRED2_RTC_30_MASK               0x0000000040000000UL
-#define UV3H_EVENT_OCCURRED2_RTC_31_MASK               0x0000000080000000UL
+       /* UVH common struct */
+       struct uvh_rh_gam_gru_overlay_config_s {
+               unsigned long   rsvd_0_45:46;
+               unsigned long   rsvd_46_51:6;
+               unsigned long   n_gru:4;                        /* RW */
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s;
+
+       /* UVXH common struct */
+       struct uvxh_rh_gam_gru_overlay_config_s {
+               unsigned long   rsvd_0_45:46;
+               unsigned long   rsvd_46_51:6;
+               unsigned long   n_gru:4;                        /* RW */
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } sx;
+
+       /* UV4A unique struct */
+       struct uv4ah_rh_gam_gru_overlay_config_s {
+               unsigned long   rsvd_0_24:25;
+               unsigned long   undef_25:1;                     /* Undefined */
+               unsigned long   base:26;                        /* RW */
+               unsigned long   n_gru:4;                        /* RW */
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s4a;
+
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_gru_overlay_config_s {
+               unsigned long   rsvd_0_24:25;
+               unsigned long   undef_25:1;                     /* Undefined */
+               unsigned long   base:20;                        /* RW */
+               unsigned long   rsvd_46_51:6;
+               unsigned long   n_gru:4;                        /* RW */
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_gru_overlay_config_s {
+               unsigned long   rsvd_0_27:28;
+               unsigned long   base:18;                        /* RW */
+               unsigned long   rsvd_46_51:6;
+               unsigned long   n_gru:4;                        /* RW */
+               unsigned long   rsvd_56_61:6;
+               unsigned long   mode:1;                         /* RW */
+               unsigned long   enable:1;                       /* RW */
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_rh_gam_gru_overlay_config_s {
+               unsigned long   rsvd_0_27:28;
+               unsigned long   base:18;                        /* RW */
+               unsigned long   rsvd_46_51:6;
+               unsigned long   n_gru:4;                        /* RW */
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s2;
+};
+
+/* ========================================================================= */
+/*                     UVH_RH_GAM_MMIOH_OVERLAY_CONFIG                       */
+/* ========================================================================= */
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG (                              \
+       is_uv(UV2) ? 0x1600030UL :                                      \
+       0)
 
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT0_SHFT 0
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT1_SHFT 1
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT2_SHFT 2
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT3_SHFT 3
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT4_SHFT 4
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT5_SHFT 5
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT6_SHFT 6
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT7_SHFT 7
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT8_SHFT 8
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT9_SHFT 9
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT10_SHFT 10
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT11_SHFT 11
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT12_SHFT 12
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT13_SHFT 13
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT14_SHFT 14
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT15_SHFT 15
-#define UV4H_EVENT_OCCURRED2_RTC_INTERVAL_INT_SHFT     16
-#define UV4H_EVENT_OCCURRED2_BAU_DASHBOARD_INT_SHFT    17
-#define UV4H_EVENT_OCCURRED2_RTC_0_SHFT                        18
-#define UV4H_EVENT_OCCURRED2_RTC_1_SHFT                        19
-#define UV4H_EVENT_OCCURRED2_RTC_2_SHFT                        20
-#define UV4H_EVENT_OCCURRED2_RTC_3_SHFT                        21
-#define UV4H_EVENT_OCCURRED2_RTC_4_SHFT                        22
-#define UV4H_EVENT_OCCURRED2_RTC_5_SHFT                        23
-#define UV4H_EVENT_OCCURRED2_RTC_6_SHFT                        24
-#define UV4H_EVENT_OCCURRED2_RTC_7_SHFT                        25
-#define UV4H_EVENT_OCCURRED2_RTC_8_SHFT                        26
-#define UV4H_EVENT_OCCURRED2_RTC_9_SHFT                        27
-#define UV4H_EVENT_OCCURRED2_RTC_10_SHFT               28
-#define UV4H_EVENT_OCCURRED2_RTC_11_SHFT               29
-#define UV4H_EVENT_OCCURRED2_RTC_12_SHFT               30
-#define UV4H_EVENT_OCCURRED2_RTC_13_SHFT               31
-#define UV4H_EVENT_OCCURRED2_RTC_14_SHFT               32
-#define UV4H_EVENT_OCCURRED2_RTC_15_SHFT               33
-#define UV4H_EVENT_OCCURRED2_RTC_16_SHFT               34
-#define UV4H_EVENT_OCCURRED2_RTC_17_SHFT               35
-#define UV4H_EVENT_OCCURRED2_RTC_18_SHFT               36
-#define UV4H_EVENT_OCCURRED2_RTC_19_SHFT               37
-#define UV4H_EVENT_OCCURRED2_RTC_20_SHFT               38
-#define UV4H_EVENT_OCCURRED2_RTC_21_SHFT               39
-#define UV4H_EVENT_OCCURRED2_RTC_22_SHFT               40
-#define UV4H_EVENT_OCCURRED2_RTC_23_SHFT               41
-#define UV4H_EVENT_OCCURRED2_RTC_24_SHFT               42
-#define UV4H_EVENT_OCCURRED2_RTC_25_SHFT               43
-#define UV4H_EVENT_OCCURRED2_RTC_26_SHFT               44
-#define UV4H_EVENT_OCCURRED2_RTC_27_SHFT               45
-#define UV4H_EVENT_OCCURRED2_RTC_28_SHFT               46
-#define UV4H_EVENT_OCCURRED2_RTC_29_SHFT               47
-#define UV4H_EVENT_OCCURRED2_RTC_30_SHFT               48
-#define UV4H_EVENT_OCCURRED2_RTC_31_SHFT               49
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT0_MASK 0x0000000000000001UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT1_MASK 0x0000000000000002UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT2_MASK 0x0000000000000004UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT3_MASK 0x0000000000000008UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT4_MASK 0x0000000000000010UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT5_MASK 0x0000000000000020UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT6_MASK 0x0000000000000040UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT7_MASK 0x0000000000000080UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT8_MASK 0x0000000000000100UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT9_MASK 0x0000000000000200UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT10_MASK 0x0000000000000400UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT11_MASK 0x0000000000000800UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT12_MASK 0x0000000000001000UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT13_MASK 0x0000000000002000UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT14_MASK 0x0000000000004000UL
-#define UV4H_EVENT_OCCURRED2_MESSAGE_ACCELERATOR_INT15_MASK 0x0000000000008000UL
-#define UV4H_EVENT_OCCURRED2_RTC_INTERVAL_INT_MASK     0x0000000000010000UL
-#define UV4H_EVENT_OCCURRED2_BAU_DASHBOARD_INT_MASK    0x0000000000020000UL
-#define UV4H_EVENT_OCCURRED2_RTC_0_MASK                        0x0000000000040000UL
-#define UV4H_EVENT_OCCURRED2_RTC_1_MASK                        0x0000000000080000UL
-#define UV4H_EVENT_OCCURRED2_RTC_2_MASK                        0x0000000000100000UL
-#define UV4H_EVENT_OCCURRED2_RTC_3_MASK                        0x0000000000200000UL
-#define UV4H_EVENT_OCCURRED2_RTC_4_MASK                        0x0000000000400000UL
-#define UV4H_EVENT_OCCURRED2_RTC_5_MASK                        0x0000000000800000UL
-#define UV4H_EVENT_OCCURRED2_RTC_6_MASK                        0x0000000001000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_7_MASK                        0x0000000002000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_8_MASK                        0x0000000004000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_9_MASK                        0x0000000008000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_10_MASK               0x0000000010000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_11_MASK               0x0000000020000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_12_MASK               0x0000000040000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_13_MASK               0x0000000080000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_14_MASK               0x0000000100000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_15_MASK               0x0000000200000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_16_MASK               0x0000000400000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_17_MASK               0x0000000800000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_18_MASK               0x0000001000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_19_MASK               0x0000002000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_20_MASK               0x0000004000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_21_MASK               0x0000008000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_22_MASK               0x0000010000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_23_MASK               0x0000020000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_24_MASK               0x0000040000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_25_MASK               0x0000080000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_26_MASK               0x0000100000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_27_MASK               0x0000200000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_28_MASK               0x0000400000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_29_MASK               0x0000800000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_30_MASK               0x0001000000000000UL
-#define UV4H_EVENT_OCCURRED2_RTC_31_MASK               0x0002000000000000UL
 
-#define UVXH_EVENT_OCCURRED2_RTC_1_MASK (                              \
-       is_uv2_hub() ? UV2H_EVENT_OCCURRED2_RTC_1_MASK :                \
-       is_uv3_hub() ? UV3H_EVENT_OCCURRED2_RTC_1_MASK :                \
-       /*is_uv4_hub*/ UV4H_EVENT_OCCURRED2_RTC_1_MASK)
 
-union uvh_event_occurred2_u {
+/* UV2 unique defines */
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_BASE_SHFT     27
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_BASE_MASK     0x00003ffff8000000UL
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_M_IO_SHFT     46
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_M_IO_MASK     0x000fc00000000000UL
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_N_IO_SHFT     52
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_N_IO_MASK     0x00f0000000000000UL
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_ENABLE_SHFT   63
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_ENABLE_MASK   0x8000000000000000UL
+
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_BASE_SHFT (                    \
+       is_uv(UV2) ? 27 :                                               \
+       uv_undefined("UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_BASE_SHFT"))
+
+union uvh_rh_gam_mmioh_overlay_config_u {
        unsigned long   v;
-       struct uv2h_event_occurred2_s {
-               unsigned long   rtc_0:1;                        /* RW */
-               unsigned long   rtc_1:1;                        /* RW */
-               unsigned long   rtc_2:1;                        /* RW */
-               unsigned long   rtc_3:1;                        /* RW */
-               unsigned long   rtc_4:1;                        /* RW */
-               unsigned long   rtc_5:1;                        /* RW */
-               unsigned long   rtc_6:1;                        /* RW */
-               unsigned long   rtc_7:1;                        /* RW */
-               unsigned long   rtc_8:1;                        /* RW */
-               unsigned long   rtc_9:1;                        /* RW */
-               unsigned long   rtc_10:1;                       /* RW */
-               unsigned long   rtc_11:1;                       /* RW */
-               unsigned long   rtc_12:1;                       /* RW */
-               unsigned long   rtc_13:1;                       /* RW */
-               unsigned long   rtc_14:1;                       /* RW */
-               unsigned long   rtc_15:1;                       /* RW */
-               unsigned long   rtc_16:1;                       /* RW */
-               unsigned long   rtc_17:1;                       /* RW */
-               unsigned long   rtc_18:1;                       /* RW */
-               unsigned long   rtc_19:1;                       /* RW */
-               unsigned long   rtc_20:1;                       /* RW */
-               unsigned long   rtc_21:1;                       /* RW */
-               unsigned long   rtc_22:1;                       /* RW */
-               unsigned long   rtc_23:1;                       /* RW */
-               unsigned long   rtc_24:1;                       /* RW */
-               unsigned long   rtc_25:1;                       /* RW */
-               unsigned long   rtc_26:1;                       /* RW */
-               unsigned long   rtc_27:1;                       /* RW */
-               unsigned long   rtc_28:1;                       /* RW */
-               unsigned long   rtc_29:1;                       /* RW */
-               unsigned long   rtc_30:1;                       /* RW */
-               unsigned long   rtc_31:1;                       /* RW */
-               unsigned long   rsvd_32_63:32;
+
+       /* UVH common struct */
+       struct uvh_rh_gam_mmioh_overlay_config_s {
+               unsigned long   rsvd_0_26:27;
+               unsigned long   base:19;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;                         /* RW */
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s;
+
+       /* UVXH common struct */
+       struct uvxh_rh_gam_mmioh_overlay_config_s {
+               unsigned long   rsvd_0_26:27;
+               unsigned long   base:19;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;                         /* RW */
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } sx;
+
+       /* UV2 unique struct */
+       struct uv2h_rh_gam_mmioh_overlay_config_s {
+               unsigned long   rsvd_0_26:27;
+               unsigned long   base:19;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;                         /* RW */
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
        } s2;
-       struct uv3h_event_occurred2_s {
-               unsigned long   rtc_0:1;                        /* RW */
-               unsigned long   rtc_1:1;                        /* RW */
-               unsigned long   rtc_2:1;                        /* RW */
-               unsigned long   rtc_3:1;                        /* RW */
-               unsigned long   rtc_4:1;                        /* RW */
-               unsigned long   rtc_5:1;                        /* RW */
-               unsigned long   rtc_6:1;                        /* RW */
-               unsigned long   rtc_7:1;                        /* RW */
-               unsigned long   rtc_8:1;                        /* RW */
-               unsigned long   rtc_9:1;                        /* RW */
-               unsigned long   rtc_10:1;                       /* RW */
-               unsigned long   rtc_11:1;                       /* RW */
-               unsigned long   rtc_12:1;                       /* RW */
-               unsigned long   rtc_13:1;                       /* RW */
-               unsigned long   rtc_14:1;                       /* RW */
-               unsigned long   rtc_15:1;                       /* RW */
-               unsigned long   rtc_16:1;                       /* RW */
-               unsigned long   rtc_17:1;                       /* RW */
-               unsigned long   rtc_18:1;                       /* RW */
-               unsigned long   rtc_19:1;                       /* RW */
-               unsigned long   rtc_20:1;                       /* RW */
-               unsigned long   rtc_21:1;                       /* RW */
-               unsigned long   rtc_22:1;                       /* RW */
-               unsigned long   rtc_23:1;                       /* RW */
-               unsigned long   rtc_24:1;                       /* RW */
-               unsigned long   rtc_25:1;                       /* RW */
-               unsigned long   rtc_26:1;                       /* RW */
-               unsigned long   rtc_27:1;                       /* RW */
-               unsigned long   rtc_28:1;                       /* RW */
-               unsigned long   rtc_29:1;                       /* RW */
-               unsigned long   rtc_30:1;                       /* RW */
-               unsigned long   rtc_31:1;                       /* RW */
-               unsigned long   rsvd_32_63:32;
+};
+
+/* ========================================================================= */
+/*                     UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0                      */
+/* ========================================================================= */
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0 (                             \
+       is_uv(UV4) ? 0x483000UL :                                       \
+       is_uv(UV3) ? 0x1603000UL :                                      \
+       0)
+
+/* UV4A unique defines */
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_SHFT   26
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK   0x000ffffffc000000UL
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_SHFT   52
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_MASK   0x03f0000000000000UL
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_ENABLE_SHFT 63
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG0_ENABLE_MASK 0x8000000000000000UL
+
+/* UV4 unique defines */
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_SHFT    26
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK    0x00003ffffc000000UL
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_SHFT    46
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_MASK    0x000fc00000000000UL
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_ENABLE_SHFT  63
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG0_ENABLE_MASK  0x8000000000000000UL
+
+/* UV3 unique defines */
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_SHFT    26
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK    0x00003ffffc000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_SHFT    46
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_M_IO_MASK    0x000fc00000000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_ENABLE_SHFT  63
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_ENABLE_MASK  0x8000000000000000UL
+
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK (                   \
+       is_uv(UV4A) ? 0x000ffffffc000000UL :                            \
+       is_uv(UV4) ? 0x00003ffffc000000UL :                             \
+       is_uv(UV3) ? 0x00003ffffc000000UL :                             \
+       0)
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_SHFT (                   \
+       is_uv(UV4) ? 26 :                                               \
+       is_uv(UV3) ? 26 :                                               \
+       -1)
+
+union uvh_rh_gam_mmioh_overlay_config0_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_rh_gam_mmioh_overlay_config0_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s;
+
+       /* UVXH common struct */
+       struct uvxh_rh_gam_mmioh_overlay_config0_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } sx;
+
+       /* UV4A unique struct */
+       struct uv4ah_rh_gam_mmioh_overlay_config0_mmr_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:26;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   undef_62:1;                     /* Undefined */
+               unsigned long   enable:1;                       /* RW */
+       } s4a;
+
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_mmioh_overlay_config0_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_mmioh_overlay_config0_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
        } s3;
-       struct uv4h_event_occurred2_s {
-               unsigned long   message_accelerator_int0:1;     /* RW */
-               unsigned long   message_accelerator_int1:1;     /* RW */
-               unsigned long   message_accelerator_int2:1;     /* RW */
-               unsigned long   message_accelerator_int3:1;     /* RW */
-               unsigned long   message_accelerator_int4:1;     /* RW */
-               unsigned long   message_accelerator_int5:1;     /* RW */
-               unsigned long   message_accelerator_int6:1;     /* RW */
-               unsigned long   message_accelerator_int7:1;     /* RW */
-               unsigned long   message_accelerator_int8:1;     /* RW */
-               unsigned long   message_accelerator_int9:1;     /* RW */
-               unsigned long   message_accelerator_int10:1;    /* RW */
-               unsigned long   message_accelerator_int11:1;    /* RW */
-               unsigned long   message_accelerator_int12:1;    /* RW */
-               unsigned long   message_accelerator_int13:1;    /* RW */
-               unsigned long   message_accelerator_int14:1;    /* RW */
-               unsigned long   message_accelerator_int15:1;    /* RW */
-               unsigned long   rtc_interval_int:1;             /* RW */
-               unsigned long   bau_dashboard_int:1;            /* RW */
-               unsigned long   rtc_0:1;                        /* RW */
-               unsigned long   rtc_1:1;                        /* RW */
-               unsigned long   rtc_2:1;                        /* RW */
-               unsigned long   rtc_3:1;                        /* RW */
-               unsigned long   rtc_4:1;                        /* RW */
-               unsigned long   rtc_5:1;                        /* RW */
-               unsigned long   rtc_6:1;                        /* RW */
-               unsigned long   rtc_7:1;                        /* RW */
-               unsigned long   rtc_8:1;                        /* RW */
-               unsigned long   rtc_9:1;                        /* RW */
-               unsigned long   rtc_10:1;                       /* RW */
-               unsigned long   rtc_11:1;                       /* RW */
-               unsigned long   rtc_12:1;                       /* RW */
-               unsigned long   rtc_13:1;                       /* RW */
-               unsigned long   rtc_14:1;                       /* RW */
-               unsigned long   rtc_15:1;                       /* RW */
-               unsigned long   rtc_16:1;                       /* RW */
-               unsigned long   rtc_17:1;                       /* RW */
-               unsigned long   rtc_18:1;                       /* RW */
-               unsigned long   rtc_19:1;                       /* RW */
-               unsigned long   rtc_20:1;                       /* RW */
-               unsigned long   rtc_21:1;                       /* RW */
-               unsigned long   rtc_22:1;                       /* RW */
-               unsigned long   rtc_23:1;                       /* RW */
-               unsigned long   rtc_24:1;                       /* RW */
-               unsigned long   rtc_25:1;                       /* RW */
-               unsigned long   rtc_26:1;                       /* RW */
-               unsigned long   rtc_27:1;                       /* RW */
-               unsigned long   rtc_28:1;                       /* RW */
-               unsigned long   rtc_29:1;                       /* RW */
-               unsigned long   rtc_30:1;                       /* RW */
-               unsigned long   rtc_31:1;                       /* RW */
-               unsigned long   rsvd_50_63:14;
+};
+
+/* ========================================================================= */
+/*                     UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1                      */
+/* ========================================================================= */
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1 (                             \
+       is_uv(UV4) ? 0x484000UL :                                       \
+       is_uv(UV3) ? 0x1604000UL :                                      \
+       0)
+
+/* UV4A unique defines */
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_SHFT   26
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK   0x000ffffffc000000UL
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_SHFT   52
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_MASK   0x03f0000000000000UL
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_ENABLE_SHFT 63
+#define UV4AH_RH_GAM_MMIOH_OVERLAY_CONFIG1_ENABLE_MASK 0x8000000000000000UL
+
+/* UV4 unique defines */
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_SHFT    26
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK    0x00003ffffc000000UL
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_SHFT    46
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_MASK    0x000fc00000000000UL
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_ENABLE_SHFT  63
+#define UV4H_RH_GAM_MMIOH_OVERLAY_CONFIG1_ENABLE_MASK  0x8000000000000000UL
+
+/* UV3 unique defines */
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_SHFT    26
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK    0x00003ffffc000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_SHFT    46
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_M_IO_MASK    0x000fc00000000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_ENABLE_SHFT  63
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_ENABLE_MASK  0x8000000000000000UL
+
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK (                   \
+       is_uv(UV4A) ? 0x000ffffffc000000UL : \
+       is_uv(UV4) ? 0x00003ffffc000000UL :                             \
+       is_uv(UV3) ? 0x00003ffffc000000UL :                             \
+       0)
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_SHFT (                   \
+       is_uv(UV4) ? 26 :                                               \
+       is_uv(UV3) ? 26 :                                               \
+       -1)
+
+union uvh_rh_gam_mmioh_overlay_config1_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_rh_gam_mmioh_overlay_config1_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s;
+
+       /* UVXH common struct */
+       struct uvxh_rh_gam_mmioh_overlay_config1_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } sx;
+
+       /* UV4A unique struct */
+       struct uv4ah_rh_gam_mmioh_overlay_config1_mmr_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:26;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   undef_62:1;                     /* Undefined */
+               unsigned long   enable:1;                       /* RW */
+       } s4a;
+
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_mmioh_overlay_config1_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
        } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_mmioh_overlay_config1_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s3;
 };
 
 /* ========================================================================= */
-/*                       UVXH_EVENT_OCCURRED2_ALIAS                          */
+/*                    UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0                      */
 /* ========================================================================= */
-#define UVXH_EVENT_OCCURRED2_ALIAS 0x70108UL
+#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0 (                            \
+       is_uv(UV4) ? 0x483800UL :                                       \
+       is_uv(UV3) ? 0x1603800UL :                                      \
+       0)
 
-#define UV2H_EVENT_OCCURRED2_ALIAS_32 0xb70
-#define UV3H_EVENT_OCCURRED2_ALIAS_32 0xb70
-#define UV4H_EVENT_OCCURRED2_ALIAS_32 0x610
-#define UVH_EVENT_OCCURRED2_ALIAS_32 (                                 \
-       is_uv2_hub() ? UV2H_EVENT_OCCURRED2_ALIAS_32 :                  \
-       is_uv3_hub() ? UV3H_EVENT_OCCURRED2_ALIAS_32 :                  \
-       /*is_uv4_hub*/ UV4H_EVENT_OCCURRED2_ALIAS_32)
+#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH (                      \
+       is_uv(UV4) ? 128 :                                              \
+       is_uv(UV3) ? 128 :                                              \
+       0)
 
+/* UV4A unique defines */
+#define UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_SHFT 0
+#define UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK 0x0000000000000fffUL
 
-/* ========================================================================= */
-/*                   UVXH_LB_BAU_SB_ACTIVATION_STATUS_2                      */
-/* ========================================================================= */
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL
-#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL
-#define UV4H_LB_BAU_SB_ACTIVATION_STATUS_2 0xc8130UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_2 (                            \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_ACTIVATION_STATUS_2 :             \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_ACTIVATION_STATUS_2 :             \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_ACTIVATION_STATUS_2)
+/* UV4 unique defines */
+#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_SHFT  0
+#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK  0x0000000000007fffUL
+
+/* UV3 unique defines */
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_SHFT  0
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK  0x0000000000007fffUL
 
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x9f0
-#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x9f0
-#define UV4H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0xa10
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_2_32 (                         \
-       is_uv2_hub() ? UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_32 :          \
-       is_uv3_hub() ? UV3H_LB_BAU_SB_ACTIVATION_STATUS_2_32 :          \
-       /*is_uv4_hub*/ UV4H_LB_BAU_SB_ACTIVATION_STATUS_2_32)
 
-#define UVXH_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
-#define UVXH_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
+union uvh_rh_gam_mmioh_redirect_config0_u {
+       unsigned long   v;
 
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
+       /* UVH common struct */
+       struct uvh_rh_gam_mmioh_redirect_config0_s {
+               unsigned long   nasid:15;                       /* RW */
+               unsigned long   rsvd_15_63:49;
+       } s;
 
-#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
-#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
+       /* UVXH common struct */
+       struct uvxh_rh_gam_mmioh_redirect_config0_s {
+               unsigned long   nasid:15;                       /* RW */
+               unsigned long   rsvd_15_63:49;
+       } sx;
 
-#define UV4H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
-#define UV4H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
+       struct uv4ah_rh_gam_mmioh_redirect_config0_s {
+               unsigned long   nasid:12;                       /* RW */
+               unsigned long   rsvd_12_63:52;
+       } s4a;
 
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_mmioh_redirect_config0_s {
+               unsigned long   nasid:15;                       /* RW */
+               unsigned long   rsvd_15_63:49;
+       } s4;
 
-union uvxh_lb_bau_sb_activation_status_2_u {
-       unsigned long   v;
-       struct uvxh_lb_bau_sb_activation_status_2_s {
-               unsigned long   aux_error:64;                   /* RW */
-       } sx;
-       struct uv2h_lb_bau_sb_activation_status_2_s {
-               unsigned long   aux_error:64;                   /* RW */
-       } s2;
-       struct uv3h_lb_bau_sb_activation_status_2_s {
-               unsigned long   aux_error:64;                   /* RW */
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_mmioh_redirect_config0_s {
+               unsigned long   nasid:15;                       /* RW */
+               unsigned long   rsvd_15_63:49;
        } s3;
-       struct uv4h_lb_bau_sb_activation_status_2_s {
-               unsigned long   aux_error:64;                   /* RW */
-       } s4;
 };
 
 /* ========================================================================= */
-/*                          UV3H_GR0_GAM_GR_CONFIG                           */
+/*                    UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1                      */
 /* ========================================================================= */
-#define UV3H_GR0_GAM_GR_CONFIG                         0xc00028UL
+#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1 (                            \
+       is_uv(UV4) ? 0x484800UL :                                       \
+       is_uv(UV3) ? 0x1604800UL :                                      \
+       0)
 
-#define UV3H_GR0_GAM_GR_CONFIG_M_SKT_SHFT              0
-#define UV3H_GR0_GAM_GR_CONFIG_SUBSPACE_SHFT           10
-#define UV3H_GR0_GAM_GR_CONFIG_M_SKT_MASK              0x000000000000003fUL
-#define UV3H_GR0_GAM_GR_CONFIG_SUBSPACE_MASK           0x0000000000000400UL
+#define UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH (                      \
+       is_uv(UV4) ? 128 :                                              \
+       is_uv(UV3) ? 128 :                                              \
+       0)
+
+/* UV4A unique defines */
+#define UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_SHFT 0
+#define UV4AH_RH_GAM_MMIOH_REDIRECT_CONFIG0_NASID_MASK 0x0000000000000fffUL
+
+/* UV4 unique defines */
+#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_SHFT  0
+#define UV4H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK  0x0000000000007fffUL
+
+/* UV3 unique defines */
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_SHFT  0
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_NASID_MASK  0x0000000000007fffUL
 
-union uv3h_gr0_gam_gr_config_u {
+
+union uvh_rh_gam_mmioh_redirect_config1_u {
        unsigned long   v;
-       struct uv3h_gr0_gam_gr_config_s {
-               unsigned long   m_skt:6;                        /* RW */
-               unsigned long   undef_6_9:4;                    /* Undefined */
-               unsigned long   subspace:1;                     /* RW */
-               unsigned long   reserved:53;
+
+       /* UVH common struct */
+       struct uvh_rh_gam_mmioh_redirect_config1_s {
+               unsigned long   nasid:15;                       /* RW */
+               unsigned long   rsvd_15_63:49;
+       } s;
+
+       /* UVXH common struct */
+       struct uvxh_rh_gam_mmioh_redirect_config1_s {
+               unsigned long   nasid:15;                       /* RW */
+               unsigned long   rsvd_15_63:49;
+       } sx;
+
+       struct uv4ah_rh_gam_mmioh_redirect_config1_s {
+               unsigned long   nasid:12;                       /* RW */
+               unsigned long   rsvd_12_63:52;
+       } s4a;
+
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_mmioh_redirect_config1_s {
+               unsigned long   nasid:15;                       /* RW */
+               unsigned long   rsvd_15_63:49;
+       } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_mmioh_redirect_config1_s {
+               unsigned long   nasid:15;                       /* RW */
+               unsigned long   rsvd_15_63:49;
        } s3;
 };
 
 /* ========================================================================= */
-/*                       UV4H_LB_PROC_INTD_QUEUE_FIRST                       */
+/*                      UVH_RH_GAM_MMR_OVERLAY_CONFIG                        */
 /* ========================================================================= */
-#define UV4H_LB_PROC_INTD_QUEUE_FIRST                  0xa4100UL
+#define UVH_RH_GAM_MMR_OVERLAY_CONFIG (                                        \
+       is_uv(UV4) ? 0x480028UL :                                       \
+       is_uv(UV3) ? 0x1600028UL :                                      \
+       is_uv(UV2) ? 0x1600028UL :                                      \
+       0)
+
+
+/* UVXH common defines */
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_BASE_SHFT       26
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_BASE_MASK (                     \
+       is_uv(UV4A) ? 0x000ffffffc000000UL :                            \
+       is_uv(UV4) ? 0x00003ffffc000000UL :                             \
+       is_uv(UV3) ? 0x00003ffffc000000UL :                             \
+       is_uv(UV2) ? 0x00003ffffc000000UL :                             \
+       0)
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_ENABLE_SHFT     63
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_ENABLE_MASK     0x8000000000000000UL
+
+/* UV4A unique defines */
+#define UV4AH_RH_GAM_GRU_OVERLAY_CONFIG_BASE_SHFT      26
+#define UV4AH_RH_GAM_GRU_OVERLAY_CONFIG_BASE_MASK      0x000ffffffc000000UL
+
+#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_BASE_MASK (                      \
+       is_uv(UV4A) ? 0x000ffffffc000000UL :                            \
+       is_uv(UV4) ? 0x00003ffffc000000UL :                             \
+       is_uv(UV3) ? 0x00003ffffc000000UL :                             \
+       is_uv(UV2) ? 0x00003ffffc000000UL :                             \
+       0)
+
+#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_BASE_SHFT (                      \
+       is_uv(UV4) ? 26 :                                               \
+       is_uv(UV3) ? 26 :                                               \
+       is_uv(UV2) ? 26 :                                               \
+       -1)
+
+union uvh_rh_gam_mmr_overlay_config_u {
+       unsigned long   v;
+
+       /* UVH common struct */
+       struct uvh_rh_gam_mmr_overlay_config_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   rsvd_46_62:17;
+               unsigned long   enable:1;                       /* RW */
+       } s;
 
-#define UV4H_LB_PROC_INTD_QUEUE_FIRST_FIRST_PAYLOAD_ADDRESS_SHFT 6
-#define UV4H_LB_PROC_INTD_QUEUE_FIRST_FIRST_PAYLOAD_ADDRESS_MASK 0x00003fffffffffc0UL
+       /* UVXH common struct */
+       struct uvxh_rh_gam_mmr_overlay_config_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   rsvd_46_62:17;
+               unsigned long   enable:1;                       /* RW */
+       } sx;
 
-union uv4h_lb_proc_intd_queue_first_u {
-       unsigned long   v;
-       struct uv4h_lb_proc_intd_queue_first_s {
-               unsigned long   undef_0_5:6;                    /* Undefined */
-               unsigned long   first_payload_address:40;       /* RW */
+       /* UV4 unique struct */
+       struct uv4h_rh_gam_mmr_overlay_config_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   rsvd_46_62:17;
+               unsigned long   enable:1;                       /* RW */
        } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rh_gam_mmr_overlay_config_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   rsvd_46_62:17;
+               unsigned long   enable:1;                       /* RW */
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_rh_gam_mmr_overlay_config_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   rsvd_46_62:17;
+               unsigned long   enable:1;                       /* RW */
+       } s2;
 };
 
 /* ========================================================================= */
-/*                       UV4H_LB_PROC_INTD_QUEUE_LAST                        */
+/*                                 UVH_RTC                                   */
 /* ========================================================================= */
-#define UV4H_LB_PROC_INTD_QUEUE_LAST                   0xa4108UL
+#define UVH_RTC (                                                      \
+       is_uv(UV5) ? 0xe0000UL :                                        \
+       is_uv(UV4) ? 0xe0000UL :                                        \
+       is_uv(UV3) ? 0x340000UL :                                       \
+       is_uv(UV2) ? 0x340000UL :                                       \
+       0)
+
+/* UVH common defines*/
+#define UVH_RTC_REAL_TIME_CLOCK_SHFT                   0
+#define UVH_RTC_REAL_TIME_CLOCK_MASK                   0x00ffffffffffffffUL
 
-#define UV4H_LB_PROC_INTD_QUEUE_LAST_LAST_PAYLOAD_ADDRESS_SHFT 5
-#define UV4H_LB_PROC_INTD_QUEUE_LAST_LAST_PAYLOAD_ADDRESS_MASK 0x00003fffffffffe0UL
 
-union uv4h_lb_proc_intd_queue_last_u {
+union uvh_rtc_u {
        unsigned long   v;
-       struct uv4h_lb_proc_intd_queue_last_s {
-               unsigned long   undef_0_4:5;                    /* Undefined */
-               unsigned long   last_payload_address:41;        /* RW */
+
+       /* UVH common struct */
+       struct uvh_rtc_s {
+               unsigned long   real_time_clock:56;             /* RW */
+               unsigned long   rsvd_56_63:8;
+       } s;
+
+       /* UV5 unique struct */
+       struct uv5h_rtc_s {
+               unsigned long   real_time_clock:56;             /* RW */
+               unsigned long   rsvd_56_63:8;
+       } s5;
+
+       /* UV4 unique struct */
+       struct uv4h_rtc_s {
+               unsigned long   real_time_clock:56;             /* RW */
+               unsigned long   rsvd_56_63:8;
        } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rtc_s {
+               unsigned long   real_time_clock:56;             /* RW */
+               unsigned long   rsvd_56_63:8;
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_rtc_s {
+               unsigned long   real_time_clock:56;             /* RW */
+               unsigned long   rsvd_56_63:8;
+       } s2;
 };
 
 /* ========================================================================= */
-/*                     UV4H_LB_PROC_INTD_SOFT_ACK_CLEAR                      */
+/*                           UVH_RTC1_INT_CONFIG                             */
 /* ========================================================================= */
-#define UV4H_LB_PROC_INTD_SOFT_ACK_CLEAR               0xa4118UL
+#define UVH_RTC1_INT_CONFIG 0x615c0UL
+
+/* UVH common defines*/
+#define UVH_RTC1_INT_CONFIG_VECTOR_SHFT                        0
+#define UVH_RTC1_INT_CONFIG_VECTOR_MASK                        0x00000000000000ffUL
+#define UVH_RTC1_INT_CONFIG_DM_SHFT                    8
+#define UVH_RTC1_INT_CONFIG_DM_MASK                    0x0000000000000700UL
+#define UVH_RTC1_INT_CONFIG_DESTMODE_SHFT              11
+#define UVH_RTC1_INT_CONFIG_DESTMODE_MASK              0x0000000000000800UL
+#define UVH_RTC1_INT_CONFIG_STATUS_SHFT                        12
+#define UVH_RTC1_INT_CONFIG_STATUS_MASK                        0x0000000000001000UL
+#define UVH_RTC1_INT_CONFIG_P_SHFT                     13
+#define UVH_RTC1_INT_CONFIG_P_MASK                     0x0000000000002000UL
+#define UVH_RTC1_INT_CONFIG_T_SHFT                     15
+#define UVH_RTC1_INT_CONFIG_T_MASK                     0x0000000000008000UL
+#define UVH_RTC1_INT_CONFIG_M_SHFT                     16
+#define UVH_RTC1_INT_CONFIG_M_MASK                     0x0000000000010000UL
+#define UVH_RTC1_INT_CONFIG_APIC_ID_SHFT               32
+#define UVH_RTC1_INT_CONFIG_APIC_ID_MASK               0xffffffff00000000UL
 
-#define UV4H_LB_PROC_INTD_SOFT_ACK_CLEAR_SOFT_ACK_PENDING_FLAGS_SHFT 0
-#define UV4H_LB_PROC_INTD_SOFT_ACK_CLEAR_SOFT_ACK_PENDING_FLAGS_MASK 0x00000000000000ffUL
 
-union uv4h_lb_proc_intd_soft_ack_clear_u {
+union uvh_rtc1_int_config_u {
        unsigned long   v;
-       struct uv4h_lb_proc_intd_soft_ack_clear_s {
-               unsigned long   soft_ack_pending_flags:8;       /* WP */
+
+       /* UVH common struct */
+       struct uvh_rtc1_int_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s;
+
+       /* UV5 unique struct */
+       struct uv5h_rtc1_int_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s5;
+
+       /* UV4 unique struct */
+       struct uv4h_rtc1_int_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
        } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_rtc1_int_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_rtc1_int_config_s {
+               unsigned long   vector_:8;                      /* RW */
+               unsigned long   dm:3;                           /* RW */
+               unsigned long   destmode:1;                     /* RW */
+               unsigned long   status:1;                       /* RO */
+               unsigned long   p:1;                            /* RO */
+               unsigned long   rsvd_14:1;
+               unsigned long   t:1;                            /* RO */
+               unsigned long   m:1;                            /* RW */
+               unsigned long   rsvd_17_31:15;
+               unsigned long   apic_id:32;                     /* RW */
+       } s2;
 };
 
 /* ========================================================================= */
-/*                    UV4H_LB_PROC_INTD_SOFT_ACK_PENDING                     */
+/*                               UVH_SCRATCH5                                */
 /* ========================================================================= */
-#define UV4H_LB_PROC_INTD_SOFT_ACK_PENDING             0xa4110UL
+#define UVH_SCRATCH5 (                                                 \
+       is_uv(UV5) ? 0xb0200UL :                                        \
+       is_uv(UV4) ? 0xb0200UL :                                        \
+       is_uv(UV3) ? 0x2d0200UL :                                       \
+       is_uv(UV2) ? 0x2d0200UL :                                       \
+       0)
+#define UV5H_SCRATCH5 0xb0200UL
+#define UV4H_SCRATCH5 0xb0200UL
+#define UV3H_SCRATCH5 0x2d0200UL
+#define UV2H_SCRATCH5 0x2d0200UL
+
+/* UVH common defines*/
+#define UVH_SCRATCH5_SCRATCH5_SHFT                     0
+#define UVH_SCRATCH5_SCRATCH5_MASK                     0xffffffffffffffffUL
+
+/* UVXH common defines */
+#define UVXH_SCRATCH5_SCRATCH5_SHFT                    0
+#define UVXH_SCRATCH5_SCRATCH5_MASK                    0xffffffffffffffffUL
+
+/* UVYH common defines */
+#define UVYH_SCRATCH5_SCRATCH5_SHFT                    0
+#define UVYH_SCRATCH5_SCRATCH5_MASK                    0xffffffffffffffffUL
+
+/* UV5 unique defines */
+#define UV5H_SCRATCH5_SCRATCH5_SHFT                    0
+#define UV5H_SCRATCH5_SCRATCH5_MASK                    0xffffffffffffffffUL
+
+/* UV4 unique defines */
+#define UV4H_SCRATCH5_SCRATCH5_SHFT                    0
+#define UV4H_SCRATCH5_SCRATCH5_MASK                    0xffffffffffffffffUL
+
+/* UV3 unique defines */
+#define UV3H_SCRATCH5_SCRATCH5_SHFT                    0
+#define UV3H_SCRATCH5_SCRATCH5_MASK                    0xffffffffffffffffUL
 
-#define UV4H_LB_PROC_INTD_SOFT_ACK_PENDING_SOFT_ACK_FLAGS_SHFT 0
-#define UV4H_LB_PROC_INTD_SOFT_ACK_PENDING_SOFT_ACK_FLAGS_MASK 0x00000000000000ffUL
+/* UV2 unique defines */
+#define UV2H_SCRATCH5_SCRATCH5_SHFT                    0
+#define UV2H_SCRATCH5_SCRATCH5_MASK                    0xffffffffffffffffUL
 
-union uv4h_lb_proc_intd_soft_ack_pending_u {
+
+union uvh_scratch5_u {
        unsigned long   v;
-       struct uv4h_lb_proc_intd_soft_ack_pending_s {
-               unsigned long   soft_ack_flags:8;               /* RW */
+
+       /* UVH common struct */
+       struct uvh_scratch5_s {
+               unsigned long   scratch5:64;                    /* RW */
+       } s;
+
+       /* UVXH common struct */
+       struct uvxh_scratch5_s {
+               unsigned long   scratch5:64;                    /* RW */
+       } sx;
+
+       /* UVYH common struct */
+       struct uvyh_scratch5_s {
+               unsigned long   scratch5:64;                    /* RW */
+       } sy;
+
+       /* UV5 unique struct */
+       struct uv5h_scratch5_s {
+               unsigned long   scratch5:64;                    /* RW */
+       } s5;
+
+       /* UV4 unique struct */
+       struct uv4h_scratch5_s {
+               unsigned long   scratch5:64;                    /* RW */
        } s4;
+
+       /* UV3 unique struct */
+       struct uv3h_scratch5_s {
+               unsigned long   scratch5:64;                    /* RW */
+       } s3;
+
+       /* UV2 unique struct */
+       struct uv2h_scratch5_s {
+               unsigned long   scratch5:64;                    /* RW */
+       } s2;
 };
 
+/* ========================================================================= */
+/*                            UVH_SCRATCH5_ALIAS                             */
+/* ========================================================================= */
+#define UVH_SCRATCH5_ALIAS (                                           \
+       is_uv(UV5) ? 0xb0208UL :                                        \
+       is_uv(UV4) ? 0xb0208UL :                                        \
+       is_uv(UV3) ? 0x2d0208UL :                                       \
+       is_uv(UV2) ? 0x2d0208UL :                                       \
+       0)
+#define UV5H_SCRATCH5_ALIAS 0xb0208UL
+#define UV4H_SCRATCH5_ALIAS 0xb0208UL
+#define UV3H_SCRATCH5_ALIAS 0x2d0208UL
+#define UV2H_SCRATCH5_ALIAS 0x2d0208UL
+
+
+/* ========================================================================= */
+/*                           UVH_SCRATCH5_ALIAS_2                            */
+/* ========================================================================= */
+#define UVH_SCRATCH5_ALIAS_2 (                                         \
+       is_uv(UV5) ? 0xb0210UL :                                        \
+       is_uv(UV4) ? 0xb0210UL :                                        \
+       is_uv(UV3) ? 0x2d0210UL :                                       \
+       is_uv(UV2) ? 0x2d0210UL :                                       \
+       0)
+#define UV5H_SCRATCH5_ALIAS_2 0xb0210UL
+#define UV4H_SCRATCH5_ALIAS_2 0xb0210UL
+#define UV3H_SCRATCH5_ALIAS_2 0x2d0210UL
+#define UV2H_SCRATCH5_ALIAS_2 0x2d0210UL
+
+
 
 #endif /* _ASM_X86_UV_UV_MMRS_H */
index 6807153..397196f 100644 (file)
@@ -8,25 +8,16 @@ struct mpc_bus;
 struct mpc_cpu;
 struct mpc_table;
 struct cpuinfo_x86;
+struct irq_domain;
 
 /**
  * struct x86_init_mpparse - platform specific mpparse ops
- * @mpc_record:                        platform specific mpc record accounting
  * @setup_ioapic_ids:          platform specific ioapic id override
- * @mpc_apic_id:               platform specific mpc apic id assignment
- * @smp_read_mpc_oem:          platform specific oem mpc table setup
- * @mpc_oem_pci_bus:           platform specific pci bus setup (default NULL)
- * @mpc_oem_bus_info:          platform specific mpc bus info
  * @find_smp_config:           find the smp configuration
  * @get_smp_config:            get the smp configuration
  */
 struct x86_init_mpparse {
-       void (*mpc_record)(unsigned int mode);
        void (*setup_ioapic_ids)(void);
-       int (*mpc_apic_id)(struct mpc_cpu *m);
-       void (*smp_read_mpc_oem)(struct mpc_table *mpc);
-       void (*mpc_oem_pci_bus)(struct mpc_bus *m);
-       void (*mpc_oem_bus_info)(struct mpc_bus *m, char *name);
        void (*find_smp_config)(void);
        void (*get_smp_config)(unsigned int early);
 };
@@ -52,12 +43,14 @@ struct x86_init_resources {
  * @intr_init:                 interrupt init code
  * @intr_mode_select:          interrupt delivery mode selection
  * @intr_mode_init:            interrupt delivery mode setup
+ * @create_pci_msi_domain:     Create the PCI/MSI interrupt domain
  */
 struct x86_init_irqs {
        void (*pre_vector_init)(void);
        void (*intr_init)(void);
        void (*intr_mode_select)(void);
        void (*intr_mode_init)(void);
+       struct irq_domain *(*create_pci_msi_domain)(void);
 };
 
 /**
@@ -283,9 +276,6 @@ struct x86_platform_ops {
 struct pci_dev;
 
 struct x86_msi_ops {
-       int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
-       void (*teardown_msi_irq)(unsigned int irq);
-       void (*teardown_msi_irqs)(struct pci_dev *dev);
        void (*restore_msi_irqs)(struct pci_dev *dev);
 };
 
index e77261d..de09af0 100644 (file)
@@ -68,6 +68,7 @@ obj-y                 += tsc.o tsc_msr.o io_delay.o rtc.o
 obj-y                  += pci-iommu_table.o
 obj-y                  += resource.o
 obj-y                  += irqflags.o
+obj-y                  += static_call.o
 
 obj-y                          += process.o
 obj-y                          += fpu/
index c3daf0a..4adbe65 100644 (file)
@@ -239,7 +239,7 @@ void __init arch_init_ideal_nops(void)
                        return;
                }
 
-               /* fall through */
+               fallthrough;
 
        default:
 #ifdef CONFIG_X86_64
@@ -1103,6 +1103,10 @@ noinstr int poke_int3_handler(struct pt_regs *regs)
                 */
                goto out_put;
 
+       case RET_INSN_OPCODE:
+               int3_emulate_ret(regs);
+               break;
+
        case CALL_INSN_OPCODE:
                int3_emulate_call(regs, (long)ip + tp->rel32);
                break;
@@ -1277,6 +1281,7 @@ static void text_poke_loc_init(struct text_poke_loc *tp, void *addr,
 
        switch (tp->opcode) {
        case INT3_INSN_OPCODE:
+       case RET_INSN_OPCODE:
                break;
 
        case CALL_INSN_OPCODE:
index 5f943b9..b3eef1d 100644 (file)
@@ -1429,6 +1429,9 @@ void __init apic_intr_mode_init(void)
                break;
        }
 
+       if (x86_platform.apic_post_init)
+               x86_platform.apic_post_init();
+
        apic_bsp_setup(upmode);
 }
 
index 21325a4..7b3c7e0 100644 (file)
@@ -800,7 +800,7 @@ static int irq_polarity(int idx)
                return IOAPIC_POL_HIGH;
        case MP_IRQPOL_RESERVED:
                pr_warn("IOAPIC: Invalid polarity: 2, defaulting to low\n");
-               /* fall through */
+               fallthrough;
        case MP_IRQPOL_ACTIVE_LOW:
        default: /* Pointless default required due to do gcc stupidity */
                return IOAPIC_POL_LOW;
@@ -848,7 +848,7 @@ static int irq_trigger(int idx)
                return IOAPIC_EDGE;
        case MP_IRQTRIG_RESERVED:
                pr_warn("IOAPIC: Invalid trigger mode 2 defaulting to level\n");
-               /* fall through */
+               fallthrough;
        case MP_IRQTRIG_LEVEL:
        default: /* Pointless default required due to do gcc stupidity */
                return IOAPIC_LEVEL;
@@ -860,10 +860,10 @@ void ioapic_set_alloc_attr(struct irq_alloc_info *info, int node,
 {
        init_irq_alloc_info(info, NULL);
        info->type = X86_IRQ_ALLOC_TYPE_IOAPIC;
-       info->ioapic_node = node;
-       info->ioapic_trigger = trigger;
-       info->ioapic_polarity = polarity;
-       info->ioapic_valid = 1;
+       info->ioapic.node = node;
+       info->ioapic.trigger = trigger;
+       info->ioapic.polarity = polarity;
+       info->ioapic.valid = 1;
 }
 
 #ifndef CONFIG_ACPI
@@ -878,32 +878,32 @@ static void ioapic_copy_alloc_attr(struct irq_alloc_info *dst,
 
        copy_irq_alloc_info(dst, src);
        dst->type = X86_IRQ_ALLOC_TYPE_IOAPIC;
-       dst->ioapic_id = mpc_ioapic_id(ioapic_idx);
-       dst->ioapic_pin = pin;
-       dst->ioapic_valid = 1;
-       if (src && src->ioapic_valid) {
-               dst->ioapic_node = src->ioapic_node;
-               dst->ioapic_trigger = src->ioapic_trigger;
-               dst->ioapic_polarity = src->ioapic_polarity;
+       dst->devid = mpc_ioapic_id(ioapic_idx);
+       dst->ioapic.pin = pin;
+       dst->ioapic.valid = 1;
+       if (src && src->ioapic.valid) {
+               dst->ioapic.node = src->ioapic.node;
+               dst->ioapic.trigger = src->ioapic.trigger;
+               dst->ioapic.polarity = src->ioapic.polarity;
        } else {
-               dst->ioapic_node = NUMA_NO_NODE;
+               dst->ioapic.node = NUMA_NO_NODE;
                if (acpi_get_override_irq(gsi, &trigger, &polarity) >= 0) {
-                       dst->ioapic_trigger = trigger;
-                       dst->ioapic_polarity = polarity;
+                       dst->ioapic.trigger = trigger;
+                       dst->ioapic.polarity = polarity;
                } else {
                        /*
                         * PCI interrupts are always active low level
                         * triggered.
                         */
-                       dst->ioapic_trigger = IOAPIC_LEVEL;
-                       dst->ioapic_polarity = IOAPIC_POL_LOW;
+                       dst->ioapic.trigger = IOAPIC_LEVEL;
+                       dst->ioapic.polarity = IOAPIC_POL_LOW;
                }
        }
 }
 
 static int ioapic_alloc_attr_node(struct irq_alloc_info *info)
 {
-       return (info && info->ioapic_valid) ? info->ioapic_node : NUMA_NO_NODE;
+       return (info && info->ioapic.valid) ? info->ioapic.node : NUMA_NO_NODE;
 }
 
 static void mp_register_handler(unsigned int irq, unsigned long trigger)
@@ -933,14 +933,14 @@ static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info)
         * pin with real trigger and polarity attributes.
         */
        if (irq < nr_legacy_irqs() && data->count == 1) {
-               if (info->ioapic_trigger != data->trigger)
-                       mp_register_handler(irq, info->ioapic_trigger);
-               data->entry.trigger = data->trigger = info->ioapic_trigger;
-               data->entry.polarity = data->polarity = info->ioapic_polarity;
+               if (info->ioapic.trigger != data->trigger)
+                       mp_register_handler(irq, info->ioapic.trigger);
+               data->entry.trigger = data->trigger = info->ioapic.trigger;
+               data->entry.polarity = data->polarity = info->ioapic.polarity;
        }
 
-       return data->trigger == info->ioapic_trigger &&
-              data->polarity == info->ioapic_polarity;
+       return data->trigger == info->ioapic.trigger &&
+              data->polarity == info->ioapic.polarity;
 }
 
 static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi,
@@ -1002,7 +1002,7 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain,
                if (!mp_check_pin_attr(irq, info))
                        return -EBUSY;
                if (__add_pin_to_irq_node(irq_data->chip_data, node, ioapic,
-                                         info->ioapic_pin))
+                                         info->ioapic.pin))
                        return -ENOMEM;
        } else {
                info->flags |= X86_IRQ_ALLOC_LEGACY;
@@ -2092,8 +2092,8 @@ static int mp_alloc_timer_irq(int ioapic, int pin)
                struct irq_alloc_info info;
 
                ioapic_set_alloc_attr(&info, NUMA_NO_NODE, 0, 0);
-               info.ioapic_id = mpc_ioapic_id(ioapic);
-               info.ioapic_pin = pin;
+               info.devid = mpc_ioapic_id(ioapic);
+               info.ioapic.pin = pin;
                mutex_lock(&ioapic_mutex);
                irq = alloc_isa_irq_from_domain(domain, 0, ioapic, pin, &info);
                mutex_unlock(&ioapic_mutex);
@@ -2243,6 +2243,7 @@ static inline void __init check_timer(void)
        legacy_pic->init(0);
        legacy_pic->make_irq(0);
        apic_write(APIC_LVT0, APIC_DM_EXTINT);
+       legacy_pic->unmask(0);
 
        unlock_ExtINT_logic();
 
@@ -2296,9 +2297,9 @@ static int mp_irqdomain_create(int ioapic)
                return 0;
 
        init_irq_alloc_info(&info, NULL);
-       info.type = X86_IRQ_ALLOC_TYPE_IOAPIC;
-       info.ioapic_id = mpc_ioapic_id(ioapic);
-       parent = irq_remapping_get_ir_irq_domain(&info);
+       info.type = X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT;
+       info.devid = mpc_ioapic_id(ioapic);
+       parent = irq_remapping_get_irq_domain(&info);
        if (!parent)
                parent = x86_vector_domain;
        else
@@ -2932,9 +2933,9 @@ int mp_ioapic_registered(u32 gsi_base)
 static void mp_irqdomain_get_attr(u32 gsi, struct mp_chip_data *data,
                                  struct irq_alloc_info *info)
 {
-       if (info && info->ioapic_valid) {
-               data->trigger = info->ioapic_trigger;
-               data->polarity = info->ioapic_polarity;
+       if (info && info->ioapic.valid) {
+               data->trigger = info->ioapic.trigger;
+               data->polarity = info->ioapic.polarity;
        } else if (acpi_get_override_irq(gsi, &data->trigger,
                                         &data->polarity) < 0) {
                /* PCI interrupts are always active low level triggered. */
@@ -2980,7 +2981,7 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
                return -EINVAL;
 
        ioapic = mp_irqdomain_ioapic_idx(domain);
-       pin = info->ioapic_pin;
+       pin = info->ioapic.pin;
        if (irq_find_mapping(domain, (irq_hw_number_t)pin) > 0)
                return -EEXIST;
 
@@ -2988,7 +2989,7 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
        if (!data)
                return -ENOMEM;
 
-       info->ioapic_entry = &data->entry;
+       info->ioapic.entry = &data->entry;
        ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
        if (ret < 0) {
                kfree(data);
@@ -2996,7 +2997,7 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
        }
 
        INIT_LIST_HEAD(&data->irq_2_pin);
-       irq_data->hwirq = info->ioapic_pin;
+       irq_data->hwirq = info->ioapic.pin;
        irq_data->chip = (domain->parent == x86_vector_domain) ?
                          &ioapic_chip : &ioapic_ir_chip;
        irq_data->chip_data = data;
@@ -3006,8 +3007,8 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
        add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
 
        local_irq_save(flags);
-       if (info->ioapic_entry)
-               mp_setup_entry(cfg, data, info->ioapic_entry);
+       if (info->ioapic.entry)
+               mp_setup_entry(cfg, data, info->ioapic.entry);
        mp_register_handler(virq, data->trigger);
        if (virq < nr_legacy_irqs())
                legacy_pic->mask(virq);
index c2b2911..6313f0a 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/apic.h>
 #include <asm/irq_remapping.h>
 
-static struct irq_domain *msi_default_domain;
+struct irq_domain *x86_pci_msi_default_domain __ro_after_init;
 
 static void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg)
 {
@@ -45,7 +45,7 @@ static void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg)
                MSI_DATA_VECTOR(cfg->vector);
 }
 
-static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
+void x86_vector_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
 {
        __irq_msi_compose_msg(irqd_cfg(data), msg);
 }
@@ -177,40 +177,10 @@ static struct irq_chip pci_msi_controller = {
        .irq_mask               = pci_msi_mask_irq,
        .irq_ack                = irq_chip_ack_parent,
        .irq_retrigger          = irq_chip_retrigger_hierarchy,
-       .irq_compose_msi_msg    = irq_msi_compose_msg,
        .irq_set_affinity       = msi_set_affinity,
        .flags                  = IRQCHIP_SKIP_SET_WAKE,
 };
 
-int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
-{
-       struct irq_domain *domain;
-       struct irq_alloc_info info;
-
-       init_irq_alloc_info(&info, NULL);
-       info.type = X86_IRQ_ALLOC_TYPE_MSI;
-       info.msi_dev = dev;
-
-       domain = irq_remapping_get_irq_domain(&info);
-       if (domain == NULL)
-               domain = msi_default_domain;
-       if (domain == NULL)
-               return -ENOSYS;
-
-       return msi_domain_alloc_irqs(domain, &dev->dev, nvec);
-}
-
-void native_teardown_msi_irq(unsigned int irq)
-{
-       irq_domain_free_irqs(irq, 1);
-}
-
-static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info,
-                                        msi_alloc_info_t *arg)
-{
-       return arg->msi_hwirq;
-}
-
 int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
                    msi_alloc_info_t *arg)
 {
@@ -218,11 +188,10 @@ int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
        struct msi_desc *desc = first_pci_msi_entry(pdev);
 
        init_irq_alloc_info(arg, NULL);
-       arg->msi_dev = pdev;
        if (desc->msi_attrib.is_msix) {
-               arg->type = X86_IRQ_ALLOC_TYPE_MSIX;
+               arg->type = X86_IRQ_ALLOC_TYPE_PCI_MSIX;
        } else {
-               arg->type = X86_IRQ_ALLOC_TYPE_MSI;
+               arg->type = X86_IRQ_ALLOC_TYPE_PCI_MSI;
                arg->flags |= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
        }
 
@@ -230,16 +199,8 @@ int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
 }
 EXPORT_SYMBOL_GPL(pci_msi_prepare);
 
-void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
-{
-       arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
-}
-EXPORT_SYMBOL_GPL(pci_msi_set_desc);
-
 static struct msi_domain_ops pci_msi_domain_ops = {
-       .get_hwirq      = pci_msi_get_hwirq,
        .msi_prepare    = pci_msi_prepare,
-       .set_desc       = pci_msi_set_desc,
 };
 
 static struct msi_domain_info pci_msi_domain_info = {
@@ -251,25 +212,32 @@ static struct msi_domain_info pci_msi_domain_info = {
        .handler_name   = "edge",
 };
 
-void __init arch_init_msi_domain(struct irq_domain *parent)
+struct irq_domain * __init native_create_pci_msi_domain(void)
 {
        struct fwnode_handle *fn;
+       struct irq_domain *d;
 
        if (disable_apic)
-               return;
+               return NULL;
 
        fn = irq_domain_alloc_named_fwnode("PCI-MSI");
-       if (fn) {
-               msi_default_domain =
-                       pci_msi_create_irq_domain(fn, &pci_msi_domain_info,
-                                                 parent);
-       }
-       if (!msi_default_domain) {
+       if (!fn)
+               return NULL;
+
+       d = pci_msi_create_irq_domain(fn, &pci_msi_domain_info,
+                                     x86_vector_domain);
+       if (!d) {
                irq_domain_free_fwnode(fn);
-               pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
+               pr_warn("Failed to initialize PCI-MSI irqdomain.\n");
        } else {
-               msi_default_domain->flags |= IRQ_DOMAIN_MSI_NOMASK_QUIRK;
+               d->flags |= IRQ_DOMAIN_MSI_NOMASK_QUIRK;
        }
+       return d;
+}
+
+void __init x86_create_pci_msi_domain(void)
+{
+       x86_pci_msi_default_domain = x86_init.irqs.create_pci_msi_domain();
 }
 
 #ifdef CONFIG_IRQ_REMAP
@@ -279,7 +247,6 @@ static struct irq_chip pci_msi_ir_controller = {
        .irq_mask               = pci_msi_mask_irq,
        .irq_ack                = irq_chip_ack_parent,
        .irq_retrigger          = irq_chip_retrigger_hierarchy,
-       .irq_set_vcpu_affinity  = irq_chip_set_vcpu_affinity_parent,
        .flags                  = IRQCHIP_SKIP_SET_WAKE,
 };
 
@@ -321,35 +288,28 @@ static struct irq_chip dmar_msi_controller = {
        .irq_ack                = irq_chip_ack_parent,
        .irq_set_affinity       = msi_domain_set_affinity,
        .irq_retrigger          = irq_chip_retrigger_hierarchy,
-       .irq_compose_msi_msg    = irq_msi_compose_msg,
        .irq_write_msi_msg      = dmar_msi_write_msg,
        .flags                  = IRQCHIP_SKIP_SET_WAKE,
 };
 
-static irq_hw_number_t dmar_msi_get_hwirq(struct msi_domain_info *info,
-                                         msi_alloc_info_t *arg)
-{
-       return arg->dmar_id;
-}
-
 static int dmar_msi_init(struct irq_domain *domain,
                         struct msi_domain_info *info, unsigned int virq,
                         irq_hw_number_t hwirq, msi_alloc_info_t *arg)
 {
-       irq_domain_set_info(domain, virq, arg->dmar_id, info->chip, NULL,
-                           handle_edge_irq, arg->dmar_data, "edge");
+       irq_domain_set_info(domain, virq, arg->devid, info->chip, NULL,
+                           handle_edge_irq, arg->data, "edge");
 
        return 0;
 }
 
 static struct msi_domain_ops dmar_msi_domain_ops = {
-       .get_hwirq      = dmar_msi_get_hwirq,
        .msi_init       = dmar_msi_init,
 };
 
 static struct msi_domain_info dmar_msi_domain_info = {
        .ops            = &dmar_msi_domain_ops,
        .chip           = &dmar_msi_controller,
+       .flags          = MSI_FLAG_USE_DEF_DOM_OPS,
 };
 
 static struct irq_domain *dmar_get_irq_domain(void)
@@ -384,8 +344,9 @@ int dmar_alloc_hwirq(int id, int node, void *arg)
 
        init_irq_alloc_info(&info, NULL);
        info.type = X86_IRQ_ALLOC_TYPE_DMAR;
-       info.dmar_id = id;
-       info.dmar_data = arg;
+       info.devid = id;
+       info.hwirq = id;
+       info.data = arg;
 
        return irq_domain_alloc_irqs(domain, 1, node, &info);
 }
@@ -419,24 +380,17 @@ static struct irq_chip hpet_msi_controller __ro_after_init = {
        .irq_ack = irq_chip_ack_parent,
        .irq_set_affinity = msi_domain_set_affinity,
        .irq_retrigger = irq_chip_retrigger_hierarchy,
-       .irq_compose_msi_msg = irq_msi_compose_msg,
        .irq_write_msi_msg = hpet_msi_write_msg,
        .flags = IRQCHIP_SKIP_SET_WAKE,
 };
 
-static irq_hw_number_t hpet_msi_get_hwirq(struct msi_domain_info *info,
-                                         msi_alloc_info_t *arg)
-{
-       return arg->hpet_index;
-}
-
 static int hpet_msi_init(struct irq_domain *domain,
                         struct msi_domain_info *info, unsigned int virq,
                         irq_hw_number_t hwirq, msi_alloc_info_t *arg)
 {
        irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
-       irq_domain_set_info(domain, virq, arg->hpet_index, info->chip, NULL,
-                           handle_edge_irq, arg->hpet_data, "edge");
+       irq_domain_set_info(domain, virq, arg->hwirq, info->chip, NULL,
+                           handle_edge_irq, arg->data, "edge");
 
        return 0;
 }
@@ -448,7 +402,6 @@ static void hpet_msi_free(struct irq_domain *domain,
 }
 
 static struct msi_domain_ops hpet_msi_domain_ops = {
-       .get_hwirq      = hpet_msi_get_hwirq,
        .msi_init       = hpet_msi_init,
        .msi_free       = hpet_msi_free,
 };
@@ -456,6 +409,7 @@ static struct msi_domain_ops hpet_msi_domain_ops = {
 static struct msi_domain_info hpet_msi_domain_info = {
        .ops            = &hpet_msi_domain_ops,
        .chip           = &hpet_msi_controller,
+       .flags          = MSI_FLAG_USE_DEF_DOM_OPS,
 };
 
 struct irq_domain *hpet_create_irq_domain(int hpet_id)
@@ -476,9 +430,9 @@ struct irq_domain *hpet_create_irq_domain(int hpet_id)
        domain_info->data = (void *)(long)hpet_id;
 
        init_irq_alloc_info(&info, NULL);
-       info.type = X86_IRQ_ALLOC_TYPE_HPET;
-       info.hpet_id = hpet_id;
-       parent = irq_remapping_get_ir_irq_domain(&info);
+       info.type = X86_IRQ_ALLOC_TYPE_HPET_GET_PARENT;
+       info.devid = hpet_id;
+       parent = irq_remapping_get_irq_domain(&info);
        if (parent == NULL)
                parent = x86_vector_domain;
        else
@@ -506,9 +460,9 @@ int hpet_assign_irq(struct irq_domain *domain, struct hpet_channel *hc,
 
        init_irq_alloc_info(&info, NULL);
        info.type = X86_IRQ_ALLOC_TYPE_HPET;
-       info.hpet_data = hc;
-       info.hpet_id = hpet_dev_id(domain);
-       info.hpet_index = dev_num;
+       info.data = hc;
+       info.devid = hpet_dev_id(domain);
+       info.hwirq = dev_num;
 
        return irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, &info);
 }
index 7bda71d..67b6f7c 100644 (file)
@@ -149,7 +149,7 @@ void __init default_setup_apic_routing(void)
                                break;
                        }
                        /* P4 and above */
-                       /* fall through */
+                       fallthrough;
                case X86_VENDOR_HYGON:
                case X86_VENDOR_AMD:
                        def_to_bigsmp = 1;
@@ -170,9 +170,6 @@ void __init default_setup_apic_routing(void)
 
        if (apic->setup_apic_routing)
                apic->setup_apic_routing();
-
-       if (x86_platform.apic_post_init)
-               x86_platform.apic_post_init();
 }
 
 void __init generic_apic_probe(void)
index bd3835d..c46720f 100644 (file)
@@ -32,9 +32,6 @@ void __init default_setup_apic_routing(void)
                        break;
                }
        }
-
-       if (x86_platform.apic_post_init)
-               x86_platform.apic_post_init();
 }
 
 int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
index dae32d9..1eac536 100644 (file)
@@ -161,6 +161,7 @@ static void apic_update_vector(struct irq_data *irqd, unsigned int newvec,
                apicd->move_in_progress = true;
                apicd->prev_vector = apicd->vector;
                apicd->prev_cpu = apicd->cpu;
+               WARN_ON_ONCE(apicd->cpu == newcpu);
        } else {
                irq_matrix_free(vector_matrix, apicd->cpu, apicd->vector,
                                managed);
@@ -713,8 +714,6 @@ int __init arch_early_irq_init(void)
        BUG_ON(x86_vector_domain == NULL);
        irq_set_default_host(x86_vector_domain);
 
-       arch_init_msi_domain(x86_vector_domain);
-
        BUG_ON(!alloc_cpumask_var(&vector_searchmask, GFP_KERNEL));
 
        /*
@@ -823,6 +822,7 @@ static struct irq_chip lapic_controller = {
        .name                   = "APIC",
        .irq_ack                = apic_ack_edge,
        .irq_set_affinity       = apic_set_affinity,
+       .irq_compose_msi_msg    = x86_vector_msi_compose_msg,
        .irq_retrigger          = apic_retrigger_irq,
 };
 
@@ -910,7 +910,7 @@ void send_cleanup_vector(struct irq_cfg *cfg)
                __send_cleanup_vector(apicd);
 }
 
-static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
+void irq_complete_move(struct irq_cfg *cfg)
 {
        struct apic_chip_data *apicd;
 
@@ -918,15 +918,16 @@ static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
        if (likely(!apicd->move_in_progress))
                return;
 
-       if (vector == apicd->vector && apicd->cpu == smp_processor_id())
+       /*
+        * If the interrupt arrived on the new target CPU, cleanup the
+        * vector on the old target CPU. A vector check is not required
+        * because an interrupt can never move from one vector to another
+        * on the same CPU.
+        */
+       if (apicd->cpu == smp_processor_id())
                __send_cleanup_vector(apicd);
 }
 
-void irq_complete_move(struct irq_cfg *cfg)
-{
-       __irq_complete_move(cfg, ~get_irq_regs()->orig_ax);
-}
-
 /*
  * Called from fixup_irqs() with @desc->lock held and interrupts disabled.
  */
index 0b6eea3..714233c 100644 (file)
@@ -5,6 +5,7 @@
  *
  * SGI UV APIC functions (note: not an Intel compatible APIC)
  *
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 #include <linux/crash_dump.h>
@@ -29,19 +30,24 @@ static int                  uv_hubbed_system;
 static int                     uv_hubless_system;
 static u64                     gru_start_paddr, gru_end_paddr;
 static union uvh_apicid                uvh_apicid;
+static int                     uv_node_id;
 
-/* Unpack OEM/TABLE ID's to be NULL terminated strings */
+/* Unpack AT/OEM/TABLE ID's to be NULL terminated strings */
+static u8 uv_archtype[UV_AT_SIZE];
 static u8 oem_id[ACPI_OEM_ID_SIZE + 1];
 static u8 oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
 
-/* Information derived from CPUID: */
+/* Information derived from CPUID and some UV MMRs */
 static struct {
        unsigned int apicid_shift;
        unsigned int apicid_mask;
        unsigned int socketid_shift;    /* aka pnode_shift for UV2/3 */
        unsigned int pnode_mask;
+       unsigned int nasid_shift;
        unsigned int gpa_shift;
        unsigned int gnode_shift;
+       unsigned int m_skt;
+       unsigned int n_skt;
 } uv_cpuid;
 
 static int uv_min_hub_revision_id;
@@ -77,6 +83,9 @@ static unsigned long __init uv_early_read_mmr(unsigned long addr)
 
 static inline bool is_GRU_range(u64 start, u64 end)
 {
+       if (!gru_start_paddr)
+               return false;
+
        return start >= gru_start_paddr && end <= gru_end_paddr;
 }
 
@@ -85,43 +94,102 @@ static bool uv_is_untracked_pat_range(u64 start, u64 end)
        return is_ISA_range(start, end) || is_GRU_range(start, end);
 }
 
-static int __init early_get_pnodeid(void)
+static void __init early_get_pnodeid(void)
 {
-       union uvh_node_id_u node_id;
-       union uvh_rh_gam_config_mmr_u  m_n_config;
        int pnode;
 
-       /* Currently, all blades have same revision number */
+       uv_cpuid.m_skt = 0;
+       if (UVH_RH10_GAM_ADDR_MAP_CONFIG) {
+               union uvh_rh10_gam_addr_map_config_u  m_n_config;
+
+               m_n_config.v = uv_early_read_mmr(UVH_RH10_GAM_ADDR_MAP_CONFIG);
+               uv_cpuid.n_skt = m_n_config.s.n_skt;
+               uv_cpuid.nasid_shift = 0;
+       } else if (UVH_RH_GAM_ADDR_MAP_CONFIG) {
+               union uvh_rh_gam_addr_map_config_u  m_n_config;
+
+       m_n_config.v = uv_early_read_mmr(UVH_RH_GAM_ADDR_MAP_CONFIG);
+               uv_cpuid.n_skt = m_n_config.s.n_skt;
+               if (is_uv(UV3))
+                       uv_cpuid.m_skt = m_n_config.s3.m_skt;
+               if (is_uv(UV2))
+                       uv_cpuid.m_skt = m_n_config.s2.m_skt;
+               uv_cpuid.nasid_shift = 1;
+       } else {
+               unsigned long GAM_ADDR_MAP_CONFIG = 0;
+
+               WARN(GAM_ADDR_MAP_CONFIG == 0,
+                       "UV: WARN: GAM_ADDR_MAP_CONFIG is not available\n");
+               uv_cpuid.n_skt = 0;
+               uv_cpuid.nasid_shift = 0;
+       }
+
+       if (is_uv(UV4|UVY))
+               uv_cpuid.gnode_shift = 2; /* min partition is 4 sockets */
+
+       uv_cpuid.pnode_mask = (1 << uv_cpuid.n_skt) - 1;
+       pnode = (uv_node_id >> uv_cpuid.nasid_shift) & uv_cpuid.pnode_mask;
+       uv_cpuid.gpa_shift = 46;        /* Default unless changed */
+
+       pr_info("UV: n_skt:%d pnmsk:%x pn:%x\n",
+               uv_cpuid.n_skt, uv_cpuid.pnode_mask, pnode);
+}
+
+/* Running on a UV Hubbed system, determine which UV Hub Type it is */
+static int __init early_set_hub_type(void)
+{
+       union uvh_node_id_u node_id;
+
+       /*
+        * The NODE_ID MMR is always at offset 0.
+        * Contains the chip part # + revision.
+        * Node_id field started with 15 bits,
+        * ... now 7 but upper 8 are masked to 0.
+        * All blades/nodes have the same part # and hub revision.
+        */
        node_id.v = uv_early_read_mmr(UVH_NODE_ID);
-       m_n_config.v = uv_early_read_mmr(UVH_RH_GAM_CONFIG_MMR);
-       uv_min_hub_revision_id = node_id.s.revision;
+       uv_node_id = node_id.sx.node_id;
 
        switch (node_id.s.part_number) {
-       case UV2_HUB_PART_NUMBER:
-       case UV2_HUB_PART_NUMBER_X:
-               uv_min_hub_revision_id += UV2_HUB_REVISION_BASE - 1;
+
+       case UV5_HUB_PART_NUMBER:
+               uv_min_hub_revision_id = node_id.s.revision
+                                        + UV5_HUB_REVISION_BASE;
+               uv_hub_type_set(UV5);
                break;
+
+       /* UV4/4A only have a revision difference */
+       case UV4_HUB_PART_NUMBER:
+               uv_min_hub_revision_id = node_id.s.revision
+                                        + UV4_HUB_REVISION_BASE;
+               uv_hub_type_set(UV4);
+               if (uv_min_hub_revision_id == UV4A_HUB_REVISION_BASE)
+                       uv_hub_type_set(UV4|UV4A);
+               break;
+
        case UV3_HUB_PART_NUMBER:
        case UV3_HUB_PART_NUMBER_X:
-               uv_min_hub_revision_id += UV3_HUB_REVISION_BASE;
+               uv_min_hub_revision_id = node_id.s.revision
+                                        + UV3_HUB_REVISION_BASE;
+               uv_hub_type_set(UV3);
                break;
 
-       /* Update: UV4A has only a modified revision to indicate HUB fixes */
-       case UV4_HUB_PART_NUMBER:
-               uv_min_hub_revision_id += UV4_HUB_REVISION_BASE - 1;
-               uv_cpuid.gnode_shift = 2; /* min partition is 4 sockets */
+       case UV2_HUB_PART_NUMBER:
+       case UV2_HUB_PART_NUMBER_X:
+               uv_min_hub_revision_id = node_id.s.revision
+                                        + UV2_HUB_REVISION_BASE - 1;
+               uv_hub_type_set(UV2);
                break;
+
+       default:
+               return 0;
        }
 
-       uv_hub_info->hub_revision = uv_min_hub_revision_id;
-       uv_cpuid.pnode_mask = (1 << m_n_config.s.n_skt) - 1;
-       pnode = (node_id.s.node_id >> 1) & uv_cpuid.pnode_mask;
-       uv_cpuid.gpa_shift = 46;        /* Default unless changed */
+       pr_info("UV: part#:%x rev:%d rev_id:%d UVtype:0x%x\n",
+               node_id.s.part_number, node_id.s.revision,
+               uv_min_hub_revision_id, is_uv(~0));
 
-       pr_info("UV: rev:%d part#:%x nodeid:%04x n_skt:%d pnmsk:%x pn:%x\n",
-               node_id.s.revision, node_id.s.part_number, node_id.s.node_id,
-               m_n_config.s.n_skt, uv_cpuid.pnode_mask, pnode);
-       return pnode;
+       return 1;
 }
 
 static void __init uv_tsc_check_sync(void)
@@ -130,38 +198,41 @@ static void __init uv_tsc_check_sync(void)
        int sync_state;
        int mmr_shift;
        char *state;
-       bool valid;
 
-       /* Accommodate different UV arch BIOSes */
+       /* Different returns from different UV BIOS versions */
        mmr = uv_early_read_mmr(UVH_TSC_SYNC_MMR);
        mmr_shift =
                is_uv2_hub() ? UVH_TSC_SYNC_SHIFT_UV2K : UVH_TSC_SYNC_SHIFT;
        sync_state = (mmr >> mmr_shift) & UVH_TSC_SYNC_MASK;
 
+       /* Check if TSC is valid for all sockets */
        switch (sync_state) {
        case UVH_TSC_SYNC_VALID:
                state = "in sync";
-               valid = true;
+               mark_tsc_async_resets("UV BIOS");
                break;
 
-       case UVH_TSC_SYNC_INVALID:
-               state = "unstable";
-               valid = false;
+       /* If BIOS state unknown, don't do anything */
+       case UVH_TSC_SYNC_UNKNOWN:
+               state = "unknown";
                break;
+
+       /* Otherwise, BIOS indicates problem with TSC */
        default:
-               state = "unknown: assuming valid";
-               valid = true;
+               state = "unstable";
+               mark_tsc_unstable("UV BIOS");
                break;
        }
        pr_info("UV: TSC sync state from BIOS:0%d(%s)\n", sync_state, state);
-
-       /* Mark flag that says TSC != 0 is valid for socket 0 */
-       if (valid)
-               mark_tsc_async_resets("UV BIOS");
-       else
-               mark_tsc_unstable("UV BIOS");
 }
 
+/* Selector for (4|4A|5) structs */
+#define uvxy_field(sname, field, undef) (      \
+       is_uv(UV4A) ? sname.s4a.field :         \
+       is_uv(UV4) ? sname.s4.field :           \
+       is_uv(UV3) ? sname.s3.field :           \
+       undef)
+
 /* [Copied from arch/x86/kernel/cpu/topology.c:detect_extended_topology()] */
 
 #define SMT_LEVEL                      0       /* Leaf 0xb SMT level */
@@ -221,29 +292,110 @@ static void __init uv_stringify(int len, char *to, char *from)
        strncpy(to, from, len-1);
 }
 
-static int __init uv_acpi_madt_oem_check(char *_oem_id, char *_oem_table_id)
+/* Find UV arch type entry in UVsystab */
+static unsigned long __init early_find_archtype(struct uv_systab *st)
+{
+       int i;
+
+       for (i = 0; st->entry[i].type != UV_SYSTAB_TYPE_UNUSED; i++) {
+               unsigned long ptr = st->entry[i].offset;
+
+               if (!ptr)
+                       continue;
+               ptr += (unsigned long)st;
+               if (st->entry[i].type == UV_SYSTAB_TYPE_ARCH_TYPE)
+                       return ptr;
+       }
+       return 0;
+}
+
+/* Validate UV arch type field in UVsystab */
+static int __init decode_arch_type(unsigned long ptr)
+{
+       struct uv_arch_type_entry *uv_ate = (struct uv_arch_type_entry *)ptr;
+       int n = strlen(uv_ate->archtype);
+
+       if (n > 0 && n < sizeof(uv_ate->archtype)) {
+               pr_info("UV: UVarchtype received from BIOS\n");
+               uv_stringify(UV_AT_SIZE, uv_archtype, uv_ate->archtype);
+               return 1;
+       }
+       return 0;
+}
+
+/* Determine if UV arch type entry might exist in UVsystab */
+static int __init early_get_arch_type(void)
 {
-       int pnodeid;
-       int uv_apic;
+       unsigned long uvst_physaddr, uvst_size, ptr;
+       struct uv_systab *st;
+       u32 rev;
+       int ret;
+
+       uvst_physaddr = get_uv_systab_phys(0);
+       if (!uvst_physaddr)
+               return 0;
+
+       st = early_memremap_ro(uvst_physaddr, sizeof(struct uv_systab));
+       if (!st) {
+               pr_err("UV: Cannot access UVsystab, remap failed\n");
+               return 0;
+       }
 
+       rev = st->revision;
+       if (rev < UV_SYSTAB_VERSION_UV5) {
+               early_memunmap(st, sizeof(struct uv_systab));
+               return 0;
+       }
+
+       uvst_size = st->size;
+       early_memunmap(st, sizeof(struct uv_systab));
+       st = early_memremap_ro(uvst_physaddr, uvst_size);
+       if (!st) {
+               pr_err("UV: Cannot access UVarchtype, remap failed\n");
+               return 0;
+       }
+
+       ptr = early_find_archtype(st);
+       if (!ptr) {
+               early_memunmap(st, uvst_size);
+               return 0;
+       }
+
+       ret = decode_arch_type(ptr);
+       early_memunmap(st, uvst_size);
+       return ret;
+}
+
+static int __init uv_set_system_type(char *_oem_id)
+{
+       /* Save OEM_ID passed from ACPI MADT */
        uv_stringify(sizeof(oem_id), oem_id, _oem_id);
-       uv_stringify(sizeof(oem_table_id), oem_table_id, _oem_table_id);
 
-       if (strncmp(oem_id, "SGI", 3) != 0) {
-               if (strncmp(oem_id, "NSGI", 4) != 0)
+       /* Check if BIOS sent us a UVarchtype */
+       if (!early_get_arch_type())
+
+               /* If not use OEM ID for UVarchtype */
+               uv_stringify(UV_AT_SIZE, uv_archtype, _oem_id);
+
+       /* Check if not hubbed */
+       if (strncmp(uv_archtype, "SGI", 3) != 0) {
+
+               /* (Not hubbed), check if not hubless */
+               if (strncmp(uv_archtype, "NSGI", 4) != 0)
+
+                       /* (Not hubless), not a UV */
                        return 0;
 
-               /* UV4 Hubless, CH, (0x11:UV4+Any) */
-               if (strncmp(oem_id, "NSGI4", 5) == 0)
+               /* UV4 Hubless: CH */
+               if (strncmp(uv_archtype, "NSGI4", 5) == 0)
                        uv_hubless_system = 0x11;
 
-               /* UV3 Hubless, UV300/MC990X w/o hub (0x9:UV3+Any) */
+               /* UV3 Hubless: UV300/MC990X w/o hub */
                else
                        uv_hubless_system = 0x9;
 
-               pr_info("UV: OEM IDs %s/%s, HUBLESS(0x%x)\n",
-                       oem_id, oem_table_id, uv_hubless_system);
-
+               pr_info("UV: OEM IDs %s/%s, SystemType %d, HUBLESS ID %x\n",
+                       oem_id, oem_table_id, uv_system_type, uv_hubless_system);
                return 0;
        }
 
@@ -252,60 +404,83 @@ static int __init uv_acpi_madt_oem_check(char *_oem_id, char *_oem_table_id)
                return 0;
        }
 
-       /* Set up early hub type field in uv_hub_info for Node 0 */
-       uv_cpu_info->p_uv_hub_info = &uv_hub_info_node0;
+       /* Set hubbed type if true */
+       uv_hub_info->hub_revision =
+               !strncmp(uv_archtype, "SGI5", 4) ? UV5_HUB_REVISION_BASE :
+               !strncmp(uv_archtype, "SGI4", 4) ? UV4_HUB_REVISION_BASE :
+               !strncmp(uv_archtype, "SGI3", 4) ? UV3_HUB_REVISION_BASE :
+               !strcmp(uv_archtype, "SGI2") ? UV2_HUB_REVISION_BASE : 0;
+
+       switch (uv_hub_info->hub_revision) {
+       case UV5_HUB_REVISION_BASE:
+               uv_hubbed_system = 0x21;
+               uv_hub_type_set(UV5);
+               break;
 
-       /*
-        * Determine UV arch type.
-        *   SGI2: UV2000/3000
-        *   SGI3: UV300 (truncated to 4 chars because of different varieties)
-        *   SGI4: UV400 (truncated to 4 chars because of different varieties)
-        */
-       if (!strncmp(oem_id, "SGI4", 4)) {
-               uv_hub_info->hub_revision = UV4_HUB_REVISION_BASE;
+       case UV4_HUB_REVISION_BASE:
                uv_hubbed_system = 0x11;
+               uv_hub_type_set(UV4);
+               break;
 
-       } else if (!strncmp(oem_id, "SGI3", 4)) {
-               uv_hub_info->hub_revision = UV3_HUB_REVISION_BASE;
+       case UV3_HUB_REVISION_BASE:
                uv_hubbed_system = 0x9;
+               uv_hub_type_set(UV3);
+               break;
 
-       } else if (!strcmp(oem_id, "SGI2")) {
-               uv_hub_info->hub_revision = UV2_HUB_REVISION_BASE;
+       case UV2_HUB_REVISION_BASE:
                uv_hubbed_system = 0x5;
+               uv_hub_type_set(UV2);
+               break;
 
-       } else {
-               uv_hub_info->hub_revision = 0;
-               goto badbios;
+       default:
+               return 0;
        }
 
-       pnodeid = early_get_pnodeid();
-       early_get_apic_socketid_shift();
+       /* Get UV hub chip part number & revision */
+       early_set_hub_type();
 
+       /* Other UV setup functions */
+       early_get_pnodeid();
+       early_get_apic_socketid_shift();
        x86_platform.is_untracked_pat_range = uv_is_untracked_pat_range;
        x86_platform.nmi_init = uv_nmi_init;
+       uv_tsc_check_sync();
+
+       return 1;
+}
+
+/* Called early to probe for the correct APIC driver */
+static int __init uv_acpi_madt_oem_check(char *_oem_id, char *_oem_table_id)
+{
+       /* Set up early hub info fields for Node 0 */
+       uv_cpu_info->p_uv_hub_info = &uv_hub_info_node0;
+
+       /* If not UV, return. */
+       if (likely(uv_set_system_type(_oem_id) == 0))
+               return 0;
+
+       /* Save and Decode OEM Table ID */
+       uv_stringify(sizeof(oem_table_id), oem_table_id, _oem_table_id);
 
-       if (!strcmp(oem_table_id, "UVX")) {
-               /* This is the most common hardware variant: */
+       /* This is the most common hardware variant, x2apic mode */
+       if (!strcmp(oem_table_id, "UVX"))
                uv_system_type = UV_X2APIC;
-               uv_apic = 0;
 
-       } else if (!strcmp(oem_table_id, "UVL")) {
-               /* Only used for very small systems:  */
+       /* Only used for very small systems, usually 1 chassis, legacy mode  */
+       else if (!strcmp(oem_table_id, "UVL"))
                uv_system_type = UV_LEGACY_APIC;
-               uv_apic = 0;
 
-       } else {
+       else
                goto badbios;
-       }
 
-       pr_info("UV: OEM IDs %s/%s, System/HUB Types %d/%d, uv_apic %d\n", oem_id, oem_table_id, uv_system_type, uv_min_hub_revision_id, uv_apic);
-       uv_tsc_check_sync();
+       pr_info("UV: OEM IDs %s/%s, System/UVType %d/0x%x, HUB RevID %d\n",
+               oem_id, oem_table_id, uv_system_type, is_uv(UV_ANY),
+               uv_min_hub_revision_id);
 
-       return uv_apic;
+       return 0;
 
 badbios:
-       pr_err("UV: OEM_ID:%s OEM_TABLE_ID:%s\n", oem_id, oem_table_id);
-       pr_err("Current UV Type or BIOS not supported\n");
+       pr_err("UV: UVarchtype:%s not supported\n", uv_archtype);
        BUG();
 }
 
@@ -673,12 +848,12 @@ static struct apic apic_x2apic_uv_x __ro_after_init = {
 };
 
 #define        UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_LENGTH      3
-#define DEST_SHIFT UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT
+#define DEST_SHIFT UVXH_RH_GAM_ALIAS_0_REDIRECT_CONFIG_DEST_BASE_SHFT
 
 static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
 {
-       union uvh_rh_gam_alias210_overlay_config_2_mmr_u alias;
-       union uvh_rh_gam_alias210_redirect_config_2_mmr_u redirect;
+       union uvh_rh_gam_alias_2_overlay_config_u alias;
+       union uvh_rh_gam_alias_2_redirect_config_u redirect;
        unsigned long m_redirect;
        unsigned long m_overlay;
        int i;
@@ -686,16 +861,16 @@ static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
        for (i = 0; i < UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_LENGTH; i++) {
                switch (i) {
                case 0:
-                       m_redirect = UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR;
-                       m_overlay  = UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR;
+                       m_redirect = UVH_RH_GAM_ALIAS_0_REDIRECT_CONFIG;
+                       m_overlay  = UVH_RH_GAM_ALIAS_0_OVERLAY_CONFIG;
                        break;
                case 1:
-                       m_redirect = UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR;
-                       m_overlay  = UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR;
+                       m_redirect = UVH_RH_GAM_ALIAS_1_REDIRECT_CONFIG;
+                       m_overlay  = UVH_RH_GAM_ALIAS_1_OVERLAY_CONFIG;
                        break;
                case 2:
-                       m_redirect = UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR;
-                       m_overlay  = UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR;
+                       m_redirect = UVH_RH_GAM_ALIAS_2_REDIRECT_CONFIG;
+                       m_overlay  = UVH_RH_GAM_ALIAS_2_OVERLAY_CONFIG;
                        break;
                }
                alias.v = uv_read_local_mmr(m_overlay);
@@ -710,6 +885,7 @@ static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
 }
 
 enum map_type {map_wb, map_uc};
+static const char * const mt[] = { "WB", "UC" };
 
 static __init void map_high(char *id, unsigned long base, int pshift, int bshift, int max_pnode, enum map_type map_type)
 {
@@ -721,23 +897,36 @@ static __init void map_high(char *id, unsigned long base, int pshift, int bshift
                pr_info("UV: Map %s_HI base address NULL\n", id);
                return;
        }
-       pr_debug("UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, paddr + bytes);
        if (map_type == map_uc)
                init_extra_mapping_uc(paddr, bytes);
        else
                init_extra_mapping_wb(paddr, bytes);
+
+       pr_info("UV: Map %s_HI 0x%lx - 0x%lx %s (%d segments)\n",
+               id, paddr, paddr + bytes, mt[map_type], max_pnode + 1);
 }
 
 static __init void map_gru_high(int max_pnode)
 {
-       union uvh_rh_gam_gru_overlay_config_mmr_u gru;
-       int shift = UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT;
-       unsigned long mask = UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK;
-       unsigned long base;
+       union uvh_rh_gam_gru_overlay_config_u gru;
+       unsigned long mask, base;
+       int shift;
+
+       if (UVH_RH_GAM_GRU_OVERLAY_CONFIG) {
+               gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG);
+               shift = UVH_RH_GAM_GRU_OVERLAY_CONFIG_BASE_SHFT;
+               mask = UVH_RH_GAM_GRU_OVERLAY_CONFIG_BASE_MASK;
+       } else if (UVH_RH10_GAM_GRU_OVERLAY_CONFIG) {
+               gru.v = uv_read_local_mmr(UVH_RH10_GAM_GRU_OVERLAY_CONFIG);
+               shift = UVH_RH10_GAM_GRU_OVERLAY_CONFIG_BASE_SHFT;
+               mask = UVH_RH10_GAM_GRU_OVERLAY_CONFIG_BASE_MASK;
+       } else {
+               pr_err("UV: GRU unavailable (no MMR)\n");
+               return;
+       }
 
-       gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
        if (!gru.s.enable) {
-               pr_info("UV: GRU disabled\n");
+               pr_info("UV: GRU disabled (by BIOS)\n");
                return;
        }
 
@@ -749,62 +938,104 @@ static __init void map_gru_high(int max_pnode)
 
 static __init void map_mmr_high(int max_pnode)
 {
-       union uvh_rh_gam_mmr_overlay_config_mmr_u mmr;
-       int shift = UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT;
+       unsigned long base;
+       int shift;
+       bool enable;
+
+       if (UVH_RH10_GAM_MMR_OVERLAY_CONFIG) {
+               union uvh_rh10_gam_mmr_overlay_config_u mmr;
+
+               mmr.v = uv_read_local_mmr(UVH_RH10_GAM_MMR_OVERLAY_CONFIG);
+               enable = mmr.s.enable;
+               base = mmr.s.base;
+               shift = UVH_RH10_GAM_MMR_OVERLAY_CONFIG_BASE_SHFT;
+       } else if (UVH_RH_GAM_MMR_OVERLAY_CONFIG) {
+               union uvh_rh_gam_mmr_overlay_config_u mmr;
+
+               mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG);
+               enable = mmr.s.enable;
+               base = mmr.s.base;
+               shift = UVH_RH_GAM_MMR_OVERLAY_CONFIG_BASE_SHFT;
+       } else {
+               pr_err("UV:%s:RH_GAM_MMR_OVERLAY_CONFIG MMR undefined?\n",
+                       __func__);
+               return;
+       }
 
-       mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR);
-       if (mmr.s.enable)
-               map_high("MMR", mmr.s.base, shift, shift, max_pnode, map_uc);
+       if (enable)
+               map_high("MMR", base, shift, shift, max_pnode, map_uc);
        else
                pr_info("UV: MMR disabled\n");
 }
 
-/* UV3/4 have identical MMIOH overlay configs, UV4A is slightly different */
-static __init void map_mmioh_high_uv34(int index, int min_pnode, int max_pnode)
-{
-       unsigned long overlay;
-       unsigned long mmr;
-       unsigned long base;
-       unsigned long nasid_mask;
-       unsigned long m_overlay;
-       int i, n, shift, m_io, max_io;
-       int nasid, lnasid, fi, li;
-       char *id;
-
-       if (index == 0) {
-               id = "MMIOH0";
-               m_overlay = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR;
-               overlay = uv_read_local_mmr(m_overlay);
-               base = overlay & UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_MASK;
-               mmr = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR;
-               m_io = (overlay & UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_MASK)
-                       >> UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT;
-               shift = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT;
-               n = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH;
-               nasid_mask = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_MASK;
-       } else {
-               id = "MMIOH1";
-               m_overlay = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR;
-               overlay = uv_read_local_mmr(m_overlay);
-               base = overlay & UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_MASK;
-               mmr = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR;
-               m_io = (overlay & UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_MASK)
-                       >> UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT;
-               shift = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT;
-               n = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH;
-               nasid_mask = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_MASK;
+/* Arch specific ENUM cases */
+enum mmioh_arch {
+       UV2_MMIOH = -1,
+       UVY_MMIOH0, UVY_MMIOH1,
+       UVX_MMIOH0, UVX_MMIOH1,
+};
+
+/* Calculate and Map MMIOH Regions */
+static void __init calc_mmioh_map(enum mmioh_arch index,
+       int min_pnode, int max_pnode,
+       int shift, unsigned long base, int m_io, int n_io)
+{
+       unsigned long mmr, nasid_mask;
+       int nasid, min_nasid, max_nasid, lnasid, mapped;
+       int i, fi, li, n, max_io;
+       char id[8];
+
+       /* One (UV2) mapping */
+       if (index == UV2_MMIOH) {
+               strncpy(id, "MMIOH", sizeof(id));
+               max_io = max_pnode;
+               mapped = 0;
+               goto map_exit;
        }
-       pr_info("UV: %s overlay 0x%lx base:0x%lx m_io:%d\n", id, overlay, base, m_io);
-       if (!(overlay & UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_MASK)) {
-               pr_info("UV: %s disabled\n", id);
+
+       /* small and large MMIOH mappings */
+       switch (index) {
+       case UVY_MMIOH0:
+               mmr = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0;
+               nasid_mask = UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK;
+               n = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH;
+               min_nasid = min_pnode;
+               max_nasid = max_pnode;
+               mapped = 1;
+               break;
+       case UVY_MMIOH1:
+               mmr = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1;
+               nasid_mask = UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK;
+               n = UVH_RH10_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH;
+               min_nasid = min_pnode;
+               max_nasid = max_pnode;
+               mapped = 1;
+               break;
+       case UVX_MMIOH0:
+               mmr = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0;
+               nasid_mask = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_MASK;
+               n = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG0_DEPTH;
+               min_nasid = min_pnode * 2;
+               max_nasid = max_pnode * 2;
+               mapped = 1;
+               break;
+       case UVX_MMIOH1:
+               mmr = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1;
+               nasid_mask = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_MASK;
+               n = UVH_RH_GAM_MMIOH_REDIRECT_CONFIG1_DEPTH;
+               min_nasid = min_pnode * 2;
+               max_nasid = max_pnode * 2;
+               mapped = 1;
+               break;
+       default:
+               pr_err("UV:%s:Invalid mapping type:%d\n", __func__, index);
                return;
        }
 
-       /* Convert to NASID: */
-       min_pnode *= 2;
-       max_pnode *= 2;
-       max_io = lnasid = fi = li = -1;
+       /* enum values chosen so (index mod 2) is MMIOH 0/1 (low/high) */
+       snprintf(id, sizeof(id), "MMIOH%d", index%2);
 
+       max_io = lnasid = fi = li = -1;
        for (i = 0; i < n; i++) {
                unsigned long m_redirect = mmr + i * 8;
                unsigned long redirect = uv_read_local_mmr(m_redirect);
@@ -814,9 +1045,12 @@ static __init void map_mmioh_high_uv34(int index, int min_pnode, int max_pnode)
                        pr_info("UV: %s redirect base 0x%lx(@0x%lx) 0x%04x\n",
                                id, redirect, m_redirect, nasid);
 
-               /* Invalid NASID: */
-               if (nasid < min_pnode || max_pnode < nasid)
+               /* Invalid NASID check */
+               if (nasid < min_nasid || max_nasid < nasid) {
+                       pr_err("UV:%s:Invalid NASID:%x (range:%x..%x)\n",
+                               __func__, index, min_nasid, max_nasid);
                        nasid = -1;
+               }
 
                if (nasid == lnasid) {
                        li = i;
@@ -839,7 +1073,8 @@ static __init void map_mmioh_high_uv34(int index, int min_pnode, int max_pnode)
                        }
                        addr1 = (base << shift) + f * (1ULL << m_io);
                        addr2 = (base << shift) + (l + 1) * (1ULL << m_io);
-                       pr_info("UV: %s[%03d..%03d] NASID 0x%04x ADDR 0x%016lx - 0x%016lx\n", id, fi, li, lnasid, addr1, addr2);
+                       pr_info("UV: %s[%03d..%03d] NASID 0x%04x ADDR 0x%016lx - 0x%016lx\n",
+                               id, fi, li, lnasid, addr1, addr2);
                        if (max_io < l)
                                max_io = l;
                }
@@ -847,49 +1082,93 @@ static __init void map_mmioh_high_uv34(int index, int min_pnode, int max_pnode)
                lnasid = nasid;
        }
 
-       pr_info("UV: %s base:0x%lx shift:%d M_IO:%d MAX_IO:%d\n", id, base, shift, m_io, max_io);
+map_exit:
+       pr_info("UV: %s base:0x%lx shift:%d m_io:%d max_io:%d max_pnode:0x%x\n",
+               id, base, shift, m_io, max_io, max_pnode);
 
-       if (max_io >= 0)
+       if (max_io >= 0 && !mapped)
                map_high(id, base, shift, m_io, max_io, map_uc);
 }
 
 static __init void map_mmioh_high(int min_pnode, int max_pnode)
 {
-       union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh;
-       unsigned long mmr, base;
-       int shift, enable, m_io, n_io;
+       /* UVY flavor */
+       if (UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0) {
+               union uvh_rh10_gam_mmioh_overlay_config0_u mmioh0;
+               union uvh_rh10_gam_mmioh_overlay_config1_u mmioh1;
+
+               mmioh0.v = uv_read_local_mmr(UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0);
+               if (unlikely(mmioh0.s.enable == 0))
+                       pr_info("UV: MMIOH0 disabled\n");
+               else
+                       calc_mmioh_map(UVY_MMIOH0, min_pnode, max_pnode,
+                               UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG0_BASE_SHFT,
+                               mmioh0.s.base, mmioh0.s.m_io, mmioh0.s.n_io);
 
-       if (is_uv3_hub() || is_uv4_hub()) {
-               /* Map both MMIOH regions: */
-               map_mmioh_high_uv34(0, min_pnode, max_pnode);
-               map_mmioh_high_uv34(1, min_pnode, max_pnode);
+               mmioh1.v = uv_read_local_mmr(UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1);
+               if (unlikely(mmioh1.s.enable == 0))
+                       pr_info("UV: MMIOH1 disabled\n");
+               else
+                       calc_mmioh_map(UVY_MMIOH1, min_pnode, max_pnode,
+                               UVH_RH10_GAM_MMIOH_OVERLAY_CONFIG1_BASE_SHFT,
+                               mmioh1.s.base, mmioh1.s.m_io, mmioh1.s.n_io);
                return;
        }
+       /* UVX flavor */
+       if (UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0) {
+               union uvh_rh_gam_mmioh_overlay_config0_u mmioh0;
+               union uvh_rh_gam_mmioh_overlay_config1_u mmioh1;
+
+               mmioh0.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0);
+               if (unlikely(mmioh0.s.enable == 0))
+                       pr_info("UV: MMIOH0 disabled\n");
+               else {
+                       unsigned long base = uvxy_field(mmioh0, base, 0);
+                       int m_io = uvxy_field(mmioh0, m_io, 0);
+                       int n_io = uvxy_field(mmioh0, n_io, 0);
+
+                       calc_mmioh_map(UVX_MMIOH0, min_pnode, max_pnode,
+                               UVH_RH_GAM_MMIOH_OVERLAY_CONFIG0_BASE_SHFT,
+                               base, m_io, n_io);
+               }
 
-       if (is_uv2_hub()) {
-               mmr     = UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR;
-               shift   = UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
-               mmioh.v = uv_read_local_mmr(mmr);
-               enable  = !!mmioh.s2.enable;
-               base    = mmioh.s2.base;
-               m_io    = mmioh.s2.m_io;
-               n_io    = mmioh.s2.n_io;
-
-               if (enable) {
-                       max_pnode &= (1 << n_io) - 1;
-                       pr_info("UV: base:0x%lx shift:%d N_IO:%d M_IO:%d max_pnode:0x%x\n",
-                               base, shift, m_io, n_io, max_pnode);
-                       map_high("MMIOH", base, shift, m_io, max_pnode, map_uc);
-               } else {
-                       pr_info("UV: MMIOH disabled\n");
+               mmioh1.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1);
+               if (unlikely(mmioh1.s.enable == 0))
+                       pr_info("UV: MMIOH1 disabled\n");
+               else {
+                       unsigned long base = uvxy_field(mmioh1, base, 0);
+                       int m_io = uvxy_field(mmioh1, m_io, 0);
+                       int n_io = uvxy_field(mmioh1, n_io, 0);
+
+                       calc_mmioh_map(UVX_MMIOH1, min_pnode, max_pnode,
+                               UVH_RH_GAM_MMIOH_OVERLAY_CONFIG1_BASE_SHFT,
+                               base, m_io, n_io);
                }
+               return;
+       }
+
+       /* UV2 flavor */
+       if (UVH_RH_GAM_MMIOH_OVERLAY_CONFIG) {
+               union uvh_rh_gam_mmioh_overlay_config_u mmioh;
+
+               mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG);
+               if (unlikely(mmioh.s2.enable == 0))
+                       pr_info("UV: MMIOH disabled\n");
+               else
+                       calc_mmioh_map(UV2_MMIOH, min_pnode, max_pnode,
+                               UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_BASE_SHFT,
+                               mmioh.s2.base, mmioh.s2.m_io, mmioh.s2.n_io);
+               return;
        }
 }
 
 static __init void map_low_mmrs(void)
 {
-       init_extra_mapping_uc(UV_GLOBAL_MMR32_BASE, UV_GLOBAL_MMR32_SIZE);
-       init_extra_mapping_uc(UV_LOCAL_MMR_BASE, UV_LOCAL_MMR_SIZE);
+       if (UV_GLOBAL_MMR32_BASE)
+               init_extra_mapping_uc(UV_GLOBAL_MMR32_BASE, UV_GLOBAL_MMR32_SIZE);
+
+       if (UV_LOCAL_MMR_BASE)
+               init_extra_mapping_uc(UV_LOCAL_MMR_BASE, UV_LOCAL_MMR_SIZE);
 }
 
 static __init void uv_rtc_init(void)
@@ -909,85 +1188,6 @@ static __init void uv_rtc_init(void)
        }
 }
 
-/*
- * percpu heartbeat timer
- */
-static void uv_heartbeat(struct timer_list *timer)
-{
-       unsigned char bits = uv_scir_info->state;
-
-       /* Flip heartbeat bit: */
-       bits ^= SCIR_CPU_HEARTBEAT;
-
-       /* Is this CPU idle? */
-       if (idle_cpu(raw_smp_processor_id()))
-               bits &= ~SCIR_CPU_ACTIVITY;
-       else
-               bits |= SCIR_CPU_ACTIVITY;
-
-       /* Update system controller interface reg: */
-       uv_set_scir_bits(bits);
-
-       /* Enable next timer period: */
-       mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL);
-}
-
-static int uv_heartbeat_enable(unsigned int cpu)
-{
-       while (!uv_cpu_scir_info(cpu)->enabled) {
-               struct timer_list *timer = &uv_cpu_scir_info(cpu)->timer;
-
-               uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY);
-               timer_setup(timer, uv_heartbeat, TIMER_PINNED);
-               timer->expires = jiffies + SCIR_CPU_HB_INTERVAL;
-               add_timer_on(timer, cpu);
-               uv_cpu_scir_info(cpu)->enabled = 1;
-
-               /* Also ensure that boot CPU is enabled: */
-               cpu = 0;
-       }
-       return 0;
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-static int uv_heartbeat_disable(unsigned int cpu)
-{
-       if (uv_cpu_scir_info(cpu)->enabled) {
-               uv_cpu_scir_info(cpu)->enabled = 0;
-               del_timer(&uv_cpu_scir_info(cpu)->timer);
-       }
-       uv_set_cpu_scir_bits(cpu, 0xff);
-       return 0;
-}
-
-static __init void uv_scir_register_cpu_notifier(void)
-{
-       cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/x2apic-uvx:online",
-                                 uv_heartbeat_enable, uv_heartbeat_disable);
-}
-
-#else /* !CONFIG_HOTPLUG_CPU */
-
-static __init void uv_scir_register_cpu_notifier(void)
-{
-}
-
-static __init int uv_init_heartbeat(void)
-{
-       int cpu;
-
-       if (is_uv_system()) {
-               for_each_online_cpu(cpu)
-                       uv_heartbeat_enable(cpu);
-       }
-
-       return 0;
-}
-
-late_initcall(uv_init_heartbeat);
-
-#endif /* !CONFIG_HOTPLUG_CPU */
-
 /* Direct Legacy VGA I/O traffic to designated IOH */
 static int uv_set_vga_state(struct pci_dev *pdev, bool decode, unsigned int command_bits, u32 flags)
 {
@@ -1027,26 +1227,22 @@ struct mn {
        unsigned char   n_lshift;
 };
 
+/* Initialize caller's MN struct and fill in values */
 static void get_mn(struct mn *mnp)
 {
-       union uvh_rh_gam_config_mmr_u m_n_config;
-       union uv3h_gr0_gam_gr_config_u m_gr_config;
-
-       /* Make sure the whole structure is well initialized: */
        memset(mnp, 0, sizeof(*mnp));
-
-       m_n_config.v    = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR);
-       mnp->n_val      = m_n_config.s.n_skt;
-
-       if (is_uv4_hub()) {
+       mnp->n_val      = uv_cpuid.n_skt;
+       if (is_uv(UV4|UVY)) {
                mnp->m_val      = 0;
                mnp->n_lshift   = 0;
        } else if (is_uv3_hub()) {
-               mnp->m_val      = m_n_config.s3.m_skt;
-               m_gr_config.v   = uv_read_local_mmr(UV3H_GR0_GAM_GR_CONFIG);
+               union uvyh_gr0_gam_gr_config_u m_gr_config;
+
+               mnp->m_val      = uv_cpuid.m_skt;
+               m_gr_config.v   = uv_read_local_mmr(UVH_GR0_GAM_GR_CONFIG);
                mnp->n_lshift   = m_gr_config.s3.m_skt;
        } else if (is_uv2_hub()) {
-               mnp->m_val      = m_n_config.s2.m_skt;
+               mnp->m_val      = uv_cpuid.m_skt;
                mnp->n_lshift   = mnp->m_val == 40 ? 40 : 39;
        }
        mnp->m_shift = mnp->m_val ? 64 - mnp->m_val : 0;
@@ -1054,7 +1250,6 @@ static void get_mn(struct mn *mnp)
 
 static void __init uv_init_hub_info(struct uv_hub_info_s *hi)
 {
-       union uvh_node_id_u node_id;
        struct mn mn;
 
        get_mn(&mn);
@@ -1067,7 +1262,9 @@ static void __init uv_init_hub_info(struct uv_hub_info_s *hi)
        hi->m_shift             = mn.m_shift;
        hi->n_lshift            = mn.n_lshift ? mn.n_lshift : 0;
        hi->hub_revision        = uv_hub_info->hub_revision;
+       hi->hub_type            = uv_hub_info->hub_type;
        hi->pnode_mask          = uv_cpuid.pnode_mask;
+       hi->nasid_shift         = uv_cpuid.nasid_shift;
        hi->min_pnode           = _min_pnode;
        hi->min_socket          = _min_socket;
        hi->pnode_to_socket     = _pnode_to_socket;
@@ -1076,9 +1273,8 @@ static void __init uv_init_hub_info(struct uv_hub_info_s *hi)
        hi->gr_table_len        = _gr_table_len;
        hi->gr_table            = _gr_table;
 
-       node_id.v               = uv_read_local_mmr(UVH_NODE_ID);
        uv_cpuid.gnode_shift    = max_t(unsigned int, uv_cpuid.gnode_shift, mn.n_val);
-       hi->gnode_extra         = (node_id.s.node_id & ~((1 << uv_cpuid.gnode_shift) - 1)) >> 1;
+       hi->gnode_extra         = (uv_node_id & ~((1 << uv_cpuid.gnode_shift) - 1)) >> 1;
        if (mn.m_val)
                hi->gnode_upper = (u64)hi->gnode_extra << mn.m_val;
 
@@ -1090,7 +1286,9 @@ static void __init uv_init_hub_info(struct uv_hub_info_s *hi)
                hi->gpa_shift           = uv_gp_table->gpa_shift;
                hi->gpa_mask            = (1UL << hi->gpa_shift) - 1;
        } else {
-               hi->global_mmr_base     = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & ~UV_MMR_ENABLE;
+               hi->global_mmr_base     =
+                       uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG) &
+                       ~UV_MMR_ENABLE;
                hi->global_mmr_shift    = _UV_GLOBAL_MMR64_PNODE_SHIFT;
        }
 
@@ -1101,7 +1299,11 @@ static void __init uv_init_hub_info(struct uv_hub_info_s *hi)
        /* Show system specific info: */
        pr_info("UV: N:%d M:%d m_shift:%d n_lshift:%d\n", hi->n_val, hi->m_val, hi->m_shift, hi->n_lshift);
        pr_info("UV: gpa_mask/shift:0x%lx/%d pnode_mask:0x%x apic_pns:%d\n", hi->gpa_mask, hi->gpa_shift, hi->pnode_mask, hi->apic_pnode_shift);
-       pr_info("UV: mmr_base/shift:0x%lx/%ld gru_base/shift:0x%lx/%ld\n", hi->global_mmr_base, hi->global_mmr_shift, hi->global_gru_base, hi->global_gru_shift);
+       pr_info("UV: mmr_base/shift:0x%lx/%ld\n", hi->global_mmr_base, hi->global_mmr_shift);
+       if (hi->global_gru_base)
+               pr_info("UV: gru_base/shift:0x%lx/%ld\n",
+                       hi->global_gru_base, hi->global_gru_shift);
+
        pr_info("UV: gnode_upper:0x%lx gnode_extra:0x%x\n", hi->gnode_upper, hi->gnode_extra);
 }
 
@@ -1173,21 +1375,25 @@ static void __init decode_gam_rng_tbl(unsigned long ptr)
        pr_info("UV: GRT: %d entries, sockets(min:%x,max:%x) pnodes(min:%x,max:%x)\n", index, _min_socket, _max_socket, _min_pnode, _max_pnode);
 }
 
+/* Walk through UVsystab decoding the fields */
 static int __init decode_uv_systab(void)
 {
        struct uv_systab *st;
        int i;
 
-       /* If system is uv3 or lower, there is no extended UVsystab */
-       if (is_uv_hubbed(0xfffffe) < uv(4) && is_uv_hubless(0xfffffe) < uv(4))
-               return 0;       /* No extended UVsystab required */
-
+       /* Get mapped UVsystab pointer */
        st = uv_systab;
+
+       /* If UVsystab is version 1, there is no extended UVsystab */
+       if (st && st->revision == UV_SYSTAB_VERSION_1)
+               return 0;
+
        if ((!st) || (st->revision < UV_SYSTAB_VERSION_UV4_LATEST)) {
                int rev = st ? st->revision : 0;
 
-               pr_err("UV: BIOS UVsystab version(%x) mismatch, expecting(%x)\n", rev, UV_SYSTAB_VERSION_UV4_LATEST);
-               pr_err("UV: Cannot support UV operations, switching to generic PC\n");
+               pr_err("UV: BIOS UVsystab mismatch, (%x < %x)\n",
+                       rev, UV_SYSTAB_VERSION_UV4_LATEST);
+               pr_err("UV: Does not support UV, switch to non-UV x86_64\n");
                uv_system_type = UV_NONE;
 
                return -EINVAL;
@@ -1199,7 +1405,8 @@ static int __init decode_uv_systab(void)
                if (!ptr)
                        continue;
 
-               ptr = ptr + (unsigned long)st;
+               /* point to payload */
+               ptr += (unsigned long)st;
 
                switch (st->entry[i].type) {
                case UV_SYSTAB_TYPE_GAM_PARAMS:
@@ -1209,32 +1416,49 @@ static int __init decode_uv_systab(void)
                case UV_SYSTAB_TYPE_GAM_RNG_TBL:
                        decode_gam_rng_tbl(ptr);
                        break;
+
+               case UV_SYSTAB_TYPE_ARCH_TYPE:
+                       /* already processed in early startup */
+                       break;
+
+               default:
+                       pr_err("UV:%s:Unrecognized UV_SYSTAB_TYPE:%d, skipped\n",
+                               __func__, st->entry[i].type);
+                       break;
                }
        }
        return 0;
 }
 
-/*
- * Set up physical blade translations from UVH_NODE_PRESENT_TABLE
- * .. NB: UVH_NODE_PRESENT_TABLE is going away,
- * .. being replaced by GAM Range Table
- */
+/* Set up physical blade translations from UVH_NODE_PRESENT_TABLE */
 static __init void boot_init_possible_blades(struct uv_hub_info_s *hub_info)
 {
+       unsigned long np;
        int i, uv_pb = 0;
 
-       pr_info("UV: NODE_PRESENT_DEPTH = %d\n", UVH_NODE_PRESENT_TABLE_DEPTH);
-       for (i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) {
-               unsigned long np;
-
-               np = uv_read_local_mmr(UVH_NODE_PRESENT_TABLE + i * 8);
-               if (np)
+       if (UVH_NODE_PRESENT_TABLE) {
+               pr_info("UV: NODE_PRESENT_DEPTH = %d\n",
+                       UVH_NODE_PRESENT_TABLE_DEPTH);
+               for (i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) {
+                       np = uv_read_local_mmr(UVH_NODE_PRESENT_TABLE + i * 8);
                        pr_info("UV: NODE_PRESENT(%d) = 0x%016lx\n", i, np);
-
+                       uv_pb += hweight64(np);
+               }
+       }
+       if (UVH_NODE_PRESENT_0) {
+               np = uv_read_local_mmr(UVH_NODE_PRESENT_0);
+               pr_info("UV: NODE_PRESENT_0 = 0x%016lx\n", np);
+               uv_pb += hweight64(np);
+       }
+       if (UVH_NODE_PRESENT_1) {
+               np = uv_read_local_mmr(UVH_NODE_PRESENT_1);
+               pr_info("UV: NODE_PRESENT_1 = 0x%016lx\n", np);
                uv_pb += hweight64(np);
        }
        if (uv_possible_blades != uv_pb)
                uv_possible_blades = uv_pb;
+
+       pr_info("UV: number nodes/possible blades %d\n", uv_pb);
 }
 
 static void __init build_socket_tables(void)
@@ -1253,7 +1477,7 @@ static void __init build_socket_tables(void)
                        pr_info("UV: No UVsystab socket table, ignoring\n");
                        return;
                }
-               pr_crit("UV: Error: UVsystab address translations not available!\n");
+               pr_err("UV: Error: UVsystab address translations not available!\n");
                BUG();
        }
 
@@ -1379,9 +1603,9 @@ static int __maybe_unused proc_hubless_show(struct seq_file *file, void *data)
        return 0;
 }
 
-static int __maybe_unused proc_oemid_show(struct seq_file *file, void *data)
+static int __maybe_unused proc_archtype_show(struct seq_file *file, void *data)
 {
-       seq_printf(file, "%s/%s\n", oem_id, oem_table_id);
+       seq_printf(file, "%s/%s\n", uv_archtype, oem_table_id);
        return 0;
 }
 
@@ -1390,7 +1614,7 @@ static __init void uv_setup_proc_files(int hubless)
        struct proc_dir_entry *pde;
 
        pde = proc_mkdir(UV_PROC_NODE, NULL);
-       proc_create_single("oemid", 0, pde, proc_oemid_show);
+       proc_create_single("archtype", 0, pde, proc_archtype_show);
        if (hubless)
                proc_create_single("hubless", 0, pde, proc_hubless_show);
        else
@@ -1429,7 +1653,8 @@ static void __init uv_system_init_hub(void)
        struct uv_hub_info_s hub_info = {0};
        int bytes, cpu, nodeid;
        unsigned short min_pnode = 9999, max_pnode = 0;
-       char *hub = is_uv4_hub() ? "UV400" :
+       char *hub = is_uv5_hub() ? "UV500" :
+                   is_uv4_hub() ? "UV400" :
                    is_uv3_hub() ? "UV300" :
                    is_uv2_hub() ? "UV2000/3000" : NULL;
 
@@ -1441,12 +1666,14 @@ static void __init uv_system_init_hub(void)
 
        map_low_mmrs();
 
-       /* Get uv_systab for decoding: */
+       /* Get uv_systab for decoding, setup UV BIOS calls */
        uv_bios_init();
 
        /* If there's an UVsystab problem then abort UV init: */
-       if (decode_uv_systab() < 0)
+       if (decode_uv_systab() < 0) {
+               pr_err("UV: Mangled UVsystab format\n");
                return;
+       }
 
        build_socket_tables();
        build_uv_gr_table();
@@ -1517,8 +1744,6 @@ static void __init uv_system_init_hub(void)
                        uv_hub_info_list(numa_node_id)->pnode = pnode;
                else if (uv_cpu_hub_info(cpu)->pnode == 0xffff)
                        uv_cpu_hub_info(cpu)->pnode = pnode;
-
-               uv_cpu_scir_info(cpu)->offset = uv_scir_offset(apicid);
        }
 
        for_each_node(nodeid) {
@@ -1547,7 +1772,6 @@ static void __init uv_system_init_hub(void)
 
        uv_nmi_setup();
        uv_cpu_init();
-       uv_scir_register_cpu_notifier();
        uv_setup_proc_files(0);
 
        /* Register Legacy VGA I/O redirection handler: */
index c7503be..57074cf 100644 (file)
@@ -248,7 +248,7 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
        switch (leaf) {
        case 1:
                l1 = &l1i;
-               /* fall through */
+               fallthrough;
        case 0:
                if (!l1->val)
                        return;
index c5cf336..345f7d9 100644 (file)
@@ -65,6 +65,9 @@ static void init_c3(struct cpuinfo_x86 *c)
                c->x86_cache_alignment = c->x86_clflush_size * 2;
                set_cpu_cap(c, X86_FEATURE_REP_GOOD);
        }
+
+       if (c->x86 >= 7)
+               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
 }
 
 enum {
@@ -90,18 +93,15 @@ enum {
 
 static void early_init_centaur(struct cpuinfo_x86 *c)
 {
-       switch (c->x86) {
 #ifdef CONFIG_X86_32
-       case 5:
-               /* Emulate MTRRs using Centaur's MCR. */
+       /* Emulate MTRRs using Centaur's MCR. */
+       if (c->x86 == 5)
                set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR);
-               break;
 #endif
-       case 6:
-               if (c->x86_model >= 0xf)
-                       set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
-               break;
-       }
+       if ((c->x86 == 6 && c->x86_model >= 0xf) ||
+           (c->x86 >= 7))
+               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+
 #ifdef CONFIG_X86_64
        set_cpu_cap(c, X86_FEATURE_SYSENTER32);
 #endif
@@ -145,9 +145,8 @@ static void init_centaur(struct cpuinfo_x86 *c)
                        set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
        }
 
-       switch (c->x86) {
 #ifdef CONFIG_X86_32
-       case 5:
+       if (c->x86 == 5) {
                switch (c->x86_model) {
                case 4:
                        name = "C6";
@@ -207,12 +206,10 @@ static void init_centaur(struct cpuinfo_x86 *c)
                        c->x86_cache_size = (cc>>24)+(dd>>24);
                }
                sprintf(c->x86_model_id, "WinChip %s", name);
-               break;
+       }
 #endif
-       case 6:
+       if (c->x86 == 6 || c->x86 >= 7)
                init_c3(c);
-               break;
-       }
 #ifdef CONFIG_X86_64
        set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
 #endif
index c5d6f17..7824fc6 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/syscore_ops.h>
 #include <linux/pgtable.h>
 
+#include <asm/cmdline.h>
 #include <asm/stackprotector.h>
 #include <asm/perf_event.h>
 #include <asm/mmu_context.h>
@@ -1221,6 +1222,59 @@ static void detect_nopl(void)
 }
 
 /*
+ * We parse cpu parameters early because fpu__init_system() is executed
+ * before parse_early_param().
+ */
+static void __init cpu_parse_early_param(void)
+{
+       char arg[128];
+       char *argptr = arg;
+       int arglen, res, bit;
+
+#ifdef CONFIG_X86_32
+       if (cmdline_find_option_bool(boot_command_line, "no387"))
+#ifdef CONFIG_MATH_EMULATION
+               setup_clear_cpu_cap(X86_FEATURE_FPU);
+#else
+               pr_err("Option 'no387' required CONFIG_MATH_EMULATION enabled.\n");
+#endif
+
+       if (cmdline_find_option_bool(boot_command_line, "nofxsr"))
+               setup_clear_cpu_cap(X86_FEATURE_FXSR);
+#endif
+
+       if (cmdline_find_option_bool(boot_command_line, "noxsave"))
+               setup_clear_cpu_cap(X86_FEATURE_XSAVE);
+
+       if (cmdline_find_option_bool(boot_command_line, "noxsaveopt"))
+               setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
+
+       if (cmdline_find_option_bool(boot_command_line, "noxsaves"))
+               setup_clear_cpu_cap(X86_FEATURE_XSAVES);
+
+       arglen = cmdline_find_option(boot_command_line, "clearcpuid", arg, sizeof(arg));
+       if (arglen <= 0)
+               return;
+
+       pr_info("Clearing CPUID bits:");
+       do {
+               res = get_option(&argptr, &bit);
+               if (res == 0 || res == 3)
+                       break;
+
+               /* If the argument was too long, the last bit may be cut off */
+               if (res == 1 && arglen >= sizeof(arg))
+                       break;
+
+               if (bit >= 0 && bit < NCAPINTS * 32) {
+                       pr_cont(" " X86_CAP_FMT, x86_cap_flag(bit));
+                       setup_clear_cpu_cap(bit);
+               }
+       } while (res == 2);
+       pr_cont("\n");
+}
+
+/*
  * Do minimum CPU detection early.
  * Fields really needed: vendor, cpuid_level, family, model, mask,
  * cache alignment.
@@ -1255,6 +1309,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
                get_cpu_cap(c);
                get_cpu_address_sizes(c);
                setup_force_cpu_cap(X86_FEATURE_CPUID);
+               cpu_parse_early_param();
 
                if (this_cpu->c_early_init)
                        this_cpu->c_early_init(c);
@@ -1413,15 +1468,7 @@ static void generic_identify(struct cpuinfo_x86 *c)
         * ESPFIX issue, we can change this.
         */
 #ifdef CONFIG_X86_32
-# ifdef CONFIG_PARAVIRT_XXL
-       do {
-               extern void native_iret(void);
-               if (pv_ops.cpu.iret == native_iret)
-                       set_cpu_bug(c, X86_BUG_ESPFIX);
-       } while (0);
-# else
        set_cpu_bug(c, X86_BUG_ESPFIX);
-# endif
 #endif
 }
 
index 3cbe24c..d502241 100644 (file)
@@ -69,6 +69,8 @@ static const struct cpuid_dep cpuid_deps[] = {
        { X86_FEATURE_CQM_MBM_TOTAL,            X86_FEATURE_CQM_LLC   },
        { X86_FEATURE_CQM_MBM_LOCAL,            X86_FEATURE_CQM_LLC   },
        { X86_FEATURE_AVX512_BF16,              X86_FEATURE_AVX512VL  },
+       { X86_FEATURE_ENQCMD,                   X86_FEATURE_XSAVES    },
+       { X86_FEATURE_PER_THREAD_MBA,           X86_FEATURE_MBA       },
        {}
 };
 
index 99be063..0c6b02d 100644 (file)
@@ -132,49 +132,49 @@ static enum smca_bank_types smca_get_bank_type(unsigned int bank)
 }
 
 static struct smca_hwid smca_hwid_mcatypes[] = {
-       /* { bank_type, hwid_mcatype, xec_bitmap } */
+       /* { bank_type, hwid_mcatype } */
 
        /* Reserved type */
-       { SMCA_RESERVED, HWID_MCATYPE(0x00, 0x0), 0x0 },
+       { SMCA_RESERVED, HWID_MCATYPE(0x00, 0x0)        },
 
        /* ZN Core (HWID=0xB0) MCA types */
-       { SMCA_LS,       HWID_MCATYPE(0xB0, 0x0), 0x1FFFFF },
-       { SMCA_LS_V2,    HWID_MCATYPE(0xB0, 0x10), 0xFFFFFF },
-       { SMCA_IF,       HWID_MCATYPE(0xB0, 0x1), 0x3FFF },
-       { SMCA_L2_CACHE, HWID_MCATYPE(0xB0, 0x2), 0xF },
-       { SMCA_DE,       HWID_MCATYPE(0xB0, 0x3), 0x1FF },
+       { SMCA_LS,       HWID_MCATYPE(0xB0, 0x0)        },
+       { SMCA_LS_V2,    HWID_MCATYPE(0xB0, 0x10)       },
+       { SMCA_IF,       HWID_MCATYPE(0xB0, 0x1)        },
+       { SMCA_L2_CACHE, HWID_MCATYPE(0xB0, 0x2)        },
+       { SMCA_DE,       HWID_MCATYPE(0xB0, 0x3)        },
        /* HWID 0xB0 MCATYPE 0x4 is Reserved */
-       { SMCA_EX,       HWID_MCATYPE(0xB0, 0x5), 0xFFF },
-       { SMCA_FP,       HWID_MCATYPE(0xB0, 0x6), 0x7F },
-       { SMCA_L3_CACHE, HWID_MCATYPE(0xB0, 0x7), 0xFF },
+       { SMCA_EX,       HWID_MCATYPE(0xB0, 0x5)        },
+       { SMCA_FP,       HWID_MCATYPE(0xB0, 0x6)        },
+       { SMCA_L3_CACHE, HWID_MCATYPE(0xB0, 0x7)        },
 
        /* Data Fabric MCA types */
-       { SMCA_CS,       HWID_MCATYPE(0x2E, 0x0), 0x1FF },
-       { SMCA_PIE,      HWID_MCATYPE(0x2E, 0x1), 0x1F },
-       { SMCA_CS_V2,    HWID_MCATYPE(0x2E, 0x2), 0x3FFF },
+       { SMCA_CS,       HWID_MCATYPE(0x2E, 0x0)        },
+       { SMCA_PIE,      HWID_MCATYPE(0x2E, 0x1)        },
+       { SMCA_CS_V2,    HWID_MCATYPE(0x2E, 0x2)        },
 
        /* Unified Memory Controller MCA type */
-       { SMCA_UMC,      HWID_MCATYPE(0x96, 0x0), 0xFF },
+       { SMCA_UMC,      HWID_MCATYPE(0x96, 0x0)        },
 
        /* Parameter Block MCA type */
-       { SMCA_PB,       HWID_MCATYPE(0x05, 0x0), 0x1 },
+       { SMCA_PB,       HWID_MCATYPE(0x05, 0x0)        },
 
        /* Platform Security Processor MCA type */
-       { SMCA_PSP,      HWID_MCATYPE(0xFF, 0x0), 0x1 },
-       { SMCA_PSP_V2,   HWID_MCATYPE(0xFF, 0x1), 0x3FFFF },
+       { SMCA_PSP,      HWID_MCATYPE(0xFF, 0x0)        },
+       { SMCA_PSP_V2,   HWID_MCATYPE(0xFF, 0x1)        },
 
        /* System Management Unit MCA type */
-       { SMCA_SMU,      HWID_MCATYPE(0x01, 0x0), 0x1 },
-       { SMCA_SMU_V2,   HWID_MCATYPE(0x01, 0x1), 0x7FF },
+       { SMCA_SMU,      HWID_MCATYPE(0x01, 0x0)        },
+       { SMCA_SMU_V2,   HWID_MCATYPE(0x01, 0x1)        },
 
        /* Microprocessor 5 Unit MCA type */
-       { SMCA_MP5,      HWID_MCATYPE(0x01, 0x2), 0x3FF },
+       { SMCA_MP5,      HWID_MCATYPE(0x01, 0x2)        },
 
        /* Northbridge IO Unit MCA type */
-       { SMCA_NBIO,     HWID_MCATYPE(0x18, 0x0), 0x1F },
+       { SMCA_NBIO,     HWID_MCATYPE(0x18, 0x0)        },
 
        /* PCI Express Unit MCA type */
-       { SMCA_PCIE,     HWID_MCATYPE(0x46, 0x0), 0x1F },
+       { SMCA_PCIE,     HWID_MCATYPE(0x46, 0x0)        },
 };
 
 struct smca_bank smca_banks[MAX_NR_BANKS];
index f43a78b..1c08cb9 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/debugfs.h>
 #include <linux/irq_work.h>
 #include <linux/export.h>
-#include <linux/jump_label.h>
 #include <linux/set_memory.h>
 #include <linux/sync_core.h>
 #include <linux/task_work.h>
@@ -373,42 +372,105 @@ static int msr_to_offset(u32 msr)
        return -1;
 }
 
+__visible bool ex_handler_rdmsr_fault(const struct exception_table_entry *fixup,
+                                     struct pt_regs *regs, int trapnr,
+                                     unsigned long error_code,
+                                     unsigned long fault_addr)
+{
+       pr_emerg("MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
+                (unsigned int)regs->cx, regs->ip, (void *)regs->ip);
+
+       show_stack_regs(regs);
+
+       panic("MCA architectural violation!\n");
+
+       while (true)
+               cpu_relax();
+
+       return true;
+}
+
 /* MSR access wrappers used for error injection */
-static u64 mce_rdmsrl(u32 msr)
+static noinstr u64 mce_rdmsrl(u32 msr)
 {
-       u64 v;
+       DECLARE_ARGS(val, low, high);
 
        if (__this_cpu_read(injectm.finished)) {
-               int offset = msr_to_offset(msr);
+               int offset;
+               u64 ret;
+
+               instrumentation_begin();
 
+               offset = msr_to_offset(msr);
                if (offset < 0)
-                       return 0;
-               return *(u64 *)((char *)this_cpu_ptr(&injectm) + offset);
-       }
+                       ret = 0;
+               else
+                       ret = *(u64 *)((char *)this_cpu_ptr(&injectm) + offset);
 
-       if (rdmsrl_safe(msr, &v)) {
-               WARN_ONCE(1, "mce: Unable to read MSR 0x%x!\n", msr);
-               /*
-                * Return zero in case the access faulted. This should
-                * not happen normally but can happen if the CPU does
-                * something weird, or if the code is buggy.
-                */
-               v = 0;
+               instrumentation_end();
+
+               return ret;
        }
 
-       return v;
+       /*
+        * RDMSR on MCA MSRs should not fault. If they do, this is very much an
+        * architectural violation and needs to be reported to hw vendor. Panic
+        * the box to not allow any further progress.
+        */
+       asm volatile("1: rdmsr\n"
+                    "2:\n"
+                    _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_rdmsr_fault)
+                    : EAX_EDX_RET(val, low, high) : "c" (msr));
+
+
+       return EAX_EDX_VAL(val, low, high);
+}
+
+__visible bool ex_handler_wrmsr_fault(const struct exception_table_entry *fixup,
+                                     struct pt_regs *regs, int trapnr,
+                                     unsigned long error_code,
+                                     unsigned long fault_addr)
+{
+       pr_emerg("MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
+                (unsigned int)regs->cx, (unsigned int)regs->dx, (unsigned int)regs->ax,
+                 regs->ip, (void *)regs->ip);
+
+       show_stack_regs(regs);
+
+       panic("MCA architectural violation!\n");
+
+       while (true)
+               cpu_relax();
+
+       return true;
 }
 
-static void mce_wrmsrl(u32 msr, u64 v)
+static noinstr void mce_wrmsrl(u32 msr, u64 v)
 {
+       u32 low, high;
+
        if (__this_cpu_read(injectm.finished)) {
-               int offset = msr_to_offset(msr);
+               int offset;
+
+               instrumentation_begin();
 
+               offset = msr_to_offset(msr);
                if (offset >= 0)
                        *(u64 *)((char *)this_cpu_ptr(&injectm) + offset) = v;
+
+               instrumentation_end();
+
                return;
        }
-       wrmsrl(msr, v);
+
+       low  = (u32)v;
+       high = (u32)(v >> 32);
+
+       /* See comment in mce_rdmsrl() */
+       asm volatile("1: wrmsr\n"
+                    "2:\n"
+                    _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_wrmsr_fault)
+                    : : "c" (msr), "a"(low), "d" (high) : "memory");
 }
 
 /*
@@ -745,7 +807,7 @@ log_it:
                        goto clear_it;
 
                mce_read_aux(&m, i);
-               m.severity = mce_severity(&m, mca_cfg.tolerant, NULL, false);
+               m.severity = mce_severity(&m, NULL, mca_cfg.tolerant, NULL, false);
                /*
                 * Don't get the IP here because it's unlikely to
                 * have anything to do with the actual error location.
@@ -794,7 +856,7 @@ static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
                        quirk_no_way_out(i, m, regs);
 
                m->bank = i;
-               if (mce_severity(m, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) {
+               if (mce_severity(m, regs, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) {
                        mce_read_aux(m, i);
                        *msg = tmp;
                        return 1;
@@ -872,7 +934,6 @@ static void mce_reign(void)
        struct mce *m = NULL;
        int global_worst = 0;
        char *msg = NULL;
-       char *nmsg = NULL;
 
        /*
         * This CPU is the Monarch and the other CPUs have run
@@ -880,12 +941,10 @@ static void mce_reign(void)
         * Grade the severity of the errors of all the CPUs.
         */
        for_each_possible_cpu(cpu) {
-               int severity = mce_severity(&per_cpu(mces_seen, cpu),
-                                           mca_cfg.tolerant,
-                                           &nmsg, true);
-               if (severity > global_worst) {
-                       msg = nmsg;
-                       global_worst = severity;
+               struct mce *mtmp = &per_cpu(mces_seen, cpu);
+
+               if (mtmp->severity > global_worst) {
+                       global_worst = mtmp->severity;
                        m = &per_cpu(mces_seen, cpu);
                }
        }
@@ -895,8 +954,11 @@ static void mce_reign(void)
         * This dumps all the mces in the log buffer and stops the
         * other CPUs.
         */
-       if (m && global_worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3)
+       if (m && global_worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3) {
+               /* call mce_severity() to get "msg" for panic */
+               mce_severity(m, NULL, mca_cfg.tolerant, &msg, true);
                mce_panic("Fatal machine check", m, msg);
+       }
 
        /*
         * For UC somewhere we let the CPU who detects it handle it.
@@ -1105,7 +1167,7 @@ static noinstr bool mce_check_crashing_cpu(void)
        return false;
 }
 
-static void __mc_scan_banks(struct mce *m, struct mce *final,
+static void __mc_scan_banks(struct mce *m, struct pt_regs *regs, struct mce *final,
                            unsigned long *toclear, unsigned long *valid_banks,
                            int no_way_out, int *worst)
 {
@@ -1140,7 +1202,7 @@ static void __mc_scan_banks(struct mce *m, struct mce *final,
                /* Set taint even when machine check was not enabled. */
                add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
 
-               severity = mce_severity(m, cfg->tolerant, NULL, true);
+               severity = mce_severity(m, regs, cfg->tolerant, NULL, true);
 
                /*
                 * When machine check was for corrected/deferred handler don't
@@ -1188,13 +1250,34 @@ static void kill_me_maybe(struct callback_head *cb)
        if (!p->mce_ripv)
                flags |= MF_MUST_KILL;
 
-       if (!memory_failure(p->mce_addr >> PAGE_SHIFT, flags)) {
+       if (!memory_failure(p->mce_addr >> PAGE_SHIFT, flags) &&
+           !(p->mce_kflags & MCE_IN_KERNEL_COPYIN)) {
                set_mce_nospec(p->mce_addr >> PAGE_SHIFT, p->mce_whole_page);
+               sync_core();
                return;
        }
 
-       pr_err("Memory error not recovered");
-       kill_me_now(cb);
+       if (p->mce_vaddr != (void __user *)-1l) {
+               force_sig_mceerr(BUS_MCEERR_AR, p->mce_vaddr, PAGE_SHIFT);
+       } else {
+               pr_err("Memory error not recovered");
+               kill_me_now(cb);
+       }
+}
+
+static void queue_task_work(struct mce *m, int kill_it)
+{
+       current->mce_addr = m->addr;
+       current->mce_kflags = m->kflags;
+       current->mce_ripv = !!(m->mcgstatus & MCG_STATUS_RIPV);
+       current->mce_whole_page = whole_page(m);
+
+       if (kill_it)
+               current->mce_kill_me.func = kill_me_now;
+       else
+               current->mce_kill_me.func = kill_me_maybe;
+
+       task_work_add(current, &current->mce_kill_me, true);
 }
 
 /*
@@ -1291,7 +1374,7 @@ noinstr void do_machine_check(struct pt_regs *regs)
                order = mce_start(&no_way_out);
        }
 
-       __mc_scan_banks(&m, final, toclear, valid_banks, no_way_out, &worst);
+       __mc_scan_banks(&m, regs, final, toclear, valid_banks, no_way_out, &worst);
 
        if (!no_way_out)
                mce_clear_state(toclear);
@@ -1313,7 +1396,7 @@ noinstr void do_machine_check(struct pt_regs *regs)
                 * make sure we have the right "msg".
                 */
                if (worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3) {
-                       mce_severity(&m, cfg->tolerant, &msg, true);
+                       mce_severity(&m, regs, cfg->tolerant, &msg, true);
                        mce_panic("Local fatal machine check!", &m, msg);
                }
        }
@@ -1330,25 +1413,16 @@ noinstr void do_machine_check(struct pt_regs *regs)
        if (worst > 0)
                irq_work_queue(&mce_irq_work);
 
-       mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);
-
-       sync_core();
-
        if (worst != MCE_AR_SEVERITY && !kill_it)
-               return;
+               goto out;
 
        /* Fault was in user mode and we need to take some action */
        if ((m.cs & 3) == 3) {
                /* If this triggers there is no way to recover. Die hard. */
                BUG_ON(!on_thread_stack() || !user_mode(regs));
 
-               current->mce_addr = m.addr;
-               current->mce_ripv = !!(m.mcgstatus & MCG_STATUS_RIPV);
-               current->mce_whole_page = whole_page(&m);
-               current->mce_kill_me.func = kill_me_maybe;
-               if (kill_it)
-                       current->mce_kill_me.func = kill_me_now;
-               task_work_add(current, &current->mce_kill_me, true);
+               queue_task_work(&m, kill_it);
+
        } else {
                /*
                 * Handle an MCE which has happened in kernel space but from
@@ -1363,7 +1437,12 @@ noinstr void do_machine_check(struct pt_regs *regs)
                        if (!fixup_exception(regs, X86_TRAP_MC, 0, 0))
                                mce_panic("Failed kernel mode recovery", &m, msg);
                }
+
+               if (m.kflags & MCE_IN_KERNEL_COPYIN)
+                       queue_task_work(&m, kill_it);
        }
+out:
+       mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);
 }
 EXPORT_SYMBOL_GPL(do_machine_check);
 
@@ -1904,6 +1983,8 @@ void (*machine_check_vector)(struct pt_regs *) = unexpected_machine_check;
 
 static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
 {
+       bool irq_state;
+
        WARN_ON_ONCE(user_mode(regs));
 
        /*
@@ -1914,7 +1995,7 @@ static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
            mce_check_crashing_cpu())
                return;
 
-       nmi_enter();
+       irq_state = idtentry_enter_nmi(regs);
        /*
         * The call targets are marked noinstr, but objtool can't figure
         * that out because it's an indirect call. Annotate it.
@@ -1925,7 +2006,7 @@ static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
        if (regs->flags & X86_EFLAGS_IF)
                trace_hardirqs_on_prepare();
        instrumentation_end();
-       nmi_exit();
+       idtentry_exit_nmi(regs, irq_state);
 }
 
 static __always_inline void exc_machine_check_user(struct pt_regs *regs)
@@ -2062,7 +2143,7 @@ void mce_disable_bank(int bank)
        and older.
  * mce=nobootlog Don't log MCEs from before booting.
  * mce=bios_cmci_threshold Don't program the CMCI threshold
- * mce=recovery force enable memcpy_mcsafe()
+ * mce=recovery force enable copy_mc_fragile()
  */
 static int __init mcheck_enable(char *str)
 {
@@ -2670,13 +2751,10 @@ static void __init mcheck_debugfs_init(void)
 static void __init mcheck_debugfs_init(void) { }
 #endif
 
-DEFINE_STATIC_KEY_FALSE(mcsafe_key);
-EXPORT_SYMBOL_GPL(mcsafe_key);
-
 static int __init mcheck_late_init(void)
 {
        if (mca_cfg.recovery)
-               static_branch_inc(&mcsafe_key);
+               enable_copy_mc_fragile();
 
        mcheck_debugfs_init();
 
index 03e5105..100fbee 100644 (file)
@@ -67,7 +67,9 @@ static int dev_mce_log(struct notifier_block *nb, unsigned long val,
 unlock:
        mutex_unlock(&mce_chrdev_read_mutex);
 
-       mce->kflags |= MCE_HANDLED_MCELOG;
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+               mce->kflags |= MCE_HANDLED_MCELOG;
+
        return NOTIFY_OK;
 }
 
index 7843ab3..3a44346 100644 (file)
@@ -199,7 +199,7 @@ static int raise_local(void)
                         * calling irq_enter, but the necessary
                         * machinery isn't exported currently.
                         */
-                       /*FALL THROUGH*/
+                       fallthrough;
                case MCJ_CTX_PROCESS:
                        raise_exception(m, NULL);
                        break;
index d8f9230..abe9fe0 100644 (file)
@@ -193,7 +193,7 @@ unsigned long cmci_intel_adjust_timer(unsigned long interval)
                if (!atomic_sub_return(1, &cmci_storm_on_cpus))
                        pr_notice("CMCI storm subsided: switching to interrupt mode\n");
 
-               /* FALLTHROUGH */
+               fallthrough;
 
        case CMCI_STORM_SUBSIDED:
                /*
index 6473070..88dcc79 100644 (file)
@@ -38,7 +38,8 @@ int mce_gen_pool_add(struct mce *mce);
 int mce_gen_pool_init(void);
 struct llist_node *mce_gen_pool_prepare_records(void);
 
-extern int (*mce_severity)(struct mce *a, int tolerant, char **msg, bool is_excp);
+extern int (*mce_severity)(struct mce *a, struct pt_regs *regs,
+                          int tolerant, char **msg, bool is_excp);
 struct dentry *mce_get_debugfs_dir(void);
 
 extern mce_banks_t mce_banks_ce_disabled;
@@ -185,4 +186,14 @@ extern bool amd_filter_mce(struct mce *m);
 static inline bool amd_filter_mce(struct mce *m)                       { return false; };
 #endif
 
+__visible bool ex_handler_rdmsr_fault(const struct exception_table_entry *fixup,
+                                     struct pt_regs *regs, int trapnr,
+                                     unsigned long error_code,
+                                     unsigned long fault_addr);
+
+__visible bool ex_handler_wrmsr_fault(const struct exception_table_entry *fixup,
+                                     struct pt_regs *regs, int trapnr,
+                                     unsigned long error_code,
+                                     unsigned long fault_addr);
+
 #endif /* __X86_MCE_INTERNAL_H__ */
index e1da619..83df991 100644 (file)
@@ -9,9 +9,14 @@
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/debugfs.h>
-#include <asm/mce.h>
 #include <linux/uaccess.h>
 
+#include <asm/mce.h>
+#include <asm/intel-family.h>
+#include <asm/traps.h>
+#include <asm/insn.h>
+#include <asm/insn-eval.h>
+
 #include "internal.h"
 
 /*
@@ -40,9 +45,14 @@ static struct severity {
        unsigned char context;
        unsigned char excp;
        unsigned char covered;
+       unsigned char cpu_model;
+       unsigned char cpu_minstepping;
+       unsigned char bank_lo, bank_hi;
        char *msg;
 } severities[] = {
 #define MCESEV(s, m, c...) { .sev = MCE_ ## s ## _SEVERITY, .msg = m, ## c }
+#define BANK_RANGE(l, h) .bank_lo = l, .bank_hi = h
+#define MODEL_STEPPING(m, s) .cpu_model = m, .cpu_minstepping = s
 #define  KERNEL                .context = IN_KERNEL
 #define  USER          .context = IN_USER
 #define  KERNEL_RECOV  .context = IN_KERNEL_RECOV
@@ -90,14 +100,9 @@ static struct severity {
                EXCP, KERNEL_RECOV, MCGMASK(MCG_STATUS_RIPV, 0)
                ),
        MCESEV(
-               DEFERRED, "Deferred error",
-               NOSER, MASK(MCI_STATUS_UC|MCI_STATUS_DEFERRED|MCI_STATUS_POISON, MCI_STATUS_DEFERRED)
-               ),
-       MCESEV(
                KEEP, "Corrected error",
                NOSER, BITCLR(MCI_STATUS_UC)
                ),
-
        /*
         * known AO MCACODs reported via MCE or CMC:
         *
@@ -113,6 +118,18 @@ static struct severity {
                AO, "Action optional: last level cache writeback error",
                SER, MASK(MCI_UC_AR|MCACOD, MCI_STATUS_UC|MCACOD_L3WB)
                ),
+       /*
+        * Quirk for Skylake/Cascade Lake. Patrol scrubber may be configured
+        * to report uncorrected errors using CMCI with a special signature.
+        * UC=0, MSCOD=0x0010, MCACOD=binary(000X 0000 1100 XXXX) reported
+        * in one of the memory controller banks.
+        * Set severity to "AO" for same action as normal patrol scrub error.
+        */
+       MCESEV(
+               AO, "Uncorrected Patrol Scrub Error",
+               SER, MASK(MCI_STATUS_UC|MCI_ADDR|0xffffeff0, MCI_ADDR|0x001000c0),
+               MODEL_STEPPING(INTEL_FAM6_SKYLAKE_X, 4), BANK_RANGE(13, 18)
+       ),
 
        /* ignore OVER for UCNA */
        MCESEV(
@@ -198,6 +215,47 @@ static struct severity {
 #define mc_recoverable(mcg) (((mcg) & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) == \
                                (MCG_STATUS_RIPV|MCG_STATUS_EIPV))
 
+static bool is_copy_from_user(struct pt_regs *regs)
+{
+       u8 insn_buf[MAX_INSN_SIZE];
+       struct insn insn;
+       unsigned long addr;
+
+       if (copy_from_kernel_nofault(insn_buf, (void *)regs->ip, MAX_INSN_SIZE))
+               return false;
+
+       kernel_insn_init(&insn, insn_buf, MAX_INSN_SIZE);
+       insn_get_opcode(&insn);
+       if (!insn.opcode.got)
+               return false;
+
+       switch (insn.opcode.value) {
+       /* MOV mem,reg */
+       case 0x8A: case 0x8B:
+       /* MOVZ mem,reg */
+       case 0xB60F: case 0xB70F:
+               insn_get_modrm(&insn);
+               insn_get_sib(&insn);
+               if (!insn.modrm.got || !insn.sib.got)
+                       return false;
+               addr = (unsigned long)insn_get_addr_ref(&insn, regs);
+               break;
+       /* REP MOVS */
+       case 0xA4: case 0xA5:
+               addr = regs->si;
+               break;
+       default:
+               return false;
+       }
+
+       if (fault_in_kernel_space(addr))
+               return false;
+
+       current->mce_vaddr = (void __user *)addr;
+
+       return true;
+}
+
 /*
  * If mcgstatus indicated that ip/cs on the stack were
  * no good, then "m->cs" will be zero and we will have
@@ -209,15 +267,25 @@ static struct severity {
  * distinguish an exception taken in user from from one
  * taken in the kernel.
  */
-static int error_context(struct mce *m)
+static int error_context(struct mce *m, struct pt_regs *regs)
 {
+       enum handler_type t;
+
        if ((m->cs & 3) == 3)
                return IN_USER;
+       if (!mc_recoverable(m->mcgstatus))
+               return IN_KERNEL;
 
-       if (mc_recoverable(m->mcgstatus) && ex_has_fault_handler(m->ip)) {
+       t = ex_get_fault_handler_type(m->ip);
+       if (t == EX_HANDLER_FAULT) {
                m->kflags |= MCE_IN_KERNEL_RECOV;
                return IN_KERNEL_RECOV;
        }
+       if (t == EX_HANDLER_UACCESS && regs && is_copy_from_user(regs)) {
+               m->kflags |= MCE_IN_KERNEL_RECOV;
+               m->kflags |= MCE_IN_KERNEL_COPYIN;
+               return IN_KERNEL_RECOV;
+       }
 
        return IN_KERNEL;
 }
@@ -253,9 +321,10 @@ static int mce_severity_amd_smca(struct mce *m, enum context err_ctx)
  * See AMD Error Scope Hierarchy table in a newer BKDG. For example
  * 49125_15h_Models_30h-3Fh_BKDG.pdf, section "RAS Features"
  */
-static int mce_severity_amd(struct mce *m, int tolerant, char **msg, bool is_excp)
+static int mce_severity_amd(struct mce *m, struct pt_regs *regs, int tolerant,
+                           char **msg, bool is_excp)
 {
-       enum context ctx = error_context(m);
+       enum context ctx = error_context(m, regs);
 
        /* Processor Context Corrupt, no need to fumble too much, die! */
        if (m->status & MCI_STATUS_PCC)
@@ -305,10 +374,11 @@ static int mce_severity_amd(struct mce *m, int tolerant, char **msg, bool is_exc
        return MCE_KEEP_SEVERITY;
 }
 
-static int mce_severity_intel(struct mce *m, int tolerant, char **msg, bool is_excp)
+static int mce_severity_intel(struct mce *m, struct pt_regs *regs,
+                             int tolerant, char **msg, bool is_excp)
 {
        enum exception excp = (is_excp ? EXCP_CONTEXT : NO_EXCP);
-       enum context ctx = error_context(m);
+       enum context ctx = error_context(m, regs);
        struct severity *s;
 
        for (s = severities;; s++) {
@@ -324,6 +394,12 @@ static int mce_severity_intel(struct mce *m, int tolerant, char **msg, bool is_e
                        continue;
                if (s->excp && excp != s->excp)
                        continue;
+               if (s->cpu_model && boot_cpu_data.x86_model != s->cpu_model)
+                       continue;
+               if (s->cpu_minstepping && boot_cpu_data.x86_stepping < s->cpu_minstepping)
+                       continue;
+               if (s->bank_lo && (m->bank < s->bank_lo || m->bank > s->bank_hi))
+                       continue;
                if (msg)
                        *msg = s->msg;
                s->covered = 1;
@@ -336,7 +412,7 @@ static int mce_severity_intel(struct mce *m, int tolerant, char **msg, bool is_e
 }
 
 /* Default to mce_severity_intel */
-int (*mce_severity)(struct mce *m, int tolerant, char **msg, bool is_excp) =
+int (*mce_severity)(struct mce *m, struct pt_regs *regs, int tolerant, char **msg, bool is_excp) =
                    mce_severity_intel;
 
 void __init mcheck_vendor_init_severity(void)
index 3112544..9834a43 100644 (file)
@@ -248,7 +248,7 @@ static void __init ms_hyperv_init_platform(void)
                        hv_host_info_edx >> 24, hv_host_info_edx & 0xFFFFFF);
        }
 
-       if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
+       if (ms_hyperv.features & HV_ACCESS_FREQUENCY_MSRS &&
            ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
                x86_platform.calibrate_tsc = hv_get_tsc_khz;
                x86_platform.calibrate_cpu = hv_get_tsc_khz;
@@ -270,7 +270,7 @@ static void __init ms_hyperv_init_platform(void)
                crash_kexec_post_notifiers = true;
 
 #ifdef CONFIG_X86_LOCAL_APIC
-       if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
+       if (ms_hyperv.features & HV_ACCESS_FREQUENCY_MSRS &&
            ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
                /*
                 * Get the APIC frequency.
@@ -296,7 +296,7 @@ static void __init ms_hyperv_init_platform(void)
        machine_ops.shutdown = hv_machine_shutdown;
        machine_ops.crash_shutdown = hv_machine_crash_shutdown;
 #endif
-       if (ms_hyperv.features & HV_X64_ACCESS_TSC_INVARIANT) {
+       if (ms_hyperv.features & HV_ACCESS_TSC_INVARIANT) {
                wrmsrl(HV_X64_MSR_TSC_INVARIANT_CONTROL, 0x1);
                setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
        } else {
@@ -330,7 +330,7 @@ static void __init ms_hyperv_init_platform(void)
        alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_hyperv_callback);
 
        /* Setup the IDT for reenlightenment notifications */
-       if (ms_hyperv.features & HV_X64_ACCESS_REENLIGHTENMENT) {
+       if (ms_hyperv.features & HV_ACCESS_REENLIGHTENMENT) {
                alloc_intr_gate(HYPERV_REENLIGHTENMENT_VECTOR,
                                asm_sysvec_hyperv_reenlightenment);
        }
index 7218280..ca67091 100644 (file)
@@ -98,7 +98,7 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
        case 7:
                if (size < 0x40)
                        break;
-               /* Else, fall through */
+               fallthrough;
        case 6:
        case 5:
        case 4:
index 6a9df71..e5f4ee8 100644 (file)
@@ -168,6 +168,7 @@ struct rdt_resource rdt_resources_all[] = {
                .name                   = "MB",
                .domains                = domain_init(RDT_RESOURCE_MBA),
                .cache_level            = 3,
+               .parse_ctrlval          = parse_bw,
                .format_str             = "%d=%*u",
                .fflags                 = RFTYPE_RES_MB,
        },
@@ -254,22 +255,30 @@ static bool __get_mem_config_intel(struct rdt_resource *r)
 {
        union cpuid_0x10_3_eax eax;
        union cpuid_0x10_x_edx edx;
-       u32 ebx, ecx;
+       u32 ebx, ecx, max_delay;
 
        cpuid_count(0x00000010, 3, &eax.full, &ebx, &ecx, &edx.full);
        r->num_closid = edx.split.cos_max + 1;
-       r->membw.max_delay = eax.split.max_delay + 1;
+       max_delay = eax.split.max_delay + 1;
        r->default_ctrl = MAX_MBA_BW;
+       r->membw.arch_needs_linear = true;
        if (ecx & MBA_IS_LINEAR) {
                r->membw.delay_linear = true;
-               r->membw.min_bw = MAX_MBA_BW - r->membw.max_delay;
-               r->membw.bw_gran = MAX_MBA_BW - r->membw.max_delay;
+               r->membw.min_bw = MAX_MBA_BW - max_delay;
+               r->membw.bw_gran = MAX_MBA_BW - max_delay;
        } else {
                if (!rdt_get_mb_table(r))
                        return false;
+               r->membw.arch_needs_linear = false;
        }
        r->data_width = 3;
 
+       if (boot_cpu_has(X86_FEATURE_PER_THREAD_MBA))
+               r->membw.throttle_mode = THREAD_THROTTLE_PER_THREAD;
+       else
+               r->membw.throttle_mode = THREAD_THROTTLE_MAX;
+       thread_throttle_mode_init();
+
        r->alloc_capable = true;
        r->alloc_enabled = true;
 
@@ -288,7 +297,13 @@ static bool __rdt_get_mem_config_amd(struct rdt_resource *r)
 
        /* AMD does not use delay */
        r->membw.delay_linear = false;
+       r->membw.arch_needs_linear = false;
 
+       /*
+        * AMD does not use memory delay throttle model to control
+        * the allocation like Intel does.
+        */
+       r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
        r->membw.min_bw = 0;
        r->membw.bw_gran = 1;
        /* Max value is 2048, Data width should be 4 in decimal */
@@ -346,19 +361,6 @@ static void rdt_get_cdp_l2_config(void)
        rdt_get_cdp_config(RDT_RESOURCE_L2, RDT_RESOURCE_L2CODE);
 }
 
-static int get_cache_id(int cpu, int level)
-{
-       struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu);
-       int i;
-
-       for (i = 0; i < ci->num_leaves; i++) {
-               if (ci->info_list[i].level == level)
-                       return ci->info_list[i].id;
-       }
-
-       return -1;
-}
-
 static void
 mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r)
 {
@@ -556,13 +558,13 @@ static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d)
  */
 static void domain_add_cpu(int cpu, struct rdt_resource *r)
 {
-       int id = get_cache_id(cpu, r->cache_level);
+       int id = get_cpu_cacheinfo_id(cpu, r->cache_level);
        struct list_head *add_pos = NULL;
        struct rdt_domain *d;
 
        d = rdt_find_domain(r, id, &add_pos);
        if (IS_ERR(d)) {
-               pr_warn("Could't find cache id for cpu %d\n", cpu);
+               pr_warn("Couldn't find cache id for CPU %d\n", cpu);
                return;
        }
 
@@ -602,12 +604,12 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
 
 static void domain_remove_cpu(int cpu, struct rdt_resource *r)
 {
-       int id = get_cache_id(cpu, r->cache_level);
+       int id = get_cpu_cacheinfo_id(cpu, r->cache_level);
        struct rdt_domain *d;
 
        d = rdt_find_domain(r, id, NULL);
        if (IS_ERR_OR_NULL(d)) {
-               pr_warn("Could't find cache id for cpu %d\n", cpu);
+               pr_warn("Couldn't find cache id for CPU %d\n", cpu);
                return;
        }
 
@@ -918,12 +920,12 @@ static __init void rdt_init_res_defs_intel(void)
                    r->rid == RDT_RESOURCE_L3CODE ||
                    r->rid == RDT_RESOURCE_L2 ||
                    r->rid == RDT_RESOURCE_L2DATA ||
-                   r->rid == RDT_RESOURCE_L2CODE)
-                       r->cbm_validate = cbm_validate_intel;
-               else if (r->rid == RDT_RESOURCE_MBA) {
+                   r->rid == RDT_RESOURCE_L2CODE) {
+                       r->cache.arch_has_sparse_bitmaps = false;
+                       r->cache.arch_has_empty_bitmaps = false;
+               } else if (r->rid == RDT_RESOURCE_MBA) {
                        r->msr_base = MSR_IA32_MBA_THRTL_BASE;
                        r->msr_update = mba_wrmsr_intel;
-                       r->parse_ctrlval = parse_bw_intel;
                }
        }
 }
@@ -938,12 +940,12 @@ static __init void rdt_init_res_defs_amd(void)
                    r->rid == RDT_RESOURCE_L3CODE ||
                    r->rid == RDT_RESOURCE_L2 ||
                    r->rid == RDT_RESOURCE_L2DATA ||
-                   r->rid == RDT_RESOURCE_L2CODE)
-                       r->cbm_validate = cbm_validate_amd;
-               else if (r->rid == RDT_RESOURCE_MBA) {
+                   r->rid == RDT_RESOURCE_L2CODE) {
+                       r->cache.arch_has_sparse_bitmaps = true;
+                       r->cache.arch_has_empty_bitmaps = true;
+               } else if (r->rid == RDT_RESOURCE_MBA) {
                        r->msr_base = MSR_IA32_MBA_BW_BASE;
                        r->msr_update = mba_wrmsr_amd;
-                       r->parse_ctrlval = parse_bw_amd;
                }
        }
 }
index 934c8fb..c877642 100644 (file)
 
 /*
  * Check whether MBA bandwidth percentage value is correct. The value is
- * checked against the minimum and maximum bandwidth values specified by
- * the hardware. The allocated bandwidth percentage is rounded to the next
- * control step available on the hardware.
- */
-static bool bw_validate_amd(char *buf, unsigned long *data,
-                           struct rdt_resource *r)
-{
-       unsigned long bw;
-       int ret;
-
-       ret = kstrtoul(buf, 10, &bw);
-       if (ret) {
-               rdt_last_cmd_printf("Non-decimal digit in MB value %s\n", buf);
-               return false;
-       }
-
-       if (bw < r->membw.min_bw || bw > r->default_ctrl) {
-               rdt_last_cmd_printf("MB value %ld out of range [%d,%d]\n", bw,
-                                   r->membw.min_bw, r->default_ctrl);
-               return false;
-       }
-
-       *data = roundup(bw, (unsigned long)r->membw.bw_gran);
-       return true;
-}
-
-int parse_bw_amd(struct rdt_parse_data *data, struct rdt_resource *r,
-                struct rdt_domain *d)
-{
-       unsigned long bw_val;
-
-       if (d->have_new_ctrl) {
-               rdt_last_cmd_printf("Duplicate domain %d\n", d->id);
-               return -EINVAL;
-       }
-
-       if (!bw_validate_amd(data->buf, &bw_val, r))
-               return -EINVAL;
-
-       d->new_ctrl = bw_val;
-       d->have_new_ctrl = true;
-
-       return 0;
-}
-
-/*
- * Check whether MBA bandwidth percentage value is correct. The value is
  * checked against the minimum and max bandwidth values specified by the
  * hardware. The allocated bandwidth percentage is rounded to the next
  * control step available on the hardware.
@@ -82,7 +35,7 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r)
        /*
         * Only linear delay values is supported for current Intel SKUs.
         */
-       if (!r->membw.delay_linear) {
+       if (!r->membw.delay_linear && r->membw.arch_needs_linear) {
                rdt_last_cmd_puts("No support for non-linear MB domains\n");
                return false;
        }
@@ -104,8 +57,8 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r)
        return true;
 }
 
-int parse_bw_intel(struct rdt_parse_data *data, struct rdt_resource *r,
-                  struct rdt_domain *d)
+int parse_bw(struct rdt_parse_data *data, struct rdt_resource *r,
+            struct rdt_domain *d)
 {
        unsigned long bw_val;
 
@@ -123,12 +76,14 @@ int parse_bw_intel(struct rdt_parse_data *data, struct rdt_resource *r,
 }
 
 /*
- * Check whether a cache bit mask is valid. The SDM says:
+ * Check whether a cache bit mask is valid.
+ * For Intel the SDM says:
  *     Please note that all (and only) contiguous '1' combinations
  *     are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.).
  * Additionally Haswell requires at least two bits set.
+ * AMD allows non-contiguous bitmasks.
  */
-bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r)
+static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r)
 {
        unsigned long first_bit, zero_bit, val;
        unsigned int cbm_len = r->cache.cbm_len;
@@ -140,7 +95,8 @@ bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r)
                return false;
        }
 
-       if (val == 0 || val > r->default_ctrl) {
+       if ((!r->cache.arch_has_empty_bitmaps && val == 0) ||
+           val > r->default_ctrl) {
                rdt_last_cmd_puts("Mask out of range\n");
                return false;
        }
@@ -148,7 +104,9 @@ bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r)
        first_bit = find_first_bit(&val, cbm_len);
        zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
 
-       if (find_next_bit(&val, cbm_len, zero_bit) < cbm_len) {
+       /* Are non-contiguous bitmaps allowed? */
+       if (!r->cache.arch_has_sparse_bitmaps &&
+           (find_next_bit(&val, cbm_len, zero_bit) < cbm_len)) {
                rdt_last_cmd_printf("The mask %lx has non-consecutive 1-bits\n", val);
                return false;
        }
@@ -164,30 +122,6 @@ bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r)
 }
 
 /*
- * Check whether a cache bit mask is valid. AMD allows non-contiguous
- * bitmasks
- */
-bool cbm_validate_amd(char *buf, u32 *data, struct rdt_resource *r)
-{
-       unsigned long val;
-       int ret;
-
-       ret = kstrtoul(buf, 16, &val);
-       if (ret) {
-               rdt_last_cmd_printf("Non-hex character in the mask %s\n", buf);
-               return false;
-       }
-
-       if (val > r->default_ctrl) {
-               rdt_last_cmd_puts("Mask out of range\n");
-               return false;
-       }
-
-       *data = val;
-       return true;
-}
-
-/*
  * Read one cache bit mask (hex). Check that it is valid for the current
  * resource type.
  */
@@ -212,7 +146,7 @@ int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r,
                return -EINVAL;
        }
 
-       if (!r->cbm_validate(data->buf, &cbm_val, r))
+       if (!cbm_validate(data->buf, &cbm_val, r))
                return -EINVAL;
 
        if ((rdtgrp->mode == RDT_MODE_EXCLUSIVE ||
index 5ffa322..80fa997 100644 (file)
@@ -283,7 +283,6 @@ struct rftype {
  * struct mbm_state - status for each MBM counter in each domain
  * @chunks:    Total data moved (multiply by rdt_group.mon_scale to get bytes)
  * @prev_msr   Value of IA32_QM_CTR for this RMID last time we read it
- * @chunks_bw  Total local data moved. Used for bandwidth calculation
  * @prev_bw_msr:Value of previous IA32_QM_CTR for bandwidth counting
  * @prev_bw    The most recent bandwidth in MBps
  * @delta_bw   Difference between the current and previous bandwidth
@@ -292,7 +291,6 @@ struct rftype {
 struct mbm_state {
        u64     chunks;
        u64     prev_msr;
-       u64     chunks_bw;
        u64     prev_bw_msr;
        u32     prev_bw;
        u32     delta_bw;
@@ -360,6 +358,8 @@ struct msr_param {
  *                     in a cache bit mask
  * @shareable_bits:    Bitmask of shareable resource with other
  *                     executing entities
+ * @arch_has_sparse_bitmaps:   True if a bitmap like f00f is valid.
+ * @arch_has_empty_bitmaps:    True if the '0' bitmap is valid.
  */
 struct rdt_cache {
        unsigned int    cbm_len;
@@ -367,25 +367,43 @@ struct rdt_cache {
        unsigned int    cbm_idx_mult;
        unsigned int    cbm_idx_offset;
        unsigned int    shareable_bits;
+       bool            arch_has_sparse_bitmaps;
+       bool            arch_has_empty_bitmaps;
+};
+
+/**
+ * enum membw_throttle_mode - System's memory bandwidth throttling mode
+ * @THREAD_THROTTLE_UNDEFINED: Not relevant to the system
+ * @THREAD_THROTTLE_MAX:       Memory bandwidth is throttled at the core
+ *                             always using smallest bandwidth percentage
+ *                             assigned to threads, aka "max throttling"
+ * @THREAD_THROTTLE_PER_THREAD:        Memory bandwidth is throttled at the thread
+ */
+enum membw_throttle_mode {
+       THREAD_THROTTLE_UNDEFINED = 0,
+       THREAD_THROTTLE_MAX,
+       THREAD_THROTTLE_PER_THREAD,
 };
 
 /**
  * struct rdt_membw - Memory bandwidth allocation related data
- * @max_delay:         Max throttle delay. Delay is the hardware
- *                     representation for memory bandwidth.
  * @min_bw:            Minimum memory bandwidth percentage user can request
  * @bw_gran:           Granularity at which the memory bandwidth is allocated
  * @delay_linear:      True if memory B/W delay is in linear scale
+ * @arch_needs_linear: True if we can't configure non-linear resources
+ * @throttle_mode:     Bandwidth throttling mode when threads request
+ *                     different memory bandwidths
  * @mba_sc:            True if MBA software controller(mba_sc) is enabled
  * @mb_map:            Mapping of memory B/W percentage to memory B/W delay
  */
 struct rdt_membw {
-       u32             max_delay;
-       u32             min_bw;
-       u32             bw_gran;
-       u32             delay_linear;
-       bool            mba_sc;
-       u32             *mb_map;
+       u32                             min_bw;
+       u32                             bw_gran;
+       u32                             delay_linear;
+       bool                            arch_needs_linear;
+       enum membw_throttle_mode        throttle_mode;
+       bool                            mba_sc;
+       u32                             *mb_map;
 };
 
 static inline bool is_llc_occupancy_enabled(void)
@@ -437,7 +455,6 @@ struct rdt_parse_data {
  * @cache:             Cache allocation related data
  * @format_str:                Per resource format string to show domain value
  * @parse_ctrlval:     Per resource function pointer to parse control values
- * @cbm_validate       Cache bitmask validate function
  * @evt_list:          List of monitoring events
  * @num_rmid:          Number of RMIDs available
  * @mon_scale:         cqm counter * mon_scale = occupancy in bytes
@@ -464,7 +481,6 @@ struct rdt_resource {
        int (*parse_ctrlval)(struct rdt_parse_data *data,
                             struct rdt_resource *r,
                             struct rdt_domain *d);
-       bool (*cbm_validate)(char *buf, u32 *data, struct rdt_resource *r);
        struct list_head        evt_list;
        int                     num_rmid;
        unsigned int            mon_scale;
@@ -474,10 +490,8 @@ struct rdt_resource {
 
 int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r,
              struct rdt_domain *d);
-int parse_bw_intel(struct rdt_parse_data *data, struct rdt_resource *r,
-                  struct rdt_domain *d);
-int parse_bw_amd(struct rdt_parse_data *data, struct rdt_resource *r,
-                struct rdt_domain *d);
+int parse_bw(struct rdt_parse_data *data, struct rdt_resource *r,
+            struct rdt_domain *d);
 
 extern struct mutex rdtgroup_mutex;
 
@@ -609,8 +623,7 @@ void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms);
 void cqm_handle_limbo(struct work_struct *work);
 bool has_busy_rmid(struct rdt_resource *r, struct rdt_domain *d);
 void __check_limbo(struct rdt_domain *d, bool force_free);
-bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r);
-bool cbm_validate_amd(char *buf, u32 *data, struct rdt_resource *r);
 void rdt_domain_reconfigure_cdp(struct rdt_resource *r);
+void __init thread_throttle_mode_init(void);
 
 #endif /* _ASM_X86_RESCTRL_INTERNAL_H */
index 837d7d0..54dffe5 100644 (file)
@@ -279,8 +279,7 @@ static void mbm_bw_count(u32 rmid, struct rmid_read *rr)
                return;
 
        chunks = mbm_overflow_count(m->prev_bw_msr, tval, rr->r->mbm_width);
-       m->chunks_bw += chunks;
-       m->chunks = m->chunks_bw;
+       m->chunks += chunks;
        cur_bw = (chunks * r->mon_scale) >> 20;
 
        if (m->delta_comp)
@@ -478,19 +477,13 @@ void cqm_handle_limbo(struct work_struct *work)
        mutex_lock(&rdtgroup_mutex);
 
        r = &rdt_resources_all[RDT_RESOURCE_L3];
-       d = get_domain_from_cpu(cpu, r);
-
-       if (!d) {
-               pr_warn_once("Failure to get domain for limbo worker\n");
-               goto out_unlock;
-       }
+       d = container_of(work, struct rdt_domain, cqm_limbo.work);
 
        __check_limbo(d, false);
 
        if (has_busy_rmid(r, d))
                schedule_delayed_work_on(cpu, &d->cqm_limbo, delay);
 
-out_unlock:
        mutex_unlock(&rdtgroup_mutex);
 }
 
@@ -520,10 +513,7 @@ void mbm_handle_overflow(struct work_struct *work)
                goto out_unlock;
 
        r = &rdt_resources_all[RDT_RESOURCE_L3];
-
-       d = get_domain_from_cpu(cpu, r);
-       if (!d)
-               goto out_unlock;
+       d = container_of(work, struct rdt_domain, mbm_over.work);
 
        list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
                mbm_update(r, d, prgrp->mon.rmid);
index 3f844f1..b494187 100644 (file)
@@ -592,6 +592,18 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
        return ret;
 }
 
+static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
+{
+       return (rdt_alloc_capable &&
+              (r->type == RDTCTRL_GROUP) && (t->closid == r->closid));
+}
+
+static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
+{
+       return (rdt_mon_capable &&
+              (r->type == RDTMON_GROUP) && (t->rmid == r->mon.rmid));
+}
+
 /**
  * rdtgroup_tasks_assigned - Test if tasks have been assigned to resource group
  * @r: Resource group
@@ -607,8 +619,7 @@ int rdtgroup_tasks_assigned(struct rdtgroup *r)
 
        rcu_read_lock();
        for_each_process_thread(p, t) {
-               if ((r->type == RDTCTRL_GROUP && t->closid == r->closid) ||
-                   (r->type == RDTMON_GROUP && t->rmid == r->mon.rmid)) {
+               if (is_closid_match(t, r) || is_rmid_match(t, r)) {
                        ret = 1;
                        break;
                }
@@ -706,8 +717,7 @@ static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
 
        rcu_read_lock();
        for_each_process_thread(p, t) {
-               if ((r->type == RDTCTRL_GROUP && t->closid == r->closid) ||
-                   (r->type == RDTMON_GROUP && t->rmid == r->mon.rmid))
+               if (is_closid_match(t, r) || is_rmid_match(t, r))
                        seq_printf(s, "%d\n", t->pid);
        }
        rcu_read_unlock();
@@ -1017,6 +1027,19 @@ static int max_threshold_occ_show(struct kernfs_open_file *of,
        return 0;
 }
 
+static int rdt_thread_throttle_mode_show(struct kernfs_open_file *of,
+                                        struct seq_file *seq, void *v)
+{
+       struct rdt_resource *r = of->kn->parent->priv;
+
+       if (r->membw.throttle_mode == THREAD_THROTTLE_PER_THREAD)
+               seq_puts(seq, "per-thread\n");
+       else
+               seq_puts(seq, "max\n");
+
+       return 0;
+}
+
 static ssize_t max_threshold_occ_write(struct kernfs_open_file *of,
                                       char *buf, size_t nbytes, loff_t off)
 {
@@ -1513,6 +1536,17 @@ static struct rftype res_common_files[] = {
                .seq_show       = rdt_delay_linear_show,
                .fflags         = RF_CTRL_INFO | RFTYPE_RES_MB,
        },
+       /*
+        * Platform specific which (if any) capabilities are provided by
+        * thread_throttle_mode. Defer "fflags" initialization to platform
+        * discovery.
+        */
+       {
+               .name           = "thread_throttle_mode",
+               .mode           = 0444,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .seq_show       = rdt_thread_throttle_mode_show,
+       },
        {
                .name           = "max_threshold_occupancy",
                .mode           = 0644,
@@ -1583,7 +1617,7 @@ static int rdtgroup_add_files(struct kernfs_node *kn, unsigned long fflags)
        lockdep_assert_held(&rdtgroup_mutex);
 
        for (rft = rfts; rft < rfts + len; rft++) {
-               if ((fflags & rft->fflags) == rft->fflags) {
+               if (rft->fflags && ((fflags & rft->fflags) == rft->fflags)) {
                        ret = rdtgroup_add_file(kn, rft);
                        if (ret)
                                goto error;
@@ -1600,6 +1634,33 @@ error:
        return ret;
 }
 
+static struct rftype *rdtgroup_get_rftype_by_name(const char *name)
+{
+       struct rftype *rfts, *rft;
+       int len;
+
+       rfts = res_common_files;
+       len = ARRAY_SIZE(res_common_files);
+
+       for (rft = rfts; rft < rfts + len; rft++) {
+               if (!strcmp(rft->name, name))
+                       return rft;
+       }
+
+       return NULL;
+}
+
+void __init thread_throttle_mode_init(void)
+{
+       struct rftype *rft;
+
+       rft = rdtgroup_get_rftype_by_name("thread_throttle_mode");
+       if (!rft)
+               return;
+
+       rft->fflags = RF_CTRL_INFO | RFTYPE_RES_MB;
+}
+
 /**
  * rdtgroup_kn_mode_restrict - Restrict user access to named resctrl file
  * @r: The resource group with which the file is associated.
@@ -2245,18 +2306,6 @@ static int reset_all_ctrls(struct rdt_resource *r)
        return 0;
 }
 
-static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
-{
-       return (rdt_alloc_capable &&
-               (r->type == RDTCTRL_GROUP) && (t->closid == r->closid));
-}
-
-static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
-{
-       return (rdt_mon_capable &&
-               (r->type == RDTMON_GROUP) && (t->rmid == r->mon.rmid));
-}
-
 /*
  * Move tasks from one to the other group. If @from is NULL, then all tasks
  * in the systems are moved unconditionally (used for teardown).
@@ -3196,7 +3245,7 @@ int __init rdtgroup_init(void)
         * It may also be ok since that would enable debugging of RDT before
         * resctrl is mounted.
         * The reason why the debugfs directory is created here and not in
-        * rdt_mount() is because rdt_mount() takes rdtgroup_mutex and
+        * rdt_get_tree() is because rdt_get_tree() takes rdtgroup_mutex and
         * during the debugfs directory creation also &sb->s_type->i_mutex_key
         * (the lockdep class of inode->i_rwsem). Other filesystem
         * interactions (eg. SyS_getdents) have the lock ordering:
index 62b137c..2eb0a8c 100644 (file)
@@ -35,12 +35,14 @@ static const struct cpuid_bit cpuid_bits[] = {
        { X86_FEATURE_CDP_L3,           CPUID_ECX,  2, 0x00000010, 1 },
        { X86_FEATURE_CDP_L2,           CPUID_ECX,  2, 0x00000010, 2 },
        { X86_FEATURE_MBA,              CPUID_EBX,  3, 0x00000010, 0 },
+       { X86_FEATURE_PER_THREAD_MBA,   CPUID_ECX,  0, 0x00000010, 3 },
        { X86_FEATURE_HW_PSTATE,        CPUID_EDX,  7, 0x80000007, 0 },
        { X86_FEATURE_CPB,              CPUID_EDX,  9, 0x80000007, 0 },
        { X86_FEATURE_PROC_FEEDBACK,    CPUID_EDX, 11, 0x80000007, 0 },
        { X86_FEATURE_MBA,              CPUID_EBX,  6, 0x80000008, 0 },
        { X86_FEATURE_SME,              CPUID_EAX,  0, 0x8000001f, 0 },
        { X86_FEATURE_SEV,              CPUID_EAX,  1, 0x8000001f, 0 },
+       { X86_FEATURE_SME_COHERENT,     CPUID_EAX, 10, 0x8000001f, 0 },
        { 0, 0, 0, 0, 0 }
 };
 
index a0e8fc7..ddffd80 100644 (file)
@@ -229,8 +229,8 @@ static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
 
        it = &of_ioapic_type[type_index];
        ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->trigger, it->polarity);
-       tmp.ioapic_id = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain));
-       tmp.ioapic_pin = fwspec->param[0];
+       tmp.devid = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain));
+       tmp.ioapic.pin = fwspec->param[0];
 
        return mp_irqdomain_alloc(domain, virq, nr_irqs, &tmp);
 }
index 48ce445..ea8d51e 100644 (file)
@@ -115,7 +115,8 @@ void show_opcodes(struct pt_regs *regs, const char *loglvl)
        unsigned long prologue = regs->ip - PROLOGUE_SIZE;
 
        if (copy_code(regs, opcodes, prologue, sizeof(opcodes))) {
-               printk("%sCode: Bad RIP value.\n", loglvl);
+               printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n",
+                      loglvl, prologue);
        } else {
                printk("%sCode: %" __stringify(PROLOGUE_SIZE) "ph <%02x> %"
                       __stringify(EPILOGUE_SIZE) "ph\n", loglvl, opcodes,
index 61ddc3a..701f196 100644 (file)
@@ -5,7 +5,6 @@
 #include <asm/fpu/internal.h>
 #include <asm/tlbflush.h>
 #include <asm/setup.h>
-#include <asm/cmdline.h>
 
 #include <linux/sched.h>
 #include <linux/sched/task.h>
@@ -238,51 +237,11 @@ static void __init fpu__init_system_ctx_switch(void)
 }
 
 /*
- * We parse fpu parameters early because fpu__init_system() is executed
- * before parse_early_param().
- */
-static void __init fpu__init_parse_early_param(void)
-{
-       char arg[32];
-       char *argptr = arg;
-       int bit;
-
-#ifdef CONFIG_X86_32
-       if (cmdline_find_option_bool(boot_command_line, "no387"))
-#ifdef CONFIG_MATH_EMULATION
-               setup_clear_cpu_cap(X86_FEATURE_FPU);
-#else
-               pr_err("Option 'no387' required CONFIG_MATH_EMULATION enabled.\n");
-#endif
-
-       if (cmdline_find_option_bool(boot_command_line, "nofxsr"))
-               setup_clear_cpu_cap(X86_FEATURE_FXSR);
-#endif
-
-       if (cmdline_find_option_bool(boot_command_line, "noxsave"))
-               setup_clear_cpu_cap(X86_FEATURE_XSAVE);
-
-       if (cmdline_find_option_bool(boot_command_line, "noxsaveopt"))
-               setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
-
-       if (cmdline_find_option_bool(boot_command_line, "noxsaves"))
-               setup_clear_cpu_cap(X86_FEATURE_XSAVES);
-
-       if (cmdline_find_option(boot_command_line, "clearcpuid", arg,
-                               sizeof(arg)) &&
-           get_option(&argptr, &bit) &&
-           bit >= 0 &&
-           bit < NCAPINTS * 32)
-               setup_clear_cpu_cap(bit);
-}
-
-/*
  * Called on the boot CPU once per system bootup, to set up the initial
  * FPU state that is later cloned into all processes:
  */
 void __init fpu__init_system(struct cpuinfo_x86 *c)
 {
-       fpu__init_parse_early_param();
        fpu__init_system_early_generic(c);
 
        /*
index 038e19c..5d80474 100644 (file)
@@ -37,6 +37,7 @@ static const char *xfeature_names[] =
        "AVX-512 ZMM_Hi256"             ,
        "Processor Trace (unused)"      ,
        "Protection Keys User registers",
+       "PASID state",
        "unknown xstate feature"        ,
 };
 
@@ -51,6 +52,7 @@ static short xsave_cpuid_features[] __initdata = {
        X86_FEATURE_AVX512F,
        X86_FEATURE_INTEL_PT,
        X86_FEATURE_PKU,
+       X86_FEATURE_ENQCMD,
 };
 
 /*
@@ -318,6 +320,7 @@ static void __init print_xstate_features(void)
        print_xstate_feature(XFEATURE_MASK_ZMM_Hi256);
        print_xstate_feature(XFEATURE_MASK_Hi16_ZMM);
        print_xstate_feature(XFEATURE_MASK_PKRU);
+       print_xstate_feature(XFEATURE_MASK_PASID);
 }
 
 /*
@@ -592,6 +595,7 @@ static void check_xstate_against_struct(int nr)
        XCHECK_SZ(sz, nr, XFEATURE_ZMM_Hi256, struct avx_512_zmm_uppers_state);
        XCHECK_SZ(sz, nr, XFEATURE_Hi16_ZMM,  struct avx_512_hi16_state);
        XCHECK_SZ(sz, nr, XFEATURE_PKRU,      struct pkru_state);
+       XCHECK_SZ(sz, nr, XFEATURE_PASID,     struct ia32_pasid_state);
 
        /*
         * Make *SURE* to add any feature numbers in below if
@@ -601,7 +605,7 @@ static void check_xstate_against_struct(int nr)
        if ((nr < XFEATURE_YMM) ||
            (nr >= XFEATURE_MAX) ||
            (nr == XFEATURE_PT_UNIMPLEMENTED_SO_FAR) ||
-           ((nr >= XFEATURE_RSRVD_COMP_10) && (nr <= XFEATURE_LBR))) {
+           ((nr >= XFEATURE_RSRVD_COMP_11) && (nr <= XFEATURE_LBR))) {
                WARN_ONCE(1, "no structure for xstate: %d\n", nr);
                XSTATE_WARN_ON(1);
        }
@@ -1398,3 +1402,60 @@ int proc_pid_arch_status(struct seq_file *m, struct pid_namespace *ns,
        return 0;
 }
 #endif /* CONFIG_PROC_PID_ARCH_STATUS */
+
+#ifdef CONFIG_IOMMU_SUPPORT
+void update_pasid(void)
+{
+       u64 pasid_state;
+       u32 pasid;
+
+       if (!cpu_feature_enabled(X86_FEATURE_ENQCMD))
+               return;
+
+       if (!current->mm)
+               return;
+
+       pasid = READ_ONCE(current->mm->pasid);
+       /* Set the valid bit in the PASID MSR/state only for valid pasid. */
+       pasid_state = pasid == PASID_DISABLED ?
+                     pasid : pasid | MSR_IA32_PASID_VALID;
+
+       /*
+        * No need to hold fregs_lock() since the task's fpstate won't
+        * be changed by others (e.g. ptrace) while the task is being
+        * switched to or is in IPI.
+        */
+       if (!test_thread_flag(TIF_NEED_FPU_LOAD)) {
+               /* The MSR is active and can be directly updated. */
+               wrmsrl(MSR_IA32_PASID, pasid_state);
+       } else {
+               struct fpu *fpu = &current->thread.fpu;
+               struct ia32_pasid_state *ppasid_state;
+               struct xregs_state *xsave;
+
+               /*
+                * The CPU's xstate registers are not currently active. Just
+                * update the PASID state in the memory buffer here. The
+                * PASID MSR will be loaded when returning to user mode.
+                */
+               xsave = &fpu->state.xsave;
+               xsave->header.xfeatures |= XFEATURE_MASK_PASID;
+               ppasid_state = get_xsave_addr(xsave, XFEATURE_PASID);
+               /*
+                * Since XFEATURE_MASK_PASID is set in xfeatures, ppasid_state
+                * won't be NULL and no need to check its value.
+                *
+                * Only update the task's PASID state when it's different
+                * from the mm's pasid.
+                */
+               if (ppasid_state->pasid != pasid_state) {
+                       /*
+                        * Invalid fpregs so that state restoring will pick up
+                        * the PASID state.
+                        */
+                       __fpu_invalidate_fpregs_state(fpu);
+                       ppasid_state->pasid = pasid_state;
+               }
+       }
+}
+#endif /* CONFIG_IOMMU_SUPPORT */
index 8cdf29f..03aa33b 100644 (file)
@@ -349,7 +349,7 @@ static int arch_build_bp_info(struct perf_event *bp,
                        hw->len = X86_BREAKPOINT_LEN_X;
                        return 0;
                }
-               /* fall through */
+               fallthrough;
        default:
                return -EINVAL;
        }
@@ -442,42 +442,6 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
 }
 
 /*
- * Dump the debug register contents to the user.
- * We can't dump our per cpu values because it
- * may contain cpu wide breakpoint, something that
- * doesn't belong to the current task.
- *
- * TODO: include non-ptrace user breakpoints (perf)
- */
-void aout_dump_debugregs(struct user *dump)
-{
-       int i;
-       int dr7 = 0;
-       struct perf_event *bp;
-       struct arch_hw_breakpoint *info;
-       struct thread_struct *thread = &current->thread;
-
-       for (i = 0; i < HBP_NUM; i++) {
-               bp = thread->ptrace_bps[i];
-
-               if (bp && !bp->attr.disabled) {
-                       dump->u_debugreg[i] = bp->attr.bp_addr;
-                       info = counter_arch_bp(bp);
-                       dr7 |= encode_dr7(i, info->len, info->type);
-               } else {
-                       dump->u_debugreg[i] = 0;
-               }
-       }
-
-       dump->u_debugreg[4] = 0;
-       dump->u_debugreg[5] = 0;
-       dump->u_debugreg[6] = current->thread.debugreg6;
-
-       dump->u_debugreg[7] = dr7;
-}
-EXPORT_SYMBOL_GPL(aout_dump_debugregs);
-
-/*
  * Release the user breakpoints used by ptrace
  */
 void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
@@ -490,7 +454,7 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
                t->ptrace_bps[i] = NULL;
        }
 
-       t->debugreg6 = 0;
+       t->virtual_dr6 = 0;
        t->ptrace_dr7 = 0;
 }
 
@@ -500,7 +464,7 @@ void hw_breakpoint_restore(void)
        set_debugreg(__this_cpu_read(cpu_debugreg[1]), 1);
        set_debugreg(__this_cpu_read(cpu_debugreg[2]), 2);
        set_debugreg(__this_cpu_read(cpu_debugreg[3]), 3);
-       set_debugreg(current->thread.debugreg6, 6);
+       set_debugreg(DR6_RESERVED, 6);
        set_debugreg(__this_cpu_read(cpu_dr7), 7);
 }
 EXPORT_SYMBOL_GPL(hw_breakpoint_restore);
@@ -523,10 +487,10 @@ EXPORT_SYMBOL_GPL(hw_breakpoint_restore);
  */
 static int hw_breakpoint_handler(struct die_args *args)
 {
-       int i, cpu, rc = NOTIFY_STOP;
+       int i, rc = NOTIFY_STOP;
        struct perf_event *bp;
-       unsigned long dr6;
        unsigned long *dr6_p;
+       unsigned long dr6;
 
        /* The DR6 value is pointed by args->err */
        dr6_p = (unsigned long *)ERR_PTR(args->err);
@@ -540,14 +504,6 @@ static int hw_breakpoint_handler(struct die_args *args)
        if ((dr6 & DR_TRAP_BITS) == 0)
                return NOTIFY_DONE;
 
-       /*
-        * Assert that local interrupts are disabled
-        * Reset the DRn bits in the virtualized register value.
-        * The ptrace trigger routine will add in whatever is needed.
-        */
-       current->thread.debugreg6 &= ~DR_TRAP_BITS;
-       cpu = get_cpu();
-
        /* Handle all the breakpoints that were triggered */
        for (i = 0; i < HBP_NUM; ++i) {
                if (likely(!(dr6 & (DR_TRAP0 << i))))
@@ -561,7 +517,7 @@ static int hw_breakpoint_handler(struct die_args *args)
                 */
                rcu_read_lock();
 
-               bp = per_cpu(bp_per_reg[i], cpu);
+               bp = this_cpu_read(bp_per_reg[i]);
                /*
                 * Reset the 'i'th TRAP bit in dr6 to denote completion of
                 * exception handling
@@ -592,12 +548,10 @@ static int hw_breakpoint_handler(struct die_args *args)
         * breakpoints (to generate signals) and b) when the system has
         * taken exception due to multiple causes
         */
-       if ((current->thread.debugreg6 & DR_TRAP_BITS) ||
+       if ((current->thread.virtual_dr6 & DR_TRAP_BITS) ||
            (dr6 & (~DR_TRAP_BITS)))
                rc = NOTIFY_DONE;
 
-       put_cpu();
-
        return rc;
 }
 
index 7ecf9ba..1bffb87 100644 (file)
@@ -149,9 +149,6 @@ static const __initconst struct idt_data apic_idts[] = {
 # ifdef CONFIG_IRQ_WORK
        INTG(IRQ_WORK_VECTOR,                   asm_sysvec_irq_work),
 # endif
-# ifdef CONFIG_X86_UV
-       INTG(UV_BAU_MESSAGE,                    asm_sysvec_uv_bau_message),
-# endif
        INTG(SPURIOUS_APIC_VECTOR,              asm_sysvec_spurious_apic_interrupt),
        INTG(ERROR_APIC_VECTOR,                 asm_sysvec_error_interrupt),
 #endif
index 1810602..c5dd503 100644 (file)
@@ -227,7 +227,7 @@ static __always_inline void handle_irq(struct irq_desc *desc,
                                       struct pt_regs *regs)
 {
        if (IS_ENABLED(CONFIG_X86_64))
-               run_on_irqstack_cond(desc->handle_irq, desc, regs);
+               run_irq_on_irqstack_cond(desc->handle_irq, desc, regs);
        else
                __handle_irq(desc, regs);
 }
index 1b4fe93..440eed5 100644 (file)
@@ -74,5 +74,5 @@ int irq_init_percpu_irqstack(unsigned int cpu)
 
 void do_softirq_own_stack(void)
 {
-       run_on_irqstack_cond(__do_softirq, NULL, NULL);
+       run_on_irqstack_cond(__do_softirq, NULL);
 }
index 68acd30..ff7878d 100644 (file)
@@ -450,7 +450,7 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
                ptr = &remcomInBuffer[1];
                if (kgdb_hex2long(&ptr, &addr))
                        linux_regs->ip = addr;
-               /* fall through */
+               fallthrough;
        case 'D':
        case 'k':
                /* clear the trace bit */
@@ -539,7 +539,7 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd)
                         * a system call which should be ignored
                         */
                        return NOTIFY_DONE;
-               /* fall through */
+               fallthrough;
        default:
                if (user_mode(regs))
                        return NOTIFY_DONE;
@@ -629,9 +629,10 @@ static void kgdb_hw_overflow_handler(struct perf_event *event,
        struct task_struct *tsk = current;
        int i;
 
-       for (i = 0; i < 4; i++)
+       for (i = 0; i < 4; i++) {
                if (breakinfo[i].enabled)
-                       tsk->thread.debugreg6 |= (DR_TRAP0 << i);
+                       tsk->thread.virtual_dr6 |= (DR_TRAP0 << i);
+       }
 }
 
 void kgdb_arch_late(void)
index fdadc37..db8f869 100644 (file)
@@ -767,124 +767,21 @@ asm(
 NOKPROBE_SYMBOL(kretprobe_trampoline);
 STACK_FRAME_NON_STANDARD(kretprobe_trampoline);
 
+
 /*
  * Called from kretprobe_trampoline
  */
 __used __visible void *trampoline_handler(struct pt_regs *regs)
 {
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
-       kprobe_opcode_t *correct_ret_addr = NULL;
-       void *frame_pointer;
-       bool skipped = false;
-
-       /*
-        * Set a dummy kprobe for avoiding kretprobe recursion.
-        * Since kretprobe never run in kprobe handler, kprobe must not
-        * be running at this point.
-        */
-       kprobe_busy_begin();
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
        /* fixup registers */
        regs->cs = __KERNEL_CS;
 #ifdef CONFIG_X86_32
-       regs->cs |= get_kernel_rpl();
        regs->gs = 0;
 #endif
-       /* We use pt_regs->sp for return address holder. */
-       frame_pointer = &regs->sp;
-       regs->ip = trampoline_address;
+       regs->ip = (unsigned long)&kretprobe_trampoline;
        regs->orig_ax = ~0UL;
 
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because multiple functions in the call path have
-        * return probes installed on them, and/or more than one
-        * return probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always pushed into the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the (chronologically) first instance's ret_addr
-        *       will be the real return address, and all the rest will
-        *       point to kretprobe_trampoline.
-        */
-       hlist_for_each_entry(ri, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-               /*
-                * Return probes must be pushed on this hash list correct
-                * order (same as return order) so that it can be popped
-                * correctly. However, if we find it is pushed it incorrect
-                * order, this means we find a function which should not be
-                * probed, because the wrong order entry is pushed on the
-                * path of processing other kretprobe itself.
-                */
-               if (ri->fp != frame_pointer) {
-                       if (!skipped)
-                               pr_warn("kretprobe is stacked incorrectly. Trying to fixup.\n");
-                       skipped = true;
-                       continue;
-               }
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               if (skipped)
-                       pr_warn("%ps must be blacklisted because of incorrect kretprobe order\n",
-                               ri->rp->kp.addr);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
-       correct_ret_addr = ri->ret_addr;
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-               if (ri->fp != frame_pointer)
-                       continue;
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               if (ri->rp && ri->rp->handler) {
-                       __this_cpu_write(current_kprobe, &ri->rp->kp);
-                       ri->ret_addr = correct_ret_addr;
-                       ri->rp->handler(ri, regs);
-                       __this_cpu_write(current_kprobe, &kprobe_busy);
-               }
-
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_hash_unlock(current, &flags);
-
-       kprobe_busy_end();
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
-       return (void *)orig_ret_address;
+       return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline, &regs->sp);
 }
 NOKPROBE_SYMBOL(trampoline_handler);
 
index 40f3804..15e0640 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/ftrace.h>
 #include <linux/frame.h>
 #include <linux/pgtable.h>
+#include <linux/static_call.h>
 
 #include <asm/text-patching.h>
 #include <asm/cacheflush.h>
@@ -181,7 +182,6 @@ optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
                /* Save skipped registers */
                regs->cs = __KERNEL_CS;
 #ifdef CONFIG_X86_32
-               regs->cs |= get_kernel_rpl();
                regs->gs = 0;
 #endif
                regs->ip = (unsigned long)op->kp.addr + INT3_INSN_SIZE;
@@ -210,7 +210,8 @@ static int copy_optimized_instructions(u8 *dest, u8 *src, u8 *real)
        /* Check whether the address range is reserved */
        if (ftrace_text_reserved(src, src + len - 1) ||
            alternatives_text_reserved(src, src + len - 1) ||
-           jump_label_text_reserved(src, src + len - 1))
+           jump_label_text_reserved(src, src + len - 1) ||
+           static_call_text_reserved(src, src + len - 1))
                return -EBUSY;
 
        return len;
index 08320b0..9663ba3 100644 (file)
@@ -270,9 +270,8 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_kvm_asyncpf_interrupt)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
        u32 token;
-       irqentry_state_t state;
 
-       state = irqentry_enter(regs);
+       ack_APIC_irq();
 
        inc_irq_stat(irq_hv_callback_count);
 
@@ -283,7 +282,6 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_kvm_asyncpf_interrupt)
                wrmsrl(MSR_KVM_ASYNC_PF_ACK, 1);
        }
 
-       irqentry_exit(regs, state);
        set_irq_regs(old_regs);
 }
 
index 411af4a..8f06449 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/irqdomain.h>
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
-#include <asm/io_apic.h>
 #include <asm/proto.h>
 #include <asm/bios_ebda.h>
 #include <asm/e820/api.h>
@@ -46,11 +45,6 @@ static int __init mpf_checksum(unsigned char *mp, int len)
        return sum & 0xFF;
 }
 
-int __init default_mpc_apic_id(struct mpc_cpu *m)
-{
-       return m->apicid;
-}
-
 static void __init MP_processor_info(struct mpc_cpu *m)
 {
        int apicid;
@@ -61,7 +55,7 @@ static void __init MP_processor_info(struct mpc_cpu *m)
                return;
        }
 
-       apicid = x86_init.mpparse.mpc_apic_id(m);
+       apicid = m->apicid;
 
        if (m->cpuflag & CPU_BOOTPROCESSOR) {
                bootup_cpu = " (Bootup-CPU)";
@@ -73,7 +67,7 @@ static void __init MP_processor_info(struct mpc_cpu *m)
 }
 
 #ifdef CONFIG_X86_IO_APIC
-void __init default_mpc_oem_bus_info(struct mpc_bus *m, char *str)
+static void __init mpc_oem_bus_info(struct mpc_bus *m, char *str)
 {
        memcpy(str, m->bustype, 6);
        str[6] = 0;
@@ -84,7 +78,7 @@ static void __init MP_bus_info(struct mpc_bus *m)
 {
        char str[7];
 
-       x86_init.mpparse.mpc_oem_bus_info(m, str);
+       mpc_oem_bus_info(m, str);
 
 #if MAX_MP_BUSSES < 256
        if (m->busid >= MAX_MP_BUSSES) {
@@ -100,9 +94,6 @@ static void __init MP_bus_info(struct mpc_bus *m)
                mp_bus_id_to_type[m->busid] = MP_BUS_ISA;
 #endif
        } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) {
-               if (x86_init.mpparse.mpc_oem_pci_bus)
-                       x86_init.mpparse.mpc_oem_pci_bus(m);
-
                clear_bit(m->busid, mp_bus_not_pci);
 #ifdef CONFIG_EISA
                mp_bus_id_to_type[m->busid] = MP_BUS_PCI;
@@ -198,8 +189,6 @@ static void __init smp_dump_mptable(struct mpc_table *mpc, unsigned char *mpt)
                        1, mpc, mpc->length, 1);
 }
 
-void __init default_smp_read_mpc_oem(struct mpc_table *mpc) { }
-
 static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early)
 {
        char str[16];
@@ -218,14 +207,7 @@ static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early)
        if (early)
                return 1;
 
-       if (mpc->oemptr)
-               x86_init.mpparse.smp_read_mpc_oem(mpc);
-
-       /*
-        *      Now process the configuration blocks.
-        */
-       x86_init.mpparse.mpc_record(0);
-
+       /* Now process the configuration blocks. */
        while (count < mpc->length) {
                switch (*mpt) {
                case MP_PROCESSOR:
@@ -256,7 +238,6 @@ static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early)
                        count = mpc->length;
                        break;
                }
-               x86_init.mpparse.mpc_record(1);
        }
 
        if (!num_processors)
@@ -312,7 +293,7 @@ static void __init construct_default_ioirq_mptable(int mpc_default_type)
                case 2:
                        if (i == 0 || i == 13)
                                continue;       /* IRQ0 & IRQ13 not connected */
-                       /* fall through */
+                       fallthrough;
                default:
                        if (i == 2)
                                continue;       /* IRQ2 is never connected */
@@ -356,7 +337,7 @@ static void __init construct_ioapic_table(int mpc_default_type)
        default:
                pr_err("???\nUnknown standard configuration %d\n",
                       mpc_default_type);
-               /* fall through */
+               fallthrough;
        case 1:
        case 5:
                memcpy(bus.bustype, "ISA   ", 6);
index 49dcfb8..c0d4098 100644 (file)
@@ -80,18 +80,30 @@ static ssize_t msr_read(struct file *file, char __user *buf,
 
 static int filter_write(u32 reg)
 {
+       /*
+        * MSRs writes usually happen all at once, and can easily saturate kmsg.
+        * Only allow one message every 30 seconds.
+        *
+        * It's possible to be smarter here and do it (for example) per-MSR, but
+        * it would certainly be more complex, and this is enough at least to
+        * avoid saturating the ring buffer.
+        */
+       static DEFINE_RATELIMIT_STATE(fw_rs, 30 * HZ, 1);
+
        switch (allow_writes) {
        case MSR_WRITES_ON:  return 0;
        case MSR_WRITES_OFF: return -EPERM;
        default: break;
        }
 
+       if (!__ratelimit(&fw_rs))
+               return 0;
+
        if (reg == MSR_IA32_ENERGY_PERF_BIAS)
                return 0;
 
-       pr_err_ratelimited("Write to unrecognized MSR 0x%x by %s\n"
-                          "Please report to x86@kernel.org\n",
-                          reg, current->comm);
+       pr_err("Write to unrecognized MSR 0x%x by %s (pid: %d). Please report to x86@kernel.org.\n",
+              reg, current->comm, current->pid);
 
        return 0;
 }
index 4fc9954..4738166 100644 (file)
@@ -102,7 +102,6 @@ fs_initcall(nmi_warning_debugfs);
 
 static void nmi_check_duration(struct nmiaction *action, u64 duration)
 {
-       u64 whole_msecs = READ_ONCE(action->max_duration);
        int remainder_ns, decimal_msecs;
 
        if (duration < nmi_longest_ns || duration < action->max_duration)
@@ -110,12 +109,12 @@ static void nmi_check_duration(struct nmiaction *action, u64 duration)
 
        action->max_duration = duration;
 
-       remainder_ns = do_div(whole_msecs, (1000 * 1000));
+       remainder_ns = do_div(duration, (1000 * 1000));
        decimal_msecs = remainder_ns / 1000;
 
        printk_ratelimited(KERN_INFO
                "INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n",
-               action->handler, whole_msecs, decimal_msecs);
+               action->handler, duration, decimal_msecs);
 }
 
 static int nmi_handle(unsigned int type, struct pt_regs *regs)
index de2138b..6c3407b 100644 (file)
@@ -263,13 +263,8 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
 struct pv_info pv_info = {
        .name = "bare hardware",
 #ifdef CONFIG_PARAVIRT_XXL
-       .kernel_rpl = 0,
-       .shared_kernel_pmd = 1, /* Only used when CONFIG_X86_PAE is set */
-
-#ifdef CONFIG_X86_64
        .extra_user_64bit_cs = __USER_CS,
 #endif
-#endif
 };
 
 /* 64-bit pagetable entries */
@@ -305,9 +300,7 @@ struct paravirt_patch_template pv_ops = {
        .cpu.load_idt           = native_load_idt,
        .cpu.store_tr           = native_store_tr,
        .cpu.load_tls           = native_load_tls,
-#ifdef CONFIG_X86_64
        .cpu.load_gs_index      = native_load_gs_index,
-#endif
        .cpu.write_ldt_entry    = native_write_ldt_entry,
        .cpu.write_gdt_entry    = native_write_gdt_entry,
        .cpu.write_idt_entry    = native_write_idt_entry,
@@ -317,9 +310,7 @@ struct paravirt_patch_template pv_ops = {
 
        .cpu.load_sp0           = native_load_sp0,
 
-#ifdef CONFIG_X86_64
        .cpu.usergs_sysret64    = native_usergs_sysret64,
-#endif
        .cpu.iret               = native_iret,
        .cpu.swapgs             = native_swapgs,
 
@@ -369,24 +360,16 @@ struct paravirt_patch_template pv_ops = {
        .mmu.release_p4d        = paravirt_nop,
 
        .mmu.set_pte            = native_set_pte,
-       .mmu.set_pte_at         = native_set_pte_at,
        .mmu.set_pmd            = native_set_pmd,
 
        .mmu.ptep_modify_prot_start     = __ptep_modify_prot_start,
        .mmu.ptep_modify_prot_commit    = __ptep_modify_prot_commit,
 
-#if CONFIG_PGTABLE_LEVELS >= 3
-#ifdef CONFIG_X86_PAE
-       .mmu.set_pte_atomic     = native_set_pte_atomic,
-       .mmu.pte_clear          = native_pte_clear,
-       .mmu.pmd_clear          = native_pmd_clear,
-#endif
        .mmu.set_pud            = native_set_pud,
 
        .mmu.pmd_val            = PTE_IDENT,
        .mmu.make_pmd           = PTE_IDENT,
 
-#if CONFIG_PGTABLE_LEVELS >= 4
        .mmu.pud_val            = PTE_IDENT,
        .mmu.make_pud           = PTE_IDENT,
 
@@ -398,8 +381,6 @@ struct paravirt_patch_template pv_ops = {
 
        .mmu.set_pgd            = native_set_pgd,
 #endif /* CONFIG_PGTABLE_LEVELS >= 5 */
-#endif /* CONFIG_PGTABLE_LEVELS >= 4 */
-#endif /* CONFIG_PGTABLE_LEVELS >= 3 */
 
        .mmu.pte_val            = PTE_IDENT,
        .mmu.pgd_val            = PTE_IDENT,
index 3eff63c..ace6e33 100644 (file)
@@ -26,14 +26,10 @@ struct patch_xxl {
        const unsigned char     mmu_read_cr3[3];
        const unsigned char     mmu_write_cr3[3];
        const unsigned char     irq_restore_fl[2];
-# ifdef CONFIG_X86_64
        const unsigned char     cpu_wbinvd[2];
        const unsigned char     cpu_usergs_sysret64[6];
        const unsigned char     cpu_swapgs[3];
        const unsigned char     mov64[3];
-# else
-       const unsigned char     cpu_iret[1];
-# endif
 };
 
 static const struct patch_xxl patch_data_xxl = {
@@ -42,7 +38,6 @@ static const struct patch_xxl patch_data_xxl = {
        .irq_save_fl            = { 0x9c, 0x58 },       // pushf; pop %[re]ax
        .mmu_read_cr2           = { 0x0f, 0x20, 0xd0 }, // mov %cr2, %[re]ax
        .mmu_read_cr3           = { 0x0f, 0x20, 0xd8 }, // mov %cr3, %[re]ax
-# ifdef CONFIG_X86_64
        .mmu_write_cr3          = { 0x0f, 0x22, 0xdf }, // mov %rdi, %cr3
        .irq_restore_fl         = { 0x57, 0x9d },       // push %rdi; popfq
        .cpu_wbinvd             = { 0x0f, 0x09 },       // wbinvd
@@ -50,19 +45,11 @@ static const struct patch_xxl patch_data_xxl = {
                                    0x48, 0x0f, 0x07 }, // swapgs; sysretq
        .cpu_swapgs             = { 0x0f, 0x01, 0xf8 }, // swapgs
        .mov64                  = { 0x48, 0x89, 0xf8 }, // mov %rdi, %rax
-# else
-       .mmu_write_cr3          = { 0x0f, 0x22, 0xd8 }, // mov %eax, %cr3
-       .irq_restore_fl         = { 0x50, 0x9d },       // push %eax; popf
-       .cpu_iret               = { 0xcf },             // iret
-# endif
 };
 
 unsigned int paravirt_patch_ident_64(void *insn_buff, unsigned int len)
 {
-#ifdef CONFIG_X86_64
        return PATCH(xxl, mov64, insn_buff, len);
-#endif
-       return 0;
 }
 # endif /* CONFIG_PARAVIRT_XXL */
 
@@ -98,13 +85,9 @@ unsigned int native_patch(u8 type, void *insn_buff, unsigned long addr,
        PATCH_CASE(mmu, read_cr3, xxl, insn_buff, len);
        PATCH_CASE(mmu, write_cr3, xxl, insn_buff, len);
 
-# ifdef CONFIG_X86_64
        PATCH_CASE(cpu, usergs_sysret64, xxl, insn_buff, len);
        PATCH_CASE(cpu, swapgs, xxl, insn_buff, len);
        PATCH_CASE(cpu, wbinvd, xxl, insn_buff, len);
-# else
-       PATCH_CASE(cpu, iret, xxl, insn_buff, len);
-# endif
 #endif
 
 #ifdef CONFIG_PARAVIRT_SPINLOCKS
index 994d839..ba4593a 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/spec-ctrl.h>
 #include <asm/io_bitmap.h>
 #include <asm/proto.h>
+#include <asm/frame.h>
 
 #include "process.h"
 
@@ -133,7 +134,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
        fork_frame = container_of(childregs, struct fork_frame, regs);
        frame = &fork_frame->frame;
 
-       frame->bp = 0;
+       frame->bp = encode_frame_pointer(childregs);
        frame->ret_addr = (unsigned long) ret_from_fork;
        p->thread.sp = (unsigned long) fork_frame;
        p->thread.io_bitmap = NULL;
@@ -684,9 +685,7 @@ void arch_cpu_idle(void)
  */
 void __cpuidle default_idle(void)
 {
-       trace_cpu_idle_rcuidle(1, smp_processor_id());
        safe_halt();
-       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 }
 #if defined(CONFIG_APM_MODULE) || defined(CONFIG_HALTPOLL_CPUIDLE_MODULE)
 EXPORT_SYMBOL(default_idle);
@@ -792,7 +791,6 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
 static __cpuidle void mwait_idle(void)
 {
        if (!current_set_polling_and_test()) {
-               trace_cpu_idle_rcuidle(1, smp_processor_id());
                if (this_cpu_has(X86_BUG_CLFLUSH_MONITOR)) {
                        mb(); /* quirk */
                        clflush((void *)&current_thread_info()->flags);
@@ -804,7 +802,6 @@ static __cpuidle void mwait_idle(void)
                        __sti_mwait(0, 0);
                else
                        local_irq_enable();
-               trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
        } else {
                local_irq_enable();
        }
index 9afefe3..df342be 100644 (file)
@@ -407,7 +407,7 @@ unsigned long x86_gsbase_read_cpu_inactive(void)
 {
        unsigned long gsbase;
 
-       if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
+       if (boot_cpu_has(X86_FEATURE_FSGSBASE)) {
                unsigned long flags;
 
                local_irq_save(flags);
@@ -422,7 +422,7 @@ unsigned long x86_gsbase_read_cpu_inactive(void)
 
 void x86_gsbase_write_cpu_inactive(unsigned long gsbase)
 {
-       if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
+       if (boot_cpu_has(X86_FEATURE_FSGSBASE)) {
                unsigned long flags;
 
                local_irq_save(flags);
@@ -439,7 +439,7 @@ unsigned long x86_fsbase_read_task(struct task_struct *task)
 
        if (task == current)
                fsbase = x86_fsbase_read_cpu();
-       else if (static_cpu_has(X86_FEATURE_FSGSBASE) ||
+       else if (boot_cpu_has(X86_FEATURE_FSGSBASE) ||
                 (task->thread.fsindex == 0))
                fsbase = task->thread.fsbase;
        else
@@ -454,7 +454,7 @@ unsigned long x86_gsbase_read_task(struct task_struct *task)
 
        if (task == current)
                gsbase = x86_gsbase_read_cpu_inactive();
-       else if (static_cpu_has(X86_FEATURE_FSGSBASE) ||
+       else if (boot_cpu_has(X86_FEATURE_FSGSBASE) ||
                 (task->thread.gsindex == 0))
                gsbase = task->thread.gsbase;
        else
index 5679aa3..bedca01 100644 (file)
@@ -204,7 +204,7 @@ static int set_segment_reg(struct task_struct *task,
        case offsetof(struct user_regs_struct, ss):
                if (unlikely(value == 0))
                        return -EIO;
-               /* Else, fall through */
+               fallthrough;
 
        default:
                *pt_regs_access(task_pt_regs(task), offset) = value;
@@ -465,7 +465,7 @@ static void ptrace_triggered(struct perf_event *bp,
                        break;
        }
 
-       thread->debugreg6 |= (DR_TRAP0 << i);
+       thread->virtual_dr6 |= (DR_TRAP0 << i);
 }
 
 /*
@@ -601,7 +601,7 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
                if (bp)
                        val = bp->hw.info.address;
        } else if (n == 6) {
-               val = thread->debugreg6;
+               val = thread->virtual_dr6 ^ DR6_RESERVED; /* Flip back to arch polarity */
        } else if (n == 7) {
                val = thread->ptrace_dr7;
        }
@@ -657,7 +657,7 @@ static int ptrace_set_debugreg(struct task_struct *tsk, int n,
        if (n < HBP_NUM) {
                rc = ptrace_set_breakpoint_addr(tsk, n, val);
        } else if (n == 6) {
-               thread->debugreg6 = val;
+               thread->virtual_dr6 = val ^ DR6_RESERVED; /* Flip to positive polarity */
                rc = 0;
        } else if (n == 7) {
                rc = ptrace_write_dr7(tsk, val);
index 1b10717..6d0df6a 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <asm/hpet.h>
 #include <asm/setup.h>
+#include <asm/mce.h>
 
 #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
 
@@ -624,10 +625,6 @@ static void amd_disable_seq_and_redirect_scrub(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3,
                        amd_disable_seq_and_redirect_scrub);
 
-#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
-#include <linux/jump_label.h>
-#include <asm/string_64.h>
-
 /* Ivy Bridge, Haswell, Broadwell */
 static void quirk_intel_brickland_xeon_ras_cap(struct pci_dev *pdev)
 {
@@ -636,7 +633,7 @@ static void quirk_intel_brickland_xeon_ras_cap(struct pci_dev *pdev)
        pci_read_config_dword(pdev, 0x84, &capid0);
 
        if (capid0 & 0x10)
-               static_branch_inc(&mcsafe_key);
+               enable_copy_mc_fragile();
 }
 
 /* Skylake */
@@ -653,7 +650,7 @@ static void quirk_intel_purley_xeon_ras_cap(struct pci_dev *pdev)
         * enabled, so memory machine check recovery is also enabled.
         */
        if ((capid0 & 0xc0) == 0xc0 || (capid5 & 0x1e0))
-               static_branch_inc(&mcsafe_key);
+               enable_copy_mc_fragile();
 
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0ec3, quirk_intel_brickland_xeon_ras_cap);
@@ -661,7 +658,6 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2fc0, quirk_intel_brickland_xeon_
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, quirk_intel_brickland_xeon_ras_cap);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2083, quirk_intel_purley_xeon_ras_cap);
 #endif
-#endif
 
 bool x86_apple_machine;
 EXPORT_SYMBOL(x86_apple_machine);
index 0ec7ced..a515e2d 100644 (file)
@@ -654,7 +654,7 @@ static void native_machine_emergency_restart(void)
 
                case BOOT_CF9_FORCE:
                        port_cf9_safe = true;
-                       /* Fall through */
+                       fallthrough;
 
                case BOOT_CF9_SAFE:
                        if (port_cf9_safe) {
index 3511736..fa16b90 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/hugetlb.h>
 #include <linux/tboot.h>
 #include <linux/usb/xhci-dbgp.h>
+#include <linux/static_call.h>
 
 #include <uapi/linux/mount.h>
 
@@ -849,6 +850,7 @@ void __init setup_arch(char **cmdline_p)
        early_cpu_init();
        arch_init_ideal_nops();
        jump_label_init();
+       static_call_init();
        early_ioremap_init();
 
        setup_olpc_ofw_pgd();
@@ -1077,6 +1079,7 @@ void __init setup_arch(char **cmdline_p)
        efi_fake_memmap();
        efi_find_mirror();
        efi_esrt_init();
+       efi_mokvar_table_init();
 
        /*
         * The EFI specification says that boot service code won't be
index d5fa494..be0d7d4 100644 (file)
@@ -726,7 +726,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
                                regs->ax = -EINTR;
                                break;
                        }
-               /* fallthrough */
+                       fallthrough;
                case -ERESTARTNOINTR:
                        regs->ax = regs->orig_ax;
                        regs->ip -= 2;
index 9ccbf05..a7f3e12 100644 (file)
@@ -27,7 +27,7 @@ static inline void signal_compat_build_tests(void)
         */
        BUILD_BUG_ON(NSIGILL  != 11);
        BUILD_BUG_ON(NSIGFPE  != 15);
-       BUILD_BUG_ON(NSIGSEGV != 7);
+       BUILD_BUG_ON(NSIGSEGV != 9);
        BUILD_BUG_ON(NSIGBUS  != 5);
        BUILD_BUG_ON(NSIGTRAP != 5);
        BUILD_BUG_ON(NSIGCHLD != 6);
index 27aa04a..f5ef689 100644 (file)
@@ -1594,14 +1594,28 @@ int native_cpu_disable(void)
        if (ret)
                return ret;
 
-       /*
-        * Disable the local APIC. Otherwise IPI broadcasts will reach
-        * it. It still responds normally to INIT, NMI, SMI, and SIPI
-        * messages.
-        */
-       apic_soft_disable();
        cpu_disable_common();
 
+        /*
+         * Disable the local APIC. Otherwise IPI broadcasts will reach
+         * it. It still responds normally to INIT, NMI, SMI, and SIPI
+         * messages.
+         *
+         * Disabling the APIC must happen after cpu_disable_common()
+         * which invokes fixup_irqs().
+         *
+         * Disabling the APIC preserves already set bits in IRR, but
+         * an interrupt arriving after disabling the local APIC does not
+         * set the corresponding IRR bit.
+         *
+         * fixup_irqs() scans IRR for set bits so it can raise a not
+         * yet handled interrupt on the new destination CPU via an IPI
+         * but obviously it can't do so for IRR bits which are not set.
+         * IOW, interrupts arriving after disabling the local APIC will
+         * be lost.
+         */
+       apic_soft_disable();
+
        return 0;
 }
 
index 2fd698e..8627fda 100644 (file)
@@ -18,13 +18,13 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
        struct unwind_state state;
        unsigned long addr;
 
-       if (regs && !consume_entry(cookie, regs->ip, false))
+       if (regs && !consume_entry(cookie, regs->ip))
                return;
 
        for (unwind_start(&state, task, regs, NULL); !unwind_done(&state);
             unwind_next_frame(&state)) {
                addr = unwind_get_return_address(&state);
-               if (!addr || !consume_entry(cookie, addr, false))
+               if (!addr || !consume_entry(cookie, addr))
                        break;
        }
 }
@@ -72,7 +72,7 @@ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
                if (!addr)
                        return -EINVAL;
 
-               if (!consume_entry(cookie, addr, false))
+               if (!consume_entry(cookie, addr))
                        return -EINVAL;
        }
 
@@ -114,7 +114,7 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
 {
        const void __user *fp = (const void __user *)regs->bp;
 
-       if (!consume_entry(cookie, regs->ip, false))
+       if (!consume_entry(cookie, regs->ip))
                return;
 
        while (1) {
@@ -128,7 +128,7 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
                        break;
                if (!frame.ret_addr)
                        break;
-               if (!consume_entry(cookie, frame.ret_addr, false))
+               if (!consume_entry(cookie, frame.ret_addr))
                        break;
                fp = frame.next_fp;
        }
diff --git a/arch/x86/kernel/static_call.c b/arch/x86/kernel/static_call.c
new file mode 100644 (file)
index 0000000..ca9a380
--- /dev/null
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/static_call.h>
+#include <linux/memory.h>
+#include <linux/bug.h>
+#include <asm/text-patching.h>
+
+enum insn_type {
+       CALL = 0, /* site call */
+       NOP = 1,  /* site cond-call */
+       JMP = 2,  /* tramp / site tail-call */
+       RET = 3,  /* tramp / site cond-tail-call */
+};
+
+static void __ref __static_call_transform(void *insn, enum insn_type type, void *func)
+{
+       int size = CALL_INSN_SIZE;
+       const void *code;
+
+       switch (type) {
+       case CALL:
+               code = text_gen_insn(CALL_INSN_OPCODE, insn, func);
+               break;
+
+       case NOP:
+               code = ideal_nops[NOP_ATOMIC5];
+               break;
+
+       case JMP:
+               code = text_gen_insn(JMP32_INSN_OPCODE, insn, func);
+               break;
+
+       case RET:
+               code = text_gen_insn(RET_INSN_OPCODE, insn, func);
+               size = RET_INSN_SIZE;
+               break;
+       }
+
+       if (memcmp(insn, code, size) == 0)
+               return;
+
+       if (unlikely(system_state == SYSTEM_BOOTING))
+               return text_poke_early(insn, code, size);
+
+       text_poke_bp(insn, code, size, NULL);
+}
+
+static void __static_call_validate(void *insn, bool tail)
+{
+       u8 opcode = *(u8 *)insn;
+
+       if (tail) {
+               if (opcode == JMP32_INSN_OPCODE ||
+                   opcode == RET_INSN_OPCODE)
+                       return;
+       } else {
+               if (opcode == CALL_INSN_OPCODE ||
+                   !memcmp(insn, ideal_nops[NOP_ATOMIC5], 5))
+                       return;
+       }
+
+       /*
+        * If we ever trigger this, our text is corrupt, we'll probably not live long.
+        */
+       WARN_ONCE(1, "unexpected static_call insn opcode 0x%x at %pS\n", opcode, insn);
+}
+
+static inline enum insn_type __sc_insn(bool null, bool tail)
+{
+       /*
+        * Encode the following table without branches:
+        *
+        *      tail    null    insn
+        *      -----+-------+------
+        *        0  |   0   |  CALL
+        *        0  |   1   |  NOP
+        *        1  |   0   |  JMP
+        *        1  |   1   |  RET
+        */
+       return 2*tail + null;
+}
+
+void arch_static_call_transform(void *site, void *tramp, void *func, bool tail)
+{
+       mutex_lock(&text_mutex);
+
+       if (tramp) {
+               __static_call_validate(tramp, true);
+               __static_call_transform(tramp, __sc_insn(!func, true), func);
+       }
+
+       if (IS_ENABLED(CONFIG_HAVE_STATIC_CALL_INLINE) && site) {
+               __static_call_validate(site, tail);
+               __static_call_transform(site, __sc_insn(!func, tail), func);
+       }
+
+       mutex_unlock(&text_mutex);
+}
+EXPORT_SYMBOL_GPL(arch_static_call_transform);
index 1f66d2d..df9c655 100644 (file)
@@ -729,20 +729,9 @@ static bool is_sysenter_singlestep(struct pt_regs *regs)
 #endif
 }
 
-static __always_inline void debug_enter(unsigned long *dr6, unsigned long *dr7)
+static __always_inline unsigned long debug_read_clear_dr6(void)
 {
-       /*
-        * Disable breakpoints during exception handling; recursive exceptions
-        * are exceedingly 'fun'.
-        *
-        * Since this function is NOKPROBE, and that also applies to
-        * HW_BREAKPOINT_X, we can't hit a breakpoint before this (XXX except a
-        * HW_BREAKPOINT_W on our stack)
-        *
-        * Entry text is excluded for HW_BP_X and cpu_entry_area, which
-        * includes the entry stack is excluded for everything.
-        */
-       *dr7 = local_db_save();
+       unsigned long dr6;
 
        /*
         * The Intel SDM says:
@@ -755,15 +744,24 @@ static __always_inline void debug_enter(unsigned long *dr6, unsigned long *dr7)
         *
         * Keep it simple: clear DR6 immediately.
         */
-       get_debugreg(*dr6, 6);
-       set_debugreg(0, 6);
-       /* Filter out all the reserved bits which are preset to 1 */
-       *dr6 &= ~DR6_RESERVED;
-}
+       get_debugreg(dr6, 6);
+       set_debugreg(DR6_RESERVED, 6);
+       dr6 ^= DR6_RESERVED; /* Flip to positive polarity */
 
-static __always_inline void debug_exit(unsigned long dr7)
-{
-       local_db_restore(dr7);
+       /*
+        * Clear the virtual DR6 value, ptrace routines will set bits here for
+        * things we want signals for.
+        */
+       current->thread.virtual_dr6 = 0;
+
+       /*
+        * The SDM says "The processor clears the BTF flag when it
+        * generates a debug exception."  Clear TIF_BLOCKSTEP to keep
+        * TIF_BLOCKSTEP in sync with the hardware BTF flag.
+        */
+       clear_thread_flag(TIF_BLOCKSTEP);
+
+       return dr6;
 }
 
 /*
@@ -790,79 +788,37 @@ static __always_inline void debug_exit(unsigned long dr7)
  *
  * May run on IST stack.
  */
-static void handle_debug(struct pt_regs *regs, unsigned long dr6, bool user)
-{
-       struct task_struct *tsk = current;
-       bool user_icebp;
-       int si_code;
-
-       /*
-        * The SDM says "The processor clears the BTF flag when it
-        * generates a debug exception."  Clear TIF_BLOCKSTEP to keep
-        * TIF_BLOCKSTEP in sync with the hardware BTF flag.
-        */
-       clear_thread_flag(TIF_BLOCKSTEP);
-
-       /*
-        * If DR6 is zero, no point in trying to handle it. The kernel is
-        * not using INT1.
-        */
-       if (!user && !dr6)
-               return;
 
+static bool notify_debug(struct pt_regs *regs, unsigned long *dr6)
+{
        /*
-        * If dr6 has no reason to give us about the origin of this trap,
-        * then it's very likely the result of an icebp/int01 trap.
-        * User wants a sigtrap for that.
+        * Notifiers will clear bits in @dr6 to indicate the event has been
+        * consumed - hw_breakpoint_handler(), single_stop_cont().
+        *
+        * Notifiers will set bits in @virtual_dr6 to indicate the desire
+        * for signals - ptrace_triggered(), kgdb_hw_overflow_handler().
         */
-       user_icebp = user && !dr6;
-
-       /* Store the virtualized DR6 value */
-       tsk->thread.debugreg6 = dr6;
-
-#ifdef CONFIG_KPROBES
-       if (kprobe_debug_handler(regs)) {
-               return;
-       }
-#endif
-
-       if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, 0,
-                      SIGTRAP) == NOTIFY_STOP) {
-               return;
-       }
-
-       /* It's safe to allow irq's after DR6 has been saved */
-       cond_local_irq_enable(regs);
-
-       if (v8086_mode(regs)) {
-               handle_vm86_trap((struct kernel_vm86_regs *) regs, 0,
-                                X86_TRAP_DB);
-               goto out;
-       }
-
-       if (WARN_ON_ONCE((dr6 & DR_STEP) && !user_mode(regs))) {
-               /*
-                * Historical junk that used to handle SYSENTER single-stepping.
-                * This should be unreachable now.  If we survive for a while
-                * without anyone hitting this warning, we'll turn this into
-                * an oops.
-                */
-               tsk->thread.debugreg6 &= ~DR_STEP;
-               set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
-               regs->flags &= ~X86_EFLAGS_TF;
-       }
-
-       si_code = get_si_code(tsk->thread.debugreg6);
-       if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS) || user_icebp)
-               send_sigtrap(regs, 0, si_code);
+       if (notify_die(DIE_DEBUG, "debug", regs, (long)dr6, 0, SIGTRAP) == NOTIFY_STOP)
+               return true;
 
-out:
-       cond_local_irq_disable(regs);
+       return false;
 }
 
 static __always_inline void exc_debug_kernel(struct pt_regs *regs,
                                             unsigned long dr6)
 {
+       /*
+        * Disable breakpoints during exception handling; recursive exceptions
+        * are exceedingly 'fun'.
+        *
+        * Since this function is NOKPROBE, and that also applies to
+        * HW_BREAKPOINT_X, we can't hit a breakpoint before this (XXX except a
+        * HW_BREAKPOINT_W on our stack)
+        *
+        * Entry text is excluded for HW_BP_X and cpu_entry_area, which
+        * includes the entry stack is excluded for everything.
+        */
+       unsigned long dr7 = local_db_save();
        bool irq_state = idtentry_enter_nmi(regs);
        instrumentation_begin();
 
@@ -879,26 +835,87 @@ static __always_inline void exc_debug_kernel(struct pt_regs *regs,
        if ((dr6 & DR_STEP) && is_sysenter_singlestep(regs))
                dr6 &= ~DR_STEP;
 
-       handle_debug(regs, dr6, false);
+       if (kprobe_debug_handler(regs))
+               goto out;
 
+       /*
+        * The kernel doesn't use INT1
+        */
+       if (!dr6)
+               goto out;
+
+       if (notify_debug(regs, &dr6))
+               goto out;
+
+       /*
+        * The kernel doesn't use TF single-step outside of:
+        *
+        *  - Kprobes, consumed through kprobe_debug_handler()
+        *  - KGDB, consumed through notify_debug()
+        *
+        * So if we get here with DR_STEP set, something is wonky.
+        *
+        * A known way to trigger this is through QEMU's GDB stub,
+        * which leaks #DB into the guest and causes IST recursion.
+        */
+       if (WARN_ON_ONCE(dr6 & DR_STEP))
+               regs->flags &= ~X86_EFLAGS_TF;
+out:
        instrumentation_end();
        idtentry_exit_nmi(regs, irq_state);
+
+       local_db_restore(dr7);
 }
 
 static __always_inline void exc_debug_user(struct pt_regs *regs,
                                           unsigned long dr6)
 {
+       bool icebp;
+
        /*
         * If something gets miswired and we end up here for a kernel mode
         * #DB, we will malfunction.
         */
        WARN_ON_ONCE(!user_mode(regs));
 
+       /*
+        * NB: We can't easily clear DR7 here because
+        * idtentry_exit_to_usermode() can invoke ptrace, schedule, access
+        * user memory, etc.  This means that a recursive #DB is possible.  If
+        * this happens, that #DB will hit exc_debug_kernel() and clear DR7.
+        * Since we're not on the IST stack right now, everything will be
+        * fine.
+        */
+
        irqentry_enter_from_user_mode(regs);
        instrumentation_begin();
 
-       handle_debug(regs, dr6, true);
+       /*
+        * If dr6 has no reason to give us about the origin of this trap,
+        * then it's very likely the result of an icebp/int01 trap.
+        * User wants a sigtrap for that.
+        */
+       icebp = !dr6;
+
+       if (notify_debug(regs, &dr6))
+               goto out;
+
+       /* It's safe to allow irq's after DR6 has been saved */
+       local_irq_enable();
+
+       if (v8086_mode(regs)) {
+               handle_vm86_trap((struct kernel_vm86_regs *)regs, 0, X86_TRAP_DB);
+               goto out_irq;
+       }
 
+       /* Add the virtual_dr6 bits for signals. */
+       dr6 |= current->thread.virtual_dr6;
+       if (dr6 & (DR_STEP | DR_TRAP_BITS) || icebp)
+               send_sigtrap(regs, 0, get_si_code(dr6));
+
+out_irq:
+       local_irq_disable();
+out:
        instrumentation_end();
        irqentry_exit_to_user_mode(regs);
 }
@@ -907,36 +924,24 @@ static __always_inline void exc_debug_user(struct pt_regs *regs,
 /* IST stack entry */
 DEFINE_IDTENTRY_DEBUG(exc_debug)
 {
-       unsigned long dr6, dr7;
-
-       debug_enter(&dr6, &dr7);
-       exc_debug_kernel(regs, dr6);
-       debug_exit(dr7);
+       exc_debug_kernel(regs, debug_read_clear_dr6());
 }
 
 /* User entry, runs on regular task stack */
 DEFINE_IDTENTRY_DEBUG_USER(exc_debug)
 {
-       unsigned long dr6, dr7;
-
-       debug_enter(&dr6, &dr7);
-       exc_debug_user(regs, dr6);
-       debug_exit(dr7);
+       exc_debug_user(regs, debug_read_clear_dr6());
 }
 #else
 /* 32 bit does not have separate entry points. */
 DEFINE_IDTENTRY_RAW(exc_debug)
 {
-       unsigned long dr6, dr7;
-
-       debug_enter(&dr6, &dr7);
+       unsigned long dr6 = debug_read_clear_dr6();
 
        if (user_mode(regs))
                exc_debug_user(regs, dr6);
        else
                exc_debug_kernel(regs, dr6);
-
-       debug_exit(dr7);
 }
 #endif
 
index 49d9250..f70dffc 100644 (file)
@@ -54,7 +54,7 @@ struct clocksource *art_related_clocksource;
 
 struct cyc2ns {
        struct cyc2ns_data data[2];     /*  0 + 2*16 = 32 */
-       seqcount_t         seq;         /* 32 + 4    = 36 */
+       seqcount_latch_t   seq;         /* 32 + 4    = 36 */
 
 }; /* fits one cacheline */
 
@@ -73,14 +73,14 @@ __always_inline void cyc2ns_read_begin(struct cyc2ns_data *data)
        preempt_disable_notrace();
 
        do {
-               seq = this_cpu_read(cyc2ns.seq.sequence);
+               seq = this_cpu_read(cyc2ns.seq.seqcount.sequence);
                idx = seq & 1;
 
                data->cyc2ns_offset = this_cpu_read(cyc2ns.data[idx].cyc2ns_offset);
                data->cyc2ns_mul    = this_cpu_read(cyc2ns.data[idx].cyc2ns_mul);
                data->cyc2ns_shift  = this_cpu_read(cyc2ns.data[idx].cyc2ns_shift);
 
-       } while (unlikely(seq != this_cpu_read(cyc2ns.seq.sequence)));
+       } while (unlikely(seq != this_cpu_read(cyc2ns.seq.seqcount.sequence)));
 }
 
 __always_inline void cyc2ns_read_end(void)
@@ -186,7 +186,7 @@ static void __init cyc2ns_init_boot_cpu(void)
 {
        struct cyc2ns *c2n = this_cpu_ptr(&cyc2ns);
 
-       seqcount_init(&c2n->seq);
+       seqcount_latch_init(&c2n->seq);
        __set_cyc2ns_scale(tsc_khz, smp_processor_id(), rdtsc());
 }
 
@@ -203,7 +203,7 @@ static void __init cyc2ns_init_secondary_cpus(void)
 
        for_each_possible_cpu(cpu) {
                if (cpu != this_cpu) {
-                       seqcount_init(&c2n->seq);
+                       seqcount_latch_init(&c2n->seq);
                        c2n = per_cpu_ptr(&cyc2ns, cpu);
                        c2n->data[0] = data[0];
                        c2n->data[1] = data[1];
index 8d5cbe1..2c304fd 100644 (file)
  * value that, lies close to the top of the kernel memory. The limit for the GDT
  * and the IDT are set to zero.
  *
- * Given that SLDT and STR are not commonly used in programs that run on WineHQ
- * or DOSEMU2, they are not emulated.
- *
- * The instruction smsw is emulated to return the value that the register CR0
+ * The instruction SMSW is emulated to return the value that the register CR0
  * has at boot time as set in the head_32.
+ * SLDT and STR are emulated to return the values that the kernel programmatically
+ * assigns:
+ * - SLDT returns (GDT_ENTRY_LDT * 8) if an LDT has been set, 0 if not.
+ * - STR returns (GDT_ENTRY_TSS * 8).
  *
  * Emulation is provided for both 32-bit and 64-bit processes.
  *
@@ -244,16 +245,34 @@ static int emulate_umip_insn(struct insn *insn, int umip_inst,
                *data_size += UMIP_GDT_IDT_LIMIT_SIZE;
                memcpy(data, &dummy_limit, UMIP_GDT_IDT_LIMIT_SIZE);
 
-       } else if (umip_inst == UMIP_INST_SMSW) {
-               unsigned long dummy_value = CR0_STATE;
+       } else if (umip_inst == UMIP_INST_SMSW || umip_inst == UMIP_INST_SLDT ||
+                  umip_inst == UMIP_INST_STR) {
+               unsigned long dummy_value;
+
+               if (umip_inst == UMIP_INST_SMSW) {
+                       dummy_value = CR0_STATE;
+               } else if (umip_inst == UMIP_INST_STR) {
+                       dummy_value = GDT_ENTRY_TSS * 8;
+               } else if (umip_inst == UMIP_INST_SLDT) {
+#ifdef CONFIG_MODIFY_LDT_SYSCALL
+                       down_read(&current->mm->context.ldt_usr_sem);
+                       if (current->mm->context.ldt)
+                               dummy_value = GDT_ENTRY_LDT * 8;
+                       else
+                               dummy_value = 0;
+                       up_read(&current->mm->context.ldt_usr_sem);
+#else
+                       dummy_value = 0;
+#endif
+               }
 
                /*
-                * Even though the CR0 register has 4 bytes, the number
+                * For these 3 instructions, the number
                 * of bytes to be copied in the result buffer is determined
                 * by whether the operand is a register or a memory location.
                 * If operand is a register, return as many bytes as the operand
                 * size. If operand is memory, return only the two least
-                * siginificant bytes of CR0.
+                * siginificant bytes.
                 */
                if (X86_MODRM_MOD(insn->modrm.value) == 3)
                        *data_size = insn->opnd_bytes;
@@ -261,7 +280,6 @@ static int emulate_umip_insn(struct insn *insn, int umip_inst,
                        *data_size = 2;
 
                memcpy(data, &dummy_value, *data_size);
-       /* STR and SLDT  are not emulated */
        } else {
                return -EINVAL;
        }
@@ -383,10 +401,6 @@ bool fixup_umip_exception(struct pt_regs *regs)
        umip_pr_warn(regs, "%s instruction cannot be used by applications.\n",
                        umip_insns[umip_inst]);
 
-       /* Do not emulate (spoof) SLDT or STR. */
-       if (umip_inst == UMIP_INST_STR || umip_inst == UMIP_INST_SLDT)
-               return false;
-
        umip_pr_warn(regs, "For now, expensive software emulation returns the result.\n");
 
        if (emulate_umip_insn(&insn, umip_inst, dummy_data, &dummy_data_size,
index 15e5aad..3fdaa04 100644 (file)
@@ -735,7 +735,7 @@ static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
                 * OPCODE1() of the "short" jmp which checks the same condition.
                 */
                opc1 = OPCODE2(insn) - 0x10;
-               /* fall through */
+               fallthrough;
        default:
                if (!is_cond_jmp_opcode(opc1))
                        return -ENOSYS;
@@ -892,7 +892,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
                        fix_ip_or_call = 0;
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                riprel_analyze(auprobe, &insn);
        }
index 9a03e5b..bf9e0ad 100644 (file)
@@ -136,6 +136,7 @@ SECTIONS
                ENTRY_TEXT
                ALIGN_ENTRY_TEXT_END
                SOFTIRQENTRY_TEXT
+               STATIC_CALL_TEXT
                *(.fixup)
                *(.gnu.warning)
 
@@ -411,10 +412,47 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+       ELF_DETAILS
 
        DISCARDS
-}
 
+       /*
+        * Make sure that the .got.plt is either completely empty or it
+        * contains only the lazy dispatch entries.
+        */
+       .got.plt (INFO) : { *(.got.plt) }
+       ASSERT(SIZEOF(.got.plt) == 0 ||
+#ifdef CONFIG_X86_64
+              SIZEOF(.got.plt) == 0x18,
+#else
+              SIZEOF(.got.plt) == 0xc,
+#endif
+              "Unexpected GOT/PLT entries detected!")
+
+       /*
+        * Sections that should stay zero sized, which is safer to
+        * explicitly check instead of blindly discarding.
+        */
+       .got : {
+               *(.got) *(.igot.*)
+       }
+       ASSERT(SIZEOF(.got) == 0, "Unexpected GOT entries detected!")
+
+       .plt : {
+               *(.plt) *(.plt.*) *(.iplt)
+       }
+       ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!")
+
+       .rel.dyn : {
+               *(.rel.*) *(.rel_*)
+       }
+       ASSERT(SIZEOF(.rel.dyn) == 0, "Unexpected run-time relocations (.rel) detected!")
+
+       .rela.dyn : {
+               *(.rela.*) *(.rela_*)
+       }
+       ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!")
+}
 
 #ifdef CONFIG_X86_32
 /*
index 123f1c1..a3038d8 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/tsc.h>
 #include <asm/iommu.h>
 #include <asm/mach_traps.h>
+#include <asm/irqdomain.h>
 
 void x86_init_noop(void) { }
 void __init x86_init_uint_noop(unsigned int unused) { }
@@ -67,11 +68,7 @@ struct x86_init_ops x86_init __initdata = {
        },
 
        .mpparse = {
-               .mpc_record             = x86_init_uint_noop,
                .setup_ioapic_ids       = x86_init_noop,
-               .mpc_apic_id            = default_mpc_apic_id,
-               .smp_read_mpc_oem       = default_smp_read_mpc_oem,
-               .mpc_oem_bus_info       = default_mpc_oem_bus_info,
                .find_smp_config        = default_find_smp_config,
                .get_smp_config         = default_get_smp_config,
        },
@@ -80,7 +77,8 @@ struct x86_init_ops x86_init __initdata = {
                .pre_vector_init        = init_ISA_irqs,
                .intr_init              = native_init_IRQ,
                .intr_mode_select       = apic_intr_mode_select,
-               .intr_mode_init         = apic_intr_mode_init
+               .intr_mode_init         = apic_intr_mode_init,
+               .create_pci_msi_domain  = native_create_pci_msi_domain,
        },
 
        .oem = {
@@ -148,28 +146,10 @@ EXPORT_SYMBOL_GPL(x86_platform);
 
 #if defined(CONFIG_PCI_MSI)
 struct x86_msi_ops x86_msi __ro_after_init = {
-       .setup_msi_irqs         = native_setup_msi_irqs,
-       .teardown_msi_irq       = native_teardown_msi_irq,
-       .teardown_msi_irqs      = default_teardown_msi_irqs,
        .restore_msi_irqs       = default_restore_msi_irqs,
 };
 
 /* MSI arch specific hooks */
-int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
-{
-       return x86_msi.setup_msi_irqs(dev, nvec, type);
-}
-
-void arch_teardown_msi_irqs(struct pci_dev *dev)
-{
-       x86_msi.teardown_msi_irqs(dev);
-}
-
-void arch_teardown_msi_irq(unsigned int irq)
-{
-       x86_msi.teardown_msi_irq(irq);
-}
-
 void arch_restore_msi_irqs(struct pci_dev *dev)
 {
        x86_msi.restore_msi_irqs(dev);
index 3fd6eec..7456f9a 100644 (file)
@@ -371,7 +371,7 @@ void kvm_set_cpu_caps(void)
                F(AVX512_4VNNIW) | F(AVX512_4FMAPS) | F(SPEC_CTRL) |
                F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES) | F(INTEL_STIBP) |
                F(MD_CLEAR) | F(AVX512_VP2INTERSECT) | F(FSRM) |
-               F(SERIALIZE)
+               F(SERIALIZE) | F(TSXLDTRK)
        );
 
        /* TSC_ADJUST and ARCH_CAPABILITIES are emulated in software. */
index d0e2825..2f6510d 100644 (file)
@@ -2505,9 +2505,14 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt,
                *reg_write(ctxt, i) = GET_SMSTATE(u32, smstate, 0x7fd0 + i * 4);
 
        val = GET_SMSTATE(u32, smstate, 0x7fcc);
-       ctxt->ops->set_dr(ctxt, 6, (val & DR6_VOLATILE) | DR6_FIXED_1);
+
+       if (ctxt->ops->set_dr(ctxt, 6, (val & DR6_VOLATILE) | DR6_FIXED_1))
+               return X86EMUL_UNHANDLEABLE;
+
        val = GET_SMSTATE(u32, smstate, 0x7fc8);
-       ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1);
+
+       if (ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1))
+               return X86EMUL_UNHANDLEABLE;
 
        selector =                 GET_SMSTATE(u32, smstate, 0x7fc4);
        set_desc_base(&desc,       GET_SMSTATE(u32, smstate, 0x7f64));
@@ -2560,16 +2565,23 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt,
        ctxt->eflags = GET_SMSTATE(u32, smstate, 0x7f70) | X86_EFLAGS_FIXED;
 
        val = GET_SMSTATE(u32, smstate, 0x7f68);
-       ctxt->ops->set_dr(ctxt, 6, (val & DR6_VOLATILE) | DR6_FIXED_1);
+
+       if (ctxt->ops->set_dr(ctxt, 6, (val & DR6_VOLATILE) | DR6_FIXED_1))
+               return X86EMUL_UNHANDLEABLE;
+
        val = GET_SMSTATE(u32, smstate, 0x7f60);
-       ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1);
+
+       if (ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1))
+               return X86EMUL_UNHANDLEABLE;
 
        cr0 =                       GET_SMSTATE(u64, smstate, 0x7f58);
        cr3 =                       GET_SMSTATE(u64, smstate, 0x7f50);
        cr4 =                       GET_SMSTATE(u64, smstate, 0x7f48);
        ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smstate, 0x7f00));
        val =                       GET_SMSTATE(u64, smstate, 0x7ed0);
-       ctxt->ops->set_msr(ctxt, MSR_EFER, val & ~EFER_LMA);
+
+       if (ctxt->ops->set_msr(ctxt, MSR_EFER, val & ~EFER_LMA))
+               return X86EMUL_UNHANDLEABLE;
 
        selector =                  GET_SMSTATE(u32, smstate, 0x7e90);
        rsm_set_desc_flags(&desc,   GET_SMSTATE(u32, smstate, 0x7e92) << 8);
@@ -3016,7 +3028,7 @@ static void string_registers_quirk(struct x86_emulate_ctxt *ctxt)
        case 0xa4:      /* movsb */
        case 0xa5:      /* movsd/w */
                *reg_rmw(ctxt, VCPU_REGS_RSI) &= (u32)-1;
-               /* fall through */
+               fallthrough;
        case 0xaa:      /* stosb */
        case 0xab:      /* stosd/w */
                *reg_rmw(ctxt, VCPU_REGS_RDI) &= (u32)-1;
index 814d3ae..8c1e833 100644 (file)
@@ -1779,7 +1779,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
                ret = kvm_hvcall_signal_event(vcpu, fast, ingpa);
                if (ret != HV_STATUS_INVALID_PORT_ID)
                        break;
-               /* fall through - maybe userspace knows this conn_id. */
+               fallthrough;    /* maybe userspace knows this conn_id */
        case HVCALL_POST_MESSAGE:
                /* don't bother userspace if it has no way to handle it */
                if (unlikely(rep || !vcpu_to_synic(vcpu)->active)) {
@@ -2000,20 +2000,20 @@ int kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
                        break;
 
                case HYPERV_CPUID_FEATURES:
-                       ent->eax |= HV_X64_MSR_VP_RUNTIME_AVAILABLE;
+                       ent->eax |= HV_MSR_VP_RUNTIME_AVAILABLE;
                        ent->eax |= HV_MSR_TIME_REF_COUNT_AVAILABLE;
-                       ent->eax |= HV_X64_MSR_SYNIC_AVAILABLE;
+                       ent->eax |= HV_MSR_SYNIC_AVAILABLE;
                        ent->eax |= HV_MSR_SYNTIMER_AVAILABLE;
-                       ent->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
-                       ent->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
-                       ent->eax |= HV_X64_MSR_VP_INDEX_AVAILABLE;
-                       ent->eax |= HV_X64_MSR_RESET_AVAILABLE;
+                       ent->eax |= HV_MSR_APIC_ACCESS_AVAILABLE;
+                       ent->eax |= HV_MSR_HYPERCALL_AVAILABLE;
+                       ent->eax |= HV_MSR_VP_INDEX_AVAILABLE;
+                       ent->eax |= HV_MSR_RESET_AVAILABLE;
                        ent->eax |= HV_MSR_REFERENCE_TSC_AVAILABLE;
-                       ent->eax |= HV_X64_ACCESS_FREQUENCY_MSRS;
-                       ent->eax |= HV_X64_ACCESS_REENLIGHTENMENT;
+                       ent->eax |= HV_ACCESS_FREQUENCY_MSRS;
+                       ent->eax |= HV_ACCESS_REENLIGHTENMENT;
 
-                       ent->ebx |= HV_X64_POST_MESSAGES;
-                       ent->ebx |= HV_X64_SIGNAL_EVENTS;
+                       ent->ebx |= HV_POST_MESSAGES;
+                       ent->ebx |= HV_SIGNAL_EVENTS;
 
                        ent->edx |= HV_FEATURE_FREQUENCY_MSRS_AVAILABLE;
                        ent->edx |= HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE;
index c47d2ac..4aa1c2e 100644 (file)
@@ -285,7 +285,7 @@ int kvm_set_routing_entry(struct kvm *kvm,
                switch (ue->u.irqchip.irqchip) {
                case KVM_IRQCHIP_PIC_SLAVE:
                        e->irqchip.pin += PIC_NUM_PINS / 2;
-                       /* fall through */
+                       fallthrough;
                case KVM_IRQCHIP_PIC_MASTER:
                        if (ue->u.irqchip.pin >= PIC_NUM_PINS / 2)
                                return -EINVAL;
index 5ccbee7..35cca2e 100644 (file)
@@ -1053,7 +1053,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
        switch (delivery_mode) {
        case APIC_DM_LOWEST:
                vcpu->arch.apic_arb_prio++;
-               /* fall through */
+               fallthrough;
        case APIC_DM_FIXED:
                if (unlikely(trig_mode && !level))
                        break;
@@ -1341,7 +1341,7 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
                break;
        case APIC_TASKPRI:
                report_tpr_access(apic, false);
-               /* fall thru */
+               fallthrough;
        default:
                val = kvm_lapic_get_reg(apic, offset);
                break;
@@ -2027,7 +2027,7 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
        case APIC_LVT0:
                apic_manage_nmi_watchdog(apic, val);
-               /* fall through */
+               fallthrough;
        case APIC_LVTTHMR:
        case APIC_LVTPC:
        case APIC_LVT1:
index a5d0207..71aa3da 100644 (file)
@@ -2469,7 +2469,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                }
 
                if (sp->unsync_children)
-                       kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
+                       kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
 
                __clear_sp_write_flooding_count(sp);
 
@@ -4422,7 +4422,7 @@ __reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
                        rsvd_bits(maxphyaddr, 51);
                rsvd_check->rsvd_bits_mask[1][4] =
                        rsvd_check->rsvd_bits_mask[0][4];
-               /* fall through */
+               fallthrough;
        case PT64_ROOT_4LEVEL:
                rsvd_check->rsvd_bits_mask[0][3] = exb_bit_rsvd |
                        nonleaf_bit8_rsvd | rsvd_bits(7, 7) |
index fb68467..e90bc43 100644 (file)
@@ -586,7 +586,6 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
        svm->vcpu.arch.mp_state = KVM_MP_STATE_RUNNABLE;
 
        /* Give the current vmcb to the guest */
-       svm_set_gif(svm, false);
 
        nested_vmcb->save.es     = vmcb->save.es;
        nested_vmcb->save.cs     = vmcb->save.cs;
@@ -632,6 +631,9 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
        /* Restore the original control entries */
        copy_vmcb_control_area(&vmcb->control, &hsave->control);
 
+       /* On vmexit the  GIF is set to false */
+       svm_set_gif(svm, false);
+
        svm->vmcb->control.tsc_offset = svm->vcpu.arch.tsc_offset =
                svm->vcpu.arch.l1_tsc_offset;
 
@@ -1132,6 +1134,9 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
        load_nested_vmcb_control(svm, &ctl);
        nested_prepare_vmcb_control(svm);
 
+       if (!nested_svm_vmrun_msrpm(svm))
+               return -EINVAL;
+
 out_set_gif:
        svm_set_gif(svm, !!(kvm_state->flags & KVM_STATE_NESTED_GIF_SET));
        return 0;
index 402dc42..3c9a45e 100644 (file)
@@ -384,7 +384,8 @@ static void sev_clflush_pages(struct page *pages[], unsigned long npages)
        uint8_t *page_virtual;
        unsigned long i;
 
-       if (npages == 0 || pages == NULL)
+       if (this_cpu_has(X86_FEATURE_SME_COHERENT) || npages == 0 ||
+           pages == NULL)
                return;
 
        for (i = 0; i < npages; i++) {
@@ -1106,6 +1107,7 @@ void sev_vm_destroy(struct kvm *kvm)
                list_for_each_safe(pos, q, head) {
                        __unregister_enc_region_locked(kvm,
                                list_entry(pos, struct enc_region, list));
+                       cond_resched();
                }
        }
 
index 03dd7ba..91ea74a 100644 (file)
@@ -2183,6 +2183,12 @@ static int iret_interception(struct vcpu_svm *svm)
        return 1;
 }
 
+static int invd_interception(struct vcpu_svm *svm)
+{
+       /* Treat an INVD instruction as a NOP and just skip it. */
+       return kvm_skip_emulated_instruction(&svm->vcpu);
+}
+
 static int invlpg_interception(struct vcpu_svm *svm)
 {
        if (!static_cpu_has(X86_FEATURE_DECODEASSISTS))
@@ -2668,7 +2674,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
        case MSR_IA32_APICBASE:
                if (kvm_vcpu_apicv_active(vcpu))
                        avic_update_vapic_bar(to_svm(vcpu), data);
-               /* Fall through */
+               fallthrough;
        default:
                return kvm_set_msr_common(vcpu, msr);
        }
@@ -2774,7 +2780,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
        [SVM_EXIT_RDPMC]                        = rdpmc_interception,
        [SVM_EXIT_CPUID]                        = cpuid_interception,
        [SVM_EXIT_IRET]                         = iret_interception,
-       [SVM_EXIT_INVD]                         = emulate_on_interception,
+       [SVM_EXIT_INVD]                         = invd_interception,
        [SVM_EXIT_PAUSE]                        = pause_interception,
        [SVM_EXIT_HLT]                          = halt_interception,
        [SVM_EXIT_INVLPG]                       = invlpg_interception,
@@ -2938,8 +2944,6 @@ static int handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
        if (npt_enabled)
                vcpu->arch.cr3 = svm->vmcb->save.cr3;
 
-       svm_complete_interrupts(svm);
-
        if (is_guest_mode(vcpu)) {
                int vmexit;
 
@@ -3504,7 +3508,6 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
        stgi();
 
        /* Any pending NMI will happen here */
-       exit_fastpath = svm_exit_handlers_fastpath(vcpu);
 
        if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
                kvm_after_interrupt(&svm->vcpu);
@@ -3518,6 +3521,7 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
        }
 
        svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
+       vmcb_mark_all_clean(svm->vmcb);
 
        /* if exit due to PF check for async PF */
        if (svm->vmcb->control.exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR)
@@ -3537,7 +3541,8 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
                     SVM_EXIT_EXCP_BASE + MC_VECTOR))
                svm_handle_mce(svm);
 
-       vmcb_mark_all_clean(svm->vmcb);
+       svm_complete_interrupts(svm);
+       exit_fastpath = svm_exit_handlers_fastpath(vcpu);
        return exit_fastpath;
 }
 
@@ -3900,21 +3905,28 @@ static int svm_pre_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
 static int svm_pre_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
-       struct vmcb *nested_vmcb;
        struct kvm_host_map map;
-       u64 guest;
-       u64 vmcb;
        int ret = 0;
 
-       guest = GET_SMSTATE(u64, smstate, 0x7ed8);
-       vmcb = GET_SMSTATE(u64, smstate, 0x7ee0);
+       if (guest_cpuid_has(vcpu, X86_FEATURE_LM)) {
+               u64 saved_efer = GET_SMSTATE(u64, smstate, 0x7ed0);
+               u64 guest = GET_SMSTATE(u64, smstate, 0x7ed8);
+               u64 vmcb = GET_SMSTATE(u64, smstate, 0x7ee0);
 
-       if (guest) {
-               if (kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb), &map) == -EINVAL)
-                       return 1;
-               nested_vmcb = map.hva;
-               ret = enter_svm_guest_mode(svm, vmcb, nested_vmcb);
-               kvm_vcpu_unmap(&svm->vcpu, &map, true);
+               if (guest) {
+                       if (!guest_cpuid_has(vcpu, X86_FEATURE_SVM))
+                               return 1;
+
+                       if (!(saved_efer & EFER_SVME))
+                               return 1;
+
+                       if (kvm_vcpu_map(&svm->vcpu,
+                                        gpa_to_gfn(vmcb), &map) == -EINVAL)
+                               return 1;
+
+                       ret = enter_svm_guest_mode(svm, vmcb, map.hva);
+                       kvm_vcpu_unmap(&svm->vcpu, &map, true);
+               }
        }
 
        return ret;
index 23b58c2..1bb6b31 100644 (file)
@@ -4404,6 +4404,14 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
        if (kvm_check_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu))
                kvm_vcpu_flush_tlb_current(vcpu);
 
+       /*
+        * VCPU_EXREG_PDPTR will be clobbered in arch/x86/kvm/vmx/vmx.h between
+        * now and the new vmentry.  Ensure that the VMCS02 PDPTR fields are
+        * up-to-date before switching to L1.
+        */
+       if (enable_ept && is_pae_paging(vcpu))
+               vmx_ept_load_pdptrs(vcpu);
+
        leave_guest_mode(vcpu);
 
        if (nested_cpu_has_preemption_timer(vmcs12))
@@ -4668,7 +4676,7 @@ void nested_vmx_pmu_entry_exit_ctls_update(struct kvm_vcpu *vcpu)
                vmx->nested.msrs.entry_ctls_high &=
                                ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL;
                vmx->nested.msrs.exit_ctls_high &=
-                               ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL;
+                               ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL;
        }
 }
 
index 46ba2e0..96979c0 100644 (file)
@@ -129,6 +129,9 @@ static bool __read_mostly enable_preemption_timer = 1;
 module_param_named(preemption_timer, enable_preemption_timer, bool, S_IRUGO);
 #endif
 
+extern bool __read_mostly allow_smaller_maxphyaddr;
+module_param(allow_smaller_maxphyaddr, bool, S_IRUGO);
+
 #define KVM_VM_CR0_ALWAYS_OFF (X86_CR0_NW | X86_CR0_CD)
 #define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST X86_CR0_NE
 #define KVM_VM_CR0_ALWAYS_ON                           \
@@ -791,6 +794,18 @@ void update_exception_bitmap(struct kvm_vcpu *vcpu)
         */
        if (is_guest_mode(vcpu))
                eb |= get_vmcs12(vcpu)->exception_bitmap;
+        else {
+               /*
+                * If EPT is enabled, #PF is only trapped if MAXPHYADDR is mismatched
+                * between guest and host.  In that case we only care about present
+                * faults.  For vmcs02, however, PFEC_MASK and PFEC_MATCH are set in
+                * prepare_vmcs02_rare.
+                */
+               bool selective_pf_trap = enable_ept && (eb & (1u << PF_VECTOR));
+               int mask = selective_pf_trap ? PFERR_PRESENT_MASK : 0;
+               vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, mask);
+               vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, mask);
+       }
 
        vmcs_write32(EXCEPTION_BITMAP, eb);
 }
@@ -2971,7 +2986,7 @@ static void vmx_flush_tlb_guest(struct kvm_vcpu *vcpu)
        vpid_sync_context(to_vmx(vcpu)->vpid);
 }
 
-static void ept_load_pdptrs(struct kvm_vcpu *vcpu)
+void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu)
 {
        struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
 
@@ -3114,7 +3129,7 @@ static void vmx_load_mmu_pgd(struct kvm_vcpu *vcpu, unsigned long pgd,
                        guest_cr3 = vcpu->arch.cr3;
                else /* vmcs01.GUEST_CR3 is already up-to-date. */
                        update_guest_cr3 = false;
-               ept_load_pdptrs(vcpu);
+               vmx_ept_load_pdptrs(vcpu);
        } else {
                guest_cr3 = pgd;
        }
@@ -4352,16 +4367,6 @@ static void init_vmcs(struct vcpu_vmx *vmx)
                vmx->pt_desc.guest.output_mask = 0x7F;
                vmcs_write64(GUEST_IA32_RTIT_CTL, 0);
        }
-
-       /*
-        * If EPT is enabled, #PF is only trapped if MAXPHYADDR is mismatched
-        * between guest and host.  In that case we only care about present
-        * faults.
-        */
-       if (enable_ept) {
-               vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, PFERR_PRESENT_MASK);
-               vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, PFERR_PRESENT_MASK);
-       }
 }
 
 static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
@@ -4654,7 +4659,7 @@ static bool rmode_exception(struct kvm_vcpu *vcpu, int vec)
                        vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
                if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
                        return false;
-               /* fall through */
+               fallthrough;
        case DB_VECTOR:
                return !(vcpu->guest_debug &
                        (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP));
@@ -4803,6 +4808,7 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
                         * EPT will cause page fault only if we need to
                         * detect illegal GPAs.
                         */
+                       WARN_ON_ONCE(!allow_smaller_maxphyaddr);
                        kvm_fixup_and_inject_pf_error(vcpu, cr2, error_code);
                        return 1;
                } else
@@ -4827,7 +4833,7 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
                }
                kvm_run->debug.arch.dr6 = dr6 | DR6_FIXED_1 | DR6_RTM;
                kvm_run->debug.arch.dr7 = vmcs_readl(GUEST_DR7);
-               /* fall through */
+               fallthrough;
        case BP_VECTOR:
                /*
                 * Update instruction length as we may reinject #BP from
@@ -5257,7 +5263,7 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
                                error_code =
                                        vmcs_read32(IDT_VECTORING_ERROR_CODE);
                        }
-                       /* fall through */
+                       fallthrough;
                case INTR_TYPE_SOFT_EXCEPTION:
                        kvm_clear_exception_queue(vcpu);
                        break;
@@ -5331,7 +5337,7 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu)
         * would also use advanced VM-exit information for EPT violations to
         * reconstruct the page fault error code.
         */
-       if (unlikely(kvm_mmu_is_illegal_gpa(vcpu, gpa)))
+       if (unlikely(allow_smaller_maxphyaddr && kvm_mmu_is_illegal_gpa(vcpu, gpa)))
                return kvm_emulate_instruction(vcpu, 0);
 
        return kvm_mmu_page_fault(vcpu, gpa, error_code, NULL, 0);
@@ -5610,7 +5616,7 @@ static int handle_invpcid(struct kvm_vcpu *vcpu)
                 * keeping track of global entries in shadow page tables.
                 */
 
-               /* fall-through */
+               fallthrough;
        case INVPCID_TYPE_ALL_INCL_GLOBAL:
                kvm_mmu_unload(vcpu);
                return kvm_skip_emulated_instruction(vcpu);
@@ -6054,6 +6060,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
                        (exit_reason != EXIT_REASON_EXCEPTION_NMI &&
                        exit_reason != EXIT_REASON_EPT_VIOLATION &&
                        exit_reason != EXIT_REASON_PML_FULL &&
+                       exit_reason != EXIT_REASON_APIC_ACCESS &&
                        exit_reason != EXIT_REASON_TASK_SWITCH)) {
                vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_DELIVERY_EV;
@@ -6578,7 +6585,7 @@ static void __vmx_complete_interrupts(struct kvm_vcpu *vcpu,
                break;
        case INTR_TYPE_SOFT_EXCEPTION:
                vcpu->arch.event_exit_inst_len = vmcs_read32(instr_len_field);
-               /* fall through */
+               fallthrough;
        case INTR_TYPE_HARD_EXCEPTION:
                if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) {
                        u32 err = vmcs_read32(error_code_field);
@@ -6588,7 +6595,7 @@ static void __vmx_complete_interrupts(struct kvm_vcpu *vcpu,
                break;
        case INTR_TYPE_SOFT_INTR:
                vcpu->arch.event_exit_inst_len = vmcs_read32(instr_len_field);
-               /* fall through */
+               fallthrough;
        case INTR_TYPE_EXT_INTR:
                kvm_queue_interrupt(vcpu, vector, type == INTR_TYPE_SOFT_INTR);
                break;
@@ -8304,11 +8311,12 @@ static int __init vmx_init(void)
        vmx_check_vmcs12_offsets();
 
        /*
-        * Intel processors don't have problems with
-        * GUEST_MAXPHYADDR < HOST_MAXPHYADDR so enable
-        * it for VMX by default
+        * Shadow paging doesn't have a (further) performance penalty
+        * from GUEST_MAXPHYADDR < HOST_MAXPHYADDR so enable it
+        * by default
         */
-       allow_smaller_maxphyaddr = true;
+       if (!enable_ept)
+               allow_smaller_maxphyaddr = true;
 
        return 0;
 }
index 26175a4..a0e4772 100644 (file)
@@ -356,6 +356,7 @@ void vmx_update_host_rsp(struct vcpu_vmx *vmx, unsigned long host_rsp);
 int vmx_find_msr_index(struct vmx_msrs *m, u32 msr);
 int vmx_handle_memory_failure(struct kvm_vcpu *vcpu, int r,
                              struct x86_exception *e);
+void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu);
 
 #define POSTED_INTR_ON  0
 #define POSTED_INTR_SN  1
@@ -551,7 +552,10 @@ static inline bool vmx_has_waitpkg(struct vcpu_vmx *vmx)
 
 static inline bool vmx_need_pf_intercept(struct kvm_vcpu *vcpu)
 {
-       return !enable_ept || cpuid_maxphyaddr(vcpu) < boot_cpu_data.x86_phys_bits;
+       if (!enable_ept)
+               return true;
+
+       return allow_smaller_maxphyaddr && cpuid_maxphyaddr(vcpu) < boot_cpu_data.x86_phys_bits;
 }
 
 void dump_vmcs(void);
index 3394528..ce856e0 100644 (file)
@@ -188,7 +188,7 @@ static struct kvm_shared_msrs __percpu *shared_msrs;
 u64 __read_mostly host_efer;
 EXPORT_SYMBOL_GPL(host_efer);
 
-bool __read_mostly allow_smaller_maxphyaddr;
+bool __read_mostly allow_smaller_maxphyaddr = 0;
 EXPORT_SYMBOL_GPL(allow_smaller_maxphyaddr);
 
 static u64 __read_mostly host_xss;
@@ -976,6 +976,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
        unsigned long old_cr4 = kvm_read_cr4(vcpu);
        unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE |
                                   X86_CR4_SMEP;
+       unsigned long mmu_role_bits = pdptr_bits | X86_CR4_SMAP | X86_CR4_PKE;
 
        if (kvm_valid_cr4(vcpu, cr4))
                return 1;
@@ -1003,7 +1004,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
        if (kvm_x86_ops.set_cr4(vcpu, cr4))
                return 1;
 
-       if (((cr4 ^ old_cr4) & pdptr_bits) ||
+       if (((cr4 ^ old_cr4) & mmu_role_bits) ||
            (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
                kvm_mmu_reset_context(vcpu);
 
@@ -1116,14 +1117,12 @@ static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
                        vcpu->arch.eff_db[dr] = val;
                break;
        case 4:
-               /* fall through */
        case 6:
                if (!kvm_dr6_valid(val))
                        return -1; /* #GP */
                vcpu->arch.dr6 = (val & DR6_VOLATILE) | kvm_dr6_fixed(vcpu);
                break;
        case 5:
-               /* fall through */
        default: /* 7 */
                if (!kvm_dr7_valid(val))
                        return -1; /* #GP */
@@ -1154,12 +1153,10 @@ int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
                *val = vcpu->arch.db[array_index_nospec(dr, size)];
                break;
        case 4:
-               /* fall through */
        case 6:
                *val = vcpu->arch.dr6;
                break;
        case 5:
-               /* fall through */
        default: /* 7 */
                *val = vcpu->arch.dr7;
                break;
@@ -2735,7 +2732,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
                return 1;
 
        if (!lapic_in_kernel(vcpu))
-               return 1;
+               return data ? 1 : 0;
 
        vcpu->arch.apf.msr_en_val = data;
 
@@ -3051,7 +3048,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
        case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3:
        case MSR_P6_PERFCTR0 ... MSR_P6_PERFCTR1:
-               pr = true; /* fall through */
+               pr = true;
+               fallthrough;
        case MSR_K7_EVNTSEL0 ... MSR_K7_EVNTSEL3:
        case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL1:
                if (kvm_pmu_is_valid_msr(vcpu, msr))
@@ -3224,9 +3222,22 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_IA32_POWER_CTL:
                msr_info->data = vcpu->arch.msr_ia32_power_ctl;
                break;
-       case MSR_IA32_TSC:
-               msr_info->data = kvm_scale_tsc(vcpu, rdtsc()) + vcpu->arch.tsc_offset;
+       case MSR_IA32_TSC: {
+               /*
+                * Intel SDM states that MSR_IA32_TSC read adds the TSC offset
+                * even when not intercepted. AMD manual doesn't explicitly
+                * state this but appears to behave the same.
+                *
+                * On userspace reads and writes, however, we unconditionally
+                * operate L1's TSC value to ensure backwards-compatible
+                * behavior for migration.
+                */
+               u64 tsc_offset = msr_info->host_initiated ? vcpu->arch.l1_tsc_offset :
+                                                           vcpu->arch.tsc_offset;
+
+               msr_info->data = kvm_scale_tsc(vcpu, rdtsc()) + tsc_offset;
                break;
+       }
        case MSR_MTRRcap:
        case 0x200 ... 0x2ff:
                return kvm_mtrr_get_msr(vcpu, msr_info->index, &msr_info->data);
@@ -3581,6 +3592,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_SMALLER_MAXPHYADDR:
                r = (int) allow_smaller_maxphyaddr;
                break;
+       case KVM_CAP_STEAL_TIME:
+               r = sched_info_on();
+               break;
        default:
                break;
        }
@@ -4359,7 +4373,7 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
        case KVM_CAP_HYPERV_SYNIC2:
                if (cap->args[0])
                        return -EINVAL;
-               /* fall through */
+               fallthrough;
 
        case KVM_CAP_HYPERV_SYNIC:
                if (!irqchip_in_kernel(vcpu->kvm))
@@ -8672,7 +8686,7 @@ static inline int vcpu_block(struct kvm *kvm, struct kvm_vcpu *vcpu)
                vcpu->arch.pv.pv_unhalted = false;
                vcpu->arch.mp_state =
                        KVM_MP_STATE_RUNNABLE;
-               /* fall through */
+               fallthrough;
        case KVM_MP_STATE_RUNNABLE:
                vcpu->arch.apf.halted = false;
                break;
index d46fff1..bad4dee 100644 (file)
@@ -24,7 +24,7 @@ ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_cmdline.o = -pg
 endif
 
-CFLAGS_cmdline.o := -fno-stack-protector
+CFLAGS_cmdline.o := -fno-stack-protector -fno-jump-tables
 endif
 
 inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
@@ -44,6 +44,7 @@ obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
 lib-y := delay.o misc.o cmdline.o cpu.o
 lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
+lib-$(CONFIG_ARCH_HAS_COPY_MC) += copy_mc.o copy_mc_64.o
 lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o insn-eval.o
 lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
 lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
index d1d7689..4304320 100644 (file)
@@ -253,28 +253,17 @@ EXPORT_SYMBOL(csum_partial)
 
 /*
 unsigned int csum_partial_copy_generic (const char *src, char *dst,
-                                 int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+                                 int len)
  */ 
 
 /*
  * Copy from ds while checksumming, otherwise like csum_partial
- *
- * The macros SRC and DST specify the type of access for the instruction.
- * thus we can call a custom exception handler for all access types.
- *
- * FIXME: could someone double-check whether I haven't mixed up some SRC and
- *       DST definitions? It's damn hard to trigger all cases.  I hope I got
- *       them all but there's no guarantee.
  */
 
-#define SRC(y...)                      \
+#define EXC(y...)                      \
        9999: y;                        \
        _ASM_EXTABLE_UA(9999b, 6001f)
 
-#define DST(y...)                      \
-       9999: y;                        \
-       _ASM_EXTABLE_UA(9999b, 6002f)
-
 #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
 
 #define ARGBASE 16             
@@ -285,20 +274,20 @@ SYM_FUNC_START(csum_partial_copy_generic)
        pushl %edi
        pushl %esi
        pushl %ebx
-       movl ARGBASE+16(%esp),%eax      # sum
        movl ARGBASE+12(%esp),%ecx      # len
        movl ARGBASE+4(%esp),%esi       # src
        movl ARGBASE+8(%esp),%edi       # dst
 
+       movl $-1, %eax                  # sum
        testl $2, %edi                  # Check alignment. 
        jz 2f                           # Jump if alignment is ok.
        subl $2, %ecx                   # Alignment uses up two bytes.
        jae 1f                          # Jump if we had at least two bytes.
        addl $2, %ecx                   # ecx was < 2.  Deal with it.
        jmp 4f
-SRC(1: movw (%esi), %bx        )
+EXC(1: movw (%esi), %bx        )
        addl $2, %esi
-DST(   movw %bx, (%edi)        )
+EXC(   movw %bx, (%edi)        )
        addl $2, %edi
        addw %bx, %ax   
        adcl $0, %eax
@@ -306,34 +295,34 @@ DST(      movw %bx, (%edi)        )
        movl %ecx, FP(%esp)
        shrl $5, %ecx
        jz 2f
-       testl %esi, %esi
-SRC(1: movl (%esi), %ebx       )
-SRC(   movl 4(%esi), %edx      )
+       testl %esi, %esi                # what's wrong with clc?
+EXC(1: movl (%esi), %ebx       )
+EXC(   movl 4(%esi), %edx      )
        adcl %ebx, %eax
-DST(   movl %ebx, (%edi)       )
+EXC(   movl %ebx, (%edi)       )
        adcl %edx, %eax
-DST(   movl %edx, 4(%edi)      )
+EXC(   movl %edx, 4(%edi)      )
 
-SRC(   movl 8(%esi), %ebx      )
-SRC(   movl 12(%esi), %edx     )
+EXC(   movl 8(%esi), %ebx      )
+EXC(   movl 12(%esi), %edx     )
        adcl %ebx, %eax
-DST(   movl %ebx, 8(%edi)      )
+EXC(   movl %ebx, 8(%edi)      )
        adcl %edx, %eax
-DST(   movl %edx, 12(%edi)     )
+EXC(   movl %edx, 12(%edi)     )
 
-SRC(   movl 16(%esi), %ebx     )
-SRC(   movl 20(%esi), %edx     )
+EXC(   movl 16(%esi), %ebx     )
+EXC(   movl 20(%esi), %edx     )
        adcl %ebx, %eax
-DST(   movl %ebx, 16(%edi)     )
+EXC(   movl %ebx, 16(%edi)     )
        adcl %edx, %eax
-DST(   movl %edx, 20(%edi)     )
+EXC(   movl %edx, 20(%edi)     )
 
-SRC(   movl 24(%esi), %ebx     )
-SRC(   movl 28(%esi), %edx     )
+EXC(   movl 24(%esi), %ebx     )
+EXC(   movl 28(%esi), %edx     )
        adcl %ebx, %eax
-DST(   movl %ebx, 24(%edi)     )
+EXC(   movl %ebx, 24(%edi)     )
        adcl %edx, %eax
-DST(   movl %edx, 28(%edi)     )
+EXC(   movl %edx, 28(%edi)     )
 
        lea 32(%esi), %esi
        lea 32(%edi), %edi
@@ -345,9 +334,9 @@ DST(        movl %edx, 28(%edi)     )
        andl $0x1c, %edx
        je 4f
        shrl $2, %edx                   # This clears CF
-SRC(3: movl (%esi), %ebx       )
+EXC(3: movl (%esi), %ebx       )
        adcl %ebx, %eax
-DST(   movl %ebx, (%edi)       )
+EXC(   movl %ebx, (%edi)       )
        lea 4(%esi), %esi
        lea 4(%edi), %edi
        dec %edx
@@ -357,39 +346,24 @@ DST(      movl %ebx, (%edi)       )
        jz 7f
        cmpl $2, %ecx
        jb 5f
-SRC(   movw (%esi), %cx        )
+EXC(   movw (%esi), %cx        )
        leal 2(%esi), %esi
-DST(   movw %cx, (%edi)        )
+EXC(   movw %cx, (%edi)        )
        leal 2(%edi), %edi
        je 6f
        shll $16,%ecx
-SRC(5: movb (%esi), %cl        )
-DST(   movb %cl, (%edi)        )
+EXC(5: movb (%esi), %cl        )
+EXC(   movb %cl, (%edi)        )
 6:     addl %ecx, %eax
        adcl $0, %eax
 7:
-5000:
 
 # Exception handler:
 .section .fixup, "ax"                                                  
 
 6001:
-       movl ARGBASE+20(%esp), %ebx     # src_err_ptr
-       movl $-EFAULT, (%ebx)
-
-       # zero the complete destination - computing the rest
-       # is too much work 
-       movl ARGBASE+8(%esp), %edi      # dst
-       movl ARGBASE+12(%esp), %ecx     # len
-       xorl %eax,%eax
-       rep ; stosb
-
-       jmp 5000b
-
-6002:
-       movl ARGBASE+24(%esp), %ebx     # dst_err_ptr
-       movl $-EFAULT,(%ebx)
-       jmp 5000b
+       xorl %eax, %eax
+       jmp 7b
 
 .previous
 
@@ -405,14 +379,14 @@ SYM_FUNC_END(csum_partial_copy_generic)
 /* Version for PentiumII/PPro */
 
 #define ROUND1(x) \
-       SRC(movl x(%esi), %ebx  )       ;       \
+       EXC(movl x(%esi), %ebx  )       ;       \
        addl %ebx, %eax                 ;       \
-       DST(movl %ebx, x(%edi)  )       ; 
+       EXC(movl %ebx, x(%edi)  )       ;
 
 #define ROUND(x) \
-       SRC(movl x(%esi), %ebx  )       ;       \
+       EXC(movl x(%esi), %ebx  )       ;       \
        adcl %ebx, %eax                 ;       \
-       DST(movl %ebx, x(%edi)  )       ;
+       EXC(movl %ebx, x(%edi)  )       ;
 
 #define ARGBASE 12
                
@@ -423,7 +397,7 @@ SYM_FUNC_START(csum_partial_copy_generic)
        movl ARGBASE+4(%esp),%esi       #src
        movl ARGBASE+8(%esp),%edi       #dst    
        movl ARGBASE+12(%esp),%ecx      #len
-       movl ARGBASE+16(%esp),%eax      #sum
+       movl $-1, %eax                  #sum
 #      movl %ecx, %edx  
        movl %ecx, %ebx  
        movl %esi, %edx
@@ -439,7 +413,7 @@ SYM_FUNC_START(csum_partial_copy_generic)
        JMP_NOSPEC ebx
 1:     addl $64,%esi
        addl $64,%edi 
-       SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
+       EXC(movb -32(%edx),%bl) ; EXC(movb (%edx),%bl)
        ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)    
        ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)    
        ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)    
@@ -453,29 +427,20 @@ SYM_FUNC_START(csum_partial_copy_generic)
        jz 7f
        cmpl $2, %edx
        jb 5f
-SRC(   movw (%esi), %dx         )
+EXC(   movw (%esi), %dx         )
        leal 2(%esi), %esi
-DST(   movw %dx, (%edi)         )
+EXC(   movw %dx, (%edi)         )
        leal 2(%edi), %edi
        je 6f
        shll $16,%edx
 5:
-SRC(   movb (%esi), %dl         )
-DST(   movb %dl, (%edi)         )
+EXC(   movb (%esi), %dl         )
+EXC(   movb %dl, (%edi)         )
 6:     addl %edx, %eax
        adcl $0, %eax
 7:
 .section .fixup, "ax"
-6001:  movl    ARGBASE+20(%esp), %ebx  # src_err_ptr   
-       movl $-EFAULT, (%ebx)
-       # zero the complete destination (computing the rest is too much work)
-       movl ARGBASE+8(%esp),%edi       # dst
-       movl ARGBASE+12(%esp),%ecx      # len
-       xorl %eax,%eax
-       rep; stosb
-       jmp 7b
-6002:  movl ARGBASE+24(%esp), %ebx     # dst_err_ptr
-       movl $-EFAULT, (%ebx)
+6001:  xorl %eax, %eax
        jmp  7b                 
 .previous                              
 
index 4f1719e..b6da093 100644 (file)
@@ -58,7 +58,7 @@ __cmdline_find_option_bool(const char *cmdline, int max_cmdline_size,
                        state = st_wordcmp;
                        opptr = option;
                        wstart = pos;
-                       /* fall through */
+                       fallthrough;
 
                case st_wordcmp:
                        if (!*opptr) {
@@ -89,7 +89,7 @@ __cmdline_find_option_bool(const char *cmdline, int max_cmdline_size,
                                break;
                        }
                        state = st_wordskip;
-                       /* fall through */
+                       fallthrough;
 
                case st_wordskip:
                        if (!c)
@@ -151,7 +151,7 @@ __cmdline_find_option(const char *cmdline, int max_cmdline_size,
 
                        state = st_wordcmp;
                        opptr = option;
-                       /* fall through */
+                       fallthrough;
 
                case st_wordcmp:
                        if ((c == '=') && !*opptr) {
@@ -172,7 +172,7 @@ __cmdline_find_option(const char *cmdline, int max_cmdline_size,
                                break;
                        }
                        state = st_wordskip;
-                       /* fall through */
+                       fallthrough;
 
                case st_wordskip:
                        if (myisspace(c))
diff --git a/arch/x86/lib/copy_mc.c b/arch/x86/lib/copy_mc.c
new file mode 100644 (file)
index 0000000..c13e8c9
--- /dev/null
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2016-2020 Intel Corporation. All rights reserved. */
+
+#include <linux/jump_label.h>
+#include <linux/uaccess.h>
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <asm/mce.h>
+
+#ifdef CONFIG_X86_MCE
+/*
+ * See COPY_MC_TEST for self-test of the copy_mc_fragile()
+ * implementation.
+ */
+static DEFINE_STATIC_KEY_FALSE(copy_mc_fragile_key);
+
+void enable_copy_mc_fragile(void)
+{
+       static_branch_inc(&copy_mc_fragile_key);
+}
+#define copy_mc_fragile_enabled (static_branch_unlikely(&copy_mc_fragile_key))
+
+/*
+ * Similar to copy_user_handle_tail, probe for the write fault point, or
+ * source exception point.
+ */
+__visible notrace unsigned long
+copy_mc_fragile_handle_tail(char *to, char *from, unsigned len)
+{
+       for (; len; --len, to++, from++)
+               if (copy_mc_fragile(to, from, 1))
+                       break;
+       return len;
+}
+#else
+/*
+ * No point in doing careful copying, or consulting a static key when
+ * there is no #MC handler in the CONFIG_X86_MCE=n case.
+ */
+void enable_copy_mc_fragile(void)
+{
+}
+#define copy_mc_fragile_enabled (0)
+#endif
+
+unsigned long copy_mc_enhanced_fast_string(void *dst, const void *src, unsigned len);
+
+/**
+ * copy_mc_to_kernel - memory copy that handles source exceptions
+ *
+ * @dst:       destination address
+ * @src:       source address
+ * @len:       number of bytes to copy
+ *
+ * Call into the 'fragile' version on systems that benefit from avoiding
+ * corner case poison consumption scenarios, For example, accessing
+ * poison across 2 cachelines with a single instruction. Almost all
+ * other uses case can use copy_mc_enhanced_fast_string() for a fast
+ * recoverable copy, or fallback to plain memcpy.
+ *
+ * Return 0 for success, or number of bytes not copied if there was an
+ * exception.
+ */
+unsigned long __must_check copy_mc_to_kernel(void *dst, const void *src, unsigned len)
+{
+       if (copy_mc_fragile_enabled)
+               return copy_mc_fragile(dst, src, len);
+       if (static_cpu_has(X86_FEATURE_ERMS))
+               return copy_mc_enhanced_fast_string(dst, src, len);
+       memcpy(dst, src, len);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(copy_mc_to_kernel);
+
+unsigned long __must_check copy_mc_to_user(void *dst, const void *src, unsigned len)
+{
+       unsigned long ret;
+
+       if (copy_mc_fragile_enabled) {
+               __uaccess_begin();
+               ret = copy_mc_fragile(dst, src, len);
+               __uaccess_end();
+               return ret;
+       }
+
+       if (static_cpu_has(X86_FEATURE_ERMS)) {
+               __uaccess_begin();
+               ret = copy_mc_enhanced_fast_string(dst, src, len);
+               __uaccess_end();
+               return ret;
+       }
+
+       return copy_user_generic(dst, src, len);
+}
diff --git a/arch/x86/lib/copy_mc_64.S b/arch/x86/lib/copy_mc_64.S
new file mode 100644 (file)
index 0000000..892d891
--- /dev/null
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2016-2020 Intel Corporation. All rights reserved. */
+
+#include <linux/linkage.h>
+#include <asm/copy_mc_test.h>
+#include <asm/export.h>
+#include <asm/asm.h>
+
+#ifndef CONFIG_UML
+
+#ifdef CONFIG_X86_MCE
+COPY_MC_TEST_CTL
+
+/*
+ * copy_mc_fragile - copy memory with indication if an exception / fault happened
+ *
+ * The 'fragile' version is opted into by platform quirks and takes
+ * pains to avoid unrecoverable corner cases like 'fast-string'
+ * instruction sequences, and consuming poison across a cacheline
+ * boundary. The non-fragile version is equivalent to memcpy()
+ * regardless of CPU machine-check-recovery capability.
+ */
+SYM_FUNC_START(copy_mc_fragile)
+       cmpl $8, %edx
+       /* Less than 8 bytes? Go to byte copy loop */
+       jb .L_no_whole_words
+
+       /* Check for bad alignment of source */
+       testl $7, %esi
+       /* Already aligned */
+       jz .L_8byte_aligned
+
+       /* Copy one byte at a time until source is 8-byte aligned */
+       movl %esi, %ecx
+       andl $7, %ecx
+       subl $8, %ecx
+       negl %ecx
+       subl %ecx, %edx
+.L_read_leading_bytes:
+       movb (%rsi), %al
+       COPY_MC_TEST_SRC %rsi 1 .E_leading_bytes
+       COPY_MC_TEST_DST %rdi 1 .E_leading_bytes
+.L_write_leading_bytes:
+       movb %al, (%rdi)
+       incq %rsi
+       incq %rdi
+       decl %ecx
+       jnz .L_read_leading_bytes
+
+.L_8byte_aligned:
+       movl %edx, %ecx
+       andl $7, %edx
+       shrl $3, %ecx
+       jz .L_no_whole_words
+
+.L_read_words:
+       movq (%rsi), %r8
+       COPY_MC_TEST_SRC %rsi 8 .E_read_words
+       COPY_MC_TEST_DST %rdi 8 .E_write_words
+.L_write_words:
+       movq %r8, (%rdi)
+       addq $8, %rsi
+       addq $8, %rdi
+       decl %ecx
+       jnz .L_read_words
+
+       /* Any trailing bytes? */
+.L_no_whole_words:
+       andl %edx, %edx
+       jz .L_done_memcpy_trap
+
+       /* Copy trailing bytes */
+       movl %edx, %ecx
+.L_read_trailing_bytes:
+       movb (%rsi), %al
+       COPY_MC_TEST_SRC %rsi 1 .E_trailing_bytes
+       COPY_MC_TEST_DST %rdi 1 .E_trailing_bytes
+.L_write_trailing_bytes:
+       movb %al, (%rdi)
+       incq %rsi
+       incq %rdi
+       decl %ecx
+       jnz .L_read_trailing_bytes
+
+       /* Copy successful. Return zero */
+.L_done_memcpy_trap:
+       xorl %eax, %eax
+.L_done:
+       ret
+SYM_FUNC_END(copy_mc_fragile)
+EXPORT_SYMBOL_GPL(copy_mc_fragile)
+
+       .section .fixup, "ax"
+       /*
+        * Return number of bytes not copied for any failure. Note that
+        * there is no "tail" handling since the source buffer is 8-byte
+        * aligned and poison is cacheline aligned.
+        */
+.E_read_words:
+       shll    $3, %ecx
+.E_leading_bytes:
+       addl    %edx, %ecx
+.E_trailing_bytes:
+       mov     %ecx, %eax
+       jmp     .L_done
+
+       /*
+        * For write fault handling, given the destination is unaligned,
+        * we handle faults on multi-byte writes with a byte-by-byte
+        * copy up to the write-protected page.
+        */
+.E_write_words:
+       shll    $3, %ecx
+       addl    %edx, %ecx
+       movl    %ecx, %edx
+       jmp copy_mc_fragile_handle_tail
+
+       .previous
+
+       _ASM_EXTABLE_FAULT(.L_read_leading_bytes, .E_leading_bytes)
+       _ASM_EXTABLE_FAULT(.L_read_words, .E_read_words)
+       _ASM_EXTABLE_FAULT(.L_read_trailing_bytes, .E_trailing_bytes)
+       _ASM_EXTABLE(.L_write_leading_bytes, .E_leading_bytes)
+       _ASM_EXTABLE(.L_write_words, .E_write_words)
+       _ASM_EXTABLE(.L_write_trailing_bytes, .E_trailing_bytes)
+#endif /* CONFIG_X86_MCE */
+
+/*
+ * copy_mc_enhanced_fast_string - memory copy with exception handling
+ *
+ * Fast string copy + fault / exception handling. If the CPU does
+ * support machine check exception recovery, but does not support
+ * recovering from fast-string exceptions then this CPU needs to be
+ * added to the copy_mc_fragile_key set of quirks. Otherwise, absent any
+ * machine check recovery support this version should be no slower than
+ * standard memcpy.
+ */
+SYM_FUNC_START(copy_mc_enhanced_fast_string)
+       movq %rdi, %rax
+       movq %rdx, %rcx
+.L_copy:
+       rep movsb
+       /* Copy successful. Return zero */
+       xorl %eax, %eax
+       ret
+SYM_FUNC_END(copy_mc_enhanced_fast_string)
+
+       .section .fixup, "ax"
+.E_copy:
+       /*
+        * On fault %rcx is updated such that the copy instruction could
+        * optionally be restarted at the fault position, i.e. it
+        * contains 'bytes remaining'. A non-zero return indicates error
+        * to copy_mc_generic() users, or indicate short transfers to
+        * user-copy routines.
+        */
+       movq %rcx, %rax
+       ret
+
+       .previous
+
+       _ASM_EXTABLE_FAULT(.L_copy, .E_copy)
+#endif /* !CONFIG_UML */
index 816f128..77b9b2a 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/asm.h>
 #include <asm/smap.h>
 #include <asm/export.h>
+#include <asm/trapnr.h>
 
 .macro ALIGN_DESTINATION
        /* check for bad alignment of destination */
@@ -36,8 +37,8 @@
        jmp .Lcopy_user_handle_tail
        .previous
 
-       _ASM_EXTABLE_UA(100b, 103b)
-       _ASM_EXTABLE_UA(101b, 103b)
+       _ASM_EXTABLE_CPY(100b, 103b)
+       _ASM_EXTABLE_CPY(101b, 103b)
        .endm
 
 /*
@@ -116,26 +117,26 @@ SYM_FUNC_START(copy_user_generic_unrolled)
 60:    jmp .Lcopy_user_handle_tail /* ecx is zerorest also */
        .previous
 
-       _ASM_EXTABLE_UA(1b, 30b)
-       _ASM_EXTABLE_UA(2b, 30b)
-       _ASM_EXTABLE_UA(3b, 30b)
-       _ASM_EXTABLE_UA(4b, 30b)
-       _ASM_EXTABLE_UA(5b, 30b)
-       _ASM_EXTABLE_UA(6b, 30b)
-       _ASM_EXTABLE_UA(7b, 30b)
-       _ASM_EXTABLE_UA(8b, 30b)
-       _ASM_EXTABLE_UA(9b, 30b)
-       _ASM_EXTABLE_UA(10b, 30b)
-       _ASM_EXTABLE_UA(11b, 30b)
-       _ASM_EXTABLE_UA(12b, 30b)
-       _ASM_EXTABLE_UA(13b, 30b)
-       _ASM_EXTABLE_UA(14b, 30b)
-       _ASM_EXTABLE_UA(15b, 30b)
-       _ASM_EXTABLE_UA(16b, 30b)
-       _ASM_EXTABLE_UA(18b, 40b)
-       _ASM_EXTABLE_UA(19b, 40b)
-       _ASM_EXTABLE_UA(21b, 50b)
-       _ASM_EXTABLE_UA(22b, 50b)
+       _ASM_EXTABLE_CPY(1b, 30b)
+       _ASM_EXTABLE_CPY(2b, 30b)
+       _ASM_EXTABLE_CPY(3b, 30b)
+       _ASM_EXTABLE_CPY(4b, 30b)
+       _ASM_EXTABLE_CPY(5b, 30b)
+       _ASM_EXTABLE_CPY(6b, 30b)
+       _ASM_EXTABLE_CPY(7b, 30b)
+       _ASM_EXTABLE_CPY(8b, 30b)
+       _ASM_EXTABLE_CPY(9b, 30b)
+       _ASM_EXTABLE_CPY(10b, 30b)
+       _ASM_EXTABLE_CPY(11b, 30b)
+       _ASM_EXTABLE_CPY(12b, 30b)
+       _ASM_EXTABLE_CPY(13b, 30b)
+       _ASM_EXTABLE_CPY(14b, 30b)
+       _ASM_EXTABLE_CPY(15b, 30b)
+       _ASM_EXTABLE_CPY(16b, 30b)
+       _ASM_EXTABLE_CPY(18b, 40b)
+       _ASM_EXTABLE_CPY(19b, 40b)
+       _ASM_EXTABLE_CPY(21b, 50b)
+       _ASM_EXTABLE_CPY(22b, 50b)
 SYM_FUNC_END(copy_user_generic_unrolled)
 EXPORT_SYMBOL(copy_user_generic_unrolled)
 
@@ -180,8 +181,8 @@ SYM_FUNC_START(copy_user_generic_string)
        jmp .Lcopy_user_handle_tail
        .previous
 
-       _ASM_EXTABLE_UA(1b, 11b)
-       _ASM_EXTABLE_UA(3b, 12b)
+       _ASM_EXTABLE_CPY(1b, 11b)
+       _ASM_EXTABLE_CPY(3b, 12b)
 SYM_FUNC_END(copy_user_generic_string)
 EXPORT_SYMBOL(copy_user_generic_string)
 
@@ -213,7 +214,7 @@ SYM_FUNC_START(copy_user_enhanced_fast_string)
        jmp .Lcopy_user_handle_tail
        .previous
 
-       _ASM_EXTABLE_UA(1b, 12b)
+       _ASM_EXTABLE_CPY(1b, 12b)
 SYM_FUNC_END(copy_user_enhanced_fast_string)
 EXPORT_SYMBOL(copy_user_enhanced_fast_string)
 
@@ -221,6 +222,7 @@ EXPORT_SYMBOL(copy_user_enhanced_fast_string)
  * Try to copy last bytes and clear the rest if needed.
  * Since protection fault in copy_from/to_user is not a normal situation,
  * it is not necessary to optimize tail handling.
+ * Don't try to copy the tail if machine check happened
  *
  * Input:
  * rdi destination
@@ -232,12 +234,25 @@ EXPORT_SYMBOL(copy_user_enhanced_fast_string)
  */
 SYM_CODE_START_LOCAL(.Lcopy_user_handle_tail)
        movl %edx,%ecx
+       cmp $X86_TRAP_MC,%eax           /* check if X86_TRAP_MC */
+       je 3f
 1:     rep movsb
 2:     mov %ecx,%eax
        ASM_CLAC
        ret
 
-       _ASM_EXTABLE_UA(1b, 2b)
+       /*
+        * Return zero to pretend that this copy succeeded. This
+        * is counter-intuitive, but needed to prevent the code
+        * in lib/iov_iter.c from retrying and running back into
+        * the poison cache line again. The machine check handler
+        * will ensure that a SIGBUS is sent to the task.
+        */
+3:     xorl %eax,%eax
+       ASM_CLAC
+       ret
+
+       _ASM_EXTABLE_CPY(1b, 2b)
 SYM_CODE_END(.Lcopy_user_handle_tail)
 
 /*
@@ -366,27 +381,27 @@ SYM_FUNC_START(__copy_user_nocache)
        jmp .Lcopy_user_handle_tail
        .previous
 
-       _ASM_EXTABLE_UA(1b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(2b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(3b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(4b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(5b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(6b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(7b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(8b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(9b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(10b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(11b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(12b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(13b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(14b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(15b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(16b, .L_fixup_4x8b_copy)
-       _ASM_EXTABLE_UA(20b, .L_fixup_8b_copy)
-       _ASM_EXTABLE_UA(21b, .L_fixup_8b_copy)
-       _ASM_EXTABLE_UA(30b, .L_fixup_4b_copy)
-       _ASM_EXTABLE_UA(31b, .L_fixup_4b_copy)
-       _ASM_EXTABLE_UA(40b, .L_fixup_1b_copy)
-       _ASM_EXTABLE_UA(41b, .L_fixup_1b_copy)
+       _ASM_EXTABLE_CPY(1b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(2b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(3b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(4b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(5b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(6b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(7b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(8b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(9b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(10b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(11b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(12b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(13b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(14b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(15b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(16b, .L_fixup_4x8b_copy)
+       _ASM_EXTABLE_CPY(20b, .L_fixup_8b_copy)
+       _ASM_EXTABLE_CPY(21b, .L_fixup_8b_copy)
+       _ASM_EXTABLE_CPY(30b, .L_fixup_4b_copy)
+       _ASM_EXTABLE_CPY(31b, .L_fixup_4b_copy)
+       _ASM_EXTABLE_CPY(40b, .L_fixup_1b_copy)
+       _ASM_EXTABLE_CPY(41b, .L_fixup_1b_copy)
 SYM_FUNC_END(__copy_user_nocache)
 EXPORT_SYMBOL(__copy_user_nocache)
index 3394a8f..1fbd8ee 100644 (file)
@@ -18,9 +18,6 @@
  * rdi  source
  * rsi  destination
  * edx  len (32bit)
- * ecx  sum (32bit)
- * r8   src_err_ptr (int)
- * r9   dst_err_ptr (int)
  *
  * Output
  * eax  64bit sum. undefined in case of exception.
 
        .macro source
 10:
-       _ASM_EXTABLE_UA(10b, .Lbad_source)
+       _ASM_EXTABLE_UA(10b, .Lfault)
        .endm
 
        .macro dest
 20:
-       _ASM_EXTABLE_UA(20b, .Lbad_dest)
+       _ASM_EXTABLE_UA(20b, .Lfault)
        .endm
 
-       /*
-        * No _ASM_EXTABLE_UA; this is used for intentional prefetch on a
-        * potentially unmapped kernel address.
-        */
-       .macro ignore L=.Lignore
-30:
-       _ASM_EXTABLE(30b, \L)
-       .endm
-
-
 SYM_FUNC_START(csum_partial_copy_generic)
-       cmpl    $3*64, %edx
-       jle     .Lignore
-
-.Lignore:
-       subq  $7*8, %rsp
-       movq  %rbx, 2*8(%rsp)
-       movq  %r12, 3*8(%rsp)
-       movq  %r14, 4*8(%rsp)
-       movq  %r13, 5*8(%rsp)
-       movq  %r15, 6*8(%rsp)
+       subq  $5*8, %rsp
+       movq  %rbx, 0*8(%rsp)
+       movq  %r12, 1*8(%rsp)
+       movq  %r14, 2*8(%rsp)
+       movq  %r13, 3*8(%rsp)
+       movq  %r15, 4*8(%rsp)
 
-       movq  %r8, (%rsp)
-       movq  %r9, 1*8(%rsp)
-
-       movl  %ecx, %eax
+       movl  $-1, %eax
+       xorl  %r9d, %r9d
        movl  %edx, %ecx
+       cmpl  $8, %ecx
+       jb    .Lshort
 
-       xorl  %r9d, %r9d
-       movq  %rcx, %r12
+       testb  $7, %sil
+       jne   .Lunaligned
+.Laligned:
+       movl  %ecx, %r12d
 
        shrq  $6, %r12
        jz      .Lhandle_tail       /* < 64 */
@@ -99,7 +84,12 @@ SYM_FUNC_START(csum_partial_copy_generic)
        source
        movq  56(%rdi), %r13
 
-       ignore 2f
+30:
+       /*
+        * No _ASM_EXTABLE_UA; this is used for intentional prefetch on a
+        * potentially unmapped kernel address.
+        */
+       _ASM_EXTABLE(30b, 2f)
        prefetcht0 5*64(%rdi)
 2:
        adcq  %rbx, %rax
@@ -131,8 +121,6 @@ SYM_FUNC_START(csum_partial_copy_generic)
        dest
        movq %r13, 56(%rsi)
 
-3:
-
        leaq 64(%rdi), %rdi
        leaq 64(%rsi), %rsi
 
@@ -142,8 +130,8 @@ SYM_FUNC_START(csum_partial_copy_generic)
 
        /* do last up to 56 bytes */
 .Lhandle_tail:
-       /* ecx: count */
-       movl %ecx, %r10d
+       /* ecx: count, rcx.63: the end result needs to be rol8 */
+       movq %rcx, %r10
        andl $63, %ecx
        shrl $3, %ecx
        jz      .Lfold
@@ -172,6 +160,7 @@ SYM_FUNC_START(csum_partial_copy_generic)
 .Lhandle_7:
        movl %r10d, %ecx
        andl $7, %ecx
+.L1:                           /* .Lshort rejoins the common path here */
        shrl $1, %ecx
        jz   .Lhandle_1
        movl $2, %edx
@@ -203,26 +192,65 @@ SYM_FUNC_START(csum_partial_copy_generic)
        adcl %r9d, %eax         /* carry */
 
 .Lende:
-       movq 2*8(%rsp), %rbx
-       movq 3*8(%rsp), %r12
-       movq 4*8(%rsp), %r14
-       movq 5*8(%rsp), %r13
-       movq 6*8(%rsp), %r15
-       addq $7*8, %rsp
+       testq %r10, %r10
+       js  .Lwas_odd
+.Lout:
+       movq 0*8(%rsp), %rbx
+       movq 1*8(%rsp), %r12
+       movq 2*8(%rsp), %r14
+       movq 3*8(%rsp), %r13
+       movq 4*8(%rsp), %r15
+       addq $5*8, %rsp
        ret
+.Lshort:
+       movl %ecx, %r10d
+       jmp  .L1
+.Lunaligned:
+       xorl %ebx, %ebx
+       testb $1, %sil
+       jne  .Lodd
+1:     testb $2, %sil
+       je   2f
+       source
+       movw (%rdi), %bx
+       dest
+       movw %bx, (%rsi)
+       leaq 2(%rdi), %rdi
+       subq $2, %rcx
+       leaq 2(%rsi), %rsi
+       addq %rbx, %rax
+2:     testb $4, %sil
+       je .Laligned
+       source
+       movl (%rdi), %ebx
+       dest
+       movl %ebx, (%rsi)
+       leaq 4(%rdi), %rdi
+       subq $4, %rcx
+       leaq 4(%rsi), %rsi
+       addq %rbx, %rax
+       jmp .Laligned
+
+.Lodd:
+       source
+       movb (%rdi), %bl
+       dest
+       movb %bl, (%rsi)
+       leaq 1(%rdi), %rdi
+       leaq 1(%rsi), %rsi
+       /* decrement, set MSB */
+       leaq -1(%rcx, %rcx), %rcx
+       rorq $1, %rcx
+       shll $8, %ebx
+       addq %rbx, %rax
+       jmp 1b
+
+.Lwas_odd:
+       roll $8, %eax
+       jmp .Lout
 
-       /* Exception handlers. Very simple, zeroing is done in the wrappers */
-.Lbad_source:
-       movq (%rsp), %rax
-       testq %rax, %rax
-       jz   .Lende
-       movl $-EFAULT, (%rax)
-       jmp  .Lende
-
-.Lbad_dest:
-       movq 8(%rsp), %rax
-       testq %rax, %rax
-       jz   .Lende
-       movl $-EFAULT, (%rax)
-       jmp .Lende
+       /* Exception: just return 0 */
+.Lfault:
+       xorl %eax, %eax
+       jmp  .Lout
 SYM_FUNC_END(csum_partial_copy_generic)
index ee63d75..1893449 100644 (file)
  * src and dst are best aligned to 64bits.
  */
 __wsum
-csum_and_copy_from_user(const void __user *src, void *dst,
-                           int len, __wsum isum, int *errp)
+csum_and_copy_from_user(const void __user *src, void *dst, int len)
 {
-       might_sleep();
-       *errp = 0;
+       __wsum sum;
 
+       might_sleep();
        if (!user_access_begin(src, len))
-               goto out_err;
-
-       /*
-        * Why 6, not 7? To handle odd addresses aligned we
-        * would need to do considerable complications to fix the
-        * checksum which is defined as an 16bit accumulator. The
-        * fix alignment code is primarily for performance
-        * compatibility with 32bit and that will handle odd
-        * addresses slowly too.
-        */
-       if (unlikely((unsigned long)src & 6)) {
-               while (((unsigned long)src & 6) && len >= 2) {
-                       __u16 val16;
-
-                       unsafe_get_user(val16, (const __u16 __user *)src, out);
-
-                       *(__u16 *)dst = val16;
-                       isum = (__force __wsum)add32_with_carry(
-                                       (__force unsigned)isum, val16);
-                       src += 2;
-                       dst += 2;
-                       len -= 2;
-               }
-       }
-       isum = csum_partial_copy_generic((__force const void *)src,
-                               dst, len, isum, errp, NULL);
-       user_access_end();
-       if (unlikely(*errp))
-               goto out_err;
-
-       return isum;
-
-out:
+               return 0;
+       sum = csum_partial_copy_generic((__force const void *)src, dst, len);
        user_access_end();
-out_err:
-       *errp = -EFAULT;
-       memset(dst, 0, len);
-
-       return isum;
+       return sum;
 }
 EXPORT_SYMBOL(csum_and_copy_from_user);
 
@@ -82,40 +46,16 @@ EXPORT_SYMBOL(csum_and_copy_from_user);
  * src and dst are best aligned to 64bits.
  */
 __wsum
-csum_and_copy_to_user(const void *src, void __user *dst,
-                         int len, __wsum isum, int *errp)
+csum_and_copy_to_user(const void *src, void __user *dst, int len)
 {
-       __wsum ret;
+       __wsum sum;
 
        might_sleep();
-
-       if (!user_access_begin(dst, len)) {
-               *errp = -EFAULT;
+       if (!user_access_begin(dst, len))
                return 0;
-       }
-
-       if (unlikely((unsigned long)dst & 6)) {
-               while (((unsigned long)dst & 6) && len >= 2) {
-                       __u16 val16 = *(__u16 *)src;
-
-                       isum = (__force __wsum)add32_with_carry(
-                                       (__force unsigned)isum, val16);
-                       unsafe_put_user(val16, (__u16 __user *)dst, out);
-                       src += 2;
-                       dst += 2;
-                       len -= 2;
-               }
-       }
-
-       *errp = 0;
-       ret = csum_partial_copy_generic(src, (void __force *)dst,
-                                       len, isum, NULL, errp);
-       user_access_end();
-       return ret;
-out:
+       sum = csum_partial_copy_generic(src, (void __force *)dst, len);
        user_access_end();
-       *errp = -EFAULT;
-       return isum;
+       return sum;
 }
 EXPORT_SYMBOL(csum_and_copy_to_user);
 
@@ -129,9 +69,9 @@ EXPORT_SYMBOL(csum_and_copy_to_user);
  * Returns an 32bit unfolded checksum of the buffer.
  */
 __wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
+csum_partial_copy_nocheck(const void *src, void *dst, int len)
 {
-       return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL);
+       return csum_partial_copy_generic(src, dst, len);
 }
 EXPORT_SYMBOL(csum_partial_copy_nocheck);
 
index c8a85b5..2cd902e 100644 (file)
@@ -35,6 +35,8 @@
 #include <asm/smap.h>
 #include <asm/export.h>
 
+#define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC
+
        .text
 SYM_FUNC_START(__get_user_1)
        mov PER_CPU_VAR(current_task), %_ASM_DX
@@ -114,6 +116,52 @@ SYM_FUNC_START(__get_user_8)
 SYM_FUNC_END(__get_user_8)
 EXPORT_SYMBOL(__get_user_8)
 
+/* .. and the same for __get_user, just without the range checks */
+SYM_FUNC_START(__get_user_nocheck_1)
+       ASM_STAC
+       ASM_BARRIER_NOSPEC
+6:     movzbl (%_ASM_AX),%edx
+       xor %eax,%eax
+       ASM_CLAC
+       ret
+SYM_FUNC_END(__get_user_nocheck_1)
+EXPORT_SYMBOL(__get_user_nocheck_1)
+
+SYM_FUNC_START(__get_user_nocheck_2)
+       ASM_STAC
+       ASM_BARRIER_NOSPEC
+7:     movzwl (%_ASM_AX),%edx
+       xor %eax,%eax
+       ASM_CLAC
+       ret
+SYM_FUNC_END(__get_user_nocheck_2)
+EXPORT_SYMBOL(__get_user_nocheck_2)
+
+SYM_FUNC_START(__get_user_nocheck_4)
+       ASM_STAC
+       ASM_BARRIER_NOSPEC
+8:     movl (%_ASM_AX),%edx
+       xor %eax,%eax
+       ASM_CLAC
+       ret
+SYM_FUNC_END(__get_user_nocheck_4)
+EXPORT_SYMBOL(__get_user_nocheck_4)
+
+SYM_FUNC_START(__get_user_nocheck_8)
+       ASM_STAC
+       ASM_BARRIER_NOSPEC
+#ifdef CONFIG_X86_64
+9:     movq (%_ASM_AX),%rdx
+#else
+9:     movl (%_ASM_AX),%edx
+10:    movl 4(%_ASM_AX),%ecx
+#endif
+       xor %eax,%eax
+       ASM_CLAC
+       ret
+SYM_FUNC_END(__get_user_nocheck_8)
+EXPORT_SYMBOL(__get_user_nocheck_8)
+
 
 SYM_CODE_START_LOCAL(.Lbad_get_user_clac)
        ASM_CLAC
@@ -134,6 +182,7 @@ bad_get_user_8:
 SYM_CODE_END(.Lbad_get_user_8_clac)
 #endif
 
+/* get_user */
        _ASM_EXTABLE_UA(1b, .Lbad_get_user_clac)
        _ASM_EXTABLE_UA(2b, .Lbad_get_user_clac)
        _ASM_EXTABLE_UA(3b, .Lbad_get_user_clac)
@@ -143,3 +192,14 @@ SYM_CODE_END(.Lbad_get_user_8_clac)
        _ASM_EXTABLE_UA(4b, .Lbad_get_user_8_clac)
        _ASM_EXTABLE_UA(5b, .Lbad_get_user_8_clac)
 #endif
+
+/* __get_user */
+       _ASM_EXTABLE_UA(6b, .Lbad_get_user_clac)
+       _ASM_EXTABLE_UA(7b, .Lbad_get_user_clac)
+       _ASM_EXTABLE_UA(8b, .Lbad_get_user_clac)
+#ifdef CONFIG_X86_64
+       _ASM_EXTABLE_UA(9b, .Lbad_get_user_clac)
+#else
+       _ASM_EXTABLE_UA(9b, .Lbad_get_user_8_clac)
+       _ASM_EXTABLE_UA(10b, .Lbad_get_user_8_clac)
+#endif
index 31600d8..5e69603 100644 (file)
@@ -179,7 +179,7 @@ static int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off)
                if (insn->addr_bytes == 2)
                        return -EINVAL;
 
-               /* fall through */
+               fallthrough;
 
        case -EDOM:
        case offsetof(struct pt_regs, bx):
@@ -362,7 +362,6 @@ static short get_segment_selector(struct pt_regs *regs, int seg_reg_idx)
                case INAT_SEG_REG_GS:
                        return vm86regs->gs;
                case INAT_SEG_REG_IGNORE:
-                       /* fall through */
                default:
                        return -EINVAL;
                }
@@ -386,7 +385,6 @@ static short get_segment_selector(struct pt_regs *regs, int seg_reg_idx)
                 */
                return get_user_gs(regs);
        case INAT_SEG_REG_IGNORE:
-               /* fall through */
        default:
                return -EINVAL;
        }
@@ -786,7 +784,7 @@ int insn_get_code_seg_params(struct pt_regs *regs)
                 */
                return INSN_CODE_SEG_PARAMS(4, 8);
        case 3: /* Invalid setting. CS.L=1, CS.D=1 */
-               /* fall through */
+               fallthrough;
        default:
                return -EINVAL;
        }
index bbcc05b..037faac 100644 (file)
@@ -4,7 +4,6 @@
 #include <linux/linkage.h>
 #include <asm/errno.h>
 #include <asm/cpufeatures.h>
-#include <asm/mcsafe_test.h>
 #include <asm/alternative-asm.h>
 #include <asm/export.h>
 
@@ -187,117 +186,3 @@ SYM_FUNC_START_LOCAL(memcpy_orig)
 SYM_FUNC_END(memcpy_orig)
 
 .popsection
-
-#ifndef CONFIG_UML
-
-MCSAFE_TEST_CTL
-
-/*
- * __memcpy_mcsafe - memory copy with machine check exception handling
- * Note that we only catch machine checks when reading the source addresses.
- * Writes to target are posted and don't generate machine checks.
- */
-SYM_FUNC_START(__memcpy_mcsafe)
-       cmpl $8, %edx
-       /* Less than 8 bytes? Go to byte copy loop */
-       jb .L_no_whole_words
-
-       /* Check for bad alignment of source */
-       testl $7, %esi
-       /* Already aligned */
-       jz .L_8byte_aligned
-
-       /* Copy one byte at a time until source is 8-byte aligned */
-       movl %esi, %ecx
-       andl $7, %ecx
-       subl $8, %ecx
-       negl %ecx
-       subl %ecx, %edx
-.L_read_leading_bytes:
-       movb (%rsi), %al
-       MCSAFE_TEST_SRC %rsi 1 .E_leading_bytes
-       MCSAFE_TEST_DST %rdi 1 .E_leading_bytes
-.L_write_leading_bytes:
-       movb %al, (%rdi)
-       incq %rsi
-       incq %rdi
-       decl %ecx
-       jnz .L_read_leading_bytes
-
-.L_8byte_aligned:
-       movl %edx, %ecx
-       andl $7, %edx
-       shrl $3, %ecx
-       jz .L_no_whole_words
-
-.L_read_words:
-       movq (%rsi), %r8
-       MCSAFE_TEST_SRC %rsi 8 .E_read_words
-       MCSAFE_TEST_DST %rdi 8 .E_write_words
-.L_write_words:
-       movq %r8, (%rdi)
-       addq $8, %rsi
-       addq $8, %rdi
-       decl %ecx
-       jnz .L_read_words
-
-       /* Any trailing bytes? */
-.L_no_whole_words:
-       andl %edx, %edx
-       jz .L_done_memcpy_trap
-
-       /* Copy trailing bytes */
-       movl %edx, %ecx
-.L_read_trailing_bytes:
-       movb (%rsi), %al
-       MCSAFE_TEST_SRC %rsi 1 .E_trailing_bytes
-       MCSAFE_TEST_DST %rdi 1 .E_trailing_bytes
-.L_write_trailing_bytes:
-       movb %al, (%rdi)
-       incq %rsi
-       incq %rdi
-       decl %ecx
-       jnz .L_read_trailing_bytes
-
-       /* Copy successful. Return zero */
-.L_done_memcpy_trap:
-       xorl %eax, %eax
-.L_done:
-       ret
-SYM_FUNC_END(__memcpy_mcsafe)
-EXPORT_SYMBOL_GPL(__memcpy_mcsafe)
-
-       .section .fixup, "ax"
-       /*
-        * Return number of bytes not copied for any failure. Note that
-        * there is no "tail" handling since the source buffer is 8-byte
-        * aligned and poison is cacheline aligned.
-        */
-.E_read_words:
-       shll    $3, %ecx
-.E_leading_bytes:
-       addl    %edx, %ecx
-.E_trailing_bytes:
-       mov     %ecx, %eax
-       jmp     .L_done
-
-       /*
-        * For write fault handling, given the destination is unaligned,
-        * we handle faults on multi-byte writes with a byte-by-byte
-        * copy up to the write-protected page.
-        */
-.E_write_words:
-       shll    $3, %ecx
-       addl    %edx, %ecx
-       movl    %ecx, %edx
-       jmp mcsafe_handle_tail
-
-       .previous
-
-       _ASM_EXTABLE_FAULT(.L_read_leading_bytes, .E_leading_bytes)
-       _ASM_EXTABLE_FAULT(.L_read_words, .E_read_words)
-       _ASM_EXTABLE_FAULT(.L_read_trailing_bytes, .E_trailing_bytes)
-       _ASM_EXTABLE(.L_write_leading_bytes, .E_leading_bytes)
-       _ASM_EXTABLE(.L_write_words, .E_write_words)
-       _ASM_EXTABLE(.L_write_trailing_bytes, .E_trailing_bytes)
-#endif
index 7c7c92d..b34a177 100644 (file)
@@ -25,7 +25,9 @@
  * Inputs:     %eax[:%edx] contains the data
  *             %ecx contains the address
  *
- * Outputs:    %eax is error code (0 or -EFAULT)
+ * Outputs:    %ecx is error code (0 or -EFAULT)
+ *
+ * Clobbers:   %ebx needed for task pointer
  *
  * These functions should not modify any other registers,
  * as they get called from within inline assembly.
@@ -38,13 +40,15 @@ SYM_FUNC_START(__put_user_1)
        ENTER
        cmp TASK_addr_limit(%_ASM_BX),%_ASM_CX
        jae .Lbad_put_user
+SYM_INNER_LABEL(__put_user_nocheck_1, SYM_L_GLOBAL)
        ASM_STAC
 1:     movb %al,(%_ASM_CX)
-       xor %eax,%eax
+       xor %ecx,%ecx
        ASM_CLAC
        ret
 SYM_FUNC_END(__put_user_1)
 EXPORT_SYMBOL(__put_user_1)
+EXPORT_SYMBOL(__put_user_nocheck_1)
 
 SYM_FUNC_START(__put_user_2)
        ENTER
@@ -52,13 +56,15 @@ SYM_FUNC_START(__put_user_2)
        sub $1,%_ASM_BX
        cmp %_ASM_BX,%_ASM_CX
        jae .Lbad_put_user
+SYM_INNER_LABEL(__put_user_nocheck_2, SYM_L_GLOBAL)
        ASM_STAC
 2:     movw %ax,(%_ASM_CX)
-       xor %eax,%eax
+       xor %ecx,%ecx
        ASM_CLAC
        ret
 SYM_FUNC_END(__put_user_2)
 EXPORT_SYMBOL(__put_user_2)
+EXPORT_SYMBOL(__put_user_nocheck_2)
 
 SYM_FUNC_START(__put_user_4)
        ENTER
@@ -66,13 +72,15 @@ SYM_FUNC_START(__put_user_4)
        sub $3,%_ASM_BX
        cmp %_ASM_BX,%_ASM_CX
        jae .Lbad_put_user
+SYM_INNER_LABEL(__put_user_nocheck_4, SYM_L_GLOBAL)
        ASM_STAC
 3:     movl %eax,(%_ASM_CX)
-       xor %eax,%eax
+       xor %ecx,%ecx
        ASM_CLAC
        ret
 SYM_FUNC_END(__put_user_4)
 EXPORT_SYMBOL(__put_user_4)
+EXPORT_SYMBOL(__put_user_nocheck_4)
 
 SYM_FUNC_START(__put_user_8)
        ENTER
@@ -80,21 +88,23 @@ SYM_FUNC_START(__put_user_8)
        sub $7,%_ASM_BX
        cmp %_ASM_BX,%_ASM_CX
        jae .Lbad_put_user
+SYM_INNER_LABEL(__put_user_nocheck_8, SYM_L_GLOBAL)
        ASM_STAC
 4:     mov %_ASM_AX,(%_ASM_CX)
 #ifdef CONFIG_X86_32
 5:     movl %edx,4(%_ASM_CX)
 #endif
-       xor %eax,%eax
+       xor %ecx,%ecx
        ASM_CLAC
        RET
 SYM_FUNC_END(__put_user_8)
 EXPORT_SYMBOL(__put_user_8)
+EXPORT_SYMBOL(__put_user_nocheck_8)
 
 SYM_CODE_START_LOCAL(.Lbad_put_user_clac)
        ASM_CLAC
 .Lbad_put_user:
-       movl $-EFAULT,%eax
+       movl $-EFAULT,%ecx
        RET
 SYM_CODE_END(.Lbad_put_user_clac)
 
index b0dfac3..508c81e 100644 (file)
@@ -56,27 +56,6 @@ unsigned long clear_user(void __user *to, unsigned long n)
 }
 EXPORT_SYMBOL(clear_user);
 
-/*
- * Similar to copy_user_handle_tail, probe for the write fault point,
- * but reuse __memcpy_mcsafe in case a new read error is encountered.
- * clac() is handled in _copy_to_iter_mcsafe().
- */
-__visible notrace unsigned long
-mcsafe_handle_tail(char *to, char *from, unsigned len)
-{
-       for (; len; --len, to++, from++) {
-               /*
-                * Call the assembly routine back directly since
-                * memcpy_mcsafe() may silently fallback to memcpy.
-                */
-               unsigned long rem = __memcpy_mcsafe(to, from, 1);
-
-               if (rem)
-                       break;
-       }
-       return len;
-}
-
 #ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE
 /**
  * clean_cache_range - write back a cache range with CLWB
@@ -120,7 +99,7 @@ long __copy_user_flushcache(void *dst, const void __user *src, unsigned size)
         */
        if (size < 8) {
                if (!IS_ALIGNED(dest, 4) || size != 4)
-                       clean_cache_range(dst, 1);
+                       clean_cache_range(dst, size);
        } else {
                if (!IS_ALIGNED(dest, 8)) {
                        dest = ALIGN(dest, boot_cpu_data.x86_clflush_size);
index 73dc66d..ec071cb 100644 (file)
@@ -186,7 +186,7 @@ void FPU_printall(void)
                case TAG_Special:
                        /* Update tagi for the printk below */
                        tagi = FPU_Special(r);
-                       /* fall through */
+                       fallthrough;
                case TAG_Valid:
                        printk("st(%d)  %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
                               getsign(r) ? '-' : '+',
index 127ea54..4a98878 100644 (file)
@@ -1352,7 +1352,7 @@ static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
                case TW_Denormal:
                        if (denormal_operand() < 0)
                                return;
-                       /* fall through */
+                       fallthrough;
                case TAG_Zero:
                case TAG_Valid:
                        setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
index 1d6cb07..5829457 100644 (file)
@@ -80,6 +80,18 @@ __visible bool ex_handler_uaccess(const struct exception_table_entry *fixup,
 }
 EXPORT_SYMBOL(ex_handler_uaccess);
 
+__visible bool ex_handler_copy(const struct exception_table_entry *fixup,
+                              struct pt_regs *regs, int trapnr,
+                              unsigned long error_code,
+                              unsigned long fault_addr)
+{
+       WARN_ONCE(trapnr == X86_TRAP_GP, "General protection fault in user access. Non-canonical address?");
+       regs->ip = ex_fixup_addr(fixup);
+       regs->ax = trapnr;
+       return true;
+}
+EXPORT_SYMBOL(ex_handler_copy);
+
 __visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
                                       struct pt_regs *regs, int trapnr,
                                       unsigned long error_code,
@@ -125,17 +137,21 @@ __visible bool ex_handler_clear_fs(const struct exception_table_entry *fixup,
 }
 EXPORT_SYMBOL(ex_handler_clear_fs);
 
-__visible bool ex_has_fault_handler(unsigned long ip)
+enum handler_type ex_get_fault_handler_type(unsigned long ip)
 {
        const struct exception_table_entry *e;
        ex_handler_t handler;
 
        e = search_exception_tables(ip);
        if (!e)
-               return false;
+               return EX_HANDLER_NONE;
        handler = ex_fixup_handler(e);
-
-       return handler == ex_handler_fault;
+       if (handler == ex_handler_fault)
+               return EX_HANDLER_FAULT;
+       else if (handler == ex_handler_uaccess || handler == ex_handler_copy)
+               return EX_HANDLER_UACCESS;
+       else
+               return EX_HANDLER_OTHER;
 }
 
 int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
index 35f1498..42606a0 100644 (file)
@@ -190,6 +190,53 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
        return pmd_k;
 }
 
+/*
+ *   Handle a fault on the vmalloc or module mapping area
+ *
+ *   This is needed because there is a race condition between the time
+ *   when the vmalloc mapping code updates the PMD to the point in time
+ *   where it synchronizes this update with the other page-tables in the
+ *   system.
+ *
+ *   In this race window another thread/CPU can map an area on the same
+ *   PMD, finds it already present and does not synchronize it with the
+ *   rest of the system yet. As a result v[mz]alloc might return areas
+ *   which are not mapped in every page-table in the system, causing an
+ *   unhandled page-fault when they are accessed.
+ */
+static noinline int vmalloc_fault(unsigned long address)
+{
+       unsigned long pgd_paddr;
+       pmd_t *pmd_k;
+       pte_t *pte_k;
+
+       /* Make sure we are in vmalloc area: */
+       if (!(address >= VMALLOC_START && address < VMALLOC_END))
+               return -1;
+
+       /*
+        * Synchronize this task's top level page-table
+        * with the 'reference' page table.
+        *
+        * Do _not_ use "current" here. We might be inside
+        * an interrupt in the middle of a task switch..
+        */
+       pgd_paddr = read_cr3_pa();
+       pmd_k = vmalloc_sync_one(__va(pgd_paddr), address);
+       if (!pmd_k)
+               return -1;
+
+       if (pmd_large(*pmd_k))
+               return 0;
+
+       pte_k = pte_offset_kernel(pmd_k, address);
+       if (!pte_present(*pte_k))
+               return -1;
+
+       return 0;
+}
+NOKPROBE_SYMBOL(vmalloc_fault);
+
 void arch_sync_kernel_mappings(unsigned long start, unsigned long end)
 {
        unsigned long addr;
@@ -1081,7 +1128,7 @@ access_error(unsigned long error_code, struct vm_area_struct *vma)
        return 0;
 }
 
-static int fault_in_kernel_space(unsigned long address)
+bool fault_in_kernel_space(unsigned long address)
 {
        /*
         * On 64-bit systems, the vsyscall page is at an address above
@@ -1110,6 +1157,37 @@ do_kern_addr_fault(struct pt_regs *regs, unsigned long hw_error_code,
         */
        WARN_ON_ONCE(hw_error_code & X86_PF_PK);
 
+#ifdef CONFIG_X86_32
+       /*
+        * We can fault-in kernel-space virtual memory on-demand. The
+        * 'reference' page table is init_mm.pgd.
+        *
+        * NOTE! We MUST NOT take any locks for this case. We may
+        * be in an interrupt or a critical region, and should
+        * only copy the information from the master page table,
+        * nothing more.
+        *
+        * Before doing this on-demand faulting, ensure that the
+        * fault is not any of the following:
+        * 1. A fault on a PTE with a reserved bit set.
+        * 2. A fault caused by a user-mode access.  (Do not demand-
+        *    fault kernel memory due to user-mode accesses).
+        * 3. A fault caused by a page-level protection violation.
+        *    (A demand fault would be on a non-present page which
+        *     would have X86_PF_PROT==0).
+        *
+        * This is only needed to close a race condition on x86-32 in
+        * the vmalloc mapping/unmapping code. See the comment above
+        * vmalloc_fault() for details. On x86-64 the race does not
+        * exist as the vmalloc mappings don't need to be synchronized
+        * there.
+        */
+       if (!(hw_error_code & (X86_PF_RSVD | X86_PF_USER | X86_PF_PROT))) {
+               if (vmalloc_fault(address) >= 0)
+                       return;
+       }
+#endif
+
        /* Was the fault spurious, caused by lazy TLB invalidation? */
        if (spurious_kernel_fault(hw_error_code, address))
                return;
index a4ac13c..b5a3fa4 100644 (file)
@@ -217,11 +217,6 @@ static void sync_global_pgds(unsigned long start, unsigned long end)
                sync_global_pgds_l4(start, end);
 }
 
-void arch_sync_kernel_mappings(unsigned long start, unsigned long end)
-{
-       sync_global_pgds(start, end);
-}
-
 /*
  * NOTE: This function is marked __ref because it calls __init function
  * (alloc_bootmem_pages). It's safe to do it ONLY when after_bootmem == 0.
@@ -1257,14 +1252,19 @@ static void __init preallocate_vmalloc_pages(void)
                if (!p4d)
                        goto failed;
 
-               /*
-                * With 5-level paging the P4D level is not folded. So the PGDs
-                * are now populated and there is no need to walk down to the
-                * PUD level.
-                */
                if (pgtable_l5_enabled())
                        continue;
 
+               /*
+                * The goal here is to allocate all possibly required
+                * hardware page tables pointed to by the top hardware
+                * level.
+                *
+                * On 4-level systems, the P4D layer is folded away and
+                * the above code does no preallocation.  Below, go down
+                * to the pud _software_ level to ensure the second
+                * hardware level is allocated on 4-level systems too.
+                */
                lvl = "pud";
                pud = pud_alloc(&init_mm, p4d, addr);
                if (!pud)
index 84d85db..9e5ccc5 100644 (file)
@@ -574,7 +574,7 @@ static bool memremap_should_map_decrypted(resource_size_t phys_addr,
                /* For SEV, these areas are encrypted */
                if (sev_active())
                        break;
-               /* Fallthrough */
+               fallthrough;
 
        case E820_TYPE_PRAM:
                return true;
index c5174b4..683cd12 100644 (file)
@@ -321,7 +321,7 @@ static int __init split_nodes_size_interleave(struct numa_meminfo *ei,
                                              u64 addr, u64 max_addr, u64 size)
 {
        return split_nodes_size_interleave_uniform(ei, pi, addr, max_addr, size,
-                       0, NULL, NUMA_NO_NODE);
+                       0, NULL, 0);
 }
 
 static int __init setup_emu2phys_nid(int *dfl_phys_nid)
index d1b2a88..40baa90 100644 (file)
@@ -1999,7 +1999,7 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
        /*
         * Before changing the encryption attribute, we need to flush caches.
         */
-       cpa_flush(&cpa, 1);
+       cpa_flush(&cpa, !this_cpu_has(X86_FEATURE_SME_COHERENT));
 
        ret = __change_page_attr_set_clr(&cpa, 1);
 
index 1a3569b..11666ba 100644 (file)
@@ -14,7 +14,6 @@
 #include <asm/nospec-branch.h>
 #include <asm/cache.h>
 #include <asm/apic.h>
-#include <asm/uv/uv.h>
 
 #include "mm_internal.h"
 
@@ -555,21 +554,12 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
                this_cpu_write(cpu_tlbstate.ctxs[new_asid].tlb_gen, next_tlb_gen);
                load_new_mm_cr3(next->pgd, new_asid, true);
 
-               /*
-                * NB: This gets called via leave_mm() in the idle path
-                * where RCU functions differently.  Tracing normally
-                * uses RCU, so we need to use the _rcuidle variant.
-                *
-                * (There is no good reason for this.  The idle code should
-                *  be rearranged to call this before rcu_idle_enter().)
-                */
-               trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
+               trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
        } else {
                /* The new ASID is already up to date. */
                load_new_mm_cr3(next->pgd, new_asid, false);
 
-               /* See above wrt _rcuidle. */
-               trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, 0);
+               trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, 0);
        }
 
        /* Make sure we write CR3 before loaded_mm. */
@@ -809,29 +799,6 @@ STATIC_NOPV void native_flush_tlb_others(const struct cpumask *cpumask,
                trace_tlb_flush(TLB_REMOTE_SEND_IPI,
                                (info->end - info->start) >> PAGE_SHIFT);
 
-       if (is_uv_system()) {
-               /*
-                * This whole special case is confused.  UV has a "Broadcast
-                * Assist Unit", which seems to be a fancy way to send IPIs.
-                * Back when x86 used an explicit TLB flush IPI, UV was
-                * optimized to use its own mechanism.  These days, x86 uses
-                * smp_call_function_many(), but UV still uses a manual IPI,
-                * and that IPI's action is out of date -- it does a manual
-                * flush instead of calling flush_tlb_func_remote().  This
-                * means that the percpu tlb_gen variables won't be updated
-                * and we'll do pointless flushes on future context switches.
-                *
-                * Rather than hooking native_flush_tlb_others() here, I think
-                * that UV should be updated so that smp_call_function_many(),
-                * etc, are optimal on UV.
-                */
-               cpumask = uv_flush_tlb_others(cpumask, info);
-               if (cpumask)
-                       smp_call_function_many(cpumask, flush_tlb_func_remote,
-                                              (void *)info, 1);
-               return;
-       }
-
        /*
         * If no page tables were freed, we can skip sending IPIs to
         * CPUs in lazy TLB mode. They will flush the CPU themselves
index df1d959..3507f45 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/smp.h>
 #include <asm/pci_x86.h>
 #include <asm/setup.h>
+#include <asm/irqdomain.h>
 
 unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
                                PCI_PROBE_MMCONF;
@@ -633,8 +634,9 @@ static void set_dev_domain_options(struct pci_dev *pdev)
 
 int pcibios_add_device(struct pci_dev *dev)
 {
-       struct setup_data *data;
        struct pci_setup_rom *rom;
+       struct irq_domain *msidom;
+       struct setup_data *data;
        u64 pa_data;
 
        pa_data = boot_params.hdr.setup_data;
@@ -661,6 +663,20 @@ int pcibios_add_device(struct pci_dev *dev)
                memunmap(data);
        }
        set_dev_domain_options(dev);
+
+       /*
+        * Setup the initial MSI domain of the device. If the underlying
+        * bus has a PCI/MSI irqdomain associated use the bus domain,
+        * otherwise set the default domain. This ensures that special irq
+        * domains e.g. VMD are preserved. The default ensures initial
+        * operation if irq remapping is not active. If irq remapping is
+        * active it will overwrite the domain pointer when the device is
+        * associated to a remapping domain.
+        */
+       msidom = dev_get_msi_domain(&dev->bus->dev);
+       if (!msidom)
+               msidom = x86_pci_msi_default_domain;
+       dev_set_msi_domain(&dev->dev, msidom);
        return 0;
 }
 
index 5fc617e..00bfa1e 100644 (file)
@@ -3,16 +3,17 @@
 #include <linux/init.h>
 #include <asm/pci_x86.h>
 #include <asm/x86_init.h>
+#include <asm/irqdomain.h>
 
 /* arch_initcall has too random ordering, so call the initializers
    in the right sequence from here. */
 static __init int pci_arch_init(void)
 {
-#ifdef CONFIG_PCI_DIRECT
-       int type = 0;
+       int type;
+
+       x86_create_pci_msi_domain();
 
        type = pci_direct_probe();
-#endif
 
        if (!(pci_probe & PCI_PROBE_NOEARLY))
                pci_mmcfg_early_init();
@@ -20,18 +21,16 @@ static __init int pci_arch_init(void)
        if (x86_init.pci.arch_init && !x86_init.pci.arch_init())
                return 0;
 
-#ifdef CONFIG_PCI_BIOS
        pci_pcbios_init();
-#endif
+
        /*
         * don't check for raw_pci_ops here because we want pcbios as last
         * fallback, yet it's needed to run first to set pcibios_last_bus
         * in case legacy PCI probing is used. otherwise detecting peer busses
         * fails.
         */
-#ifdef CONFIG_PCI_DIRECT
        pci_direct_init(type);
-#endif
+
        if (!raw_pci_ops && !raw_pci_ext_ops)
                printk(KERN_ERR
                "PCI: Fatal: No config space access function found\n");
index 89395a5..c552cd2 100644 (file)
@@ -157,6 +157,13 @@ static int acpi_register_gsi_xen(struct device *dev, u32 gsi,
 struct xen_pci_frontend_ops *xen_pci_frontend;
 EXPORT_SYMBOL_GPL(xen_pci_frontend);
 
+struct xen_msi_ops {
+       int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
+       void (*teardown_msi_irqs)(struct pci_dev *dev);
+};
+
+static struct xen_msi_ops xen_msi_ops __ro_after_init;
+
 static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
        int irq, ret, i;
@@ -372,28 +379,122 @@ static void xen_initdom_restore_msi_irqs(struct pci_dev *dev)
                WARN(ret && ret != -ENOSYS, "restore_msi -> %d\n", ret);
        }
 }
-#endif
+#else /* CONFIG_XEN_DOM0 */
+#define xen_initdom_setup_msi_irqs     NULL
+#define xen_initdom_restore_msi_irqs   NULL
+#endif /* !CONFIG_XEN_DOM0 */
 
 static void xen_teardown_msi_irqs(struct pci_dev *dev)
 {
        struct msi_desc *msidesc;
+       int i;
+
+       for_each_pci_msi_entry(msidesc, dev) {
+               if (msidesc->irq) {
+                       for (i = 0; i < msidesc->nvec_used; i++)
+                               xen_destroy_irq(msidesc->irq + i);
+               }
+       }
+}
+
+static void xen_pv_teardown_msi_irqs(struct pci_dev *dev)
+{
+       struct msi_desc *msidesc = first_pci_msi_entry(dev);
 
-       msidesc = first_pci_msi_entry(dev);
        if (msidesc->msi_attrib.is_msix)
                xen_pci_frontend_disable_msix(dev);
        else
                xen_pci_frontend_disable_msi(dev);
 
-       /* Free the IRQ's and the msidesc using the generic code. */
-       default_teardown_msi_irqs(dev);
+       xen_teardown_msi_irqs(dev);
 }
 
-static void xen_teardown_msi_irq(unsigned int irq)
+static int xen_msi_domain_alloc_irqs(struct irq_domain *domain,
+                                    struct device *dev,  int nvec)
 {
-       xen_destroy_irq(irq);
+       int type;
+
+       if (WARN_ON_ONCE(!dev_is_pci(dev)))
+               return -EINVAL;
+
+       if (first_msi_entry(dev)->msi_attrib.is_msix)
+               type = PCI_CAP_ID_MSIX;
+       else
+               type = PCI_CAP_ID_MSI;
+
+       return xen_msi_ops.setup_msi_irqs(to_pci_dev(dev), nvec, type);
 }
 
-#endif
+static void xen_msi_domain_free_irqs(struct irq_domain *domain,
+                                    struct device *dev)
+{
+       if (WARN_ON_ONCE(!dev_is_pci(dev)))
+               return;
+
+       xen_msi_ops.teardown_msi_irqs(to_pci_dev(dev));
+}
+
+static struct msi_domain_ops xen_pci_msi_domain_ops = {
+       .domain_alloc_irqs      = xen_msi_domain_alloc_irqs,
+       .domain_free_irqs       = xen_msi_domain_free_irqs,
+};
+
+static struct msi_domain_info xen_pci_msi_domain_info = {
+       .ops                    = &xen_pci_msi_domain_ops,
+};
+
+/*
+ * This irq domain is a blatant violation of the irq domain design, but
+ * distangling XEN into real irq domains is not a job for mere mortals with
+ * limited XENology. But it's the least dangerous way for a mere mortal to
+ * get rid of the arch_*_msi_irqs() hackery in order to store the irq
+ * domain pointer in struct device. This irq domain wrappery allows to do
+ * that without breaking XEN terminally.
+ */
+static __init struct irq_domain *xen_create_pci_msi_domain(void)
+{
+       struct irq_domain *d = NULL;
+       struct fwnode_handle *fn;
+
+       fn = irq_domain_alloc_named_fwnode("XEN-MSI");
+       if (fn)
+               d = msi_create_irq_domain(fn, &xen_pci_msi_domain_info, NULL);
+
+       /* FIXME: No idea how to survive if this fails */
+       BUG_ON(!d);
+
+       return d;
+}
+
+static __init void xen_setup_pci_msi(void)
+{
+       if (xen_pv_domain()) {
+               if (xen_initial_domain()) {
+                       xen_msi_ops.setup_msi_irqs = xen_initdom_setup_msi_irqs;
+                       x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs;
+               } else {
+                       xen_msi_ops.setup_msi_irqs = xen_setup_msi_irqs;
+               }
+               xen_msi_ops.teardown_msi_irqs = xen_pv_teardown_msi_irqs;
+               pci_msi_ignore_mask = 1;
+       } else if (xen_hvm_domain()) {
+               xen_msi_ops.setup_msi_irqs = xen_hvm_setup_msi_irqs;
+               xen_msi_ops.teardown_msi_irqs = xen_teardown_msi_irqs;
+       } else {
+               WARN_ON_ONCE(1);
+               return;
+       }
+
+       /*
+        * Override the PCI/MSI irq domain init function. No point
+        * in allocating the native domain and never use it.
+        */
+       x86_init.irqs.create_pci_msi_domain = xen_create_pci_msi_domain;
+}
+
+#else /* CONFIG_PCI_MSI */
+static inline void xen_setup_pci_msi(void) { }
+#endif /* CONFIG_PCI_MSI */
 
 int __init pci_xen_init(void)
 {
@@ -410,17 +511,12 @@ int __init pci_xen_init(void)
        /* Keep ACPI out of the picture */
        acpi_noirq_set();
 
-#ifdef CONFIG_PCI_MSI
-       x86_msi.setup_msi_irqs = xen_setup_msi_irqs;
-       x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
-       x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs;
-       pci_msi_ignore_mask = 1;
-#endif
+       xen_setup_pci_msi();
        return 0;
 }
 
 #ifdef CONFIG_PCI_MSI
-void __init xen_msi_init(void)
+static void __init xen_hvm_msi_init(void)
 {
        if (!disable_apic) {
                /*
@@ -435,9 +531,7 @@ void __init xen_msi_init(void)
                    ((eax & XEN_HVM_CPUID_APIC_ACCESS_VIRT) && boot_cpu_has(X86_FEATURE_APIC)))
                        return;
        }
-
-       x86_msi.setup_msi_irqs = xen_hvm_setup_msi_irqs;
-       x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
+       xen_setup_pci_msi();
 }
 #endif
 
@@ -460,7 +554,7 @@ int __init pci_xen_hvm_init(void)
         * We need to wait until after x2apic is initialized
         * before we can set MSI IRQ ops.
         */
-       x86_platform.apic_post_init = xen_msi_init;
+       x86_platform.apic_post_init = xen_hvm_msi_init;
 #endif
        return 0;
 }
@@ -470,12 +564,7 @@ int __init pci_xen_initial_domain(void)
 {
        int irq;
 
-#ifdef CONFIG_PCI_MSI
-       x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
-       x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
-       x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs;
-       pci_msi_ignore_mask = 1;
-#endif
+       xen_setup_pci_msi();
        __acpi_register_gsi = acpi_register_gsi_xen;
        __acpi_unregister_gsi = NULL;
        /*
index d37ebe6..8a26e70 100644 (file)
@@ -90,6 +90,9 @@ static const unsigned long * const efi_tables[] = {
        &efi.tpm_log,
        &efi.tpm_final_log,
        &efi_rng_seed,
+#ifdef CONFIG_LOAD_UEFI_KEYS
+       &efi.mokvar_table,
+#endif
 };
 
 u64 efi_setup;         /* efi setup_data physical address */
index a3693c8..224ff05 100644 (file)
@@ -1,2 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_X86_UV)           += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o uv_nmi.o
+obj-$(CONFIG_X86_UV)           += bios_uv.o uv_irq.o uv_sysfs.o uv_time.o uv_nmi.o
index a2f447d..54511ea 100644 (file)
@@ -2,8 +2,9 @@
 /*
  * BIOS run time interface routines.
  *
- *  Copyright (c) 2008-2009 Silicon Graphics, Inc.  All Rights Reserved.
- *  Copyright (c) Russ Anderson <rja@sgi.com>
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+ * Copyright (C) 2007-2017 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) Russ Anderson <rja@sgi.com>
  */
 
 #include <linux/efi.h>
@@ -170,16 +171,27 @@ int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus)
                                (u64)decode, (u64)domain, (u64)bus, 0, 0);
 }
 
-int uv_bios_init(void)
+unsigned long get_uv_systab_phys(bool msg)
 {
-       uv_systab = NULL;
        if ((uv_systab_phys == EFI_INVALID_TABLE_ADDR) ||
            !uv_systab_phys || efi_runtime_disabled()) {
-               pr_crit("UV: UVsystab: missing\n");
-               return -EEXIST;
+               if (msg)
+                       pr_crit("UV: UVsystab: missing\n");
+               return 0;
        }
+       return uv_systab_phys;
+}
+
+int uv_bios_init(void)
+{
+       unsigned long uv_systab_phys_addr;
+
+       uv_systab = NULL;
+       uv_systab_phys_addr = get_uv_systab_phys(1);
+       if (!uv_systab_phys_addr)
+               return -EEXIST;
 
-       uv_systab = ioremap(uv_systab_phys, sizeof(struct uv_systab));
+       uv_systab = ioremap(uv_systab_phys_addr, sizeof(struct uv_systab));
        if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) {
                pr_err("UV: UVsystab: bad signature!\n");
                iounmap(uv_systab);
@@ -191,7 +203,7 @@ int uv_bios_init(void)
                int size = uv_systab->size;
 
                iounmap(uv_systab);
-               uv_systab = ioremap(uv_systab_phys, size);
+               uv_systab = ioremap(uv_systab_phys_addr, size);
                if (!uv_systab) {
                        pr_err("UV: UVsystab: ioremap(%d) failed!\n", size);
                        return -EFAULT;
diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c
deleted file mode 100644 (file)
index 62ea907..0000000
+++ /dev/null
@@ -1,2097 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *     SGI UltraViolet TLB flush routines.
- *
- *     (c) 2008-2014 Cliff Wickman <cpw@sgi.com>, SGI.
- */
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
-#include <linux/debugfs.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-
-#include <asm/mmu_context.h>
-#include <asm/uv/uv.h>
-#include <asm/uv/uv_mmrs.h>
-#include <asm/uv/uv_hub.h>
-#include <asm/uv/uv_bau.h>
-#include <asm/apic.h>
-#include <asm/tsc.h>
-#include <asm/irq_vectors.h>
-#include <asm/timer.h>
-
-static struct bau_operations ops __ro_after_init;
-
-static int timeout_us;
-static bool nobau = true;
-static int nobau_perm;
-
-/* tunables: */
-static int max_concurr         = MAX_BAU_CONCURRENT;
-static int max_concurr_const   = MAX_BAU_CONCURRENT;
-static int plugged_delay       = PLUGGED_DELAY;
-static int plugsb4reset                = PLUGSB4RESET;
-static int giveup_limit                = GIVEUP_LIMIT;
-static int timeoutsb4reset     = TIMEOUTSB4RESET;
-static int ipi_reset_limit     = IPI_RESET_LIMIT;
-static int complete_threshold  = COMPLETE_THRESHOLD;
-static int congested_respns_us = CONGESTED_RESPONSE_US;
-static int congested_reps      = CONGESTED_REPS;
-static int disabled_period     = DISABLED_PERIOD;
-
-static struct tunables tunables[] = {
-       {&max_concurr,           MAX_BAU_CONCURRENT}, /* must be [0] */
-       {&plugged_delay,         PLUGGED_DELAY},
-       {&plugsb4reset,          PLUGSB4RESET},
-       {&timeoutsb4reset,       TIMEOUTSB4RESET},
-       {&ipi_reset_limit,       IPI_RESET_LIMIT},
-       {&complete_threshold,    COMPLETE_THRESHOLD},
-       {&congested_respns_us,   CONGESTED_RESPONSE_US},
-       {&congested_reps,        CONGESTED_REPS},
-       {&disabled_period,       DISABLED_PERIOD},
-       {&giveup_limit,          GIVEUP_LIMIT}
-};
-
-static struct dentry *tunables_dir;
-
-/* these correspond to the statistics printed by ptc_seq_show() */
-static char *stat_description[] = {
-       "sent:     number of shootdown messages sent",
-       "stime:    time spent sending messages",
-       "numuvhubs: number of hubs targeted with shootdown",
-       "numuvhubs16: number times 16 or more hubs targeted",
-       "numuvhubs8: number times 8 or more hubs targeted",
-       "numuvhubs4: number times 4 or more hubs targeted",
-       "numuvhubs2: number times 2 or more hubs targeted",
-       "numuvhubs1: number times 1 hub targeted",
-       "numcpus:  number of cpus targeted with shootdown",
-       "dto:      number of destination timeouts",
-       "retries:  destination timeout retries sent",
-       "rok:   :  destination timeouts successfully retried",
-       "resetp:   ipi-style resource resets for plugs",
-       "resett:   ipi-style resource resets for timeouts",
-       "giveup:   fall-backs to ipi-style shootdowns",
-       "sto:      number of source timeouts",
-       "bz:       number of stay-busy's",
-       "throt:    number times spun in throttle",
-       "swack:   image of UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE",
-       "recv:     shootdown messages received",
-       "rtime:    time spent processing messages",
-       "all:      shootdown all-tlb messages",
-       "one:      shootdown one-tlb messages",
-       "mult:     interrupts that found multiple messages",
-       "none:     interrupts that found no messages",
-       "retry:    number of retry messages processed",
-       "canc:     number messages canceled by retries",
-       "nocan:    number retries that found nothing to cancel",
-       "reset:    number of ipi-style reset requests processed",
-       "rcan:     number messages canceled by reset requests",
-       "disable:  number times use of the BAU was disabled",
-       "enable:   number times use of the BAU was re-enabled"
-};
-
-static int __init setup_bau(char *arg)
-{
-       int result;
-
-       if (!arg)
-               return -EINVAL;
-
-       result = strtobool(arg, &nobau);
-       if (result)
-               return result;
-
-       /* we need to flip the logic here, so that bau=y sets nobau to false */
-       nobau = !nobau;
-
-       if (!nobau)
-               pr_info("UV BAU Enabled\n");
-       else
-               pr_info("UV BAU Disabled\n");
-
-       return 0;
-}
-early_param("bau", setup_bau);
-
-/* base pnode in this partition */
-static int uv_base_pnode __read_mostly;
-
-static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
-static DEFINE_PER_CPU(struct bau_control, bau_control);
-static DEFINE_PER_CPU(cpumask_var_t, uv_flush_tlb_mask);
-
-static void
-set_bau_on(void)
-{
-       int cpu;
-       struct bau_control *bcp;
-
-       if (nobau_perm) {
-               pr_info("BAU not initialized; cannot be turned on\n");
-               return;
-       }
-       nobau = false;
-       for_each_present_cpu(cpu) {
-               bcp = &per_cpu(bau_control, cpu);
-               bcp->nobau = false;
-       }
-       pr_info("BAU turned on\n");
-       return;
-}
-
-static void
-set_bau_off(void)
-{
-       int cpu;
-       struct bau_control *bcp;
-
-       nobau = true;
-       for_each_present_cpu(cpu) {
-               bcp = &per_cpu(bau_control, cpu);
-               bcp->nobau = true;
-       }
-       pr_info("BAU turned off\n");
-       return;
-}
-
-/*
- * Determine the first node on a uvhub. 'Nodes' are used for kernel
- * memory allocation.
- */
-static int __init uvhub_to_first_node(int uvhub)
-{
-       int node, b;
-
-       for_each_online_node(node) {
-               b = uv_node_to_blade_id(node);
-               if (uvhub == b)
-                       return node;
-       }
-       return -1;
-}
-
-/*
- * Determine the apicid of the first cpu on a uvhub.
- */
-static int __init uvhub_to_first_apicid(int uvhub)
-{
-       int cpu;
-
-       for_each_present_cpu(cpu)
-               if (uvhub == uv_cpu_to_blade_id(cpu))
-                       return per_cpu(x86_cpu_to_apicid, cpu);
-       return -1;
-}
-
-/*
- * Free a software acknowledge hardware resource by clearing its Pending
- * bit. This will return a reply to the sender.
- * If the message has timed out, a reply has already been sent by the
- * hardware but the resource has not been released. In that case our
- * clear of the Timeout bit (as well) will free the resource. No reply will
- * be sent (the hardware will only do one reply per message).
- */
-static void reply_to_message(struct msg_desc *mdp, struct bau_control *bcp,
-                                               int do_acknowledge)
-{
-       unsigned long dw;
-       struct bau_pq_entry *msg;
-
-       msg = mdp->msg;
-       if (!msg->canceled && do_acknowledge) {
-               dw = (msg->swack_vec << UV_SW_ACK_NPENDING) | msg->swack_vec;
-               ops.write_l_sw_ack(dw);
-       }
-       msg->replied_to = 1;
-       msg->swack_vec = 0;
-}
-
-/*
- * Process the receipt of a RETRY message
- */
-static void bau_process_retry_msg(struct msg_desc *mdp,
-                                       struct bau_control *bcp)
-{
-       int i;
-       int cancel_count = 0;
-       unsigned long msg_res;
-       unsigned long mmr = 0;
-       struct bau_pq_entry *msg = mdp->msg;
-       struct bau_pq_entry *msg2;
-       struct ptc_stats *stat = bcp->statp;
-
-       stat->d_retries++;
-       /*
-        * cancel any message from msg+1 to the retry itself
-        */
-       for (msg2 = msg+1, i = 0; i < DEST_Q_SIZE; msg2++, i++) {
-               if (msg2 > mdp->queue_last)
-                       msg2 = mdp->queue_first;
-               if (msg2 == msg)
-                       break;
-
-               /* same conditions for cancellation as do_reset */
-               if ((msg2->replied_to == 0) && (msg2->canceled == 0) &&
-                   (msg2->swack_vec) && ((msg2->swack_vec &
-                       msg->swack_vec) == 0) &&
-                   (msg2->sending_cpu == msg->sending_cpu) &&
-                   (msg2->msg_type != MSG_NOOP)) {
-                       mmr = ops.read_l_sw_ack();
-                       msg_res = msg2->swack_vec;
-                       /*
-                        * This is a message retry; clear the resources held
-                        * by the previous message only if they timed out.
-                        * If it has not timed out we have an unexpected
-                        * situation to report.
-                        */
-                       if (mmr & (msg_res << UV_SW_ACK_NPENDING)) {
-                               unsigned long mr;
-                               /*
-                                * Is the resource timed out?
-                                * Make everyone ignore the cancelled message.
-                                */
-                               msg2->canceled = 1;
-                               stat->d_canceled++;
-                               cancel_count++;
-                               mr = (msg_res << UV_SW_ACK_NPENDING) | msg_res;
-                               ops.write_l_sw_ack(mr);
-                       }
-               }
-       }
-       if (!cancel_count)
-               stat->d_nocanceled++;
-}
-
-/*
- * Do all the things a cpu should do for a TLB shootdown message.
- * Other cpu's may come here at the same time for this message.
- */
-static void bau_process_message(struct msg_desc *mdp, struct bau_control *bcp,
-                                               int do_acknowledge)
-{
-       short socket_ack_count = 0;
-       short *sp;
-       struct atomic_short *asp;
-       struct ptc_stats *stat = bcp->statp;
-       struct bau_pq_entry *msg = mdp->msg;
-       struct bau_control *smaster = bcp->socket_master;
-
-       /*
-        * This must be a normal message, or retry of a normal message
-        */
-       if (msg->address == TLB_FLUSH_ALL) {
-               flush_tlb_local();
-               stat->d_alltlb++;
-       } else {
-               flush_tlb_one_user(msg->address);
-               stat->d_onetlb++;
-       }
-       stat->d_requestee++;
-
-       /*
-        * One cpu on each uvhub has the additional job on a RETRY
-        * of releasing the resource held by the message that is
-        * being retried.  That message is identified by sending
-        * cpu number.
-        */
-       if (msg->msg_type == MSG_RETRY && bcp == bcp->uvhub_master)
-               bau_process_retry_msg(mdp, bcp);
-
-       /*
-        * This is a swack message, so we have to reply to it.
-        * Count each responding cpu on the socket. This avoids
-        * pinging the count's cache line back and forth between
-        * the sockets.
-        */
-       sp = &smaster->socket_acknowledge_count[mdp->msg_slot];
-       asp = (struct atomic_short *)sp;
-       socket_ack_count = atom_asr(1, asp);
-       if (socket_ack_count == bcp->cpus_in_socket) {
-               int msg_ack_count;
-               /*
-                * Both sockets dump their completed count total into
-                * the message's count.
-                */
-               *sp = 0;
-               asp = (struct atomic_short *)&msg->acknowledge_count;
-               msg_ack_count = atom_asr(socket_ack_count, asp);
-
-               if (msg_ack_count == bcp->cpus_in_uvhub) {
-                       /*
-                        * All cpus in uvhub saw it; reply
-                        * (unless we are in the UV2 workaround)
-                        */
-                       reply_to_message(mdp, bcp, do_acknowledge);
-               }
-       }
-
-       return;
-}
-
-/*
- * Determine the first cpu on a pnode.
- */
-static int pnode_to_first_cpu(int pnode, struct bau_control *smaster)
-{
-       int cpu;
-       struct hub_and_pnode *hpp;
-
-       for_each_present_cpu(cpu) {
-               hpp = &smaster->thp[cpu];
-               if (pnode == hpp->pnode)
-                       return cpu;
-       }
-       return -1;
-}
-
-/*
- * Last resort when we get a large number of destination timeouts is
- * to clear resources held by a given cpu.
- * Do this with IPI so that all messages in the BAU message queue
- * can be identified by their nonzero swack_vec field.
- *
- * This is entered for a single cpu on the uvhub.
- * The sender want's this uvhub to free a specific message's
- * swack resources.
- */
-static void do_reset(void *ptr)
-{
-       int i;
-       struct bau_control *bcp = &per_cpu(bau_control, smp_processor_id());
-       struct reset_args *rap = (struct reset_args *)ptr;
-       struct bau_pq_entry *msg;
-       struct ptc_stats *stat = bcp->statp;
-
-       stat->d_resets++;
-       /*
-        * We're looking for the given sender, and
-        * will free its swack resource.
-        * If all cpu's finally responded after the timeout, its
-        * message 'replied_to' was set.
-        */
-       for (msg = bcp->queue_first, i = 0; i < DEST_Q_SIZE; msg++, i++) {
-               unsigned long msg_res;
-               /* do_reset: same conditions for cancellation as
-                  bau_process_retry_msg() */
-               if ((msg->replied_to == 0) &&
-                   (msg->canceled == 0) &&
-                   (msg->sending_cpu == rap->sender) &&
-                   (msg->swack_vec) &&
-                   (msg->msg_type != MSG_NOOP)) {
-                       unsigned long mmr;
-                       unsigned long mr;
-                       /*
-                        * make everyone else ignore this message
-                        */
-                       msg->canceled = 1;
-                       /*
-                        * only reset the resource if it is still pending
-                        */
-                       mmr = ops.read_l_sw_ack();
-                       msg_res = msg->swack_vec;
-                       mr = (msg_res << UV_SW_ACK_NPENDING) | msg_res;
-                       if (mmr & msg_res) {
-                               stat->d_rcanceled++;
-                               ops.write_l_sw_ack(mr);
-                       }
-               }
-       }
-       return;
-}
-
-/*
- * Use IPI to get all target uvhubs to release resources held by
- * a given sending cpu number.
- */
-static void reset_with_ipi(struct pnmask *distribution, struct bau_control *bcp)
-{
-       int pnode;
-       int apnode;
-       int maskbits;
-       int sender = bcp->cpu;
-       cpumask_t *mask = bcp->uvhub_master->cpumask;
-       struct bau_control *smaster = bcp->socket_master;
-       struct reset_args reset_args;
-
-       reset_args.sender = sender;
-       cpumask_clear(mask);
-       /* find a single cpu for each uvhub in this distribution mask */
-       maskbits = sizeof(struct pnmask) * BITSPERBYTE;
-       /* each bit is a pnode relative to the partition base pnode */
-       for (pnode = 0; pnode < maskbits; pnode++) {
-               int cpu;
-               if (!bau_uvhub_isset(pnode, distribution))
-                       continue;
-               apnode = pnode + bcp->partition_base_pnode;
-               cpu = pnode_to_first_cpu(apnode, smaster);
-               cpumask_set_cpu(cpu, mask);
-       }
-
-       /* IPI all cpus; preemption is already disabled */
-       smp_call_function_many(mask, do_reset, (void *)&reset_args, 1);
-       return;
-}
-
-/*
- * Not to be confused with cycles_2_ns() from tsc.c; this gives a relative
- * number, not an absolute. It converts a duration in cycles to a duration in
- * ns.
- */
-static inline unsigned long long cycles_2_ns(unsigned long long cyc)
-{
-       struct cyc2ns_data data;
-       unsigned long long ns;
-
-       cyc2ns_read_begin(&data);
-       ns = mul_u64_u32_shr(cyc, data.cyc2ns_mul, data.cyc2ns_shift);
-       cyc2ns_read_end();
-
-       return ns;
-}
-
-/*
- * The reverse of the above; converts a duration in ns to a duration in cycles.
- */
-static inline unsigned long long ns_2_cycles(unsigned long long ns)
-{
-       struct cyc2ns_data data;
-       unsigned long long cyc;
-
-       cyc2ns_read_begin(&data);
-       cyc = (ns << data.cyc2ns_shift) / data.cyc2ns_mul;
-       cyc2ns_read_end();
-
-       return cyc;
-}
-
-static inline unsigned long cycles_2_us(unsigned long long cyc)
-{
-       return cycles_2_ns(cyc) / NSEC_PER_USEC;
-}
-
-static inline cycles_t sec_2_cycles(unsigned long sec)
-{
-       return ns_2_cycles(sec * NSEC_PER_SEC);
-}
-
-static inline unsigned long long usec_2_cycles(unsigned long usec)
-{
-       return ns_2_cycles(usec * NSEC_PER_USEC);
-}
-
-/*
- * wait for all cpus on this hub to finish their sends and go quiet
- * leaves uvhub_quiesce set so that no new broadcasts are started by
- * bau_flush_send_and_wait()
- */
-static inline void quiesce_local_uvhub(struct bau_control *hmaster)
-{
-       atom_asr(1, (struct atomic_short *)&hmaster->uvhub_quiesce);
-}
-
-/*
- * mark this quiet-requestor as done
- */
-static inline void end_uvhub_quiesce(struct bau_control *hmaster)
-{
-       atom_asr(-1, (struct atomic_short *)&hmaster->uvhub_quiesce);
-}
-
-/*
- * UV2 could have an extra bit of status in the ACTIVATION_STATUS_2 register.
- * But not currently used.
- */
-static unsigned long uv2_3_read_status(unsigned long offset, int rshft, int desc)
-{
-       return ((read_lmmr(offset) >> rshft) & UV_ACT_STATUS_MASK) << 1;
-}
-
-/*
- * Entered when a bau descriptor has gone into a permanent busy wait because
- * of a hardware bug.
- * Workaround the bug.
- */
-static int handle_uv2_busy(struct bau_control *bcp)
-{
-       struct ptc_stats *stat = bcp->statp;
-
-       stat->s_uv2_wars++;
-       bcp->busy = 1;
-       return FLUSH_GIVEUP;
-}
-
-static int uv2_3_wait_completion(struct bau_desc *bau_desc,
-                               struct bau_control *bcp, long try)
-{
-       unsigned long descriptor_stat;
-       cycles_t ttm;
-       u64 mmr_offset = bcp->status_mmr;
-       int right_shift = bcp->status_index;
-       int desc = bcp->uvhub_cpu;
-       long busy_reps = 0;
-       struct ptc_stats *stat = bcp->statp;
-
-       descriptor_stat = uv2_3_read_status(mmr_offset, right_shift, desc);
-
-       /* spin on the status MMR, waiting for it to go idle */
-       while (descriptor_stat != UV2H_DESC_IDLE) {
-               if (descriptor_stat == UV2H_DESC_SOURCE_TIMEOUT) {
-                       /*
-                        * A h/w bug on the destination side may
-                        * have prevented the message being marked
-                        * pending, thus it doesn't get replied to
-                        * and gets continually nacked until it times
-                        * out with a SOURCE_TIMEOUT.
-                        */
-                       stat->s_stimeout++;
-                       return FLUSH_GIVEUP;
-               } else if (descriptor_stat == UV2H_DESC_DEST_TIMEOUT) {
-                       ttm = get_cycles();
-
-                       /*
-                        * Our retries may be blocked by all destination
-                        * swack resources being consumed, and a timeout
-                        * pending.  In that case hardware returns the
-                        * ERROR that looks like a destination timeout.
-                        * Without using the extended status we have to
-                        * deduce from the short time that this was a
-                        * strong nack.
-                        */
-                       if (cycles_2_us(ttm - bcp->send_message) < timeout_us) {
-                               bcp->conseccompletes = 0;
-                               stat->s_plugged++;
-                               /* FLUSH_RETRY_PLUGGED causes hang on boot */
-                               return FLUSH_GIVEUP;
-                       }
-                       stat->s_dtimeout++;
-                       bcp->conseccompletes = 0;
-                       /* FLUSH_RETRY_TIMEOUT causes hang on boot */
-                       return FLUSH_GIVEUP;
-               } else {
-                       busy_reps++;
-                       if (busy_reps > 1000000) {
-                               /* not to hammer on the clock */
-                               busy_reps = 0;
-                               ttm = get_cycles();
-                               if ((ttm - bcp->send_message) > bcp->timeout_interval)
-                                       return handle_uv2_busy(bcp);
-                       }
-                       /*
-                        * descriptor_stat is still BUSY
-                        */
-                       cpu_relax();
-               }
-               descriptor_stat = uv2_3_read_status(mmr_offset, right_shift, desc);
-       }
-       bcp->conseccompletes++;
-       return FLUSH_COMPLETE;
-}
-
-/*
- * Returns the status of current BAU message for cpu desc as a bit field
- * [Error][Busy][Aux]
- */
-static u64 read_status(u64 status_mmr, int index, int desc)
-{
-       u64 stat;
-
-       stat = ((read_lmmr(status_mmr) >> index) & UV_ACT_STATUS_MASK) << 1;
-       stat |= (read_lmmr(UVH_LB_BAU_SB_ACTIVATION_STATUS_2) >> desc) & 0x1;
-
-       return stat;
-}
-
-static int uv4_wait_completion(struct bau_desc *bau_desc,
-                               struct bau_control *bcp, long try)
-{
-       struct ptc_stats *stat = bcp->statp;
-       u64 descriptor_stat;
-       u64 mmr = bcp->status_mmr;
-       int index = bcp->status_index;
-       int desc = bcp->uvhub_cpu;
-
-       descriptor_stat = read_status(mmr, index, desc);
-
-       /* spin on the status MMR, waiting for it to go idle */
-       while (descriptor_stat != UV2H_DESC_IDLE) {
-               switch (descriptor_stat) {
-               case UV2H_DESC_SOURCE_TIMEOUT:
-                       stat->s_stimeout++;
-                       return FLUSH_GIVEUP;
-
-               case UV2H_DESC_DEST_TIMEOUT:
-                       stat->s_dtimeout++;
-                       bcp->conseccompletes = 0;
-                       return FLUSH_RETRY_TIMEOUT;
-
-               case UV2H_DESC_DEST_STRONG_NACK:
-                       stat->s_plugged++;
-                       bcp->conseccompletes = 0;
-                       return FLUSH_RETRY_PLUGGED;
-
-               case UV2H_DESC_DEST_PUT_ERR:
-                       bcp->conseccompletes = 0;
-                       return FLUSH_GIVEUP;
-
-               default:
-                       /* descriptor_stat is still BUSY */
-                       cpu_relax();
-               }
-               descriptor_stat = read_status(mmr, index, desc);
-       }
-       bcp->conseccompletes++;
-       return FLUSH_COMPLETE;
-}
-
-/*
- * Our retries are blocked by all destination sw ack resources being
- * in use, and a timeout is pending. In that case hardware immediately
- * returns the ERROR that looks like a destination timeout.
- */
-static void destination_plugged(struct bau_desc *bau_desc,
-                       struct bau_control *bcp,
-                       struct bau_control *hmaster, struct ptc_stats *stat)
-{
-       udelay(bcp->plugged_delay);
-       bcp->plugged_tries++;
-
-       if (bcp->plugged_tries >= bcp->plugsb4reset) {
-               bcp->plugged_tries = 0;
-
-               quiesce_local_uvhub(hmaster);
-
-               spin_lock(&hmaster->queue_lock);
-               reset_with_ipi(&bau_desc->distribution, bcp);
-               spin_unlock(&hmaster->queue_lock);
-
-               end_uvhub_quiesce(hmaster);
-
-               bcp->ipi_attempts++;
-               stat->s_resets_plug++;
-       }
-}
-
-static void destination_timeout(struct bau_desc *bau_desc,
-                       struct bau_control *bcp, struct bau_control *hmaster,
-                       struct ptc_stats *stat)
-{
-       hmaster->max_concurr = 1;
-       bcp->timeout_tries++;
-       if (bcp->timeout_tries >= bcp->timeoutsb4reset) {
-               bcp->timeout_tries = 0;
-
-               quiesce_local_uvhub(hmaster);
-
-               spin_lock(&hmaster->queue_lock);
-               reset_with_ipi(&bau_desc->distribution, bcp);
-               spin_unlock(&hmaster->queue_lock);
-
-               end_uvhub_quiesce(hmaster);
-
-               bcp->ipi_attempts++;
-               stat->s_resets_timeout++;
-       }
-}
-
-/*
- * Stop all cpus on a uvhub from using the BAU for a period of time.
- * This is reversed by check_enable.
- */
-static void disable_for_period(struct bau_control *bcp, struct ptc_stats *stat)
-{
-       int tcpu;
-       struct bau_control *tbcp;
-       struct bau_control *hmaster;
-       cycles_t tm1;
-
-       hmaster = bcp->uvhub_master;
-       spin_lock(&hmaster->disable_lock);
-       if (!bcp->baudisabled) {
-               stat->s_bau_disabled++;
-               tm1 = get_cycles();
-               for_each_present_cpu(tcpu) {
-                       tbcp = &per_cpu(bau_control, tcpu);
-                       if (tbcp->uvhub_master == hmaster) {
-                               tbcp->baudisabled = 1;
-                               tbcp->set_bau_on_time =
-                                       tm1 + bcp->disabled_period;
-                       }
-               }
-       }
-       spin_unlock(&hmaster->disable_lock);
-}
-
-static void count_max_concurr(int stat, struct bau_control *bcp,
-                               struct bau_control *hmaster)
-{
-       bcp->plugged_tries = 0;
-       bcp->timeout_tries = 0;
-       if (stat != FLUSH_COMPLETE)
-               return;
-       if (bcp->conseccompletes <= bcp->complete_threshold)
-               return;
-       if (hmaster->max_concurr >= hmaster->max_concurr_const)
-               return;
-       hmaster->max_concurr++;
-}
-
-static void record_send_stats(cycles_t time1, cycles_t time2,
-               struct bau_control *bcp, struct ptc_stats *stat,
-               int completion_status, int try)
-{
-       cycles_t elapsed;
-
-       if (time2 > time1) {
-               elapsed = time2 - time1;
-               stat->s_time += elapsed;
-
-               if ((completion_status == FLUSH_COMPLETE) && (try == 1)) {
-                       bcp->period_requests++;
-                       bcp->period_time += elapsed;
-                       if ((elapsed > usec_2_cycles(bcp->cong_response_us)) &&
-                           (bcp->period_requests > bcp->cong_reps) &&
-                           ((bcp->period_time / bcp->period_requests) >
-                                       usec_2_cycles(bcp->cong_response_us))) {
-                               stat->s_congested++;
-                               disable_for_period(bcp, stat);
-                       }
-               }
-       } else
-               stat->s_requestor--;
-
-       if (completion_status == FLUSH_COMPLETE && try > 1)
-               stat->s_retriesok++;
-       else if (completion_status == FLUSH_GIVEUP) {
-               stat->s_giveup++;
-               if (get_cycles() > bcp->period_end)
-                       bcp->period_giveups = 0;
-               bcp->period_giveups++;
-               if (bcp->period_giveups == 1)
-                       bcp->period_end = get_cycles() + bcp->disabled_period;
-               if (bcp->period_giveups > bcp->giveup_limit) {
-                       disable_for_period(bcp, stat);
-                       stat->s_giveuplimit++;
-               }
-       }
-}
-
-/*
- * Handle the completion status of a message send.
- */
-static void handle_cmplt(int completion_status, struct bau_desc *bau_desc,
-                       struct bau_control *bcp, struct bau_control *hmaster,
-                       struct ptc_stats *stat)
-{
-       if (completion_status == FLUSH_RETRY_PLUGGED)
-               destination_plugged(bau_desc, bcp, hmaster, stat);
-       else if (completion_status == FLUSH_RETRY_TIMEOUT)
-               destination_timeout(bau_desc, bcp, hmaster, stat);
-}
-
-/*
- * Send a broadcast and wait for it to complete.
- *
- * The flush_mask contains the cpus the broadcast is to be sent to including
- * cpus that are on the local uvhub.
- *
- * Returns 0 if all flushing represented in the mask was done.
- * Returns 1 if it gives up entirely and the original cpu mask is to be
- * returned to the kernel.
- */
-static int uv_flush_send_and_wait(struct cpumask *flush_mask,
-                                 struct bau_control *bcp,
-                                 struct bau_desc *bau_desc)
-{
-       int seq_number = 0;
-       int completion_stat = 0;
-       long try = 0;
-       unsigned long index;
-       cycles_t time1;
-       cycles_t time2;
-       struct ptc_stats *stat = bcp->statp;
-       struct bau_control *hmaster = bcp->uvhub_master;
-       struct uv2_3_bau_msg_header *uv2_3_hdr = NULL;
-
-       while (hmaster->uvhub_quiesce)
-               cpu_relax();
-
-       time1 = get_cycles();
-       uv2_3_hdr = &bau_desc->header.uv2_3_hdr;
-
-       do {
-               if (try == 0) {
-                       uv2_3_hdr->msg_type = MSG_REGULAR;
-                       seq_number = bcp->message_number++;
-               } else {
-                       uv2_3_hdr->msg_type = MSG_RETRY;
-                       stat->s_retry_messages++;
-               }
-
-               uv2_3_hdr->sequence = seq_number;
-               index = (1UL << AS_PUSH_SHIFT) | bcp->uvhub_cpu;
-               bcp->send_message = get_cycles();
-
-               write_mmr_activation(index);
-
-               try++;
-               completion_stat = ops.wait_completion(bau_desc, bcp, try);
-
-               handle_cmplt(completion_stat, bau_desc, bcp, hmaster, stat);
-
-               if (bcp->ipi_attempts >= bcp->ipi_reset_limit) {
-                       bcp->ipi_attempts = 0;
-                       stat->s_overipilimit++;
-                       completion_stat = FLUSH_GIVEUP;
-                       break;
-               }
-               cpu_relax();
-       } while ((completion_stat == FLUSH_RETRY_PLUGGED) ||
-                (completion_stat == FLUSH_RETRY_TIMEOUT));
-
-       time2 = get_cycles();
-
-       count_max_concurr(completion_stat, bcp, hmaster);
-
-       while (hmaster->uvhub_quiesce)
-               cpu_relax();
-
-       atomic_dec(&hmaster->active_descriptor_count);
-
-       record_send_stats(time1, time2, bcp, stat, completion_stat, try);
-
-       if (completion_stat == FLUSH_GIVEUP)
-               /* FLUSH_GIVEUP will fall back to using IPI's for tlb flush */
-               return 1;
-       return 0;
-}
-
-/*
- * The BAU is disabled for this uvhub. When the disabled time period has
- * expired re-enable it.
- * Return 0 if it is re-enabled for all cpus on this uvhub.
- */
-static int check_enable(struct bau_control *bcp, struct ptc_stats *stat)
-{
-       int tcpu;
-       struct bau_control *tbcp;
-       struct bau_control *hmaster;
-
-       hmaster = bcp->uvhub_master;
-       spin_lock(&hmaster->disable_lock);
-       if (bcp->baudisabled && (get_cycles() >= bcp->set_bau_on_time)) {
-               stat->s_bau_reenabled++;
-               for_each_present_cpu(tcpu) {
-                       tbcp = &per_cpu(bau_control, tcpu);
-                       if (tbcp->uvhub_master == hmaster) {
-                               tbcp->baudisabled = 0;
-                               tbcp->period_requests = 0;
-                               tbcp->period_time = 0;
-                               tbcp->period_giveups = 0;
-                       }
-               }
-               spin_unlock(&hmaster->disable_lock);
-               return 0;
-       }
-       spin_unlock(&hmaster->disable_lock);
-       return -1;
-}
-
-static void record_send_statistics(struct ptc_stats *stat, int locals, int hubs,
-                               int remotes, struct bau_desc *bau_desc)
-{
-       stat->s_requestor++;
-       stat->s_ntargcpu += remotes + locals;
-       stat->s_ntargremotes += remotes;
-       stat->s_ntarglocals += locals;
-
-       /* uvhub statistics */
-       hubs = bau_uvhub_weight(&bau_desc->distribution);
-       if (locals) {
-               stat->s_ntarglocaluvhub++;
-               stat->s_ntargremoteuvhub += (hubs - 1);
-       } else
-               stat->s_ntargremoteuvhub += hubs;
-
-       stat->s_ntarguvhub += hubs;
-
-       if (hubs >= 16)
-               stat->s_ntarguvhub16++;
-       else if (hubs >= 8)
-               stat->s_ntarguvhub8++;
-       else if (hubs >= 4)
-               stat->s_ntarguvhub4++;
-       else if (hubs >= 2)
-               stat->s_ntarguvhub2++;
-       else
-               stat->s_ntarguvhub1++;
-}
-
-/*
- * Translate a cpu mask to the uvhub distribution mask in the BAU
- * activation descriptor.
- */
-static int set_distrib_bits(struct cpumask *flush_mask, struct bau_control *bcp,
-                       struct bau_desc *bau_desc, int *localsp, int *remotesp)
-{
-       int cpu;
-       int pnode;
-       int cnt = 0;
-       struct hub_and_pnode *hpp;
-
-       for_each_cpu(cpu, flush_mask) {
-               /*
-                * The distribution vector is a bit map of pnodes, relative
-                * to the partition base pnode (and the partition base nasid
-                * in the header).
-                * Translate cpu to pnode and hub using a local memory array.
-                */
-               hpp = &bcp->socket_master->thp[cpu];
-               pnode = hpp->pnode - bcp->partition_base_pnode;
-               bau_uvhub_set(pnode, &bau_desc->distribution);
-               cnt++;
-               if (hpp->uvhub == bcp->uvhub)
-                       (*localsp)++;
-               else
-                       (*remotesp)++;
-       }
-       if (!cnt)
-               return 1;
-       return 0;
-}
-
-/*
- * globally purge translation cache of a virtual address or all TLB's
- * @cpumask: mask of all cpu's in which the address is to be removed
- * @mm: mm_struct containing virtual address range
- * @start: start virtual address to be removed from TLB
- * @end: end virtual address to be remove from TLB
- * @cpu: the current cpu
- *
- * This is the entry point for initiating any UV global TLB shootdown.
- *
- * Purges the translation caches of all specified processors of the given
- * virtual address, or purges all TLB's on specified processors.
- *
- * The caller has derived the cpumask from the mm_struct.  This function
- * is called only if there are bits set in the mask. (e.g. flush_tlb_page())
- *
- * The cpumask is converted into a uvhubmask of the uvhubs containing
- * those cpus.
- *
- * Note that this function should be called with preemption disabled.
- *
- * Returns NULL if all remote flushing was done.
- * Returns pointer to cpumask if some remote flushing remains to be
- * done.  The returned pointer is valid till preemption is re-enabled.
- */
-const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
-                                         const struct flush_tlb_info *info)
-{
-       unsigned int cpu = smp_processor_id();
-       int locals = 0, remotes = 0, hubs = 0;
-       struct bau_desc *bau_desc;
-       struct cpumask *flush_mask;
-       struct ptc_stats *stat;
-       struct bau_control *bcp;
-       unsigned long descriptor_status, status, address;
-
-       bcp = &per_cpu(bau_control, cpu);
-
-       if (bcp->nobau)
-               return cpumask;
-
-       stat = bcp->statp;
-       stat->s_enters++;
-
-       if (bcp->busy) {
-               descriptor_status =
-                       read_lmmr(UVH_LB_BAU_SB_ACTIVATION_STATUS_0);
-               status = ((descriptor_status >> (bcp->uvhub_cpu *
-                       UV_ACT_STATUS_SIZE)) & UV_ACT_STATUS_MASK) << 1;
-               if (status == UV2H_DESC_BUSY)
-                       return cpumask;
-               bcp->busy = 0;
-       }
-
-       /* bau was disabled due to slow response */
-       if (bcp->baudisabled) {
-               if (check_enable(bcp, stat)) {
-                       stat->s_ipifordisabled++;
-                       return cpumask;
-               }
-       }
-
-       /*
-        * Each sending cpu has a per-cpu mask which it fills from the caller's
-        * cpu mask.  All cpus are converted to uvhubs and copied to the
-        * activation descriptor.
-        */
-       flush_mask = (struct cpumask *)per_cpu(uv_flush_tlb_mask, cpu);
-       /* don't actually do a shootdown of the local cpu */
-       cpumask_andnot(flush_mask, cpumask, cpumask_of(cpu));
-
-       if (cpumask_test_cpu(cpu, cpumask))
-               stat->s_ntargself++;
-
-       bau_desc = bcp->descriptor_base;
-       bau_desc += (ITEMS_PER_DESC * bcp->uvhub_cpu);
-       bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
-       if (set_distrib_bits(flush_mask, bcp, bau_desc, &locals, &remotes))
-               return NULL;
-
-       record_send_statistics(stat, locals, hubs, remotes, bau_desc);
-
-       if (!info->end || (info->end - info->start) <= PAGE_SIZE)
-               address = info->start;
-       else
-               address = TLB_FLUSH_ALL;
-
-       switch (bcp->uvhub_version) {
-       case UV_BAU_V2:
-       case UV_BAU_V3:
-               bau_desc->payload.uv2_3.address = address;
-               bau_desc->payload.uv2_3.sending_cpu = cpu;
-               break;
-       case UV_BAU_V4:
-               bau_desc->payload.uv4.address = address;
-               bau_desc->payload.uv4.sending_cpu = cpu;
-               bau_desc->payload.uv4.qualifier = BAU_DESC_QUALIFIER;
-               break;
-       }
-
-       /*
-        * uv_flush_send_and_wait returns 0 if all cpu's were messaged,
-        * or 1 if it gave up and the original cpumask should be returned.
-        */
-       if (!uv_flush_send_and_wait(flush_mask, bcp, bau_desc))
-               return NULL;
-       else
-               return cpumask;
-}
-
-/*
- * Search the message queue for any 'other' unprocessed message with the
- * same software acknowledge resource bit vector as the 'msg' message.
- */
-static struct bau_pq_entry *find_another_by_swack(struct bau_pq_entry *msg,
-                                                 struct bau_control *bcp)
-{
-       struct bau_pq_entry *msg_next = msg + 1;
-       unsigned char swack_vec = msg->swack_vec;
-
-       if (msg_next > bcp->queue_last)
-               msg_next = bcp->queue_first;
-       while (msg_next != msg) {
-               if ((msg_next->canceled == 0) && (msg_next->replied_to == 0) &&
-                               (msg_next->swack_vec == swack_vec))
-                       return msg_next;
-               msg_next++;
-               if (msg_next > bcp->queue_last)
-                       msg_next = bcp->queue_first;
-       }
-       return NULL;
-}
-
-/*
- * UV2 needs to work around a bug in which an arriving message has not
- * set a bit in the UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE register.
- * Such a message must be ignored.
- */
-static void process_uv2_message(struct msg_desc *mdp, struct bau_control *bcp)
-{
-       unsigned long mmr_image;
-       unsigned char swack_vec;
-       struct bau_pq_entry *msg = mdp->msg;
-       struct bau_pq_entry *other_msg;
-
-       mmr_image = ops.read_l_sw_ack();
-       swack_vec = msg->swack_vec;
-
-       if ((swack_vec & mmr_image) == 0) {
-               /*
-                * This message was assigned a swack resource, but no
-                * reserved acknowlegment is pending.
-                * The bug has prevented this message from setting the MMR.
-                */
-               /*
-                * Some message has set the MMR 'pending' bit; it might have
-                * been another message.  Look for that message.
-                */
-               other_msg = find_another_by_swack(msg, bcp);
-               if (other_msg) {
-                       /*
-                        * There is another. Process this one but do not
-                        * ack it.
-                        */
-                       bau_process_message(mdp, bcp, 0);
-                       /*
-                        * Let the natural processing of that other message
-                        * acknowledge it. Don't get the processing of sw_ack's
-                        * out of order.
-                        */
-                       return;
-               }
-       }
-
-       /*
-        * Either the MMR shows this one pending a reply or there is no
-        * other message using this sw_ack, so it is safe to acknowledge it.
-        */
-       bau_process_message(mdp, bcp, 1);
-
-       return;
-}
-
-/*
- * The BAU message interrupt comes here. (registered by set_intr_gate)
- * See entry_64.S
- *
- * We received a broadcast assist message.
- *
- * Interrupts are disabled; this interrupt could represent
- * the receipt of several messages.
- *
- * All cores/threads on this hub get this interrupt.
- * The last one to see it does the software ack.
- * (the resource will not be freed until noninterruptable cpus see this
- *  interrupt; hardware may timeout the s/w ack and reply ERROR)
- */
-DEFINE_IDTENTRY_SYSVEC(sysvec_uv_bau_message)
-{
-       int count = 0;
-       cycles_t time_start;
-       struct bau_pq_entry *msg;
-       struct bau_control *bcp;
-       struct ptc_stats *stat;
-       struct msg_desc msgdesc;
-
-       ack_APIC_irq();
-       kvm_set_cpu_l1tf_flush_l1d();
-       time_start = get_cycles();
-
-       bcp = &per_cpu(bau_control, smp_processor_id());
-       stat = bcp->statp;
-
-       msgdesc.queue_first = bcp->queue_first;
-       msgdesc.queue_last = bcp->queue_last;
-
-       msg = bcp->bau_msg_head;
-       while (msg->swack_vec) {
-               count++;
-
-               msgdesc.msg_slot = msg - msgdesc.queue_first;
-               msgdesc.msg = msg;
-               if (bcp->uvhub_version == UV_BAU_V2)
-                       process_uv2_message(&msgdesc, bcp);
-               else
-                       /* no error workaround for uv3 */
-                       bau_process_message(&msgdesc, bcp, 1);
-
-               msg++;
-               if (msg > msgdesc.queue_last)
-                       msg = msgdesc.queue_first;
-               bcp->bau_msg_head = msg;
-       }
-       stat->d_time += (get_cycles() - time_start);
-       if (!count)
-               stat->d_nomsg++;
-       else if (count > 1)
-               stat->d_multmsg++;
-}
-
-/*
- * Each target uvhub (i.e. a uvhub that has cpu's) needs to have
- * shootdown message timeouts enabled.  The timeout does not cause
- * an interrupt, but causes an error message to be returned to
- * the sender.
- */
-static void __init enable_timeouts(void)
-{
-       int uvhub;
-       int nuvhubs;
-       int pnode;
-       unsigned long mmr_image;
-
-       nuvhubs = uv_num_possible_blades();
-
-       for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
-               if (!uv_blade_nr_possible_cpus(uvhub))
-                       continue;
-
-               pnode = uv_blade_to_pnode(uvhub);
-               mmr_image = read_mmr_misc_control(pnode);
-               /*
-                * Set the timeout period and then lock it in, in three
-                * steps; captures and locks in the period.
-                *
-                * To program the period, the SOFT_ACK_MODE must be off.
-                */
-               mmr_image &= ~(1L << SOFTACK_MSHIFT);
-               write_mmr_misc_control(pnode, mmr_image);
-               /*
-                * Set the 4-bit period.
-                */
-               mmr_image &= ~((unsigned long)0xf << SOFTACK_PSHIFT);
-               mmr_image |= (SOFTACK_TIMEOUT_PERIOD << SOFTACK_PSHIFT);
-               write_mmr_misc_control(pnode, mmr_image);
-
-               mmr_image |= (1L << SOFTACK_MSHIFT);
-               if (is_uv2_hub()) {
-                       /* do not touch the legacy mode bit */
-                       /* hw bug workaround; do not use extended status */
-                       mmr_image &= ~(1L << UV2_EXT_SHFT);
-               } else if (is_uv3_hub()) {
-                       mmr_image &= ~(1L << PREFETCH_HINT_SHFT);
-                       mmr_image |= (1L << SB_STATUS_SHFT);
-               }
-               write_mmr_misc_control(pnode, mmr_image);
-       }
-}
-
-static void *ptc_seq_start(struct seq_file *file, loff_t *offset)
-{
-       if (*offset < num_possible_cpus())
-               return offset;
-       return NULL;
-}
-
-static void *ptc_seq_next(struct seq_file *file, void *data, loff_t *offset)
-{
-       (*offset)++;
-       if (*offset < num_possible_cpus())
-               return offset;
-       return NULL;
-}
-
-static void ptc_seq_stop(struct seq_file *file, void *data)
-{
-}
-
-/*
- * Display the statistics thru /proc/sgi_uv/ptc_statistics
- * 'data' points to the cpu number
- * Note: see the descriptions in stat_description[].
- */
-static int ptc_seq_show(struct seq_file *file, void *data)
-{
-       struct ptc_stats *stat;
-       struct bau_control *bcp;
-       int cpu;
-
-       cpu = *(loff_t *)data;
-       if (!cpu) {
-               seq_puts(file,
-                        "# cpu bauoff sent stime self locals remotes ncpus localhub ");
-               seq_puts(file, "remotehub numuvhubs numuvhubs16 numuvhubs8 ");
-               seq_puts(file,
-                        "numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries ");
-               seq_puts(file,
-                        "rok resetp resett giveup sto bz throt disable ");
-               seq_puts(file,
-                        "enable wars warshw warwaits enters ipidis plugged ");
-               seq_puts(file,
-                        "ipiover glim cong swack recv rtime all one mult ");
-               seq_puts(file, "none retry canc nocan reset rcan\n");
-       }
-       if (cpu < num_possible_cpus() && cpu_online(cpu)) {
-               bcp = &per_cpu(bau_control, cpu);
-               if (bcp->nobau) {
-                       seq_printf(file, "cpu %d bau disabled\n", cpu);
-                       return 0;
-               }
-               stat = bcp->statp;
-               /* source side statistics */
-               seq_printf(file,
-                       "cpu %d %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
-                          cpu, bcp->nobau, stat->s_requestor,
-                          cycles_2_us(stat->s_time),
-                          stat->s_ntargself, stat->s_ntarglocals,
-                          stat->s_ntargremotes, stat->s_ntargcpu,
-                          stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub,
-                          stat->s_ntarguvhub, stat->s_ntarguvhub16);
-               seq_printf(file, "%ld %ld %ld %ld %ld %ld ",
-                          stat->s_ntarguvhub8, stat->s_ntarguvhub4,
-                          stat->s_ntarguvhub2, stat->s_ntarguvhub1,
-                          stat->s_dtimeout, stat->s_strongnacks);
-               seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld ",
-                          stat->s_retry_messages, stat->s_retriesok,
-                          stat->s_resets_plug, stat->s_resets_timeout,
-                          stat->s_giveup, stat->s_stimeout,
-                          stat->s_busy, stat->s_throttles);
-               seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
-                          stat->s_bau_disabled, stat->s_bau_reenabled,
-                          stat->s_uv2_wars, stat->s_uv2_wars_hw,
-                          stat->s_uv2_war_waits, stat->s_enters,
-                          stat->s_ipifordisabled, stat->s_plugged,
-                          stat->s_overipilimit, stat->s_giveuplimit,
-                          stat->s_congested);
-
-               /* destination side statistics */
-               seq_printf(file,
-                       "%lx %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n",
-                          ops.read_g_sw_ack(uv_cpu_to_pnode(cpu)),
-                          stat->d_requestee, cycles_2_us(stat->d_time),
-                          stat->d_alltlb, stat->d_onetlb, stat->d_multmsg,
-                          stat->d_nomsg, stat->d_retries, stat->d_canceled,
-                          stat->d_nocanceled, stat->d_resets,
-                          stat->d_rcanceled);
-       }
-       return 0;
-}
-
-/*
- * Display the tunables thru debugfs
- */
-static ssize_t tunables_read(struct file *file, char __user *userbuf,
-                               size_t count, loff_t *ppos)
-{
-       char *buf;
-       int ret;
-
-       buf = kasprintf(GFP_KERNEL, "%s %s %s\n%d %d %d %d %d %d %d %d %d %d\n",
-               "max_concur plugged_delay plugsb4reset timeoutsb4reset",
-               "ipi_reset_limit complete_threshold congested_response_us",
-               "congested_reps disabled_period giveup_limit",
-               max_concurr, plugged_delay, plugsb4reset,
-               timeoutsb4reset, ipi_reset_limit, complete_threshold,
-               congested_respns_us, congested_reps, disabled_period,
-               giveup_limit);
-
-       if (!buf)
-               return -ENOMEM;
-
-       ret = simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
-       kfree(buf);
-       return ret;
-}
-
-/*
- * handle a write to /proc/sgi_uv/ptc_statistics
- * -1: reset the statistics
- *  0: display meaning of the statistics
- */
-static ssize_t ptc_proc_write(struct file *file, const char __user *user,
-                               size_t count, loff_t *data)
-{
-       int cpu;
-       int i;
-       int elements;
-       long input_arg;
-       char optstr[64];
-       struct ptc_stats *stat;
-
-       if (count == 0 || count > sizeof(optstr))
-               return -EINVAL;
-       if (copy_from_user(optstr, user, count))
-               return -EFAULT;
-       optstr[count - 1] = '\0';
-
-       if (!strcmp(optstr, "on")) {
-               set_bau_on();
-               return count;
-       } else if (!strcmp(optstr, "off")) {
-               set_bau_off();
-               return count;
-       }
-
-       if (kstrtol(optstr, 10, &input_arg) < 0) {
-               pr_debug("%s is invalid\n", optstr);
-               return -EINVAL;
-       }
-
-       if (input_arg == 0) {
-               elements = ARRAY_SIZE(stat_description);
-               pr_debug("# cpu:      cpu number\n");
-               pr_debug("Sender statistics:\n");
-               for (i = 0; i < elements; i++)
-                       pr_debug("%s\n", stat_description[i]);
-       } else if (input_arg == -1) {
-               for_each_present_cpu(cpu) {
-                       stat = &per_cpu(ptcstats, cpu);
-                       memset(stat, 0, sizeof(struct ptc_stats));
-               }
-       }
-
-       return count;
-}
-
-static int local_atoi(const char *name)
-{
-       int val = 0;
-
-       for (;; name++) {
-               switch (*name) {
-               case '0' ... '9':
-                       val = 10*val+(*name-'0');
-                       break;
-               default:
-                       return val;
-               }
-       }
-}
-
-/*
- * Parse the values written to /sys/kernel/debug/sgi_uv/bau_tunables.
- * Zero values reset them to defaults.
- */
-static int parse_tunables_write(struct bau_control *bcp, char *instr,
-                               int count)
-{
-       char *p;
-       char *q;
-       int cnt = 0;
-       int val;
-       int e = ARRAY_SIZE(tunables);
-
-       p = instr + strspn(instr, WHITESPACE);
-       q = p;
-       for (; *p; p = q + strspn(q, WHITESPACE)) {
-               q = p + strcspn(p, WHITESPACE);
-               cnt++;
-               if (q == p)
-                       break;
-       }
-       if (cnt != e) {
-               pr_info("bau tunable error: should be %d values\n", e);
-               return -EINVAL;
-       }
-
-       p = instr + strspn(instr, WHITESPACE);
-       q = p;
-       for (cnt = 0; *p; p = q + strspn(q, WHITESPACE), cnt++) {
-               q = p + strcspn(p, WHITESPACE);
-               val = local_atoi(p);
-               switch (cnt) {
-               case 0:
-                       if (val == 0) {
-                               max_concurr = MAX_BAU_CONCURRENT;
-                               max_concurr_const = MAX_BAU_CONCURRENT;
-                               continue;
-                       }
-                       if (val < 1 || val > bcp->cpus_in_uvhub) {
-                               pr_debug(
-                               "Error: BAU max concurrent %d is invalid\n",
-                               val);
-                               return -EINVAL;
-                       }
-                       max_concurr = val;
-                       max_concurr_const = val;
-                       continue;
-               default:
-                       if (val == 0)
-                               *tunables[cnt].tunp = tunables[cnt].deflt;
-                       else
-                               *tunables[cnt].tunp = val;
-                       continue;
-               }
-       }
-       return 0;
-}
-
-/*
- * Handle a write to debugfs. (/sys/kernel/debug/sgi_uv/bau_tunables)
- */
-static ssize_t tunables_write(struct file *file, const char __user *user,
-                               size_t count, loff_t *data)
-{
-       int cpu;
-       int ret;
-       char instr[100];
-       struct bau_control *bcp;
-
-       if (count == 0 || count > sizeof(instr)-1)
-               return -EINVAL;
-       if (copy_from_user(instr, user, count))
-               return -EFAULT;
-
-       instr[count] = '\0';
-
-       cpu = get_cpu();
-       bcp = &per_cpu(bau_control, cpu);
-       ret = parse_tunables_write(bcp, instr, count);
-       put_cpu();
-       if (ret)
-               return ret;
-
-       for_each_present_cpu(cpu) {
-               bcp = &per_cpu(bau_control, cpu);
-               bcp->max_concurr         = max_concurr;
-               bcp->max_concurr_const   = max_concurr;
-               bcp->plugged_delay       = plugged_delay;
-               bcp->plugsb4reset        = plugsb4reset;
-               bcp->timeoutsb4reset     = timeoutsb4reset;
-               bcp->ipi_reset_limit     = ipi_reset_limit;
-               bcp->complete_threshold  = complete_threshold;
-               bcp->cong_response_us    = congested_respns_us;
-               bcp->cong_reps           = congested_reps;
-               bcp->disabled_period     = sec_2_cycles(disabled_period);
-               bcp->giveup_limit        = giveup_limit;
-       }
-       return count;
-}
-
-static const struct seq_operations uv_ptc_seq_ops = {
-       .start          = ptc_seq_start,
-       .next           = ptc_seq_next,
-       .stop           = ptc_seq_stop,
-       .show           = ptc_seq_show
-};
-
-static int ptc_proc_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &uv_ptc_seq_ops);
-}
-
-static int tunables_open(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static const struct proc_ops uv_ptc_proc_ops = {
-       .proc_open      = ptc_proc_open,
-       .proc_read      = seq_read,
-       .proc_write     = ptc_proc_write,
-       .proc_lseek     = seq_lseek,
-       .proc_release   = seq_release,
-};
-
-static const struct file_operations tunables_fops = {
-       .open           = tunables_open,
-       .read           = tunables_read,
-       .write          = tunables_write,
-       .llseek         = default_llseek,
-};
-
-static int __init uv_ptc_init(void)
-{
-       struct proc_dir_entry *proc_uv_ptc;
-
-       if (!is_uv_system())
-               return 0;
-
-       proc_uv_ptc = proc_create(UV_PTC_BASENAME, 0444, NULL,
-                                 &uv_ptc_proc_ops);
-       if (!proc_uv_ptc) {
-               pr_err("unable to create %s proc entry\n",
-                      UV_PTC_BASENAME);
-               return -EINVAL;
-       }
-
-       tunables_dir = debugfs_create_dir(UV_BAU_TUNABLES_DIR, NULL);
-       debugfs_create_file(UV_BAU_TUNABLES_FILE, 0600, tunables_dir, NULL,
-                           &tunables_fops);
-       return 0;
-}
-
-/*
- * Initialize the sending side's sending buffers.
- */
-static void activation_descriptor_init(int node, int pnode, int base_pnode)
-{
-       int i;
-       int cpu;
-       unsigned long gpa;
-       unsigned long m;
-       unsigned long n;
-       size_t dsize;
-       struct bau_desc *bau_desc;
-       struct bau_desc *bd2;
-       struct uv2_3_bau_msg_header *uv2_3_hdr;
-       struct bau_control *bcp;
-
-       /*
-        * each bau_desc is 64 bytes; there are 8 (ITEMS_PER_DESC)
-        * per cpu; and one per cpu on the uvhub (ADP_SZ)
-        */
-       dsize = sizeof(struct bau_desc) * ADP_SZ * ITEMS_PER_DESC;
-       bau_desc = kmalloc_node(dsize, GFP_KERNEL, node);
-       BUG_ON(!bau_desc);
-
-       gpa = uv_gpa(bau_desc);
-       n = uv_gpa_to_gnode(gpa);
-       m = ops.bau_gpa_to_offset(gpa);
-
-       /* the 14-bit pnode */
-       write_mmr_descriptor_base(pnode,
-               (n << UVH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT | m));
-       /*
-        * Initializing all 8 (ITEMS_PER_DESC) descriptors for each
-        * cpu even though we only use the first one; one descriptor can
-        * describe a broadcast to 256 uv hubs.
-        */
-       for (i = 0, bd2 = bau_desc; i < (ADP_SZ * ITEMS_PER_DESC); i++, bd2++) {
-               memset(bd2, 0, sizeof(struct bau_desc));
-               /*
-                * BIOS uses legacy mode, but uv2 and uv3 hardware always
-                * uses native mode for selective broadcasts.
-                */
-               uv2_3_hdr = &bd2->header.uv2_3_hdr;
-               uv2_3_hdr->swack_flag      = 1;
-               uv2_3_hdr->base_dest_nasid = UV_PNODE_TO_NASID(base_pnode);
-               uv2_3_hdr->dest_subnodeid  = UV_LB_SUBNODEID;
-               uv2_3_hdr->command         = UV_NET_ENDPOINT_INTD;
-       }
-       for_each_present_cpu(cpu) {
-               if (pnode != uv_blade_to_pnode(uv_cpu_to_blade_id(cpu)))
-                       continue;
-               bcp = &per_cpu(bau_control, cpu);
-               bcp->descriptor_base = bau_desc;
-       }
-}
-
-/*
- * initialize the destination side's receiving buffers
- * entered for each uvhub in the partition
- * - node is first node (kernel memory notion) on the uvhub
- * - pnode is the uvhub's physical identifier
- */
-static void pq_init(int node, int pnode)
-{
-       int cpu;
-       size_t plsize;
-       char *cp;
-       void *vp;
-       unsigned long gnode, first, last, tail;
-       struct bau_pq_entry *pqp;
-       struct bau_control *bcp;
-
-       plsize = (DEST_Q_SIZE + 1) * sizeof(struct bau_pq_entry);
-       vp = kmalloc_node(plsize, GFP_KERNEL, node);
-       BUG_ON(!vp);
-
-       pqp = (struct bau_pq_entry *)vp;
-       cp = (char *)pqp + 31;
-       pqp = (struct bau_pq_entry *)(((unsigned long)cp >> 5) << 5);
-
-       for_each_present_cpu(cpu) {
-               if (pnode != uv_cpu_to_pnode(cpu))
-                       continue;
-               /* for every cpu on this pnode: */
-               bcp = &per_cpu(bau_control, cpu);
-               bcp->queue_first        = pqp;
-               bcp->bau_msg_head       = pqp;
-               bcp->queue_last         = pqp + (DEST_Q_SIZE - 1);
-       }
-
-       first = ops.bau_gpa_to_offset(uv_gpa(pqp));
-       last = ops.bau_gpa_to_offset(uv_gpa(pqp + (DEST_Q_SIZE - 1)));
-
-       /*
-        * Pre UV4, the gnode is required to locate the payload queue
-        * and the payload queue tail must be maintained by the kernel.
-        */
-       bcp = &per_cpu(bau_control, smp_processor_id());
-       if (bcp->uvhub_version <= UV_BAU_V3) {
-               tail = first;
-               gnode = uv_gpa_to_gnode(uv_gpa(pqp));
-               first = (gnode << UV_PAYLOADQ_GNODE_SHIFT) | tail;
-               write_mmr_payload_tail(pnode, tail);
-       }
-
-       ops.write_payload_first(pnode, first);
-       ops.write_payload_last(pnode, last);
-
-       /* in effect, all msg_type's are set to MSG_NOOP */
-       memset(pqp, 0, sizeof(struct bau_pq_entry) * DEST_Q_SIZE);
-}
-
-/*
- * Initialization of each UV hub's structures
- */
-static void __init init_uvhub(int uvhub, int vector, int base_pnode)
-{
-       int node;
-       int pnode;
-       unsigned long apicid;
-
-       node = uvhub_to_first_node(uvhub);
-       pnode = uv_blade_to_pnode(uvhub);
-
-       activation_descriptor_init(node, pnode, base_pnode);
-
-       pq_init(node, pnode);
-       /*
-        * The below initialization can't be in firmware because the
-        * messaging IRQ will be determined by the OS.
-        */
-       apicid = uvhub_to_first_apicid(uvhub);
-       write_mmr_data_config(pnode, ((apicid << 32) | vector));
-}
-
-/*
- * We will set BAU_MISC_CONTROL with a timeout period.
- * But the BIOS has set UVH_AGING_PRESCALE_SEL and UVH_TRANSACTION_TIMEOUT.
- * So the destination timeout period has to be calculated from them.
- */
-static int calculate_destination_timeout(void)
-{
-       unsigned long mmr_image;
-       int mult1;
-       int base;
-       int ret;
-
-       /* same destination timeout for uv2 and uv3 */
-       /* 4 bits  0/1 for 10/80us base, 3 bits of multiplier */
-       mmr_image = uv_read_local_mmr(UVH_LB_BAU_MISC_CONTROL);
-       mmr_image = (mmr_image & UV_SA_MASK) >> UV_SA_SHFT;
-       if (mmr_image & (1L << UV2_ACK_UNITS_SHFT))
-               base = 80;
-       else
-               base = 10;
-       mult1 = mmr_image & UV2_ACK_MASK;
-       ret = mult1 * base;
-
-       return ret;
-}
-
-static void __init init_per_cpu_tunables(void)
-{
-       int cpu;
-       struct bau_control *bcp;
-
-       for_each_present_cpu(cpu) {
-               bcp = &per_cpu(bau_control, cpu);
-               bcp->baudisabled                = 0;
-               if (nobau)
-                       bcp->nobau              = true;
-               bcp->statp                      = &per_cpu(ptcstats, cpu);
-               /* time interval to catch a hardware stay-busy bug */
-               bcp->timeout_interval           = usec_2_cycles(2*timeout_us);
-               bcp->max_concurr                = max_concurr;
-               bcp->max_concurr_const          = max_concurr;
-               bcp->plugged_delay              = plugged_delay;
-               bcp->plugsb4reset               = plugsb4reset;
-               bcp->timeoutsb4reset            = timeoutsb4reset;
-               bcp->ipi_reset_limit            = ipi_reset_limit;
-               bcp->complete_threshold         = complete_threshold;
-               bcp->cong_response_us           = congested_respns_us;
-               bcp->cong_reps                  = congested_reps;
-               bcp->disabled_period            = sec_2_cycles(disabled_period);
-               bcp->giveup_limit               = giveup_limit;
-               spin_lock_init(&bcp->queue_lock);
-               spin_lock_init(&bcp->uvhub_lock);
-               spin_lock_init(&bcp->disable_lock);
-       }
-}
-
-/*
- * Scan all cpus to collect blade and socket summaries.
- */
-static int __init get_cpu_topology(int base_pnode,
-                                       struct uvhub_desc *uvhub_descs,
-                                       unsigned char *uvhub_mask)
-{
-       int cpu;
-       int pnode;
-       int uvhub;
-       int socket;
-       struct bau_control *bcp;
-       struct uvhub_desc *bdp;
-       struct socket_desc *sdp;
-
-       for_each_present_cpu(cpu) {
-               bcp = &per_cpu(bau_control, cpu);
-
-               memset(bcp, 0, sizeof(struct bau_control));
-
-               pnode = uv_cpu_hub_info(cpu)->pnode;
-               if ((pnode - base_pnode) >= UV_DISTRIBUTION_SIZE) {
-                       pr_emerg(
-                               "cpu %d pnode %d-%d beyond %d; BAU disabled\n",
-                               cpu, pnode, base_pnode, UV_DISTRIBUTION_SIZE);
-                       return 1;
-               }
-
-               bcp->osnode = cpu_to_node(cpu);
-               bcp->partition_base_pnode = base_pnode;
-
-               uvhub = uv_cpu_hub_info(cpu)->numa_blade_id;
-               *(uvhub_mask + (uvhub/8)) |= (1 << (uvhub%8));
-               bdp = &uvhub_descs[uvhub];
-
-               bdp->num_cpus++;
-               bdp->uvhub = uvhub;
-               bdp->pnode = pnode;
-
-               /* kludge: 'assuming' one node per socket, and assuming that
-                  disabling a socket just leaves a gap in node numbers */
-               socket = bcp->osnode & 1;
-               bdp->socket_mask |= (1 << socket);
-               sdp = &bdp->socket[socket];
-               sdp->cpu_number[sdp->num_cpus] = cpu;
-               sdp->num_cpus++;
-               if (sdp->num_cpus > MAX_CPUS_PER_SOCKET) {
-                       pr_emerg("%d cpus per socket invalid\n",
-                               sdp->num_cpus);
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-/*
- * Each socket is to get a local array of pnodes/hubs.
- */
-static void make_per_cpu_thp(struct bau_control *smaster)
-{
-       int cpu;
-       size_t hpsz = sizeof(struct hub_and_pnode) * num_possible_cpus();
-
-       smaster->thp = kzalloc_node(hpsz, GFP_KERNEL, smaster->osnode);
-       for_each_present_cpu(cpu) {
-               smaster->thp[cpu].pnode = uv_cpu_hub_info(cpu)->pnode;
-               smaster->thp[cpu].uvhub = uv_cpu_hub_info(cpu)->numa_blade_id;
-       }
-}
-
-/*
- * Each uvhub is to get a local cpumask.
- */
-static void make_per_hub_cpumask(struct bau_control *hmaster)
-{
-       int sz = sizeof(cpumask_t);
-
-       hmaster->cpumask = kzalloc_node(sz, GFP_KERNEL, hmaster->osnode);
-}
-
-/*
- * Initialize all the per_cpu information for the cpu's on a given socket,
- * given what has been gathered into the socket_desc struct.
- * And reports the chosen hub and socket masters back to the caller.
- */
-static int scan_sock(struct socket_desc *sdp, struct uvhub_desc *bdp,
-                       struct bau_control **smasterp,
-                       struct bau_control **hmasterp)
-{
-       int i, cpu, uvhub_cpu;
-       struct bau_control *bcp;
-
-       for (i = 0; i < sdp->num_cpus; i++) {
-               cpu = sdp->cpu_number[i];
-               bcp = &per_cpu(bau_control, cpu);
-               bcp->cpu = cpu;
-               if (i == 0) {
-                       *smasterp = bcp;
-                       if (!(*hmasterp))
-                               *hmasterp = bcp;
-               }
-               bcp->cpus_in_uvhub = bdp->num_cpus;
-               bcp->cpus_in_socket = sdp->num_cpus;
-               bcp->socket_master = *smasterp;
-               bcp->uvhub = bdp->uvhub;
-               if (is_uv2_hub())
-                       bcp->uvhub_version = UV_BAU_V2;
-               else if (is_uv3_hub())
-                       bcp->uvhub_version = UV_BAU_V3;
-               else if (is_uv4_hub())
-                       bcp->uvhub_version = UV_BAU_V4;
-               else {
-                       pr_emerg("uvhub version not 1, 2, 3, or 4\n");
-                       return 1;
-               }
-               bcp->uvhub_master = *hmasterp;
-               uvhub_cpu = uv_cpu_blade_processor_id(cpu);
-               bcp->uvhub_cpu = uvhub_cpu;
-
-               /*
-                * The ERROR and BUSY status registers are located pairwise over
-                * the STATUS_0 and STATUS_1 mmrs; each an array[32] of 2 bits.
-                */
-               if (uvhub_cpu < UV_CPUS_PER_AS) {
-                       bcp->status_mmr = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
-                       bcp->status_index = uvhub_cpu * UV_ACT_STATUS_SIZE;
-               } else {
-                       bcp->status_mmr = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
-                       bcp->status_index = (uvhub_cpu - UV_CPUS_PER_AS)
-                                               * UV_ACT_STATUS_SIZE;
-               }
-
-               if (bcp->uvhub_cpu >= MAX_CPUS_PER_UVHUB) {
-                       pr_emerg("%d cpus per uvhub invalid\n",
-                               bcp->uvhub_cpu);
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-/*
- * Summarize the blade and socket topology into the per_cpu structures.
- */
-static int __init summarize_uvhub_sockets(int nuvhubs,
-                       struct uvhub_desc *uvhub_descs,
-                       unsigned char *uvhub_mask)
-{
-       int socket;
-       int uvhub;
-       unsigned short socket_mask;
-
-       for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
-               struct uvhub_desc *bdp;
-               struct bau_control *smaster = NULL;
-               struct bau_control *hmaster = NULL;
-
-               if (!(*(uvhub_mask + (uvhub/8)) & (1 << (uvhub%8))))
-                       continue;
-
-               bdp = &uvhub_descs[uvhub];
-               socket_mask = bdp->socket_mask;
-               socket = 0;
-               while (socket_mask) {
-                       struct socket_desc *sdp;
-                       if ((socket_mask & 1)) {
-                               sdp = &bdp->socket[socket];
-                               if (scan_sock(sdp, bdp, &smaster, &hmaster))
-                                       return 1;
-                               make_per_cpu_thp(smaster);
-                       }
-                       socket++;
-                       socket_mask = (socket_mask >> 1);
-               }
-               make_per_hub_cpumask(hmaster);
-       }
-       return 0;
-}
-
-/*
- * initialize the bau_control structure for each cpu
- */
-static int __init init_per_cpu(int nuvhubs, int base_part_pnode)
-{
-       struct uvhub_desc *uvhub_descs;
-       unsigned char *uvhub_mask = NULL;
-
-       if (is_uv3_hub() || is_uv2_hub())
-               timeout_us = calculate_destination_timeout();
-
-       uvhub_descs = kcalloc(nuvhubs, sizeof(struct uvhub_desc), GFP_KERNEL);
-       if (!uvhub_descs)
-               goto fail;
-
-       uvhub_mask = kzalloc((nuvhubs+7)/8, GFP_KERNEL);
-       if (!uvhub_mask)
-               goto fail;
-
-       if (get_cpu_topology(base_part_pnode, uvhub_descs, uvhub_mask))
-               goto fail;
-
-       if (summarize_uvhub_sockets(nuvhubs, uvhub_descs, uvhub_mask))
-               goto fail;
-
-       kfree(uvhub_descs);
-       kfree(uvhub_mask);
-       init_per_cpu_tunables();
-       return 0;
-
-fail:
-       kfree(uvhub_descs);
-       kfree(uvhub_mask);
-       return 1;
-}
-
-static const struct bau_operations uv2_3_bau_ops __initconst = {
-       .bau_gpa_to_offset       = uv_gpa_to_offset,
-       .read_l_sw_ack           = read_mmr_sw_ack,
-       .read_g_sw_ack           = read_gmmr_sw_ack,
-       .write_l_sw_ack          = write_mmr_sw_ack,
-       .write_g_sw_ack          = write_gmmr_sw_ack,
-       .write_payload_first     = write_mmr_payload_first,
-       .write_payload_last      = write_mmr_payload_last,
-       .wait_completion         = uv2_3_wait_completion,
-};
-
-static const struct bau_operations uv4_bau_ops __initconst = {
-       .bau_gpa_to_offset       = uv_gpa_to_soc_phys_ram,
-       .read_l_sw_ack           = read_mmr_proc_sw_ack,
-       .read_g_sw_ack           = read_gmmr_proc_sw_ack,
-       .write_l_sw_ack          = write_mmr_proc_sw_ack,
-       .write_g_sw_ack          = write_gmmr_proc_sw_ack,
-       .write_payload_first     = write_mmr_proc_payload_first,
-       .write_payload_last      = write_mmr_proc_payload_last,
-       .wait_completion         = uv4_wait_completion,
-};
-
-/*
- * Initialization of BAU-related structures
- */
-static int __init uv_bau_init(void)
-{
-       int uvhub;
-       int pnode;
-       int nuvhubs;
-       int cur_cpu;
-       int cpus;
-       int vector;
-       cpumask_var_t *mask;
-
-       if (!is_uv_system())
-               return 0;
-
-       if (is_uv4_hub())
-               ops = uv4_bau_ops;
-       else if (is_uv3_hub())
-               ops = uv2_3_bau_ops;
-       else if (is_uv2_hub())
-               ops = uv2_3_bau_ops;
-
-       nuvhubs = uv_num_possible_blades();
-       if (nuvhubs < 2) {
-               pr_crit("UV: BAU disabled - insufficient hub count\n");
-               goto err_bau_disable;
-       }
-
-       for_each_possible_cpu(cur_cpu) {
-               mask = &per_cpu(uv_flush_tlb_mask, cur_cpu);
-               zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu));
-       }
-
-       uv_base_pnode = 0x7fffffff;
-       for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
-               cpus = uv_blade_nr_possible_cpus(uvhub);
-               if (cpus && (uv_blade_to_pnode(uvhub) < uv_base_pnode))
-                       uv_base_pnode = uv_blade_to_pnode(uvhub);
-       }
-
-       /* software timeouts are not supported on UV4 */
-       if (is_uv3_hub() || is_uv2_hub())
-               enable_timeouts();
-
-       if (init_per_cpu(nuvhubs, uv_base_pnode)) {
-               pr_crit("UV: BAU disabled - per CPU init failed\n");
-               goto err_bau_disable;
-       }
-
-       vector = UV_BAU_MESSAGE;
-       for_each_possible_blade(uvhub) {
-               if (uv_blade_nr_possible_cpus(uvhub))
-                       init_uvhub(uvhub, vector, uv_base_pnode);
-       }
-
-       for_each_possible_blade(uvhub) {
-               if (uv_blade_nr_possible_cpus(uvhub)) {
-                       unsigned long val;
-                       unsigned long mmr;
-                       pnode = uv_blade_to_pnode(uvhub);
-                       /* INIT the bau */
-                       val = 1L << 63;
-                       write_gmmr_activation(pnode, val);
-                       mmr = 1; /* should be 1 to broadcast to both sockets */
-                       write_mmr_data_broadcast(pnode, mmr);
-               }
-       }
-
-       return 0;
-
-err_bau_disable:
-
-       for_each_possible_cpu(cur_cpu)
-               free_cpumask_var(per_cpu(uv_flush_tlb_mask, cur_cpu));
-
-       set_bau_off();
-       nobau_perm = 1;
-
-       return -EINVAL;
-}
-core_initcall(uv_bau_init);
-fs_initcall(uv_ptc_init);
index abb6075..18ca226 100644 (file)
@@ -90,15 +90,15 @@ static int uv_domain_alloc(struct irq_domain *domain, unsigned int virq,
 
        ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
        if (ret >= 0) {
-               if (info->uv_limit == UV_AFFINITY_CPU)
+               if (info->uv.limit == UV_AFFINITY_CPU)
                        irq_set_status_flags(virq, IRQ_NO_BALANCING);
                else
                        irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
 
-               chip_data->pnode = uv_blade_to_pnode(info->uv_blade);
-               chip_data->offset = info->uv_offset;
+               chip_data->pnode = uv_blade_to_pnode(info->uv.blade);
+               chip_data->offset = info->uv.offset;
                irq_domain_set_info(domain, virq, virq, &uv_irq_chip, chip_data,
-                                   handle_percpu_irq, NULL, info->uv_name);
+                                   handle_percpu_irq, NULL, info->uv.name);
        } else {
                kfree(chip_data);
        }
@@ -193,10 +193,10 @@ int uv_setup_irq(char *irq_name, int cpu, int mmr_blade,
 
        init_irq_alloc_info(&info, cpumask_of(cpu));
        info.type = X86_IRQ_ALLOC_TYPE_UV;
-       info.uv_limit = limit;
-       info.uv_blade = mmr_blade;
-       info.uv_offset = mmr_offset;
-       info.uv_name = irq_name;
+       info.uv.limit = limit;
+       info.uv.blade = mmr_blade;
+       info.uv.offset = mmr_offset;
+       info.uv.name = irq_name;
 
        return irq_domain_alloc_irqs(domain, 1,
                                     uv_blade_to_memory_nid(mmr_blade), &info);
index 9d08ff5..0f5cbcf 100644 (file)
@@ -2,8 +2,9 @@
 /*
  * SGI NMI support routines
  *
- *  Copyright (c) 2009-2013 Silicon Graphics, Inc.  All Rights Reserved.
- *  Copyright (c) Mike Travis
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
+ * Copyright (C) 2007-2017 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) Mike Travis
  */
 
 #include <linux/cpu.h>
@@ -54,6 +55,20 @@ static struct uv_hub_nmi_s **uv_hub_nmi_list;
 
 DEFINE_PER_CPU(struct uv_cpu_nmi_s, uv_cpu_nmi);
 
+/* Newer SMM NMI handler, not present in all systems */
+static unsigned long uvh_nmi_mmrx;             /* UVH_EVENT_OCCURRED0/1 */
+static unsigned long uvh_nmi_mmrx_clear;       /* UVH_EVENT_OCCURRED0/1_ALIAS */
+static int uvh_nmi_mmrx_shift;                 /* UVH_EVENT_OCCURRED0/1_EXTIO_INT0_SHFT */
+static int uvh_nmi_mmrx_mask;                  /* UVH_EVENT_OCCURRED0/1_EXTIO_INT0_MASK */
+static char *uvh_nmi_mmrx_type;                        /* "EXTIO_INT0" */
+
+/* Non-zero indicates newer SMM NMI handler present */
+static unsigned long uvh_nmi_mmrx_supported;   /* UVH_EXTIO_INT0_BROADCAST */
+
+/* Indicates to BIOS that we want to use the newer SMM NMI handler */
+static unsigned long uvh_nmi_mmrx_req;         /* UVH_BIOS_KERNEL_MMR_ALIAS_2 */
+static int uvh_nmi_mmrx_req_shift;             /* 62 */
+
 /* UV hubless values */
 #define NMI_CONTROL_PORT       0x70
 #define NMI_DUMMY_PORT         0x71
@@ -227,13 +242,43 @@ static inline bool uv_nmi_action_is(const char *action)
 /* Setup which NMI support is present in system */
 static void uv_nmi_setup_mmrs(void)
 {
-       if (uv_read_local_mmr(UVH_NMI_MMRX_SUPPORTED)) {
-               uv_write_local_mmr(UVH_NMI_MMRX_REQ,
-                                       1UL << UVH_NMI_MMRX_REQ_SHIFT);
-               nmi_mmr = UVH_NMI_MMRX;
-               nmi_mmr_clear = UVH_NMI_MMRX_CLEAR;
-               nmi_mmr_pending = 1UL << UVH_NMI_MMRX_SHIFT;
-               pr_info("UV: SMI NMI support: %s\n", UVH_NMI_MMRX_TYPE);
+       /* First determine arch specific MMRs to handshake with BIOS */
+       if (UVH_EVENT_OCCURRED0_EXTIO_INT0_MASK) {
+               uvh_nmi_mmrx = UVH_EVENT_OCCURRED0;
+               uvh_nmi_mmrx_clear = UVH_EVENT_OCCURRED0_ALIAS;
+               uvh_nmi_mmrx_shift = UVH_EVENT_OCCURRED0_EXTIO_INT0_SHFT;
+               uvh_nmi_mmrx_mask = UVH_EVENT_OCCURRED0_EXTIO_INT0_MASK;
+               uvh_nmi_mmrx_type = "OCRD0-EXTIO_INT0";
+
+               uvh_nmi_mmrx_supported = UVH_EXTIO_INT0_BROADCAST;
+               uvh_nmi_mmrx_req = UVH_BIOS_KERNEL_MMR_ALIAS_2;
+               uvh_nmi_mmrx_req_shift = 62;
+
+       } else if (UVH_EVENT_OCCURRED1_EXTIO_INT0_MASK) {
+               uvh_nmi_mmrx = UVH_EVENT_OCCURRED1;
+               uvh_nmi_mmrx_clear = UVH_EVENT_OCCURRED1_ALIAS;
+               uvh_nmi_mmrx_shift = UVH_EVENT_OCCURRED1_EXTIO_INT0_SHFT;
+               uvh_nmi_mmrx_mask = UVH_EVENT_OCCURRED1_EXTIO_INT0_MASK;
+               uvh_nmi_mmrx_type = "OCRD1-EXTIO_INT0";
+
+               uvh_nmi_mmrx_supported = UVH_EXTIO_INT0_BROADCAST;
+               uvh_nmi_mmrx_req = UVH_BIOS_KERNEL_MMR_ALIAS_2;
+               uvh_nmi_mmrx_req_shift = 62;
+
+       } else {
+               pr_err("UV:%s:cannot find EVENT_OCCURRED*_EXTIO_INT0\n",
+                       __func__);
+               return;
+       }
+
+       /* Then find out if new NMI is supported */
+       if (likely(uv_read_local_mmr(uvh_nmi_mmrx_supported))) {
+               uv_write_local_mmr(uvh_nmi_mmrx_req,
+                                       1UL << uvh_nmi_mmrx_req_shift);
+               nmi_mmr = uvh_nmi_mmrx;
+               nmi_mmr_clear = uvh_nmi_mmrx_clear;
+               nmi_mmr_pending = 1UL << uvh_nmi_mmrx_shift;
+               pr_info("UV: SMI NMI support: %s\n", uvh_nmi_mmrx_type);
        } else {
                nmi_mmr = UVH_NMI_MMR;
                nmi_mmr_clear = UVH_NMI_MMR_CLEAR;
@@ -1049,5 +1094,5 @@ void __init uv_nmi_setup_hubless(void)
        /* Ensure NMI enabled in Processor Interface Reg: */
        uv_reassert_nmi();
        uv_register_nmi_notifier();
-       pr_info("UV: Hubless NMI enabled\n");
+       pr_info("UV: PCH NMI enabled\n");
 }
index f82a133..54663f3 100644 (file)
@@ -2,6 +2,7 @@
 /*
  * SGI RTC clock/timer routines.
  *
+ *  (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  *  Copyright (c) 2009-2013 Silicon Graphics, Inc.  All Rights Reserved.
  *  Copyright (c) Dimitri Sivanich
  */
@@ -52,7 +53,7 @@ struct uv_rtc_timer_head {
        struct {
                int     lcpu;           /* systemwide logical cpu number */
                u64     expires;        /* next timer expiration for this cpu */
-       } cpu[1];
+       } cpu[];
 };
 
 /*
@@ -84,10 +85,8 @@ static void uv_rtc_send_IPI(int cpu)
 /* Check for an RTC interrupt pending */
 static int uv_intr_pending(int pnode)
 {
-       if (is_uvx_hub())
-               return uv_read_global_mmr64(pnode, UVXH_EVENT_OCCURRED2) &
-                       UVXH_EVENT_OCCURRED2_RTC_1_MASK;
-       return 0;
+       return uv_read_global_mmr64(pnode, UVH_EVENT_OCCURRED2) &
+               UVH_EVENT_OCCURRED2_RTC_1_MASK;
 }
 
 /* Setup interrupt and return non-zero if early expiration occurred. */
@@ -101,8 +100,8 @@ static int uv_setup_intr(int cpu, u64 expires)
                UVH_RTC1_INT_CONFIG_M_MASK);
        uv_write_global_mmr64(pnode, UVH_INT_CMPB, -1L);
 
-       uv_write_global_mmr64(pnode, UVXH_EVENT_OCCURRED2_ALIAS,
-                             UVXH_EVENT_OCCURRED2_RTC_1_MASK);
+       uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED2_ALIAS,
+                             UVH_EVENT_OCCURRED2_RTC_1_MASK);
 
        val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
                ((u64)apicid << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
@@ -148,9 +147,8 @@ static __init int uv_rtc_allocate_timers(void)
                struct uv_rtc_timer_head *head = blade_info[bid];
 
                if (!head) {
-                       head = kmalloc_node(sizeof(struct uv_rtc_timer_head) +
-                               (uv_blade_nr_possible_cpus(bid) *
-                                       2 * sizeof(u64)),
+                       head = kmalloc_node(struct_size(head, cpu,
+                               uv_blade_nr_possible_cpus(bid)),
                                GFP_KERNEL, nid);
                        if (!head) {
                                uv_rtc_deallocate_timers();
index ff6bba2..b078245 100644 (file)
  */
 extern __wsum csum_partial(const void *buff, int len, __wsum sum);
 
-/*
- *     Note: when you get a NULL pointer exception here this means someone
- *     passed in an incorrect kernel address to one of these functions.
- *
- *     If you use these functions directly please don't forget the
- *     access_ok().
- */
-
-static __inline__
-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                      int len, __wsum sum)
-{
-       memcpy(dst, src, len);
-       return csum_partial(dst, len, sum);
-}
-
 /**
  * csum_fold - Fold and invert a 32bit checksum.
  * sum: 32bit unfolded sum
index b9ac7c9..0b13c29 100644 (file)
@@ -35,27 +35,4 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
        return csum_fold(sum);
 }
 
-/*
- *     Copy and checksum to user
- */
-#define HAVE_CSUM_COPY_USER
-static __inline__ __wsum csum_and_copy_to_user(const void *src,
-                                                    void __user *dst,
-                                                    int len, __wsum sum, int *err_ptr)
-{
-       if (access_ok(dst, len)) {
-               if (copy_to_user(dst, src, len)) {
-                       *err_ptr = -EFAULT;
-                       return (__force __wsum)-1;
-               }
-
-               return csum_partial(src, len, sum);
-       }
-
-       if (len)
-               *err_ptr = -EFAULT;
-
-       return (__force __wsum)-1; /* invalid checksum */
-}
-
 #endif
index 22e741e..41485a8 100644 (file)
@@ -1014,8 +1014,6 @@ void __init xen_setup_vcpu_info_placement(void)
 }
 
 static const struct pv_info xen_info __initconst = {
-       .shared_kernel_pmd = 0,
-
        .extra_user_64bit_cs = FLAT_USER_CS64,
        .name = "Xen",
 };
@@ -1314,10 +1312,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
                                   xen_start_info->nr_pages);
        xen_reserve_special_pages();
 
-       /* keep using Xen gdt for now; no urgent need to change it */
-
-       pv_info.kernel_rpl = 0;
-
        /*
         * We used to do this in xen_arch_setup, but that is too late
         * on AMD were early_cpu_init (run before ->arch_setup()) calls
index 3273c98..eda7814 100644 (file)
@@ -285,13 +285,6 @@ static void xen_set_pte(pte_t *ptep, pte_t pteval)
        __xen_set_pte(ptep, pteval);
 }
 
-static void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
-                   pte_t *ptep, pte_t pteval)
-{
-       trace_xen_mmu_set_pte_at(mm, addr, ptep, pteval);
-       __xen_set_pte(ptep, pteval);
-}
-
 pte_t xen_ptep_modify_prot_start(struct vm_area_struct *vma,
                                 unsigned long addr, pte_t *ptep)
 {
@@ -2105,7 +2098,6 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
        .release_pmd = xen_release_pmd_init,
 
        .set_pte = xen_set_pte_init,
-       .set_pte_at = xen_set_pte_at,
        .set_pmd = xen_set_pmd_hyper,
 
        .ptep_modify_prot_start = __ptep_modify_prot_start,
index 243a5fe..44ec1d0 100644 (file)
@@ -37,32 +37,27 @@ asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
  * better 64-bit) boundary
  */
 
-asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
-                                           int len, __wsum sum,
-                                           int *src_err_ptr, int *dst_err_ptr);
+asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
 
+#define _HAVE_ARCH_CSUM_AND_COPY
 /*
  *     Note: when you get a NULL pointer exception here this means someone
  *     passed in an incorrect kernel address to one of these functions.
  */
 static inline
-__wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                       int len, __wsum sum)
+__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
 {
-       return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL);
+       return csum_partial_copy_generic(src, dst, len);
 }
 
 #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
 static inline
 __wsum csum_and_copy_from_user(const void __user *src, void *dst,
-                                  int len, __wsum sum, int *err_ptr)
+                                  int len)
 {
-       if (access_ok(src, len))
-               return csum_partial_copy_generic((__force const void *)src, dst,
-                                       len, sum, err_ptr, NULL);
-       if (len)
-               *err_ptr = -EFAULT;
-       return sum;
+       if (!access_ok(src, len))
+               return 0;
+       return csum_partial_copy_generic((__force const void *)src, dst, len);
 }
 
 /*
@@ -243,15 +238,10 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
  */
 #define HAVE_CSUM_COPY_USER
 static __inline__ __wsum csum_and_copy_to_user(const void *src,
-                                              void __user *dst, int len,
-                                              __wsum sum, int *err_ptr)
+                                              void __user *dst, int len)
 {
-       if (access_ok(dst, len))
-               return csum_partial_copy_generic(src,dst,len,sum,NULL,err_ptr);
-
-       if (len)
-               *err_ptr = -EFAULT;
-
-       return (__force __wsum)-1; /* invalid checksum */
+       if (!access_ok(dst, len))
+               return 0;
+       return csum_partial_copy_generic(src, (__force void *)dst, len);
 }
 #endif
index 76cee34..b3b17d6 100644 (file)
@@ -448,7 +448,7 @@ static void do_signal(struct pt_regs *regs)
                                                regs->areg[2] = -EINTR;
                                                break;
                                        }
-                                       /* fallthrough */
+                                       fallthrough;
                                case -ERESTARTNOINTR:
                                        regs->areg[2] = regs->syscall;
                                        regs->pc -= 3;
index 4cb9ca5..cf1bed1 100644 (file)
@@ -175,19 +175,14 @@ ENDPROC(csum_partial)
  */
 
 /*
-unsigned int csum_partial_copy_generic (const char *src, char *dst, int len,
-                                       int sum, int *src_err_ptr, int *dst_err_ptr)
+unsigned int csum_partial_copy_generic (const char *src, char *dst, int len)
        a2  = src
        a3  = dst
        a4  = len
        a5  = sum
-       a6  = src_err_ptr
-       a7  = dst_err_ptr
        a8  = temp
        a9  = temp
        a10 = temp
-       a11 = original len for exception handling
-       a12 = original dst for exception handling
 
     This function is optimized for 4-byte aligned addresses.  Other
     alignments work, but not nearly as efficiently.
@@ -196,8 +191,7 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, int len,
 ENTRY(csum_partial_copy_generic)
 
        abi_entry_default
-       mov     a12, a3
-       mov     a11, a4
+       movi    a5, -1
        or      a10, a2, a3
 
        /* We optimize the following alignment tests for the 4-byte
@@ -228,26 +222,26 @@ ENTRY(csum_partial_copy_generic)
 #endif
 EX(10f)        l32i    a9, a2, 0
 EX(10f)        l32i    a8, a2, 4
-EX(11f)        s32i    a9, a3, 0
-EX(11f)        s32i    a8, a3, 4
+EX(10f)        s32i    a9, a3, 0
+EX(10f)        s32i    a8, a3, 4
        ONES_ADD(a5, a9)
        ONES_ADD(a5, a8)
 EX(10f)        l32i    a9, a2, 8
 EX(10f)        l32i    a8, a2, 12
-EX(11f)        s32i    a9, a3, 8
-EX(11f)        s32i    a8, a3, 12
+EX(10f)        s32i    a9, a3, 8
+EX(10f)        s32i    a8, a3, 12
        ONES_ADD(a5, a9)
        ONES_ADD(a5, a8)
 EX(10f)        l32i    a9, a2, 16
 EX(10f)        l32i    a8, a2, 20
-EX(11f)        s32i    a9, a3, 16
-EX(11f)        s32i    a8, a3, 20
+EX(10f)        s32i    a9, a3, 16
+EX(10f)        s32i    a8, a3, 20
        ONES_ADD(a5, a9)
        ONES_ADD(a5, a8)
 EX(10f)        l32i    a9, a2, 24
 EX(10f)        l32i    a8, a2, 28
-EX(11f)        s32i    a9, a3, 24
-EX(11f)        s32i    a8, a3, 28
+EX(10f)        s32i    a9, a3, 24
+EX(10f)        s32i    a8, a3, 28
        ONES_ADD(a5, a9)
        ONES_ADD(a5, a8)
        addi    a2, a2, 32
@@ -267,7 +261,7 @@ EX(11f)     s32i    a8, a3, 28
 .Loop6:
 #endif
 EX(10f)        l32i    a9, a2, 0
-EX(11f)        s32i    a9, a3, 0
+EX(10f)        s32i    a9, a3, 0
        ONES_ADD(a5, a9)
        addi    a2, a2, 4
        addi    a3, a3, 4
@@ -298,7 +292,7 @@ EX(11f)     s32i    a9, a3, 0
 .Loop7:
 #endif
 EX(10f)        l16ui   a9, a2, 0
-EX(11f)        s16i    a9, a3, 0
+EX(10f)        s16i    a9, a3, 0
        ONES_ADD(a5, a9)
        addi    a2, a2, 2
        addi    a3, a3, 2
@@ -309,7 +303,7 @@ EX(11f)     s16i    a9, a3, 0
        /* This section processes a possible trailing odd byte. */
        _bbci.l a4, 0, 8f       /* 1-byte chunk */
 EX(10f)        l8ui    a9, a2, 0
-EX(11f)        s8i     a9, a3, 0
+EX(10f)        s8i     a9, a3, 0
 #ifdef __XTENSA_EB__
        slli    a9, a9, 8       /* shift byte to bits 8..15 */
 #endif
@@ -334,8 +328,8 @@ EX(11f)     s8i     a9, a3, 0
 #endif
 EX(10f)        l8ui    a9, a2, 0
 EX(10f)        l8ui    a8, a2, 1
-EX(11f)        s8i     a9, a3, 0
-EX(11f)        s8i     a8, a3, 1
+EX(10f)        s8i     a9, a3, 0
+EX(10f)        s8i     a8, a3, 1
 #ifdef __XTENSA_EB__
        slli    a9, a9, 8       /* combine into a single 16-bit value */
 #else                          /* for checksum computation */
@@ -356,38 +350,7 @@ ENDPROC(csum_partial_copy_generic)
 
 # Exception handler:
 .section .fixup, "ax"
-/*
-       a6  = src_err_ptr
-       a7  = dst_err_ptr
-       a11 = original len for exception handling
-       a12 = original dst for exception handling
-*/
-
 10:
-       _movi   a2, -EFAULT
-       s32i    a2, a6, 0       /* src_err_ptr */
-
-       # clear the complete destination - computing the rest
-       # is too much work
-       movi    a2, 0
-#if XCHAL_HAVE_LOOPS
-       loopgtz a11, 2f
-#else
-       beqz    a11, 2f
-       add     a11, a11, a12   /* a11 = ending address */
-.Leloop:
-#endif
-       s8i     a2, a12, 0
-       addi    a12, a12, 1
-#if !XCHAL_HAVE_LOOPS
-       blt     a12, a11, .Leloop
-#endif
-2:
-       abi_ret_default
-
-11:
-       movi    a2, -EFAULT
-       s32i    a2, a7, 0       /* dst_err_ptr */
        movi    a2, 0
        abi_ret_default
 
index 2e5f569..d390566 100644 (file)
@@ -525,7 +525,7 @@ ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
        case 3:
                if (newline != '\n')
                        return -EINVAL;
-               /* fall through */
+               fallthrough;
        case 2:
                if (length <= 0)
                        return -EINVAL;
index 68882b9..b791e20 100644 (file)
@@ -332,7 +332,7 @@ static void bfqg_put(struct bfq_group *bfqg)
                kfree(bfqg);
 }
 
-void bfqg_and_blkg_get(struct bfq_group *bfqg)
+static void bfqg_and_blkg_get(struct bfq_group *bfqg)
 {
        /* see comments in bfq_bic_update_cgroup for why refcounting bfqg */
        bfqg_get(bfqg);
index a4c0bec..fa98470 100644 (file)
@@ -4980,7 +4980,7 @@ bfq_set_next_ioprio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
                pr_err("bdi %s: bfq: bad prio class %d\n",
                                bdi_dev_name(bfqq->bfqd->queue->backing_dev_info),
                                ioprio_class);
-               /* fall through */
+               fallthrough;
        case IOPRIO_CLASS_NONE:
                /*
                 * No prio set, inherit CPU scheduling settings.
@@ -5112,7 +5112,7 @@ static struct bfq_queue **bfq_async_queue_prio(struct bfq_data *bfqd,
                return &bfqg->async_bfqq[0][ioprio];
        case IOPRIO_CLASS_NONE:
                ioprio = IOPRIO_NORM;
-               /* fall through */
+               fallthrough;
        case IOPRIO_CLASS_BE:
                return &bfqg->async_bfqq[1][ioprio];
        case IOPRIO_CLASS_IDLE:
@@ -5896,18 +5896,6 @@ static void bfq_finish_requeue_request(struct request *rq)
        struct bfq_data *bfqd;
 
        /*
-        * Requeue and finish hooks are invoked in blk-mq without
-        * checking whether the involved request is actually still
-        * referenced in the scheduler. To handle this fact, the
-        * following two checks make this function exit in case of
-        * spurious invocations, for which there is nothing to do.
-        *
-        * First, check whether rq has nothing to do with an elevator.
-        */
-       if (unlikely(!(rq->rq_flags & RQF_ELVPRIV)))
-               return;
-
-       /*
         * rq either is not associated with any icq, or is an already
         * requeued request that has not (yet) been re-inserted into
         * a bfq_queue.
index cd224aa..7038952 100644 (file)
@@ -986,7 +986,6 @@ struct bfq_group *bfq_find_set_group(struct bfq_data *bfqd,
 struct blkcg_gq *bfqg_to_blkg(struct bfq_group *bfqg);
 struct bfq_group *bfqq_group(struct bfq_queue *bfqq);
 struct bfq_group *bfq_create_group_hierarchy(struct bfq_data *bfqd, int node);
-void bfqg_and_blkg_get(struct bfq_group *bfqg);
 void bfqg_and_blkg_put(struct bfq_group *bfqg);
 
 #ifdef CONFIG_BFQ_GROUP_IOSCHED
index eb0e2a6..26776bd 100644 (file)
@@ -533,9 +533,7 @@ static void bfq_get_entity(struct bfq_entity *entity)
                bfqq->ref++;
                bfq_log_bfqq(bfqq->bfqd, bfqq, "get_entity: %p %d",
                             bfqq, bfqq->ref);
-       } else
-               bfqg_and_blkg_get(container_of(entity, struct bfq_group,
-                                              entity));
+       }
 }
 
 /**
@@ -649,14 +647,8 @@ static void bfq_forget_entity(struct bfq_service_tree *st,
 
        entity->on_st_or_in_serv = false;
        st->wsum -= entity->weight;
-       if (is_in_service)
-               return;
-
-       if (bfqq)
+       if (bfqq && !is_in_service)
                bfq_put_queue(bfqq);
-       else
-               bfqg_and_blkg_put(container_of(entity, struct bfq_group,
-                                              entity));
 }
 
 /**
index c63ba04..e865ea5 100644 (file)
@@ -740,8 +740,8 @@ static inline bool page_is_mergeable(const struct bio_vec *bv,
                struct page *page, unsigned int len, unsigned int off,
                bool *same_page)
 {
-       phys_addr_t vec_end_addr = page_to_phys(bv->bv_page) +
-               bv->bv_offset + bv->bv_len - 1;
+       size_t bv_end = bv->bv_offset + bv->bv_len;
+       phys_addr_t vec_end_addr = page_to_phys(bv->bv_page) + bv_end - 1;
        phys_addr_t page_addr = page_to_phys(page);
 
        if (vec_end_addr + 1 != page_addr + off)
@@ -750,9 +750,9 @@ static inline bool page_is_mergeable(const struct bio_vec *bv,
                return false;
 
        *same_page = ((vec_end_addr & PAGE_MASK) == page_addr);
-       if (!*same_page && pfn_to_page(PFN_DOWN(vec_end_addr)) + 1 != page)
-               return false;
-       return true;
+       if (*same_page)
+               return true;
+       return (bv->bv_page + bv_end / PAGE_SIZE) == (page + off / PAGE_SIZE);
 }
 
 /*
@@ -879,8 +879,10 @@ bool __bio_try_merge_page(struct bio *bio, struct page *page,
                struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
 
                if (page_is_mergeable(bv, page, len, off, same_page)) {
-                       if (bio->bi_iter.bi_size > UINT_MAX - len)
+                       if (bio->bi_iter.bi_size > UINT_MAX - len) {
+                               *same_page = false;
                                return false;
+                       }
                        bv->bv_len += len;
                        bio->bi_iter.bi_size += len;
                        return true;
index 619a79b..c195365 100644 (file)
@@ -1152,13 +1152,15 @@ int blkcg_init_queue(struct request_queue *q)
        if (preloaded)
                radix_tree_preload_end();
 
-       ret = blk_iolatency_init(q);
+       ret = blk_throtl_init(q);
        if (ret)
                goto err_destroy_all;
 
-       ret = blk_throtl_init(q);
-       if (ret)
+       ret = blk_iolatency_init(q);
+       if (ret) {
+               blk_throtl_exit(q);
                goto err_destroy_all;
+       }
        return 0;
 
 err_destroy_all:
index d9d6326..10c08ac 100644 (file)
@@ -539,6 +539,7 @@ struct request_queue *blk_alloc_queue(int node_id)
                goto fail_stats;
 
        q->backing_dev_info->ra_pages = VM_READAHEAD_PAGES;
+       q->backing_dev_info->io_pages = VM_READAHEAD_PAGES;
        q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK;
        q->node = node_id;
 
index 413e0b5..d37b55d 100644 (file)
@@ -2092,14 +2092,15 @@ static void ioc_pd_free(struct blkg_policy_data *pd)
 {
        struct ioc_gq *iocg = pd_to_iocg(pd);
        struct ioc *ioc = iocg->ioc;
+       unsigned long flags;
 
        if (ioc) {
-               spin_lock(&ioc->lock);
+               spin_lock_irqsave(&ioc->lock, flags);
                if (!list_empty(&iocg->active_list)) {
                        propagate_active_weight(iocg, 0, 0);
                        list_del_init(&iocg->active_list);
                }
-               spin_unlock(&ioc->lock);
+               spin_unlock_irqrestore(&ioc->lock, flags);
 
                hrtimer_cancel(&iocg->waitq_timer);
                hrtimer_cancel(&iocg->delay_timer);
index 6529e3a..f685d63 100644 (file)
@@ -154,7 +154,7 @@ static inline unsigned get_max_io_size(struct request_queue *q,
        if (max_sectors > start_offset)
                return max_sectors - start_offset;
 
-       return sectors & (lbs - 1);
+       return sectors & ~(lbs - 1);
 }
 
 static inline unsigned get_max_segment_size(const struct request_queue *q,
@@ -533,10 +533,17 @@ int __blk_rq_map_sg(struct request_queue *q, struct request *rq,
 }
 EXPORT_SYMBOL(__blk_rq_map_sg);
 
+static inline unsigned int blk_rq_get_max_segments(struct request *rq)
+{
+       if (req_op(rq) == REQ_OP_DISCARD)
+               return queue_max_discard_segments(rq->q);
+       return queue_max_segments(rq->q);
+}
+
 static inline int ll_new_hw_segment(struct request *req, struct bio *bio,
                unsigned int nr_phys_segs)
 {
-       if (req->nr_phys_segments + nr_phys_segs > queue_max_segments(req->q))
+       if (req->nr_phys_segments + nr_phys_segs > blk_rq_get_max_segments(req))
                goto no_merge;
 
        if (blk_integrity_merge_bio(req->q, req, bio) == false)
@@ -624,7 +631,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
                return 0;
 
        total_phys_segments = req->nr_phys_segments + next->nr_phys_segments;
-       if (total_phys_segments > queue_max_segments(q))
+       if (total_phys_segments > blk_rq_get_max_segments(req))
                return 0;
 
        if (blk_integrity_merge_rq(q, req, next) == false)
index a19cdf1..d2790e5 100644 (file)
@@ -78,6 +78,15 @@ void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx)
                return;
        clear_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
 
+       /*
+        * Order clearing SCHED_RESTART and list_empty_careful(&hctx->dispatch)
+        * in blk_mq_run_hw_queue(). Its pair is the barrier in
+        * blk_mq_dispatch_rq_list(). So dispatch code won't see SCHED_RESTART,
+        * meantime new request added to hctx->dispatch is missed to check in
+        * blk_mq_run_hw_queue().
+        */
+       smp_mb();
+
        blk_mq_run_hw_queue(hctx, true);
 }
 
index 126021f..e81ca1b 100644 (file)
@@ -66,7 +66,7 @@ static inline void blk_mq_sched_requeue_request(struct request *rq)
        struct request_queue *q = rq->q;
        struct elevator_queue *e = q->elevator;
 
-       if (e && e->type->ops.requeue_request)
+       if ((rq->rq_flags & RQF_ELVPRIV) && e && e->type->ops.requeue_request)
                e->type->ops.requeue_request(rq);
 }
 
index 0015a18..cdced4a 100644 (file)
@@ -1412,6 +1412,11 @@ out:
 
        hctx->dispatched[queued_to_index(queued)]++;
 
+       /* If we didn't flush the entire list, we could have told the driver
+        * there was more coming, but that turned out to be a lie.
+        */
+       if ((!list_empty(list) || errors) && q->mq_ops->commit_rqs && queued)
+               q->mq_ops->commit_rqs(hctx);
        /*
         * Any items that need requeuing? Stuff them into hctx->dispatch,
         * that is where we will continue on next queue run.
@@ -1425,19 +1430,20 @@ out:
 
                blk_mq_release_budgets(q, nr_budgets);
 
-               /*
-                * If we didn't flush the entire list, we could have told
-                * the driver there was more coming, but that turned out to
-                * be a lie.
-                */
-               if (q->mq_ops->commit_rqs && queued)
-                       q->mq_ops->commit_rqs(hctx);
-
                spin_lock(&hctx->lock);
                list_splice_tail_init(list, &hctx->dispatch);
                spin_unlock(&hctx->lock);
 
                /*
+                * Order adding requests to hctx->dispatch and checking
+                * SCHED_RESTART flag. The pair of this smp_mb() is the one
+                * in blk_mq_sched_restart(). Avoid restart code path to
+                * miss the new added requests to hctx->dispatch, meantime
+                * SCHED_RESTART is observed here.
+                */
+               smp_mb();
+
+               /*
                 * If SCHED_RESTART was set by the caller of this function and
                 * it is no longer set that means that it was cleared by another
                 * thread and hence that a queue rerun is needed.
@@ -1834,6 +1840,7 @@ void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
 /**
  * blk_mq_request_bypass_insert - Insert a request at dispatch list.
  * @rq: Pointer to request to be inserted.
+ * @at_head: true if the request should be inserted at the head of the list.
  * @run_queue: If we should run the hardware queue after inserting the request.
  *
  * Should only be used carefully, when the caller knows we want to
@@ -2016,7 +2023,8 @@ insert:
        if (bypass_insert)
                return BLK_STS_RESOURCE;
 
-       blk_mq_request_bypass_insert(rq, false, run_queue);
+       blk_mq_sched_insert_request(rq, false, run_queue, false);
+
        return BLK_STS_OK;
 }
 
@@ -2068,6 +2076,7 @@ void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
                struct list_head *list)
 {
        int queued = 0;
+       int errors = 0;
 
        while (!list_empty(list)) {
                blk_status_t ret;
@@ -2084,6 +2093,7 @@ void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
                                break;
                        }
                        blk_mq_end_request(rq, ret);
+                       errors++;
                } else
                        queued++;
        }
@@ -2093,7 +2103,8 @@ void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
         * the driver there was more coming, but that turned out to
         * be a lie.
         */
-       if (!list_empty(list) && hctx->queue->mq_ops->commit_rqs && queued)
+       if ((!list_empty(list) || errors) &&
+            hctx->queue->mq_ops->commit_rqs && queued)
                hctx->queue->mq_ops->commit_rqs(hctx);
 }
 
index 76a7e03..34b721a 100644 (file)
@@ -801,6 +801,52 @@ bool blk_queue_can_use_dma_map_merging(struct request_queue *q,
 }
 EXPORT_SYMBOL_GPL(blk_queue_can_use_dma_map_merging);
 
+/**
+ * blk_queue_set_zoned - configure a disk queue zoned model.
+ * @disk:      the gendisk of the queue to configure
+ * @model:     the zoned model to set
+ *
+ * Set the zoned model of the request queue of @disk according to @model.
+ * When @model is BLK_ZONED_HM (host managed), this should be called only
+ * if zoned block device support is enabled (CONFIG_BLK_DEV_ZONED option).
+ * If @model specifies BLK_ZONED_HA (host aware), the effective model used
+ * depends on CONFIG_BLK_DEV_ZONED settings and on the existence of partitions
+ * on the disk.
+ */
+void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
+{
+       switch (model) {
+       case BLK_ZONED_HM:
+               /*
+                * Host managed devices are supported only if
+                * CONFIG_BLK_DEV_ZONED is enabled.
+                */
+               WARN_ON_ONCE(!IS_ENABLED(CONFIG_BLK_DEV_ZONED));
+               break;
+       case BLK_ZONED_HA:
+               /*
+                * Host aware devices can be treated either as regular block
+                * devices (similar to drive managed devices) or as zoned block
+                * devices to take advantage of the zone command set, similarly
+                * to host managed devices. We try the latter if there are no
+                * partitions and zoned block device support is enabled, else
+                * we do nothing special as far as the block layer is concerned.
+                */
+               if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) ||
+                   disk_has_partitions(disk))
+                       model = BLK_ZONED_NONE;
+               break;
+       case BLK_ZONED_NONE:
+       default:
+               if (WARN_ON_ONCE(model != BLK_ZONED_NONE))
+                       model = BLK_ZONED_NONE;
+               break;
+       }
+
+       disk->queue->limits.zoned = model;
+}
+EXPORT_SYMBOL_GPL(blk_queue_set_zoned);
+
 static int __init blk_settings_init(void)
 {
        blk_max_low_pfn = max_low_pfn - 1;
index 7da302f..ae3dd1f 100644 (file)
@@ -137,6 +137,7 @@ void blk_stat_add_callback(struct request_queue *q,
                           struct blk_stat_callback *cb)
 {
        unsigned int bucket;
+       unsigned long flags;
        int cpu;
 
        for_each_possible_cpu(cpu) {
@@ -147,20 +148,22 @@ void blk_stat_add_callback(struct request_queue *q,
                        blk_rq_stat_init(&cpu_stat[bucket]);
        }
 
-       spin_lock(&q->stats->lock);
+       spin_lock_irqsave(&q->stats->lock, flags);
        list_add_tail_rcu(&cb->list, &q->stats->callbacks);
        blk_queue_flag_set(QUEUE_FLAG_STATS, q);
-       spin_unlock(&q->stats->lock);
+       spin_unlock_irqrestore(&q->stats->lock, flags);
 }
 
 void blk_stat_remove_callback(struct request_queue *q,
                              struct blk_stat_callback *cb)
 {
-       spin_lock(&q->stats->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&q->stats->lock, flags);
        list_del_rcu(&cb->list);
        if (list_empty(&q->stats->callbacks) && !q->stats->enable_accounting)
                blk_queue_flag_clear(QUEUE_FLAG_STATS, q);
-       spin_unlock(&q->stats->lock);
+       spin_unlock_irqrestore(&q->stats->lock, flags);
 
        del_timer_sync(&cb->timer);
 }
@@ -183,10 +186,12 @@ void blk_stat_free_callback(struct blk_stat_callback *cb)
 
 void blk_stat_enable_accounting(struct request_queue *q)
 {
-       spin_lock(&q->stats->lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&q->stats->lock, flags);
        q->stats->enable_accounting = true;
        blk_queue_flag_set(QUEUE_FLAG_STATS, q);
-       spin_unlock(&q->stats->lock);
+       spin_unlock_irqrestore(&q->stats->lock, flags);
 }
 EXPORT_SYMBOL_GPL(blk_stat_enable_accounting);
 
index 0fa615e..fd41008 100644 (file)
@@ -528,7 +528,7 @@ static inline bool wbt_should_throttle(struct rq_wb *rwb, struct bio *bio)
                if ((bio->bi_opf & (REQ_SYNC | REQ_IDLE)) ==
                    (REQ_SYNC | REQ_IDLE))
                        return false;
-               /* fallthrough */
+               fallthrough;
        case REQ_OP_DISCARD:
                return true;
        default:
index fb7b347..d185396 100644 (file)
@@ -378,7 +378,7 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
        bset->timeout_fn = timeout;
 
        set = &bset->tag_set;
-       set->ops = &bsg_mq_ops,
+       set->ops = &bsg_mq_ops;
        set->nr_hw_queues = 1;
        set->queue_depth = 128;
        set->numa_node = NUMA_NO_NODE;
index 77bcab1..04ebd37 100644 (file)
@@ -71,7 +71,7 @@ int ioprio_check_cap(int ioprio)
                case IOPRIO_CLASS_RT:
                        if (!capable(CAP_SYS_ADMIN))
                                return -EPERM;
-                       /* fall through */
+                       fallthrough;
                        /* rt has prio field too */
                case IOPRIO_CLASS_BE:
                        if (data >= IOPRIO_BE_NR || data < 0)
index e62a98a..722406b 100644 (file)
@@ -278,6 +278,15 @@ static void hd_struct_free_work(struct work_struct *work)
 {
        struct hd_struct *part =
                container_of(to_rcu_work(work), struct hd_struct, rcu_work);
+       struct gendisk *disk = part_to_disk(part);
+
+       /*
+        * Release the disk reference acquired in delete_partition here.
+        * We can't release it in hd_struct_free because the final put_device
+        * needs process context and thus can't be run directly from a
+        * percpu_ref ->release handler.
+        */
+       put_device(disk_to_dev(disk));
 
        part->start_sect = 0;
        part->nr_sects = 0;
@@ -293,7 +302,6 @@ static void hd_struct_free(struct percpu_ref *ref)
                rcu_dereference_protected(disk->part_tbl, 1);
 
        rcu_assign_pointer(ptbl->last_lookup, NULL);
-       put_device(disk_to_dev(disk));
 
        INIT_RCU_WORK(&part->rcu_work, hd_struct_free_work);
        queue_rcu_work(system_wq, &part->rcu_work);
@@ -524,19 +532,20 @@ int bdev_add_partition(struct block_device *bdev, int partno,
 int bdev_del_partition(struct block_device *bdev, int partno)
 {
        struct block_device *bdevp;
-       struct hd_struct *part;
-       int ret = 0;
+       struct hd_struct *part = NULL;
+       int ret;
 
-       part = disk_get_part(bdev->bd_disk, partno);
-       if (!part)
-               return -ENXIO;
-
-       ret = -ENOMEM;
-       bdevp = bdget(part_devt(part));
+       bdevp = bdget_disk(bdev->bd_disk, partno);
        if (!bdevp)
-               goto out_put_part;
+               return -ENXIO;
 
        mutex_lock(&bdevp->bd_mutex);
+       mutex_lock_nested(&bdev->bd_mutex, 1);
+
+       ret = -ENXIO;
+       part = disk_get_part(bdev->bd_disk, partno);
+       if (!part)
+               goto out_unlock;
 
        ret = -EBUSY;
        if (bdevp->bd_openers)
@@ -545,16 +554,14 @@ int bdev_del_partition(struct block_device *bdev, int partno)
        sync_blockdev(bdevp);
        invalidate_bdev(bdevp);
 
-       mutex_lock_nested(&bdev->bd_mutex, 1);
        delete_partition(bdev->bd_disk, part);
-       mutex_unlock(&bdev->bd_mutex);
-
        ret = 0;
 out_unlock:
+       mutex_unlock(&bdev->bd_mutex);
        mutex_unlock(&bdevp->bd_mutex);
        bdput(bdevp);
-out_put_part:
-       disk_put_part(part);
+       if (part)
+               disk_put_part(part);
        return ret;
 }
 
index d6e18df..4b044e6 100644 (file)
@@ -305,8 +305,6 @@ int ibm_partition(struct parsed_partitions *state)
        if (!disk->fops->getgeo)
                goto out_exit;
        fn = symbol_get(dasd_biodasdinfo);
-       if (!fn)
-               goto out_exit;
        blocksize = bdev_logical_block_size(bdev);
        if (blocksize <= 0)
                goto out_symbol;
@@ -326,7 +324,7 @@ int ibm_partition(struct parsed_partitions *state)
        geo->start = get_start_sect(bdev);
        if (disk->fops->getgeo(bdev, geo))
                goto out_freeall;
-       if (fn(disk, info)) {
+       if (!fn || fn(disk, info)) {
                kfree(info);
                info = NULL;
        }
@@ -370,7 +368,8 @@ out_nolab:
 out_nogeo:
        kfree(info);
 out_symbol:
-       symbol_put(dasd_biodasdinfo);
+       if (fn)
+               symbol_put(dasd_biodasdinfo);
 out_exit:
        return res;
 }
index ef722f0..97e0b16 100644 (file)
@@ -333,16 +333,8 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
                struct iov_iter i;
                struct iovec *iov = NULL;
 
-#ifdef CONFIG_COMPAT
-               if (in_compat_syscall())
-                       ret = compat_import_iovec(rq_data_dir(rq),
-                                  hdr->dxferp, hdr->iovec_count,
-                                  0, &iov, &i);
-               else
-#endif
-                       ret = import_iovec(rq_data_dir(rq),
-                                  hdr->dxferp, hdr->iovec_count,
-                                  0, &iov, &i);
+               ret = import_iovec(rq_data_dir(rq), hdr->dxferp,
+                                  hdr->iovec_count, 0, &iov, &i);
                if (ret < 0)
                        goto out_free_cdb;
 
@@ -651,6 +643,7 @@ struct compat_cdrom_generic_command {
        compat_int_t    stat;
        compat_caddr_t  sense;
        unsigned char   data_direction;
+       unsigned char   pad[3];
        compat_int_t    quiet;
        compat_int_t    timeout;
        compat_caddr_t  reserved[1];
index 1b57419..094ef56 100644 (file)
@@ -260,6 +260,23 @@ config CRYPTO_ECRDSA
          standard algorithms (called GOST algorithms). Only signature verification
          is implemented.
 
+config CRYPTO_SM2
+       tristate "SM2 algorithm"
+       select CRYPTO_SM3
+       select CRYPTO_AKCIPHER
+       select CRYPTO_MANAGER
+       select MPILIB
+       select ASN1
+       help
+         Generic implementation of the SM2 public key algorithm. It was
+         published by State Encryption Management Bureau, China.
+         as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012.
+
+         References:
+         https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02
+         http://www.oscca.gov.cn/sca/xxgk/2010-12/17/content_1002386.shtml
+         http://www.gmbz.org.cn/main/bzlb.html
+
 config CRYPTO_CURVE25519
        tristate "Curve25519 algorithm"
        select CRYPTO_KPP
@@ -1185,6 +1202,7 @@ config CRYPTO_AES_PPC_SPE
 
 config CRYPTO_ANUBIS
        tristate "Anubis cipher algorithm"
+       depends on CRYPTO_USER_API_ENABLE_OBSOLETE
        select CRYPTO_ALGAPI
        help
          Anubis cipher algorithm.
@@ -1199,6 +1217,7 @@ config CRYPTO_ANUBIS
 
 config CRYPTO_ARC4
        tristate "ARC4 cipher algorithm"
+       depends on CRYPTO_USER_API_ENABLE_OBSOLETE
        select CRYPTO_SKCIPHER
        select CRYPTO_LIB_ARC4
        help
@@ -1423,6 +1442,7 @@ config CRYPTO_FCRYPT
 
 config CRYPTO_KHAZAD
        tristate "Khazad cipher algorithm"
+       depends on CRYPTO_USER_API_ENABLE_OBSOLETE
        select CRYPTO_ALGAPI
        help
          Khazad cipher algorithm.
@@ -1486,6 +1506,7 @@ config CRYPTO_CHACHA_MIPS
 
 config CRYPTO_SEED
        tristate "SEED cipher algorithm"
+       depends on CRYPTO_USER_API_ENABLE_OBSOLETE
        select CRYPTO_ALGAPI
        help
          SEED cipher algorithm (RFC4269).
@@ -1612,6 +1633,7 @@ config CRYPTO_SM4
 
 config CRYPTO_TEA
        tristate "TEA, XTEA and XETA cipher algorithms"
+       depends on CRYPTO_USER_API_ENABLE_OBSOLETE
        select CRYPTO_ALGAPI
        help
          TEA cipher algorithm.
@@ -1870,6 +1892,15 @@ config CRYPTO_USER_API_RNG
          This option enables the user-spaces interface for random
          number generator algorithms.
 
+config CRYPTO_USER_API_RNG_CAVP
+       bool "Enable CAVP testing of DRBG"
+       depends on CRYPTO_USER_API_RNG && CRYPTO_DRBG
+       help
+         This option enables extra API for CAVP testing via the user-space
+         interface: resetting of DRBG entropy, and providing Additional Data.
+         This should only be enabled for CAVP testing. You should say
+         no unless you know what this is.
+
 config CRYPTO_USER_API_AEAD
        tristate "User-space interface for AEAD cipher algorithms"
        depends on NET
@@ -1881,6 +1912,15 @@ config CRYPTO_USER_API_AEAD
          This option enables the user-spaces interface for AEAD
          cipher algorithms.
 
+config CRYPTO_USER_API_ENABLE_OBSOLETE
+       bool "Enable obsolete cryptographic algorithms for userspace"
+       depends on CRYPTO_USER_API
+       default y
+       help
+         Allow obsolete cryptographic algorithms to be selected that have
+         already been phased out from internal use by the kernel, and are
+         only useful for userspace clients that still rely on them.
+
 config CRYPTO_STATS
        bool "Crypto usage statistics for User-space"
        depends on CRYPTO_USER
index 4ca12b6..b279483 100644 (file)
@@ -42,6 +42,14 @@ rsa_generic-y += rsa_helper.o
 rsa_generic-y += rsa-pkcs1pad.o
 obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o
 
+$(obj)/sm2signature.asn1.o: $(obj)/sm2signature.asn1.c $(obj)/sm2signature.asn1.h
+$(obj)/sm2.o: $(obj)/sm2signature.asn1.h
+
+sm2_generic-y += sm2signature.asn1.o
+sm2_generic-y += sm2.o
+
+obj-$(CONFIG_CRYPTO_SM2) += sm2_generic.o
+
 crypto_acompress-y := acompress.o
 crypto_acompress-y += scompress.o
 obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o
index a6f581a..d11db80 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/rwsem.h>
+#include <linux/sched.h>
 #include <linux/sched/signal.h>
 #include <linux/security.h>
 
@@ -253,6 +254,14 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
                if (!type->setauthsize)
                        goto unlock;
                err = type->setauthsize(ask->private, optlen);
+               break;
+       case ALG_SET_DRBG_ENTROPY:
+               if (sock->state == SS_CONNECTED)
+                       goto unlock;
+               if (!type->setentropy)
+                       goto unlock;
+
+               err = type->setentropy(ask->private, optval, optlen);
        }
 
 unlock:
@@ -285,6 +294,11 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern)
        security_sock_graft(sk2, newsock);
        security_sk_clone(sk, sk2);
 
+       /*
+        * newsock->ops assigned here to allow type->accept call to override
+        * them when required.
+        */
+       newsock->ops = type->ops;
        err = type->accept(ask->private, sk2);
 
        nokey = err == -ENOKEY;
@@ -303,7 +317,6 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern)
        alg_sk(sk2)->parent = sk;
        alg_sk(sk2)->type = type;
 
-       newsock->ops = type->ops;
        newsock->state = SS_CONNECTED;
 
        if (nokey)
@@ -845,9 +858,15 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size,
        }
 
        lock_sock(sk);
-       if (ctx->init && (init || !ctx->more)) {
-               err = -EINVAL;
-               goto unlock;
+       if (ctx->init && !ctx->more) {
+               if (ctx->used) {
+                       err = -EINVAL;
+                       goto unlock;
+               }
+
+               pr_info_once(
+                       "%s sent an empty control message without MSG_MORE.\n",
+                       current->comm);
        }
        ctx->init = true;
 
index d9d65d1..c2ca631 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <crypto/internal/hash.h>
 #include <crypto/scatterwalk.h>
-#include <linux/bug.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -46,10 +45,7 @@ static int hash_walk_next(struct crypto_hash_walk *walk)
        unsigned int nbytes = min(walk->entrylen,
                                  ((unsigned int)(PAGE_SIZE)) - offset);
 
-       if (walk->flags & CRYPTO_ALG_ASYNC)
-               walk->data = kmap(walk->pg);
-       else
-               walk->data = kmap_atomic(walk->pg);
+       walk->data = kmap_atomic(walk->pg);
        walk->data += offset;
 
        if (offset & alignmask) {
@@ -99,16 +95,8 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err)
                }
        }
 
-       if (walk->flags & CRYPTO_ALG_ASYNC)
-               kunmap(walk->pg);
-       else {
-               kunmap_atomic(walk->data);
-               /*
-                * The may sleep test only makes sense for sync users.
-                * Async users don't need to sleep here anyway.
-                */
-               crypto_yield(walk->flags);
-       }
+       kunmap_atomic(walk->data);
+       crypto_yield(walk->flags);
 
        if (err)
                return err;
@@ -140,33 +128,12 @@ int crypto_hash_walk_first(struct ahash_request *req,
 
        walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req));
        walk->sg = req->src;
-       walk->flags = req->base.flags & CRYPTO_TFM_REQ_MASK;
+       walk->flags = req->base.flags;
 
        return hash_walk_new_entry(walk);
 }
 EXPORT_SYMBOL_GPL(crypto_hash_walk_first);
 
-int crypto_ahash_walk_first(struct ahash_request *req,
-                           struct crypto_hash_walk *walk)
-{
-       walk->total = req->nbytes;
-
-       if (!walk->total) {
-               walk->entrylen = 0;
-               return 0;
-       }
-
-       walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req));
-       walk->sg = req->src;
-       walk->flags = req->base.flags & CRYPTO_TFM_REQ_MASK;
-       walk->flags |= CRYPTO_ALG_ASYNC;
-
-       BUILD_BUG_ON(CRYPTO_TFM_REQ_MASK & CRYPTO_ALG_ASYNC);
-
-       return hash_walk_new_entry(walk);
-}
-EXPORT_SYMBOL_GPL(crypto_ahash_walk_first);
-
 static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
                                unsigned int keylen)
 {
@@ -477,6 +444,14 @@ static int ahash_def_finup(struct ahash_request *req)
        return ahash_def_finup_finish1(req, err);
 }
 
+static void crypto_ahash_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
+       struct ahash_alg *alg = crypto_ahash_alg(hash);
+
+       alg->exit_tfm(hash);
+}
+
 static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
 {
        struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
@@ -500,7 +475,10 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
                ahash_set_needkey(hash);
        }
 
-       return 0;
+       if (alg->exit_tfm)
+               tfm->exit = crypto_ahash_exit_tfm;
+
+       return alg->init_tfm ? alg->init_tfm(hash) : 0;
 }
 
 static unsigned int crypto_ahash_extsize(struct crypto_alg *alg)
index 21efa78..42493b4 100644 (file)
@@ -78,7 +78,7 @@ static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm,
        SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm);
 
        skcipher_request_set_sync_tfm(skreq, null_tfm);
-       skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_BACKLOG,
+       skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_SLEEP,
                                      NULL, NULL);
        skcipher_request_set_crypt(skreq, src, dst, len, NULL);
 
@@ -120,7 +120,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
 
        /*
         * Make sure sufficient data is present -- note, the same check is
-        * is also present in sendmsg/sendpage. The checks in sendpage/sendmsg
+        * also present in sendmsg/sendpage. The checks in sendpage/sendmsg
         * shall provide an information to the data sender that something is
         * wrong, but they are irrelevant to maintain the kernel integrity.
         * We need this check here too in case user space decides to not honor
@@ -291,19 +291,20 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
                areq->outlen = outlen;
 
                aead_request_set_callback(&areq->cra_u.aead_req,
-                                         CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                         CRYPTO_TFM_REQ_MAY_SLEEP,
                                          af_alg_async_cb, areq);
                err = ctx->enc ? crypto_aead_encrypt(&areq->cra_u.aead_req) :
                                 crypto_aead_decrypt(&areq->cra_u.aead_req);
 
                /* AIO operation in progress */
-               if (err == -EINPROGRESS || err == -EBUSY)
+               if (err == -EINPROGRESS)
                        return -EIOCBQUEUED;
 
                sock_put(sk);
        } else {
                /* Synchronous operation */
                aead_request_set_callback(&areq->cra_u.aead_req,
+                                         CRYPTO_TFM_REQ_MAY_SLEEP |
                                          CRYPTO_TFM_REQ_MAY_BACKLOG,
                                          crypto_req_done, &ctx->wait);
                err = crypto_wait_req(ctx->enc ?
index 6300e05..407408c 100644 (file)
@@ -38,6 +38,7 @@
  * DAMAGE.
  */
 
+#include <linux/capability.h>
 #include <linux/module.h>
 #include <crypto/rng.h>
 #include <linux/random.h>
@@ -53,15 +54,26 @@ struct rng_ctx {
 #define MAXSIZE 128
        unsigned int len;
        struct crypto_rng *drng;
+       u8 *addtl;
+       size_t addtl_len;
 };
 
-static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
-                      int flags)
+struct rng_parent_ctx {
+       struct crypto_rng *drng;
+       u8 *entropy;
+};
+
+static void rng_reset_addtl(struct rng_ctx *ctx)
 {
-       struct sock *sk = sock->sk;
-       struct alg_sock *ask = alg_sk(sk);
-       struct rng_ctx *ctx = ask->private;
-       int err;
+       kfree_sensitive(ctx->addtl);
+       ctx->addtl = NULL;
+       ctx->addtl_len = 0;
+}
+
+static int _rng_recvmsg(struct crypto_rng *drng, struct msghdr *msg, size_t len,
+                       u8 *addtl, size_t addtl_len)
+{
+       int err = 0;
        int genlen = 0;
        u8 result[MAXSIZE];
 
@@ -82,7 +94,7 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
         * seeding as they automatically seed. The X9.31 DRNG will return
         * an error if it was not seeded properly.
         */
-       genlen = crypto_rng_get_bytes(ctx->drng, result, len);
+       genlen = crypto_rng_generate(drng, addtl, addtl_len, result, len);
        if (genlen < 0)
                return genlen;
 
@@ -92,6 +104,63 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
        return err ? err : len;
 }
 
+static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+                      int flags)
+{
+       struct sock *sk = sock->sk;
+       struct alg_sock *ask = alg_sk(sk);
+       struct rng_ctx *ctx = ask->private;
+
+       return _rng_recvmsg(ctx->drng, msg, len, NULL, 0);
+}
+
+static int rng_test_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+                           int flags)
+{
+       struct sock *sk = sock->sk;
+       struct alg_sock *ask = alg_sk(sk);
+       struct rng_ctx *ctx = ask->private;
+       int ret;
+
+       lock_sock(sock->sk);
+       ret = _rng_recvmsg(ctx->drng, msg, len, ctx->addtl, ctx->addtl_len);
+       rng_reset_addtl(ctx);
+       release_sock(sock->sk);
+
+       return ret;
+}
+
+static int rng_test_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
+{
+       int err;
+       struct alg_sock *ask = alg_sk(sock->sk);
+       struct rng_ctx *ctx = ask->private;
+
+       lock_sock(sock->sk);
+       if (len > MAXSIZE) {
+               err = -EMSGSIZE;
+               goto unlock;
+       }
+
+       rng_reset_addtl(ctx);
+       ctx->addtl = kmalloc(len, GFP_KERNEL);
+       if (!ctx->addtl) {
+               err = -ENOMEM;
+               goto unlock;
+       }
+
+       err = memcpy_from_msg(ctx->addtl, msg, len);
+       if (err) {
+               rng_reset_addtl(ctx);
+               goto unlock;
+       }
+       ctx->addtl_len = len;
+
+unlock:
+       release_sock(sock->sk);
+       return err ? err : len;
+}
+
 static struct proto_ops algif_rng_ops = {
        .family         =       PF_ALG,
 
@@ -111,14 +180,53 @@ static struct proto_ops algif_rng_ops = {
        .recvmsg        =       rng_recvmsg,
 };
 
+static struct proto_ops __maybe_unused algif_rng_test_ops = {
+       .family         =       PF_ALG,
+
+       .connect        =       sock_no_connect,
+       .socketpair     =       sock_no_socketpair,
+       .getname        =       sock_no_getname,
+       .ioctl          =       sock_no_ioctl,
+       .listen         =       sock_no_listen,
+       .shutdown       =       sock_no_shutdown,
+       .mmap           =       sock_no_mmap,
+       .bind           =       sock_no_bind,
+       .accept         =       sock_no_accept,
+       .sendpage       =       sock_no_sendpage,
+
+       .release        =       af_alg_release,
+       .recvmsg        =       rng_test_recvmsg,
+       .sendmsg        =       rng_test_sendmsg,
+};
+
 static void *rng_bind(const char *name, u32 type, u32 mask)
 {
-       return crypto_alloc_rng(name, type, mask);
+       struct rng_parent_ctx *pctx;
+       struct crypto_rng *rng;
+
+       pctx = kzalloc(sizeof(*pctx), GFP_KERNEL);
+       if (!pctx)
+               return ERR_PTR(-ENOMEM);
+
+       rng = crypto_alloc_rng(name, type, mask);
+       if (IS_ERR(rng)) {
+               kfree(pctx);
+               return ERR_CAST(rng);
+       }
+
+       pctx->drng = rng;
+       return pctx;
 }
 
 static void rng_release(void *private)
 {
-       crypto_free_rng(private);
+       struct rng_parent_ctx *pctx = private;
+
+       if (unlikely(!pctx))
+               return;
+       crypto_free_rng(pctx->drng);
+       kfree_sensitive(pctx->entropy);
+       kfree_sensitive(pctx);
 }
 
 static void rng_sock_destruct(struct sock *sk)
@@ -126,6 +234,7 @@ static void rng_sock_destruct(struct sock *sk)
        struct alg_sock *ask = alg_sk(sk);
        struct rng_ctx *ctx = ask->private;
 
+       rng_reset_addtl(ctx);
        sock_kfree_s(sk, ctx, ctx->len);
        af_alg_release_parent(sk);
 }
@@ -133,6 +242,7 @@ static void rng_sock_destruct(struct sock *sk)
 static int rng_accept_parent(void *private, struct sock *sk)
 {
        struct rng_ctx *ctx;
+       struct rng_parent_ctx *pctx = private;
        struct alg_sock *ask = alg_sk(sk);
        unsigned int len = sizeof(*ctx);
 
@@ -141,6 +251,8 @@ static int rng_accept_parent(void *private, struct sock *sk)
                return -ENOMEM;
 
        ctx->len = len;
+       ctx->addtl = NULL;
+       ctx->addtl_len = 0;
 
        /*
         * No seeding done at that point -- if multiple accepts are
@@ -148,20 +260,58 @@ static int rng_accept_parent(void *private, struct sock *sk)
         * state of the RNG.
         */
 
-       ctx->drng = private;
+       ctx->drng = pctx->drng;
        ask->private = ctx;
        sk->sk_destruct = rng_sock_destruct;
 
+       /*
+        * Non NULL pctx->entropy means that CAVP test has been initiated on
+        * this socket, replace proto_ops algif_rng_ops with algif_rng_test_ops.
+        */
+       if (IS_ENABLED(CONFIG_CRYPTO_USER_API_RNG_CAVP) && pctx->entropy)
+               sk->sk_socket->ops = &algif_rng_test_ops;
+
        return 0;
 }
 
 static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen)
 {
+       struct rng_parent_ctx *pctx = private;
        /*
         * Check whether seedlen is of sufficient size is done in RNG
         * implementations.
         */
-       return crypto_rng_reset(private, seed, seedlen);
+       return crypto_rng_reset(pctx->drng, seed, seedlen);
+}
+
+static int __maybe_unused rng_setentropy(void *private, sockptr_t entropy,
+                                        unsigned int len)
+{
+       struct rng_parent_ctx *pctx = private;
+       u8 *kentropy = NULL;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (pctx->entropy)
+               return -EINVAL;
+
+       if (len > MAXSIZE)
+               return -EMSGSIZE;
+
+       if (len) {
+               kentropy = memdup_sockptr(entropy, len);
+               if (IS_ERR(kentropy))
+                       return PTR_ERR(kentropy);
+       }
+
+       crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len);
+       /*
+        * Since rng doesn't perform any memory management for the entropy
+        * buffer, save kentropy pointer to pctx now to free it after use.
+        */
+       pctx->entropy = kentropy;
+       return 0;
 }
 
 static const struct af_alg_type algif_type_rng = {
@@ -169,6 +319,9 @@ static const struct af_alg_type algif_type_rng = {
        .release        =       rng_release,
        .accept         =       rng_accept_parent,
        .setkey         =       rng_setkey,
+#ifdef CONFIG_CRYPTO_USER_API_RNG_CAVP
+       .setentropy     =       rng_setentropy,
+#endif
        .ops            =       &algif_rng_ops,
        .name           =       "rng",
        .owner          =       THIS_MODULE
index 478f3b8..ee8890e 100644 (file)
@@ -123,7 +123,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
                        crypto_skcipher_decrypt(&areq->cra_u.skcipher_req);
 
                /* AIO operation in progress */
-               if (err == -EINPROGRESS || err == -EBUSY)
+               if (err == -EINPROGRESS)
                        return -EIOCBQUEUED;
 
                sock_put(sk);
index aa79571..3254dcc 100644 (file)
@@ -11,7 +11,9 @@
 #include <crypto/arc4.h>
 #include <crypto/internal/skcipher.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/sched.h>
 
 static int crypto_arc4_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
                              unsigned int key_len)
@@ -39,6 +41,14 @@ static int crypto_arc4_crypt(struct skcipher_request *req)
        return err;
 }
 
+static int crypto_arc4_init(struct crypto_skcipher *tfm)
+{
+       pr_warn_ratelimited("\"%s\" (%ld) uses obsolete ecb(arc4) skcipher\n",
+                           current->comm, (unsigned long)current->pid);
+
+       return 0;
+}
+
 static struct skcipher_alg arc4_alg = {
        /*
         * For legacy reasons, this is named "ecb(arc4)", not "arc4".
@@ -55,6 +65,7 @@ static struct skcipher_alg arc4_alg = {
        .setkey                 =       crypto_arc4_setkey,
        .encrypt                =       crypto_arc4_crypt,
        .decrypt                =       crypto_arc4_crypt,
+       .init                   =       crypto_arc4_init,
 };
 
 static int __init arc4_init(void)
index d8410ff..8892908 100644 (file)
@@ -17,6 +17,8 @@
 #include <keys/asymmetric-subtype.h>
 #include <crypto/public_key.h>
 #include <crypto/akcipher.h>
+#include <crypto/sm2.h>
+#include <crypto/sm3_base.h>
 
 MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
 MODULE_AUTHOR("Red Hat, Inc.");
@@ -246,6 +248,61 @@ error_free_tfm:
        return ret;
 }
 
+#if IS_REACHABLE(CONFIG_CRYPTO_SM2)
+static int cert_sig_digest_update(const struct public_key_signature *sig,
+                                 struct crypto_akcipher *tfm_pkey)
+{
+       struct crypto_shash *tfm;
+       struct shash_desc *desc;
+       size_t desc_size;
+       unsigned char dgst[SM3_DIGEST_SIZE];
+       int ret;
+
+       BUG_ON(!sig->data);
+
+       ret = sm2_compute_z_digest(tfm_pkey, SM2_DEFAULT_USERID,
+                                       SM2_DEFAULT_USERID_LEN, dgst);
+       if (ret)
+               return ret;
+
+       tfm = crypto_alloc_shash(sig->hash_algo, 0, 0);
+       if (IS_ERR(tfm))
+               return PTR_ERR(tfm);
+
+       desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+       desc = kzalloc(desc_size, GFP_KERNEL);
+       if (!desc) {
+               ret = -ENOMEM;
+               goto error_free_tfm;
+       }
+
+       desc->tfm = tfm;
+
+       ret = crypto_shash_init(desc);
+       if (ret < 0)
+               goto error_free_desc;
+
+       ret = crypto_shash_update(desc, dgst, SM3_DIGEST_SIZE);
+       if (ret < 0)
+               goto error_free_desc;
+
+       ret = crypto_shash_finup(desc, sig->data, sig->data_size, sig->digest);
+
+error_free_desc:
+       kfree(desc);
+error_free_tfm:
+       crypto_free_shash(tfm);
+       return ret;
+}
+#else
+static inline int cert_sig_digest_update(
+       const struct public_key_signature *sig,
+       struct crypto_akcipher *tfm_pkey)
+{
+       return -ENOTSUPP;
+}
+#endif /* ! IS_REACHABLE(CONFIG_CRYPTO_SM2) */
+
 /*
  * Verify a signature using a public key.
  */
@@ -299,6 +356,12 @@ int public_key_verify_signature(const struct public_key *pkey,
        if (ret)
                goto error_free_key;
 
+       if (strcmp(sig->pkey_algo, "sm2") == 0 && sig->data_size) {
+               ret = cert_sig_digest_update(sig, tfm);
+               if (ret)
+                       goto error_free_key;
+       }
+
        sg_init_table(src_sg, 2);
        sg_set_buf(&src_sg[0], sig->s, sig->s_size);
        sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
index 26ec20e..52c9b45 100644 (file)
@@ -234,6 +234,10 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
        case OID_gost2012Signature512:
                ctx->cert->sig->hash_algo = "streebog512";
                goto ecrdsa;
+
+       case OID_SM2_with_SM3:
+               ctx->cert->sig->hash_algo = "sm3";
+               goto sm2;
        }
 
 rsa_pkcs1:
@@ -246,6 +250,11 @@ ecrdsa:
        ctx->cert->sig->encoding = "raw";
        ctx->algo_oid = ctx->last_oid;
        return 0;
+sm2:
+       ctx->cert->sig->pkey_algo = "sm2";
+       ctx->cert->sig->encoding = "raw";
+       ctx->algo_oid = ctx->last_oid;
+       return 0;
 }
 
 /*
@@ -266,7 +275,8 @@ int x509_note_signature(void *context, size_t hdrlen,
        }
 
        if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 ||
-           strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0) {
+           strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 ||
+           strcmp(ctx->cert->sig->pkey_algo, "sm2") == 0) {
                /* Discard the BIT STRING metadata */
                if (vlen < 1 || *(const u8 *)value != 0)
                        return -EBADMSG;
@@ -451,13 +461,20 @@ int x509_extract_key_data(void *context, size_t hdrlen,
        struct x509_parse_context *ctx = context;
 
        ctx->key_algo = ctx->last_oid;
-       if (ctx->last_oid == OID_rsaEncryption)
+       switch (ctx->last_oid) {
+       case OID_rsaEncryption:
                ctx->cert->pub->pkey_algo = "rsa";
-       else if (ctx->last_oid == OID_gost2012PKey256 ||
-                ctx->last_oid == OID_gost2012PKey512)
+               break;
+       case OID_gost2012PKey256:
+       case OID_gost2012PKey512:
                ctx->cert->pub->pkey_algo = "ecrdsa";
-       else
+               break;
+       case OID_id_ecPublicKey:
+               ctx->cert->pub->pkey_algo = "sm2";
+               break;
+       default:
                return -ENOPKG;
+       }
 
        /* Discard the BIT STRING metadata */
        if (vlen < 1 || *(const u8 *)value != 0)
index d964cc8..ae450eb 100644 (file)
@@ -30,6 +30,9 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
        pr_devel("==>%s()\n", __func__);
 
+       sig->data = cert->tbs;
+       sig->data_size = cert->tbs_size;
+
        if (!cert->pub->pkey_algo)
                cert->unsupported_key = true;
 
index e6f6273..0d9509d 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include <crypto/algapi.h>
-#include <crypto/cbc.h>
 #include <crypto/internal/skcipher.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/log2.h>
 #include <linux/module.h>
 
-static inline void crypto_cbc_encrypt_one(struct crypto_skcipher *tfm,
-                                         const u8 *src, u8 *dst)
+static int crypto_cbc_encrypt_segment(struct skcipher_walk *walk,
+                                     struct crypto_skcipher *skcipher)
 {
-       crypto_cipher_encrypt_one(skcipher_cipher_simple(tfm), dst, src);
+       unsigned int bsize = crypto_skcipher_blocksize(skcipher);
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
+       unsigned int nbytes = walk->nbytes;
+       u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       struct crypto_cipher *cipher;
+       struct crypto_tfm *tfm;
+       u8 *iv = walk->iv;
+
+       cipher = skcipher_cipher_simple(skcipher);
+       tfm = crypto_cipher_tfm(cipher);
+       fn = crypto_cipher_alg(cipher)->cia_encrypt;
+
+       do {
+               crypto_xor(iv, src, bsize);
+               fn(tfm, dst, iv);
+               memcpy(iv, dst, bsize);
+
+               src += bsize;
+               dst += bsize;
+       } while ((nbytes -= bsize) >= bsize);
+
+       return nbytes;
+}
+
+static int crypto_cbc_encrypt_inplace(struct skcipher_walk *walk,
+                                     struct crypto_skcipher *skcipher)
+{
+       unsigned int bsize = crypto_skcipher_blocksize(skcipher);
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
+       unsigned int nbytes = walk->nbytes;
+       u8 *src = walk->src.virt.addr;
+       struct crypto_cipher *cipher;
+       struct crypto_tfm *tfm;
+       u8 *iv = walk->iv;
+
+       cipher = skcipher_cipher_simple(skcipher);
+       tfm = crypto_cipher_tfm(cipher);
+       fn = crypto_cipher_alg(cipher)->cia_encrypt;
+
+       do {
+               crypto_xor(src, iv, bsize);
+               fn(tfm, src, src);
+               iv = src;
+
+               src += bsize;
+       } while ((nbytes -= bsize) >= bsize);
+
+       memcpy(walk->iv, iv, bsize);
+
+       return nbytes;
 }
 
 static int crypto_cbc_encrypt(struct skcipher_request *req)
 {
-       return crypto_cbc_encrypt_walk(req, crypto_cbc_encrypt_one);
+       struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+       struct skcipher_walk walk;
+       int err;
+
+       err = skcipher_walk_virt(&walk, req, false);
+
+       while (walk.nbytes) {
+               if (walk.src.virt.addr == walk.dst.virt.addr)
+                       err = crypto_cbc_encrypt_inplace(&walk, skcipher);
+               else
+                       err = crypto_cbc_encrypt_segment(&walk, skcipher);
+               err = skcipher_walk_done(&walk, err);
+       }
+
+       return err;
+}
+
+static int crypto_cbc_decrypt_segment(struct skcipher_walk *walk,
+                                     struct crypto_skcipher *skcipher)
+{
+       unsigned int bsize = crypto_skcipher_blocksize(skcipher);
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
+       unsigned int nbytes = walk->nbytes;
+       u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       struct crypto_cipher *cipher;
+       struct crypto_tfm *tfm;
+       u8 *iv = walk->iv;
+
+       cipher = skcipher_cipher_simple(skcipher);
+       tfm = crypto_cipher_tfm(cipher);
+       fn = crypto_cipher_alg(cipher)->cia_decrypt;
+
+       do {
+               fn(tfm, dst, src);
+               crypto_xor(dst, iv, bsize);
+               iv = src;
+
+               src += bsize;
+               dst += bsize;
+       } while ((nbytes -= bsize) >= bsize);
+
+       memcpy(walk->iv, iv, bsize);
+
+       return nbytes;
 }
 
-static inline void crypto_cbc_decrypt_one(struct crypto_skcipher *tfm,
-                                         const u8 *src, u8 *dst)
+static int crypto_cbc_decrypt_inplace(struct skcipher_walk *walk,
+                                     struct crypto_skcipher *skcipher)
 {
-       crypto_cipher_decrypt_one(skcipher_cipher_simple(tfm), dst, src);
+       unsigned int bsize = crypto_skcipher_blocksize(skcipher);
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
+       unsigned int nbytes = walk->nbytes;
+       u8 *src = walk->src.virt.addr;
+       u8 last_iv[MAX_CIPHER_BLOCKSIZE];
+       struct crypto_cipher *cipher;
+       struct crypto_tfm *tfm;
+
+       cipher = skcipher_cipher_simple(skcipher);
+       tfm = crypto_cipher_tfm(cipher);
+       fn = crypto_cipher_alg(cipher)->cia_decrypt;
+
+       /* Start of the last block. */
+       src += nbytes - (nbytes & (bsize - 1)) - bsize;
+       memcpy(last_iv, src, bsize);
+
+       for (;;) {
+               fn(tfm, src, src);
+               if ((nbytes -= bsize) < bsize)
+                       break;
+               crypto_xor(src, src - bsize, bsize);
+               src -= bsize;
+       }
+
+       crypto_xor(src, walk->iv, bsize);
+       memcpy(walk->iv, last_iv, bsize);
+
+       return nbytes;
 }
 
 static int crypto_cbc_decrypt(struct skcipher_request *req)
 {
-       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
        struct skcipher_walk walk;
        int err;
 
        err = skcipher_walk_virt(&walk, req, false);
 
        while (walk.nbytes) {
-               err = crypto_cbc_decrypt_blocks(&walk, tfm,
-                                               crypto_cbc_decrypt_one);
+               if (walk.src.virt.addr == walk.dst.virt.addr)
+                       err = crypto_cbc_decrypt_inplace(&walk, skcipher);
+               else
+                       err = crypto_cbc_decrypt_segment(&walk, skcipher);
                err = skcipher_walk_done(&walk, err);
        }
 
index 7fa9b07..7686147 100644 (file)
@@ -15,7 +15,7 @@
  * pages =        {},
  * month =        {June},
  *}
- * Used by the iSCSI driver, possibly others, and derived from the
+ * Used by the iSCSI driver, possibly others, and derived from
  * the iscsi-crc.c module of the linux-iscsi driver at
  * http://linux-iscsi.sourceforge.net.
  *
@@ -50,7 +50,7 @@ struct chksum_desc_ctx {
 };
 
 /*
- * Steps through buffer one byte at at time, calculates reflected
+ * Steps through buffer one byte at a time, calculates reflected
  * crc using table.
  */
 
index d90c007..e843982 100644 (file)
@@ -35,7 +35,7 @@ struct chksum_desc_ctx {
 };
 
 /*
- * Steps through buffer one byte at at time, calculates reflected
+ * Steps through buffer one byte at a time, calculates reflected
  * crc using table.
  */
 
index 198a8eb..cff21f4 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/err.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <crypto/engine.h>
 #include <uapi/linux/sched/types.h>
 #include "internal.h"
@@ -465,7 +466,7 @@ EXPORT_SYMBOL_GPL(crypto_engine_stop);
  * crypto-engine queue.
  * @dev: the device attached with one hardware engine
  * @retry_support: whether hardware has support for retry mechanism
- * @cbk_do_batch: pointer to a callback function to be invoked when executing a
+ * @cbk_do_batch: pointer to a callback function to be invoked when executing
  *                a batch of requests.
  *                This has the form:
  *                callback(struct crypto_engine *engine)
index e99fe34..3132967 100644 (file)
@@ -1521,7 +1521,7 @@ static int drbg_prepare_hrng(struct drbg_state *drbg)
 
        case -EALREADY:
                err = 0;
-               /* fall through */
+               fallthrough;
 
        default:
                drbg->random_ready.func = NULL;
index 887ec21..6a3fd09 100644 (file)
@@ -22,6 +22,7 @@
 #include <crypto/internal/akcipher.h>
 #include <crypto/akcipher.h>
 #include <linux/oid_registry.h>
+#include <linux/scatterlist.h>
 #include "ecrdsa_params.asn1.h"
 #include "ecrdsa_pub_key.asn1.h"
 #include "ecc.h"
index 1b92a5a..976ec9d 100644 (file)
 
 #include <crypto/algapi.h>
 #include <linux/completion.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/notifier.h>
+#include <linux/numa.h>
+#include <linux/refcount.h>
 #include <linux/rwsem.h>
-#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
 
 struct crypto_instance;
 struct crypto_template;
@@ -140,5 +138,11 @@ static inline void crypto_notify(unsigned long val, void *v)
        blocking_notifier_call_chain(&crypto_chain, val, v);
 }
 
+static inline void crypto_yield(u32 flags)
+{
+       if (flags & CRYPTO_TFM_REQ_MAY_SLEEP)
+               cond_resched();
+}
+
 #endif /* _CRYPTO_INTERNAL_H */
 
index eb7d1dd..e8a4165 100644 (file)
  * DAMAGE.
  */
 
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/fips.h>
 #include <linux/time.h>
-#include <linux/crypto.h>
 #include <crypto/internal/rng.h>
 
 #include "jitterentropy.h"
index 08d8c2b..12fccb9 100644 (file)
@@ -36,7 +36,7 @@ static void c_stop(struct seq_file *m, void *p)
 static int c_show(struct seq_file *m, void *p)
 {
        struct crypto_alg *alg = list_entry(p, struct crypto_alg, cra_list);
-       
+
        seq_printf(m, "name         : %s\n", alg->cra_name);
        seq_printf(m, "driver       : %s\n", alg->cra_driver_name);
        seq_printf(m, "module       : %s\n", module_name(alg->cra_module));
@@ -59,7 +59,7 @@ static int c_show(struct seq_file *m, void *p)
                alg->cra_type->show(m, alg);
                goto out;
        }
-       
+
        switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
        case CRYPTO_ALG_TYPE_CIPHER:
                seq_printf(m, "type         : cipher\n");
index ddd3d10..8ac3e73 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/random.h>
+#include <linux/scatterlist.h>
 
 /*
  * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
diff --git a/crypto/sm2.c b/crypto/sm2.c
new file mode 100644 (file)
index 0000000..767e160
--- /dev/null
@@ -0,0 +1,481 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * SM2 asymmetric public-key algorithm
+ * as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012 SM2 and
+ * described at https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02
+ *
+ * Copyright (c) 2020, Alibaba Group.
+ * Authors: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
+ */
+
+#include <linux/module.h>
+#include <linux/mpi.h>
+#include <crypto/internal/akcipher.h>
+#include <crypto/akcipher.h>
+#include <crypto/hash.h>
+#include <crypto/sm3_base.h>
+#include <crypto/rng.h>
+#include <crypto/sm2.h>
+#include "sm2signature.asn1.h"
+
+#define MPI_NBYTES(m)   ((mpi_get_nbits(m) + 7) / 8)
+
+struct ecc_domain_parms {
+       const char *desc;           /* Description of the curve.  */
+       unsigned int nbits;         /* Number of bits.  */
+       unsigned int fips:1; /* True if this is a FIPS140-2 approved curve */
+
+       /* The model describing this curve.  This is mainly used to select
+        * the group equation.
+        */
+       enum gcry_mpi_ec_models model;
+
+       /* The actual ECC dialect used.  This is used for curve specific
+        * optimizations and to select encodings etc.
+        */
+       enum ecc_dialects dialect;
+
+       const char *p;              /* The prime defining the field.  */
+       const char *a, *b;          /* The coefficients.  For Twisted Edwards
+                                    * Curves b is used for d.  For Montgomery
+                                    * Curves (a,b) has ((A-2)/4,B^-1).
+                                    */
+       const char *n;              /* The order of the base point.  */
+       const char *g_x, *g_y;      /* Base point.  */
+       unsigned int h;             /* Cofactor.  */
+};
+
+static const struct ecc_domain_parms sm2_ecp = {
+       .desc = "sm2p256v1",
+       .nbits = 256,
+       .fips = 0,
+       .model = MPI_EC_WEIERSTRASS,
+       .dialect = ECC_DIALECT_STANDARD,
+       .p   = "0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff",
+       .a   = "0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc",
+       .b   = "0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93",
+       .n   = "0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123",
+       .g_x = "0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7",
+       .g_y = "0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0",
+       .h = 1
+};
+
+static int sm2_ec_ctx_init(struct mpi_ec_ctx *ec)
+{
+       const struct ecc_domain_parms *ecp = &sm2_ecp;
+       MPI p, a, b;
+       MPI x, y;
+       int rc = -EINVAL;
+
+       p = mpi_scanval(ecp->p);
+       a = mpi_scanval(ecp->a);
+       b = mpi_scanval(ecp->b);
+       if (!p || !a || !b)
+               goto free_p;
+
+       x = mpi_scanval(ecp->g_x);
+       y = mpi_scanval(ecp->g_y);
+       if (!x || !y)
+               goto free;
+
+       rc = -ENOMEM;
+       /* mpi_ec_setup_elliptic_curve */
+       ec->G = mpi_point_new(0);
+       if (!ec->G)
+               goto free;
+
+       mpi_set(ec->G->x, x);
+       mpi_set(ec->G->y, y);
+       mpi_set_ui(ec->G->z, 1);
+
+       rc = -EINVAL;
+       ec->n = mpi_scanval(ecp->n);
+       if (!ec->n) {
+               mpi_point_release(ec->G);
+               goto free;
+       }
+
+       ec->h = ecp->h;
+       ec->name = ecp->desc;
+       mpi_ec_init(ec, ecp->model, ecp->dialect, 0, p, a, b);
+
+       rc = 0;
+
+free:
+       mpi_free(x);
+       mpi_free(y);
+free_p:
+       mpi_free(p);
+       mpi_free(a);
+       mpi_free(b);
+
+       return rc;
+}
+
+static void sm2_ec_ctx_deinit(struct mpi_ec_ctx *ec)
+{
+       mpi_ec_deinit(ec);
+
+       memset(ec, 0, sizeof(*ec));
+}
+
+static int sm2_ec_ctx_reset(struct mpi_ec_ctx *ec)
+{
+       sm2_ec_ctx_deinit(ec);
+       return sm2_ec_ctx_init(ec);
+}
+
+/* RESULT must have been initialized and is set on success to the
+ * point given by VALUE.
+ */
+static int sm2_ecc_os2ec(MPI_POINT result, MPI value)
+{
+       int rc;
+       size_t n;
+       const unsigned char *buf;
+       unsigned char *buf_memory;
+       MPI x, y;
+
+       n = (mpi_get_nbits(value)+7)/8;
+       buf_memory = kmalloc(n, GFP_KERNEL);
+       rc = mpi_print(GCRYMPI_FMT_USG, buf_memory, n, &n, value);
+       if (rc) {
+               kfree(buf_memory);
+               return rc;
+       }
+       buf = buf_memory;
+
+       if (n < 1) {
+               kfree(buf_memory);
+               return -EINVAL;
+       }
+       if (*buf != 4) {
+               kfree(buf_memory);
+               return -EINVAL; /* No support for point compression.  */
+       }
+       if (((n-1)%2)) {
+               kfree(buf_memory);
+               return -EINVAL;
+       }
+       n = (n-1)/2;
+       x = mpi_read_raw_data(buf + 1, n);
+       if (!x) {
+               kfree(buf_memory);
+               return -ENOMEM;
+       }
+       y = mpi_read_raw_data(buf + 1 + n, n);
+       kfree(buf_memory);
+       if (!y) {
+               mpi_free(x);
+               return -ENOMEM;
+       }
+
+       mpi_normalize(x);
+       mpi_normalize(y);
+
+       mpi_set(result->x, x);
+       mpi_set(result->y, y);
+       mpi_set_ui(result->z, 1);
+
+       mpi_free(x);
+       mpi_free(y);
+
+       return 0;
+}
+
+struct sm2_signature_ctx {
+       MPI sig_r;
+       MPI sig_s;
+};
+
+int sm2_get_signature_r(void *context, size_t hdrlen, unsigned char tag,
+                               const void *value, size_t vlen)
+{
+       struct sm2_signature_ctx *sig = context;
+
+       if (!value || !vlen)
+               return -EINVAL;
+
+       sig->sig_r = mpi_read_raw_data(value, vlen);
+       if (!sig->sig_r)
+               return -ENOMEM;
+
+       return 0;
+}
+
+int sm2_get_signature_s(void *context, size_t hdrlen, unsigned char tag,
+                               const void *value, size_t vlen)
+{
+       struct sm2_signature_ctx *sig = context;
+
+       if (!value || !vlen)
+               return -EINVAL;
+
+       sig->sig_s = mpi_read_raw_data(value, vlen);
+       if (!sig->sig_s)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int sm2_z_digest_update(struct shash_desc *desc,
+                       MPI m, unsigned int pbytes)
+{
+       static const unsigned char zero[32];
+       unsigned char *in;
+       unsigned int inlen;
+
+       in = mpi_get_buffer(m, &inlen, NULL);
+       if (!in)
+               return -EINVAL;
+
+       if (inlen < pbytes) {
+               /* padding with zero */
+               crypto_sm3_update(desc, zero, pbytes - inlen);
+               crypto_sm3_update(desc, in, inlen);
+       } else if (inlen > pbytes) {
+               /* skip the starting zero */
+               crypto_sm3_update(desc, in + inlen - pbytes, pbytes);
+       } else {
+               crypto_sm3_update(desc, in, inlen);
+       }
+
+       kfree(in);
+       return 0;
+}
+
+static int sm2_z_digest_update_point(struct shash_desc *desc,
+               MPI_POINT point, struct mpi_ec_ctx *ec, unsigned int pbytes)
+{
+       MPI x, y;
+       int ret = -EINVAL;
+
+       x = mpi_new(0);
+       y = mpi_new(0);
+
+       if (!mpi_ec_get_affine(x, y, point, ec) &&
+               !sm2_z_digest_update(desc, x, pbytes) &&
+               !sm2_z_digest_update(desc, y, pbytes))
+               ret = 0;
+
+       mpi_free(x);
+       mpi_free(y);
+       return ret;
+}
+
+int sm2_compute_z_digest(struct crypto_akcipher *tfm,
+                       const unsigned char *id, size_t id_len,
+                       unsigned char dgst[SM3_DIGEST_SIZE])
+{
+       struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
+       uint16_t bits_len;
+       unsigned char entl[2];
+       SHASH_DESC_ON_STACK(desc, NULL);
+       unsigned int pbytes;
+
+       if (id_len > (USHRT_MAX / 8) || !ec->Q)
+               return -EINVAL;
+
+       bits_len = (uint16_t)(id_len * 8);
+       entl[0] = bits_len >> 8;
+       entl[1] = bits_len & 0xff;
+
+       pbytes = MPI_NBYTES(ec->p);
+
+       /* ZA = H256(ENTLA | IDA | a | b | xG | yG | xA | yA) */
+       sm3_base_init(desc);
+       crypto_sm3_update(desc, entl, 2);
+       crypto_sm3_update(desc, id, id_len);
+
+       if (sm2_z_digest_update(desc, ec->a, pbytes) ||
+               sm2_z_digest_update(desc, ec->b, pbytes) ||
+               sm2_z_digest_update_point(desc, ec->G, ec, pbytes) ||
+               sm2_z_digest_update_point(desc, ec->Q, ec, pbytes))
+               return -EINVAL;
+
+       crypto_sm3_final(desc, dgst);
+       return 0;
+}
+EXPORT_SYMBOL(sm2_compute_z_digest);
+
+static int _sm2_verify(struct mpi_ec_ctx *ec, MPI hash, MPI sig_r, MPI sig_s)
+{
+       int rc = -EINVAL;
+       struct gcry_mpi_point sG, tP;
+       MPI t = NULL;
+       MPI x1 = NULL, y1 = NULL;
+
+       mpi_point_init(&sG);
+       mpi_point_init(&tP);
+       x1 = mpi_new(0);
+       y1 = mpi_new(0);
+       t = mpi_new(0);
+
+       /* r, s in [1, n-1] */
+       if (mpi_cmp_ui(sig_r, 1) < 0 || mpi_cmp(sig_r, ec->n) > 0 ||
+               mpi_cmp_ui(sig_s, 1) < 0 || mpi_cmp(sig_s, ec->n) > 0) {
+               goto leave;
+       }
+
+       /* t = (r + s) % n, t == 0 */
+       mpi_addm(t, sig_r, sig_s, ec->n);
+       if (mpi_cmp_ui(t, 0) == 0)
+               goto leave;
+
+       /* sG + tP = (x1, y1) */
+       rc = -EBADMSG;
+       mpi_ec_mul_point(&sG, sig_s, ec->G, ec);
+       mpi_ec_mul_point(&tP, t, ec->Q, ec);
+       mpi_ec_add_points(&sG, &sG, &tP, ec);
+       if (mpi_ec_get_affine(x1, y1, &sG, ec))
+               goto leave;
+
+       /* R = (e + x1) % n */
+       mpi_addm(t, hash, x1, ec->n);
+
+       /* check R == r */
+       rc = -EKEYREJECTED;
+       if (mpi_cmp(t, sig_r))
+               goto leave;
+
+       rc = 0;
+
+leave:
+       mpi_point_free_parts(&sG);
+       mpi_point_free_parts(&tP);
+       mpi_free(x1);
+       mpi_free(y1);
+       mpi_free(t);
+
+       return rc;
+}
+
+static int sm2_verify(struct akcipher_request *req)
+{
+       struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+       struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
+       unsigned char *buffer;
+       struct sm2_signature_ctx sig;
+       MPI hash;
+       int ret;
+
+       if (unlikely(!ec->Q))
+               return -EINVAL;
+
+       buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       sg_pcopy_to_buffer(req->src,
+               sg_nents_for_len(req->src, req->src_len + req->dst_len),
+               buffer, req->src_len + req->dst_len, 0);
+
+       sig.sig_r = NULL;
+       sig.sig_s = NULL;
+       ret = asn1_ber_decoder(&sm2signature_decoder, &sig,
+                               buffer, req->src_len);
+       if (ret)
+               goto error;
+
+       ret = -ENOMEM;
+       hash = mpi_read_raw_data(buffer + req->src_len, req->dst_len);
+       if (!hash)
+               goto error;
+
+       ret = _sm2_verify(ec, hash, sig.sig_r, sig.sig_s);
+
+       mpi_free(hash);
+error:
+       mpi_free(sig.sig_r);
+       mpi_free(sig.sig_s);
+       kfree(buffer);
+       return ret;
+}
+
+static int sm2_set_pub_key(struct crypto_akcipher *tfm,
+                       const void *key, unsigned int keylen)
+{
+       struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
+       MPI a;
+       int rc;
+
+       rc = sm2_ec_ctx_reset(ec);
+       if (rc)
+               return rc;
+
+       ec->Q = mpi_point_new(0);
+       if (!ec->Q)
+               return -ENOMEM;
+
+       /* include the uncompressed flag '0x04' */
+       rc = -ENOMEM;
+       a = mpi_read_raw_data(key, keylen);
+       if (!a)
+               goto error;
+
+       mpi_normalize(a);
+       rc = sm2_ecc_os2ec(ec->Q, a);
+       mpi_free(a);
+       if (rc)
+               goto error;
+
+       return 0;
+
+error:
+       mpi_point_release(ec->Q);
+       ec->Q = NULL;
+       return rc;
+}
+
+static unsigned int sm2_max_size(struct crypto_akcipher *tfm)
+{
+       /* Unlimited max size */
+       return PAGE_SIZE;
+}
+
+static int sm2_init_tfm(struct crypto_akcipher *tfm)
+{
+       struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
+
+       return sm2_ec_ctx_init(ec);
+}
+
+static void sm2_exit_tfm(struct crypto_akcipher *tfm)
+{
+       struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);
+
+       sm2_ec_ctx_deinit(ec);
+}
+
+static struct akcipher_alg sm2 = {
+       .verify = sm2_verify,
+       .set_pub_key = sm2_set_pub_key,
+       .max_size = sm2_max_size,
+       .init = sm2_init_tfm,
+       .exit = sm2_exit_tfm,
+       .base = {
+               .cra_name = "sm2",
+               .cra_driver_name = "sm2-generic",
+               .cra_priority = 100,
+               .cra_module = THIS_MODULE,
+               .cra_ctxsize = sizeof(struct mpi_ec_ctx),
+       },
+};
+
+static int sm2_init(void)
+{
+       return crypto_register_akcipher(&sm2);
+}
+
+static void sm2_exit(void)
+{
+       crypto_unregister_akcipher(&sm2);
+}
+
+subsys_initcall(sm2_init);
+module_exit(sm2_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tianjia Zhang <tianjia.zhang@linux.alibaba.com>");
+MODULE_DESCRIPTION("SM2 generic algorithm");
+MODULE_ALIAS_CRYPTO("sm2-generic");
diff --git a/crypto/sm2signature.asn1 b/crypto/sm2signature.asn1
new file mode 100644 (file)
index 0000000..ab8c0b7
--- /dev/null
@@ -0,0 +1,4 @@
+Sm2Signature ::= SEQUENCE {
+       sig_r   INTEGER ({ sm2_get_signature_r }),
+       sig_s   INTEGER ({ sm2_get_signature_s })
+}
index 3468975..193c458 100644 (file)
@@ -149,17 +149,18 @@ int crypto_sm3_update(struct shash_desc *desc, const u8 *data,
 }
 EXPORT_SYMBOL(crypto_sm3_update);
 
-static int sm3_final(struct shash_desc *desc, u8 *out)
+int crypto_sm3_final(struct shash_desc *desc, u8 *out)
 {
        sm3_base_do_finalize(desc, sm3_generic_block_fn);
        return sm3_base_finish(desc, out);
 }
+EXPORT_SYMBOL(crypto_sm3_final);
 
 int crypto_sm3_finup(struct shash_desc *desc, const u8 *data,
                        unsigned int len, u8 *hash)
 {
        sm3_base_do_update(desc, data, len, sm3_generic_block_fn);
-       return sm3_final(desc, hash);
+       return crypto_sm3_final(desc, hash);
 }
 EXPORT_SYMBOL(crypto_sm3_finup);
 
@@ -167,7 +168,7 @@ static struct shash_alg sm3_alg = {
        .digestsize     =       SM3_DIGEST_SIZE,
        .init           =       sm3_base_init,
        .update         =       crypto_sm3_update,
-       .final          =       sm3_final,
+       .final          =       crypto_sm3_final,
        .finup          =       crypto_sm3_finup,
        .descsize       =       sizeof(struct sm3_state),
        .base           =       {
index ba0b770..eea0f45 100644 (file)
@@ -63,6 +63,7 @@ static u32 type;
 static u32 mask;
 static int mode;
 static u32 num_mb = 8;
+static unsigned int klen;
 static char *tvmem[TVMEMSIZE];
 
 static const char *check[] = {
@@ -398,7 +399,7 @@ static void test_mb_aead_speed(const char *algo, int enc, int secs,
                                        ret = do_one_aead_op(cur->req, ret);
 
                                        if (ret) {
-                                               pr_err("calculating auth failed failed (%d)\n",
+                                               pr_err("calculating auth failed (%d)\n",
                                                       ret);
                                                break;
                                        }
@@ -648,7 +649,7 @@ static void test_aead_speed(const char *algo, int enc, unsigned int secs,
                                                     crypto_aead_encrypt(req));
 
                                if (ret) {
-                                       pr_err("calculating auth failed failed (%d)\n",
+                                       pr_err("calculating auth failed (%d)\n",
                                               ret);
                                        break;
                                }
@@ -864,8 +865,8 @@ static void test_mb_ahash_speed(const char *algo, unsigned int secs,
                        goto out;
                }
 
-               if (speed[i].klen)
-                       crypto_ahash_setkey(tfm, tvmem[0], speed[i].klen);
+               if (klen)
+                       crypto_ahash_setkey(tfm, tvmem[0], klen);
 
                for (k = 0; k < num_mb; k++)
                        ahash_request_set_crypt(data[k].req, data[k].sg,
@@ -1099,8 +1100,8 @@ static void test_ahash_speed_common(const char *algo, unsigned int secs,
                        break;
                }
 
-               if (speed[i].klen)
-                       crypto_ahash_setkey(tfm, tvmem[0], speed[i].klen);
+               if (klen)
+                       crypto_ahash_setkey(tfm, tvmem[0], klen);
 
                pr_info("test%3u "
                        "(%5u byte blocks,%5u bytes per update,%4u updates): ",
@@ -2348,121 +2349,122 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                        test_hash_speed(alg, sec, generic_hash_speed_template);
                        break;
                }
-               /* fall through */
+               fallthrough;
        case 301:
                test_hash_speed("md4", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 302:
                test_hash_speed("md5", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 303:
                test_hash_speed("sha1", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 304:
                test_hash_speed("sha256", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 305:
                test_hash_speed("sha384", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 306:
                test_hash_speed("sha512", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 307:
                test_hash_speed("wp256", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 308:
                test_hash_speed("wp384", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 309:
                test_hash_speed("wp512", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 310:
                test_hash_speed("tgr128", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 311:
                test_hash_speed("tgr160", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 312:
                test_hash_speed("tgr192", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 313:
                test_hash_speed("sha224", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 314:
                test_hash_speed("rmd128", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 315:
                test_hash_speed("rmd160", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 316:
                test_hash_speed("rmd256", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 317:
                test_hash_speed("rmd320", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 318:
-               test_hash_speed("ghash-generic", sec, hash_speed_template_16);
+               klen = 16;
+               test_hash_speed("ghash", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 319:
                test_hash_speed("crc32c", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 320:
                test_hash_speed("crct10dif", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 321:
                test_hash_speed("poly1305", sec, poly1305_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 322:
                test_hash_speed("sha3-224", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 323:
                test_hash_speed("sha3-256", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 324:
                test_hash_speed("sha3-384", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 325:
                test_hash_speed("sha3-512", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 326:
                test_hash_speed("sm3", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 327:
                test_hash_speed("streebog256", sec,
                                generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 328:
                test_hash_speed("streebog512", sec,
                                generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
-               /* fall through */
+               fallthrough;
        case 399:
                break;
 
@@ -2471,121 +2473,121 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                        test_ahash_speed(alg, sec, generic_hash_speed_template);
                        break;
                }
-               /* fall through */
+               fallthrough;
        case 401:
                test_ahash_speed("md4", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 402:
                test_ahash_speed("md5", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 403:
                test_ahash_speed("sha1", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 404:
                test_ahash_speed("sha256", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 405:
                test_ahash_speed("sha384", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 406:
                test_ahash_speed("sha512", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 407:
                test_ahash_speed("wp256", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 408:
                test_ahash_speed("wp384", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 409:
                test_ahash_speed("wp512", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 410:
                test_ahash_speed("tgr128", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 411:
                test_ahash_speed("tgr160", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 412:
                test_ahash_speed("tgr192", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 413:
                test_ahash_speed("sha224", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 414:
                test_ahash_speed("rmd128", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 415:
                test_ahash_speed("rmd160", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 416:
                test_ahash_speed("rmd256", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 417:
                test_ahash_speed("rmd320", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 418:
                test_ahash_speed("sha3-224", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 419:
                test_ahash_speed("sha3-256", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 420:
                test_ahash_speed("sha3-384", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 421:
                test_ahash_speed("sha3-512", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 422:
                test_mb_ahash_speed("sha1", sec, generic_hash_speed_template,
                                    num_mb);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 423:
                test_mb_ahash_speed("sha256", sec, generic_hash_speed_template,
                                    num_mb);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 424:
                test_mb_ahash_speed("sha512", sec, generic_hash_speed_template,
                                    num_mb);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 425:
                test_mb_ahash_speed("sm3", sec, generic_hash_speed_template,
                                    num_mb);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 426:
                test_mb_ahash_speed("streebog256", sec,
                                    generic_hash_speed_template, num_mb);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 427:
                test_mb_ahash_speed("streebog512", sec,
                                    generic_hash_speed_template, num_mb);
                if (mode > 400 && mode < 500) break;
-               /* fall through */
+               fallthrough;
        case 499:
                break;
 
@@ -3076,6 +3078,8 @@ MODULE_PARM_DESC(sec, "Length in seconds of speed tests "
                      "(defaults to zero which uses CPU cycles instead)");
 module_param(num_mb, uint, 0000);
 MODULE_PARM_DESC(num_mb, "Number of concurrent requests to be used in mb speed tests (defaults to 8)");
+module_param(klen, uint, 0);
+MODULE_PARM_DESC(klen, "Key length (defaults to 0)");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Quick & dirty crypto testing module");
index 7e5fea8..9f65467 100644 (file)
@@ -25,7 +25,6 @@ struct aead_speed_template {
 struct hash_speed {
        unsigned int blen;      /* buffer length */
        unsigned int plen;      /* per-update length */
-       unsigned int klen;      /* key length */
 };
 
 /*
@@ -97,34 +96,6 @@ static struct hash_speed generic_hash_speed_template[] = {
        {  .blen = 0,   .plen = 0, }
 };
 
-static struct hash_speed hash_speed_template_16[] = {
-       { .blen = 16,   .plen = 16,     .klen = 16, },
-       { .blen = 64,   .plen = 16,     .klen = 16, },
-       { .blen = 64,   .plen = 64,     .klen = 16, },
-       { .blen = 256,  .plen = 16,     .klen = 16, },
-       { .blen = 256,  .plen = 64,     .klen = 16, },
-       { .blen = 256,  .plen = 256,    .klen = 16, },
-       { .blen = 1024, .plen = 16,     .klen = 16, },
-       { .blen = 1024, .plen = 256,    .klen = 16, },
-       { .blen = 1024, .plen = 1024,   .klen = 16, },
-       { .blen = 2048, .plen = 16,     .klen = 16, },
-       { .blen = 2048, .plen = 256,    .klen = 16, },
-       { .blen = 2048, .plen = 1024,   .klen = 16, },
-       { .blen = 2048, .plen = 2048,   .klen = 16, },
-       { .blen = 4096, .plen = 16,     .klen = 16, },
-       { .blen = 4096, .plen = 256,    .klen = 16, },
-       { .blen = 4096, .plen = 1024,   .klen = 16, },
-       { .blen = 4096, .plen = 4096,   .klen = 16, },
-       { .blen = 8192, .plen = 16,     .klen = 16, },
-       { .blen = 8192, .plen = 256,    .klen = 16, },
-       { .blen = 8192, .plen = 1024,   .klen = 16, },
-       { .blen = 8192, .plen = 4096,   .klen = 16, },
-       { .blen = 8192, .plen = 8192,   .klen = 16, },
-
-       /* End marker */
-       {  .blen = 0,   .plen = 0,      .klen = 0, }
-};
-
 static struct hash_speed poly1305_speed_template[] = {
        { .blen = 96,   .plen = 16, },
        { .blen = 96,   .plen = 32, },
index 23c27fc..a64a639 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/uio.h>
 #include <crypto/rng.h>
 #include <crypto/drbg.h>
 #include <crypto/akcipher.h>
@@ -3954,7 +3955,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
        key = kmalloc(vecs->key_len + sizeof(u32) * 2 + vecs->param_len,
                      GFP_KERNEL);
        if (!key)
-               goto free_xbuf;
+               goto free_req;
        memcpy(key, vecs->key, vecs->key_len);
        ptr = key + vecs->key_len;
        ptr = test_pack_u32(ptr, vecs->algo);
@@ -3966,7 +3967,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
        else
                err = crypto_akcipher_set_priv_key(tfm, key, vecs->key_len);
        if (err)
-               goto free_req;
+               goto free_key;
 
        /*
         * First run test which do not require a private key, such as
@@ -3976,7 +3977,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
        out_len_max = crypto_akcipher_maxsize(tfm);
        outbuf_enc = kzalloc(out_len_max, GFP_KERNEL);
        if (!outbuf_enc)
-               goto free_req;
+               goto free_key;
 
        if (!vecs->siggen_sigver_test) {
                m = vecs->m;
@@ -3995,6 +3996,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
                op = "verify";
        }
 
+       err = -E2BIG;
        if (WARN_ON(m_size > PAGE_SIZE))
                goto free_all;
        memcpy(xbuf[0], m, m_size);
@@ -4025,7 +4027,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
                pr_err("alg: akcipher: %s test failed. err %d\n", op, err);
                goto free_all;
        }
-       if (!vecs->siggen_sigver_test) {
+       if (!vecs->siggen_sigver_test && c) {
                if (req->dst_len != c_size) {
                        pr_err("alg: akcipher: %s test failed. Invalid output len\n",
                               op);
@@ -4056,6 +4058,12 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
                goto free_all;
        }
 
+       if (!vecs->siggen_sigver_test && !c) {
+               c = outbuf_enc;
+               c_size = req->dst_len;
+       }
+
+       err = -E2BIG;
        op = vecs->siggen_sigver_test ? "sign" : "decrypt";
        if (WARN_ON(c_size > PAGE_SIZE))
                goto free_all;
@@ -4092,9 +4100,10 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
 free_all:
        kfree(outbuf_dec);
        kfree(outbuf_enc);
+free_key:
+       kfree(key);
 free_req:
        akcipher_request_free(req);
-       kfree(key);
 free_xbuf:
        testmgr_free_buf(xbuf);
        return err;
@@ -5377,6 +5386,12 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .hash = __VECS(sha512_tv_template)
                }
        }, {
+               .alg = "sm2",
+               .test = alg_test_akcipher,
+               .suite = {
+                       .akcipher = __VECS(sm2_tv_template)
+               }
+       }, {
                .alg = "sm3",
                .test = alg_test_hash,
                .suite = {
index b9a2d73..8c83811 100644 (file)
@@ -3792,6 +3792,65 @@ static const struct hash_testvec hmac_streebog512_tv_template[] = {
        },
 };
 
+/*
+ * SM2 test vectors.
+ */
+static const struct akcipher_testvec sm2_tv_template[] = {
+       { /* Generated from openssl */
+       .key =
+       "\x04"
+       "\x8e\xa0\x33\x69\x91\x7e\x3d\xec\xad\x8e\xf0\x45\x5e\x13\x3e\x68"
+       "\x5b\x8c\xab\x5c\xc6\xc8\x50\xdf\x91\x00\xe0\x24\x73\x4d\x31\xf2"
+       "\x2e\xc0\xd5\x6b\xee\xda\x98\x93\xec\xd8\x36\xaa\xb9\xcf\x63\x82"
+       "\xef\xa7\x1a\x03\xed\x16\xba\x74\xb8\x8b\xf9\xe5\x70\x39\xa4\x70",
+       .key_len = 65,
+       .param_len = 0,
+       .c =
+       "\x30\x45"
+       "\x02\x20"
+       "\x70\xab\xb6\x7d\xd6\x54\x80\x64\x42\x7e\x2d\x05\x08\x36\xc9\x96"
+       "\x25\xc2\xbb\xff\x08\xe5\x43\x15\x5e\xf3\x06\xd9\x2b\x2f\x0a\x9f"
+       "\x02\x21"
+       "\x00"
+       "\xbf\x21\x5f\x7e\x5d\x3f\x1a\x4d\x8f\x84\xc2\xe9\xa6\x4c\xa4\x18"
+       "\xb2\xb8\x46\xf4\x32\x96\xfa\x57\xc6\x29\xd4\x89\xae\xcc\xda\xdb",
+       .c_size = 71,
+       .algo = OID_SM2_with_SM3,
+       .m =
+       "\x47\xa7\xbf\xd3\xda\xc4\x79\xee\xda\x8b\x4f\xe8\x40\x94\xd4\x32"
+       "\x8f\xf1\xcd\x68\x4d\xbd\x9b\x1d\xe0\xd8\x9a\x5d\xad\x85\x47\x5c",
+       .m_size = 32,
+       .public_key_vec = true,
+       .siggen_sigver_test = true,
+       },
+       { /* From libgcrypt */
+       .key =
+       "\x04"
+       "\x87\x59\x38\x9a\x34\xaa\xad\x07\xec\xf4\xe0\xc8\xc2\x65\x0a\x44"
+       "\x59\xc8\xd9\x26\xee\x23\x78\x32\x4e\x02\x61\xc5\x25\x38\xcb\x47"
+       "\x75\x28\x10\x6b\x1e\x0b\x7c\x8d\xd5\xff\x29\xa9\xc8\x6a\x89\x06"
+       "\x56\x56\xeb\x33\x15\x4b\xc0\x55\x60\x91\xef\x8a\xc9\xd1\x7d\x78",
+       .key_len = 65,
+       .param_len = 0,
+       .c =
+       "\x30\x44"
+       "\x02\x20"
+       "\xd9\xec\xef\xe8\x5f\xee\x3c\x59\x57\x8e\x5b\xab\xb3\x02\xe1\x42"
+       "\x4b\x67\x2c\x0b\x26\xb6\x51\x2c\x3e\xfc\xc6\x49\xec\xfe\x89\xe5"
+       "\x02\x20"
+       "\x43\x45\xd0\xa5\xff\xe5\x13\x27\x26\xd0\xec\x37\xad\x24\x1e\x9a"
+       "\x71\x9a\xa4\x89\xb0\x7e\x0f\xc4\xbb\x2d\x50\xd0\xe5\x7f\x7a\x68",
+       .c_size = 70,
+       .algo = OID_SM2_with_SM3,
+       .m =
+       "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x00"
+       "\x12\x34\x56\x78\x9a\xbc\xde\xf0\x12\x34\x56\x78\x9a\xbc\xde\xf0",
+       .m_size = 32,
+       .public_key_vec = true,
+       .siggen_sigver_test = true,
+       },
+};
+
 /* Example vectors below taken from
  * http://www.oscca.gov.cn/UpFile/20101222141857786.pdf
  *
index ea7349e..eacbf4f 100644 (file)
@@ -54,49 +54,63 @@ EXPORT_SYMBOL(xor_blocks);
 /* Set of all registered templates.  */
 static struct xor_block_template *__initdata template_list;
 
-#define BENCH_SIZE (PAGE_SIZE)
+#ifndef MODULE
+static void __init do_xor_register(struct xor_block_template *tmpl)
+{
+       tmpl->next = template_list;
+       template_list = tmpl;
+}
+
+static int __init register_xor_blocks(void)
+{
+       active_template = XOR_SELECT_TEMPLATE(NULL);
+
+       if (!active_template) {
+#define xor_speed      do_xor_register
+               // register all the templates and pick the first as the default
+               XOR_TRY_TEMPLATES;
+#undef xor_speed
+               active_template = template_list;
+       }
+       return 0;
+}
+#endif
+
+#define BENCH_SIZE     4096
+#define REPS           800U
 
 static void __init
 do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
 {
        int speed;
-       unsigned long now, j;
-       int i, count, max;
+       int i, j;
+       ktime_t min, start, diff;
 
        tmpl->next = template_list;
        template_list = tmpl;
 
        preempt_disable();
 
-       /*
-        * Count the number of XORs done during a whole jiffy, and use
-        * this to calculate the speed of checksumming.  We use a 2-page
-        * allocation to have guaranteed color L1-cache layout.
-        */
-       max = 0;
-       for (i = 0; i < 5; i++) {
-               j = jiffies;
-               count = 0;
-               while ((now = jiffies) == j)
-                       cpu_relax();
-               while (time_before(jiffies, now + 1)) {
+       min = (ktime_t)S64_MAX;
+       for (i = 0; i < 3; i++) {
+               start = ktime_get();
+               for (j = 0; j < REPS; j++) {
                        mb(); /* prevent loop optimzation */
                        tmpl->do_2(BENCH_SIZE, b1, b2);
                        mb();
-                       count++;
-                       mb();
                }
-               if (count > max)
-                       max = count;
+               diff = ktime_sub(ktime_get(), start);
+               if (diff < min)
+                       min = diff;
        }
 
        preempt_enable();
 
-       speed = max * (HZ * BENCH_SIZE / 1024);
+       // bytes/ns == GB/s, multiply by 1000 to get MB/s [not MiB/s]
+       speed = (1000 * REPS * BENCH_SIZE) / (unsigned int)ktime_to_ns(min);
        tmpl->speed = speed;
 
-       printk(KERN_INFO "   %-10s: %5d.%03d MB/sec\n", tmpl->name,
-              speed / 1000, speed % 1000);
+       pr_info("   %-16s: %5d MB/sec\n", tmpl->name, speed);
 }
 
 static int __init
@@ -129,14 +143,15 @@ calibrate_xor_blocks(void)
 #define xor_speed(templ)       do_xor_speed((templ), b1, b2)
 
        printk(KERN_INFO "xor: measuring software checksum speed\n");
+       template_list = NULL;
        XOR_TRY_TEMPLATES;
        fastest = template_list;
        for (f = fastest; f; f = f->next)
                if (f->speed > fastest->speed)
                        fastest = f;
 
-       printk(KERN_INFO "xor: using function: %s (%d.%03d MB/sec)\n",
-              fastest->name, fastest->speed / 1000, fastest->speed % 1000);
+       pr_info("xor: using function: %s (%d MB/sec)\n",
+              fastest->name, fastest->speed);
 
 #undef xor_speed
 
@@ -150,6 +165,10 @@ static __exit void xor_exit(void) { }
 
 MODULE_LICENSE("GPL");
 
+#ifndef MODULE
 /* when built-in xor.o must initialize before drivers/md/md.o */
-core_initcall(calibrate_xor_blocks);
+core_initcall(register_xor_blocks);
+#endif
+
+module_init(calibrate_xor_blocks);
 module_exit(xor_exit);
index c2b452a..9861302 100644 (file)
@@ -290,7 +290,7 @@ static int vt_notifier_call(struct notifier_block *blk,
                        break;
                case '\t':
                        c = ' ';
-                       /* Fallthrough */
+                       fallthrough;
                default:
                        if (c < 32)
                                /* Ignore other control sequences */
index 0803c20..07ecbbd 100644 (file)
@@ -42,6 +42,11 @@ config SPEAKUP
                one of the listed synthesizers, you should say n.
 
 if SPEAKUP
+
+config SPEAKUP_SERIALIO
+       def_bool y
+       depends on ISA || COMPILE_TEST
+
 config SPEAKUP_SYNTH_ACNTSA
        tristate "Accent SA synthesizer support"
        help
@@ -52,7 +57,7 @@ config SPEAKUP_SYNTH_ACNTSA
 
 config SPEAKUP_SYNTH_ACNTPC
        tristate "Accent PC synthesizer support"
-       depends on ISA || COMPILE_TEST
+       depends on SPEAKUP_SERIALIO
        help
                This is the Speakup driver for the accent pc
                synthesizer.  You can say y to build it into the kernel,
@@ -104,7 +109,7 @@ config SPEAKUP_SYNTH_DECEXT
 
 config SPEAKUP_SYNTH_DECPC
        depends on m
-       depends on ISA || COMPILE_TEST
+       depends on SPEAKUP_SERIALIO
        tristate "DECtalk PC (big ISA card) synthesizer support"
        help
 
@@ -127,7 +132,7 @@ config SPEAKUP_SYNTH_DECPC
 
 config SPEAKUP_SYNTH_DTLK
        tristate "DoubleTalk PC synthesizer support"
-       depends on ISA || COMPILE_TEST
+       depends on SPEAKUP_SERIALIO
        help
 
                This is the Speakup driver for the internal DoubleTalk
@@ -138,7 +143,7 @@ config SPEAKUP_SYNTH_DTLK
 
 config SPEAKUP_SYNTH_KEYPC
        tristate "Keynote Gold PC synthesizer support"
-       depends on ISA || COMPILE_TEST
+       depends on SPEAKUP_SERIALIO
        help
 
                This is the Speakup driver for the Keynote Gold
index 5befb49..6e4bfac 100644 (file)
@@ -25,8 +25,8 @@ speakup-y := \
        keyhelp.o \
        kobjects.o \
        selection.o \
-       serialio.o \
        spk_ttyio.o \
        synth.o \
        thread.o \
        varhandlers.o
+speakup-$(CONFIG_SPEAKUP_SERIALIO) += serialio.o
index 177a298..403b01d 100644 (file)
@@ -32,6 +32,7 @@ static void spk_serial_tiocmset(unsigned int set, unsigned int clear);
 static unsigned char spk_serial_in(void);
 static unsigned char spk_serial_in_nowait(void);
 static void spk_serial_flush_buffer(void);
+static int spk_serial_wait_for_xmitr(struct spk_synth *in_synth);
 
 struct spk_io_ops spk_serial_io_ops = {
        .synth_out = spk_serial_out,
@@ -40,6 +41,7 @@ struct spk_io_ops spk_serial_io_ops = {
        .synth_in = spk_serial_in,
        .synth_in_nowait = spk_serial_in_nowait,
        .flush_buffer = spk_serial_flush_buffer,
+       .wait_for_xmitr = spk_serial_wait_for_xmitr,
 };
 EXPORT_SYMBOL_GPL(spk_serial_io_ops);
 
@@ -211,7 +213,7 @@ void spk_stop_serial_interrupt(void)
 }
 EXPORT_SYMBOL_GPL(spk_stop_serial_interrupt);
 
-int spk_wait_for_xmitr(struct spk_synth *in_synth)
+static int spk_serial_wait_for_xmitr(struct spk_synth *in_synth)
 {
        int tmout = SPK_XMITR_TIMEOUT;
 
@@ -280,7 +282,7 @@ static void spk_serial_flush_buffer(void)
 
 static int spk_serial_out(struct spk_synth *in_synth, const char ch)
 {
-       if (in_synth->alive && spk_wait_for_xmitr(in_synth)) {
+       if (in_synth->alive && spk_serial_wait_for_xmitr(in_synth)) {
                outb_p(ch, speakup_info.port_tts);
                return 1;
        }
@@ -295,7 +297,7 @@ const char *spk_serial_synth_immediate(struct spk_synth *synth,
        while ((ch = *buff)) {
                if (ch == '\n')
                        ch = synth->procspeech;
-               if (spk_wait_for_xmitr(synth))
+               if (spk_serial_wait_for_xmitr(synth))
                        outb(ch, speakup_info.port_tts);
                else
                        return buff;
index c75b408..0f4bcbe 100644 (file)
@@ -34,7 +34,6 @@
 
 const struct old_serial_port *spk_serial_init(int index);
 void spk_stop_serial_interrupt(void);
-int spk_wait_for_xmitr(struct spk_synth *in_synth);
 void spk_serial_release(void);
 void spk_ttyio_release(void);
 void spk_ttyio_register_ldisc(void);
index 9b95f77..a831ff6 100644 (file)
@@ -116,6 +116,7 @@ static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear);
 static unsigned char spk_ttyio_in(void);
 static unsigned char spk_ttyio_in_nowait(void);
 static void spk_ttyio_flush_buffer(void);
+static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth);
 
 struct spk_io_ops spk_ttyio_ops = {
        .synth_out = spk_ttyio_out,
@@ -125,6 +126,7 @@ struct spk_io_ops spk_ttyio_ops = {
        .synth_in = spk_ttyio_in,
        .synth_in_nowait = spk_ttyio_in_nowait,
        .flush_buffer = spk_ttyio_flush_buffer,
+       .wait_for_xmitr = spk_ttyio_wait_for_xmitr,
 };
 EXPORT_SYMBOL_GPL(spk_ttyio_ops);
 
@@ -286,6 +288,11 @@ static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear)
        mutex_unlock(&speakup_tty_mutex);
 }
 
+static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth)
+{
+       return 1;
+}
+
 static unsigned char ttyio_in(int timeout)
 {
        struct spk_ldisc_data *ldisc_data = speakup_tty->disc_data;
index d3272c6..7398f11 100644 (file)
@@ -158,6 +158,7 @@ struct spk_io_ops {
        unsigned char (*synth_in)(void);
        unsigned char (*synth_in_nowait)(void);
        void (*flush_buffer)(void);
+       int (*wait_for_xmitr)(struct spk_synth *synth);
 };
 
 struct spk_synth {
index 3568bfb..ac47dba 100644 (file)
@@ -159,7 +159,7 @@ int spk_synth_is_alive_restart(struct spk_synth *synth)
 {
        if (synth->alive)
                return 1;
-       if (spk_wait_for_xmitr(synth) > 0) {
+       if (synth->io_ops->wait_for_xmitr(synth) > 0) {
                /* restart */
                synth->alive = 1;
                synth_printf("%s", synth->init);
index 4c34837..806b8ce 100644 (file)
@@ -99,8 +99,8 @@ static int fch_misc_setup(struct apd_private_data *pdata)
        if (ret < 0)
                return -ENOENT;
 
-       acpi_dev_get_property(adev, "is-rv", ACPI_TYPE_INTEGER, &obj);
-       clk_data->is_rv = obj->integer.value;
+       if (!acpi_dev_get_property(adev, "is-rv", ACPI_TYPE_INTEGER, &obj))
+               clk_data->is_rv = obj->integer.value;
 
        list_for_each_entry(rentry, &resource_list, node) {
                clk_data->base = devm_ioremap(&adev->dev, rentry->res->start,
index ec782e4..e670785 100644 (file)
@@ -811,8 +811,7 @@ static inline const struct iommu_ops *iort_fwspec_iommu_ops(struct device *dev)
        return (fwspec && fwspec->ops) ? fwspec->ops : NULL;
 }
 
-static inline int iort_add_device_replay(const struct iommu_ops *ops,
-                                        struct device *dev)
+static inline int iort_add_device_replay(struct device *dev)
 {
        int err = 0;
 
@@ -1072,7 +1071,7 @@ const struct iommu_ops *iort_iommu_configure_id(struct device *dev,
         */
        if (!err) {
                ops = iort_fwspec_iommu_ops(dev);
-               err = iort_add_device_replay(ops, dev);
+               err = iort_add_device_replay(dev);
        }
 
        /* Ignore all other errors apart from EPROBE_DEFER */
@@ -1087,11 +1086,6 @@ const struct iommu_ops *iort_iommu_configure_id(struct device *dev,
 }
 
 #else
-static inline const struct iommu_ops *iort_fwspec_iommu_ops(struct device *dev)
-{ return NULL; }
-static inline int iort_add_device_replay(const struct iommu_ops *ops,
-                                        struct device *dev)
-{ return 0; }
 int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
 { return 0; }
 const struct iommu_ops *iort_iommu_configure_id(struct device *dev,
index 6ad8cb0..4a0b077 100644 (file)
@@ -350,7 +350,7 @@ void __iomem __ref
 
        pg_off = round_down(phys, PAGE_SIZE);
        pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
-       virt = acpi_map(pg_off, pg_sz);
+       virt = acpi_map(phys, size);
        if (!virt) {
                mutex_unlock(&acpi_ioremap_lock);
                kfree(map);
@@ -358,7 +358,7 @@ void __iomem __ref
        }
 
        INIT_LIST_HEAD(&map->list);
-       map->virt = virt;
+       map->virt = (void __iomem __force *)((unsigned long)virt & PAGE_MASK);
        map->phys = pg_off;
        map->size = pg_sz;
        map->track.refcount = 1;
@@ -1575,11 +1575,26 @@ static acpi_status acpi_deactivate_mem_region(acpi_handle handle, u32 level,
 acpi_status acpi_release_memory(acpi_handle handle, struct resource *res,
                                u32 level)
 {
+       acpi_status status;
+
        if (!(res->flags & IORESOURCE_MEM))
                return AE_TYPE;
 
-       return acpi_walk_namespace(ACPI_TYPE_REGION, handle, level,
-                                  acpi_deactivate_mem_region, NULL, res, NULL);
+       status = acpi_walk_namespace(ACPI_TYPE_REGION, handle, level,
+                                    acpi_deactivate_mem_region, NULL,
+                                    res, NULL);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       /*
+        * Wait for all of the mappings queued up for removal by
+        * acpi_deactivate_mem_region() to actually go away.
+        */
+       synchronize_rcu();
+       rcu_barrier();
+       flush_scheduled_work();
+
+       return AE_OK;
 }
 EXPORT_SYMBOL_GPL(acpi_release_memory);
 
index 71a30b0..f66236c 100644 (file)
@@ -161,18 +161,10 @@ static void lapic_timer_propagate_broadcast(struct acpi_processor *pr)
 }
 
 /* Power(C) State timer broadcast control */
-static void lapic_timer_state_broadcast(struct acpi_processor *pr,
-                                      struct acpi_processor_cx *cx,
-                                      int broadcast)
+static bool lapic_timer_needs_broadcast(struct acpi_processor *pr,
+                                       struct acpi_processor_cx *cx)
 {
-       int state = cx - pr->power.states;
-
-       if (state >= pr->power.timer_broadcast_on_state) {
-               if (broadcast)
-                       tick_broadcast_enter();
-               else
-                       tick_broadcast_exit();
-       }
+       return cx - pr->power.states >= pr->power.timer_broadcast_on_state;
 }
 
 #else
@@ -180,10 +172,11 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
 static void lapic_timer_check_state(int state, struct acpi_processor *pr,
                                   struct acpi_processor_cx *cstate) { }
 static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) { }
-static void lapic_timer_state_broadcast(struct acpi_processor *pr,
-                                      struct acpi_processor_cx *cx,
-                                      int broadcast)
+
+static bool lapic_timer_needs_broadcast(struct acpi_processor *pr,
+                                       struct acpi_processor_cx *cx)
 {
+       return false;
 }
 
 #endif
@@ -566,32 +559,43 @@ static DEFINE_RAW_SPINLOCK(c3_lock);
 
 /**
  * acpi_idle_enter_bm - enters C3 with proper BM handling
+ * @drv: cpuidle driver
  * @pr: Target processor
  * @cx: Target state context
- * @timer_bc: Whether or not to change timer mode to broadcast
+ * @index: index of target state
  */
-static void acpi_idle_enter_bm(struct acpi_processor *pr,
-                              struct acpi_processor_cx *cx, bool timer_bc)
+static int acpi_idle_enter_bm(struct cpuidle_driver *drv,
+                              struct acpi_processor *pr,
+                              struct acpi_processor_cx *cx,
+                              int index)
 {
-       acpi_unlazy_tlb(smp_processor_id());
-
-       /*
-        * Must be done before busmaster disable as we might need to
-        * access HPET !
-        */
-       if (timer_bc)
-               lapic_timer_state_broadcast(pr, cx, 1);
+       static struct acpi_processor_cx safe_cx = {
+               .entry_method = ACPI_CSTATE_HALT,
+       };
 
        /*
         * disable bus master
         * bm_check implies we need ARB_DIS
         * bm_control implies whether we can do ARB_DIS
         *
-        * That leaves a case where bm_check is set and bm_control is
-        * not set. In that case we cannot do much, we enter C3
-        * without doing anything.
+        * That leaves a case where bm_check is set and bm_control is not set.
+        * In that case we cannot do much, we enter C3 without doing anything.
         */
-       if (pr->flags.bm_control) {
+       bool dis_bm = pr->flags.bm_control;
+
+       /* If we can skip BM, demote to a safe state. */
+       if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
+               dis_bm = false;
+               index = drv->safe_state_index;
+               if (index >= 0) {
+                       cx = this_cpu_read(acpi_cstate[index]);
+               } else {
+                       cx = &safe_cx;
+                       index = -EBUSY;
+               }
+       }
+
+       if (dis_bm) {
                raw_spin_lock(&c3_lock);
                c3_cpu_count++;
                /* Disable bus master arbitration when all CPUs are in C3 */
@@ -600,18 +604,21 @@ static void acpi_idle_enter_bm(struct acpi_processor *pr,
                raw_spin_unlock(&c3_lock);
        }
 
+       rcu_idle_enter();
+
        acpi_idle_do_entry(cx);
 
+       rcu_idle_exit();
+
        /* Re-enable bus master arbitration */
-       if (pr->flags.bm_control) {
+       if (dis_bm) {
                raw_spin_lock(&c3_lock);
                acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
                c3_cpu_count--;
                raw_spin_unlock(&c3_lock);
        }
 
-       if (timer_bc)
-               lapic_timer_state_broadcast(pr, cx, 0);
+       return index;
 }
 
 static int acpi_idle_enter(struct cpuidle_device *dev,
@@ -625,32 +632,21 @@ static int acpi_idle_enter(struct cpuidle_device *dev,
                return -EINVAL;
 
        if (cx->type != ACPI_STATE_C1) {
+               if (cx->type == ACPI_STATE_C3 && pr->flags.bm_check)
+                       return acpi_idle_enter_bm(drv, pr, cx, index);
+
+               /* C2 to C1 demotion. */
                if (acpi_idle_fallback_to_c1(pr) && num_online_cpus() > 1) {
                        index = ACPI_IDLE_STATE_START;
                        cx = per_cpu(acpi_cstate[index], dev->cpu);
-               } else if (cx->type == ACPI_STATE_C3 && pr->flags.bm_check) {
-                       if (cx->bm_sts_skip || !acpi_idle_bm_check()) {
-                               acpi_idle_enter_bm(pr, cx, true);
-                               return index;
-                       } else if (drv->safe_state_index >= 0) {
-                               index = drv->safe_state_index;
-                               cx = per_cpu(acpi_cstate[index], dev->cpu);
-                       } else {
-                               acpi_safe_halt();
-                               return -EBUSY;
-                       }
                }
        }
 
-       lapic_timer_state_broadcast(pr, cx, 1);
-
        if (cx->type == ACPI_STATE_C3)
                ACPI_FLUSH_CPU_CACHE();
 
        acpi_idle_do_entry(cx);
 
-       lapic_timer_state_broadcast(pr, cx, 0);
-
        return index;
 }
 
@@ -666,7 +662,13 @@ static int acpi_idle_enter_s2idle(struct cpuidle_device *dev,
                        return 0;
 
                if (pr->flags.bm_check) {
-                       acpi_idle_enter_bm(pr, cx, false);
+                       u8 bm_sts_skip = cx->bm_sts_skip;
+
+                       /* Don't check BM_STS, do an unconditional ARB_DIS for S2IDLE */
+                       cx->bm_sts_skip = 1;
+                       acpi_idle_enter_bm(drv, pr, cx, index);
+                       cx->bm_sts_skip = bm_sts_skip;
+
                        return 0;
                } else {
                        ACPI_FLUSH_CPU_CACHE();
@@ -682,11 +684,13 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
 {
        int i, count = ACPI_IDLE_STATE_START;
        struct acpi_processor_cx *cx;
+       struct cpuidle_state *state;
 
        if (max_cstate == 0)
                max_cstate = 1;
 
        for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
+               state = &acpi_idle_driver.states[count];
                cx = &pr->power.states[i];
 
                if (!cx->valid)
@@ -694,6 +698,15 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
 
                per_cpu(acpi_cstate[count], dev->cpu) = cx;
 
+               if (lapic_timer_needs_broadcast(pr, cx))
+                       state->flags |= CPUIDLE_FLAG_TIMER_STOP;
+
+               if (cx->type == ACPI_STATE_C3) {
+                       state->flags |= CPUIDLE_FLAG_TLB_FLUSHED;
+                       if (pr->flags.bm_check)
+                               state->flags |= CPUIDLE_FLAG_RCU_IDLE;
+               }
+
                count++;
                if (count == CPUIDLE_STATE_MAX)
                        break;
index 0c0a736..fbd8eaa 100644 (file)
@@ -807,8 +807,7 @@ static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
                                (sstatus & 0xf) != 1)
                        break;
 
-               ata_link_printk(link, KERN_INFO, "avn bounce port%d\n",
-                               port);
+               ata_link_info(link,  "avn bounce port%d\n", port);
 
                pci_read_config_word(pdev, 0x92, &val);
                val &= ~(1 << port);
index 6853dbb..49f7acb 100644 (file)
@@ -470,7 +470,7 @@ static int brcm_ahci_probe(struct platform_device *pdev)
        switch (priv->version) {
        case BRCM_SATA_BCM7425:
                hpriv->flags |= AHCI_HFLAG_DELAY_ENGINE;
-               /* fall through */
+               fallthrough;
        case BRCM_SATA_NSP:
                hpriv->flags |= AHCI_HFLAG_NO_NCQ;
                priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
index 129556f..86261de 100644 (file)
@@ -326,7 +326,7 @@ static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port,
                                node);
                        break;
                }
-               /* fall through */
+               fallthrough;
        case -ENODEV:
                /* continue normally */
                hpriv->phys[port] = NULL;
index b1cd4d9..f546a57 100644 (file)
@@ -190,7 +190,7 @@ struct ata_link *ata_link_next(struct ata_link *link, struct ata_port *ap,
                case ATA_LITER_PMP_FIRST:
                        if (sata_pmp_attached(ap))
                                return ap->pmp_link;
-                       /* fall through */
+                       fallthrough;
                case ATA_LITER_HOST_FIRST:
                        return &ap->link;
                }
@@ -201,11 +201,11 @@ struct ata_link *ata_link_next(struct ata_link *link, struct ata_port *ap,
                case ATA_LITER_HOST_FIRST:
                        if (sata_pmp_attached(ap))
                                return ap->pmp_link;
-                       /* fall through */
+                       fallthrough;
                case ATA_LITER_PMP_FIRST:
                        if (unlikely(ap->slave_link))
                                return ap->slave_link;
-                       /* fall through */
+                       fallthrough;
                case ATA_LITER_EDGE:
                        return NULL;
                }
@@ -523,7 +523,7 @@ int atapi_cmd_type(u8 opcode)
        case ATA_12:
                if (atapi_passthru16)
                        return ATAPI_PASS_THRU;
-               /* fall thru */
+               fallthrough;
        default:
                return ATAPI_MISC;
        }
@@ -1800,7 +1800,7 @@ retry:
        switch (class) {
        case ATA_DEV_SEMB:
                class = ATA_DEV_ATA;    /* some hard drives report SEMB sig */
-               /* fall through */
+               fallthrough;
        case ATA_DEV_ATA:
        case ATA_DEV_ZAC:
                tf.command = ATA_CMD_ID_ATA;
@@ -2907,7 +2907,7 @@ int ata_bus_probe(struct ata_port *ap)
        case -ENODEV:
                /* give it just one more chance */
                tries[dev->devno] = min(tries[dev->devno], 1);
-               /* fall through */
+               fallthrough;
        case -EIO:
                if (tries[dev->devno] == 1) {
                        /* This is the last chance, better to slow
@@ -3158,7 +3158,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
 
        case ATA_DNXFER_FORCE_PIO0:
                pio_mask &= 1;
-               /* fall through */
+               fallthrough;
        case ATA_DNXFER_FORCE_PIO:
                mwdma_mask = 0;
                udma_mask = 0;
@@ -3868,9 +3868,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        /* https://bugzilla.kernel.org/show_bug.cgi?id=15573 */
        { "C300-CTFDDAC128MAG", "0001",         ATA_HORKAGE_NONCQ, },
 
-       /* Some Sandisk SSDs lock up hard with NCQ enabled.  Reported on
-          SD7SN6S256G and SD8SN8U256G */
-       { "SanDisk SD[78]SN*G", NULL,           ATA_HORKAGE_NONCQ, },
+       /* Sandisk SD7/8/9s lock up hard on large trims */
+       { "SanDisk SD[789]*",   NULL,           ATA_HORKAGE_MAX_TRIM_128M, },
 
        /* devices which puke on READ_NATIVE_MAX */
        { "HDS724040KLSA80",    "KFAOA20N",     ATA_HORKAGE_BROKEN_HPA, },
@@ -4694,7 +4693,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
                            qc->tf.feature != SETFEATURES_RA_ON &&
                            qc->tf.feature != SETFEATURES_RA_OFF)
                                break;
-                       /* fall through */
+                       fallthrough;
                case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */
                case ATA_CMD_SET_MULTI: /* multi_count changed */
                        /* revalidate device */
index 474c6c3..d912eaa 100644 (file)
@@ -1576,7 +1576,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
        case ATA_DEV_ZAC:
                if (stat & ATA_SENSE)
                        ata_eh_request_sense(qc, qc->scsicmd);
-               /* fall through */
+               fallthrough;
        case ATA_DEV_ATA:
                if (err & ATA_ICRC)
                        qc->err_mask |= AC_ERR_ATA_BUS;
@@ -3473,11 +3473,11 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
        case -ENODEV:
                /* device missing or wrong IDENTIFY data, schedule probing */
                ehc->i.probe_mask |= (1 << dev->devno);
-               /* fall through */
+               fallthrough;
        case -EINVAL:
                /* give it just one more chance */
                ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
-               /* fall through */
+               fallthrough;
        case -EIO:
                if (ehc->tries[dev->devno] == 1) {
                        /* This is the last chance, better to slow
index ec23320..7043191 100644 (file)
@@ -2080,6 +2080,7 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
 
 static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
 {
+       struct ata_device *dev = args->dev;
        u16 min_io_sectors;
 
        rbuf[1] = 0xb0;
@@ -2105,7 +2106,12 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
         * with the unmap bit set.
         */
        if (ata_id_has_trim(args->id)) {
-               put_unaligned_be64(65535 * ATA_MAX_TRIM_RNUM, &rbuf[36]);
+               u64 max_blocks = 65535 * ATA_MAX_TRIM_RNUM;
+
+               if (dev->horkage & ATA_HORKAGE_MAX_TRIM_128M)
+                       max_blocks = 128 << (20 - SECTOR_SHIFT);
+
+               put_unaligned_be64(max_blocks, &rbuf[36]);
                put_unaligned_be32(1, &rbuf[28]);
        }
 
@@ -4162,7 +4168,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
                                ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b6);
                                break;
                        }
-                       /* Fallthrough */
+                       fallthrough;
                default:
                        ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
                        break;
@@ -4198,7 +4204,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
         * turning this into a no-op.
         */
        case SYNCHRONIZE_CACHE:
-               /* fall through */
+               fallthrough;
 
        /* no-op's, complete with success */
        case REZERO_UNIT:
index e01a3a6..2bc5fc8 100644 (file)
@@ -157,7 +157,7 @@ static int atp867x_get_active_clocks_shifted(struct ata_port *ap,
        default:
                printk(KERN_WARNING "ATP867X: active %dclk is invalid. "
                        "Using 12clk.\n", clk);
-               /* fall through */
+               fallthrough;
        case 9 ... 12:
                clocks = 7;     /* 12 clk */
                break;
@@ -190,7 +190,7 @@ static int atp867x_get_recover_clocks_shifted(unsigned int clk)
        default:
                printk(KERN_WARNING "ATP867X: recover %dclk is invalid. "
                        "Using default 12clk.\n", clk);
-               /* fall through */
+               fallthrough;
        case 12:        /* default 12 clk */
                clocks = 0;
                break;
index 916bf02..7511e11 100644 (file)
@@ -369,7 +369,7 @@ static int serverworks_fixup(struct pci_dev *pdev)
                break;
        case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
                ata_pci_bmdma_clear_simplex(pdev);
-               /* fall through */
+               fallthrough;
        case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
        case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
                rc = serverworks_fixup_csb(pdev);
index d7228f8..664ef65 100644 (file)
@@ -2010,7 +2010,7 @@ static void mv_rw_multi_errata_sata24(struct ata_queued_cmd *qc)
                                break;
                        case ATA_CMD_WRITE_MULTI_FUA_EXT:
                                tf->flags &= ~ATA_TFLAG_FUA; /* ugh */
-                               /* fall through */
+                               fallthrough;
                        case ATA_CMD_WRITE_MULTI_EXT:
                                tf->command = ATA_CMD_PIO_WRITE_EXT;
                                break;
@@ -2044,7 +2044,7 @@ static enum ata_completion_errors mv_qc_prep(struct ata_queued_cmd *qc)
        case ATA_PROT_DMA:
                if (tf->command == ATA_CMD_DSM)
                        return AC_ERR_OK;
-               /* fall-thru */
+               fallthrough;
        case ATA_PROT_NCQ:
                break;  /* continue below */
        case ATA_PROT_PIO:
@@ -2296,7 +2296,7 @@ static unsigned int mv_qc_issue_fis(struct ata_queued_cmd *qc)
        switch (qc->tf.protocol) {
        case ATAPI_PROT_PIO:
                pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
-               /* fall through */
+               fallthrough;
        case ATAPI_PROT_NODATA:
                ap->hsm_task_state = HSM_ST_FIRST;
                break;
@@ -2347,7 +2347,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
                                return AC_ERR_OTHER;
                        break;  /* use bmdma for this */
                }
-               /* fall thru */
+               fallthrough;
        case ATA_PROT_NCQ:
                mv_start_edma(ap, port_mmio, pp, qc->tf.protocol);
                pp->req_idx = (pp->req_idx + 1) & MV_MAX_Q_DEPTH_MASK;
@@ -2376,7 +2376,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
                                      ": attempting PIO w/multiple DRQ: "
                                      "this may fail due to h/w errata\n");
                }
-               /* fall through */
+               fallthrough;
        case ATA_PROT_NODATA:
        case ATAPI_PROT_PIO:
        case ATAPI_PROT_NODATA:
@@ -3864,7 +3864,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
                                " and avoid the final two gigabytes on"
                                " all RocketRAID BIOS initialized drives.\n");
                }
-               /* fall through */
+               fallthrough;
        case chip_6042:
                hpriv->ops = &mv6xxx_ops;
                hp_flags |= MV_HP_GEN_IIE;
index 8729f78..7815da8 100644 (file)
@@ -637,7 +637,7 @@ static enum ata_completion_errors pdc_qc_prep(struct ata_queued_cmd *qc)
        switch (qc->tf.protocol) {
        case ATA_PROT_DMA:
                pdc_fill_sg(qc);
-               /*FALLTHROUGH*/
+               fallthrough;
        case ATA_PROT_NODATA:
                i = pdc_pkt_header(&qc->tf, qc->ap->bmdma_prd_dma,
                                   qc->dev->devno, pp->pkt);
@@ -652,7 +652,7 @@ static enum ata_completion_errors pdc_qc_prep(struct ata_queued_cmd *qc)
                break;
        case ATAPI_PROT_DMA:
                pdc_fill_sg(qc);
-               /*FALLTHROUGH*/
+               fallthrough;
        case ATAPI_PROT_NODATA:
                pdc_atapi_pkt(qc);
                break;
@@ -1022,11 +1022,11 @@ static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc)
        case ATAPI_PROT_NODATA:
                if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
                        break;
-               /*FALLTHROUGH*/
+               fallthrough;
        case ATA_PROT_NODATA:
                if (qc->tf.flags & ATA_TFLAG_POLLING)
                        break;
-               /*FALLTHROUGH*/
+               fallthrough;
        case ATAPI_PROT_DMA:
        case ATA_PROT_DMA:
                pdc_packet_start(qc);
index 2c7b30c..4c01190 100644 (file)
@@ -669,7 +669,7 @@ static unsigned int pdc20621_qc_issue(struct ata_queued_cmd *qc)
        case ATA_PROT_NODATA:
                if (qc->tf.flags & ATA_TFLAG_POLLING)
                        break;
-               /*FALLTHROUGH*/
+               fallthrough;
        case ATA_PROT_DMA:
                pdc20621_packet_start(qc);
                return 0;
index 39be444..316a994 100644 (file)
@@ -2224,7 +2224,7 @@ static int eni_init_one(struct pci_dev *pci_dev,
 
        rc = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32));
        if (rc < 0)
-               goto out;
+               goto err_disable;
 
        rc = -ENOMEM;
        eni_dev = kmalloc(sizeof(struct eni_dev), GFP_KERNEL);
index 2ca9ec8..0ddd611 100644 (file)
@@ -711,7 +711,7 @@ static void process_txdone_queue (struct fs_dev *dev, struct queue *q)
 
                switch (STATUS_CODE (qe)) {
                case 0x01: /* This is for AAL0 where we put the chip in streaming mode */
-                       /* Fall through */
+                       fallthrough;
                case 0x02:
                        /* Process a real txdone entry. */
                        tmp = qe->p0;
@@ -998,6 +998,7 @@ static int fs_open(struct atm_vcc *atm_vcc)
                                error = make_rate (pcr, r, &tmc0, NULL);
                                if (error) {
                                        kfree(tc);
+                                       kfree(vcc);
                                        return error;
                                }
                        }
index a81bc49..9a70bee 100644 (file)
@@ -376,33 +376,33 @@ fore200e_shutdown(struct fore200e* fore200e)
     case FORE200E_STATE_COMPLETE:
        kfree(fore200e->stats);
 
-       /* fall through */
+       fallthrough;
     case FORE200E_STATE_IRQ:
        free_irq(fore200e->irq, fore200e->atm_dev);
 
-       /* fall through */
+       fallthrough;
     case FORE200E_STATE_ALLOC_BUF:
        fore200e_free_rx_buf(fore200e);
 
-       /* fall through */
+       fallthrough;
     case FORE200E_STATE_INIT_BSQ:
        fore200e_uninit_bs_queue(fore200e);
 
-       /* fall through */
+       fallthrough;
     case FORE200E_STATE_INIT_RXQ:
        fore200e_dma_chunk_free(fore200e, &fore200e->host_rxq.status);
        fore200e_dma_chunk_free(fore200e, &fore200e->host_rxq.rpd);
 
-       /* fall through */
+       fallthrough;
     case FORE200E_STATE_INIT_TXQ:
        fore200e_dma_chunk_free(fore200e, &fore200e->host_txq.status);
        fore200e_dma_chunk_free(fore200e, &fore200e->host_txq.tpd);
 
-       /* fall through */
+       fallthrough;
     case FORE200E_STATE_INIT_CMDQ:
        fore200e_dma_chunk_free(fore200e, &fore200e->host_cmdq.status);
 
-       /* fall through */
+       fallthrough;
     case FORE200E_STATE_INITIALIZE:
        /* nothing to do for that state */
 
@@ -415,7 +415,7 @@ fore200e_shutdown(struct fore200e* fore200e)
     case FORE200E_STATE_MAP:
        fore200e->bus->unmap(fore200e);
 
-       /* fall through */
+       fallthrough;
     case FORE200E_STATE_CONFIGURE:
        /* nothing to do for that state */
 
index 8af793f..17f44ab 100644 (file)
@@ -1944,14 +1944,14 @@ he_tasklet(unsigned long data)
                switch (type) {
                        case ITYPE_RBRQ_THRESH:
                                HPRINTK("rbrq%d threshold\n", group);
-                               /* fall through */
+                               fallthrough;
                        case ITYPE_RBRQ_TIMER:
                                if (he_service_rbrq(he_dev, group))
                                        he_service_rbpl(he_dev, group);
                                break;
                        case ITYPE_TBRQ_THRESH:
                                HPRINTK("tbrq%d threshold\n", group);
-                               /* fall through */
+                               fallthrough;
                        case ITYPE_TPD_COMPLETE:
                                he_service_tbrq(he_dev, group);
                                break;
index 6387185..3c081b6 100644 (file)
@@ -192,7 +192,7 @@ static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
        switch (cmd) {
                case IDT77105_GETSTATZ:
                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                       /* fall through */
+                       fallthrough;
                case IDT77105_GETSTAT:
                        return fetch_stats(dev, arg, cmd == IDT77105_GETSTATZ);
                case ATM_SETLOOP:
index 986c131..ac811cf 100644 (file)
@@ -2019,7 +2019,7 @@ static int lanai_normalize_ci(struct lanai_dev *lanai,
        switch (*vpip) {
                case ATM_VPI_ANY:
                        *vpip = 0;
-                       /* FALLTHROUGH */
+                       fallthrough;
                case 0:
                        break;
                default:
index ee059c7..cf5fffc 100644 (file)
@@ -1447,7 +1447,7 @@ static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
        switch (cmd) {
                case ZATM_GETPOOLZ:
                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                       /* fall through */
+                       fallthrough;
                case ZATM_GETPOOL:
                        {
                                struct zatm_pool_info info;
index dea0314..0b1c99c 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Driver for the on-board character LCD found on some ARM reference boards
  * This is basically an Hitachi HD44780 LCD with a custom IP block to drive it
- * http://en.wikipedia.org/wiki/HD44780_Character_LCD
+ * https://en.wikipedia.org/wiki/HD44780_Character_LCD
  * Currently it will just display the text "ARM Linux" and the linux version
  *
  * Author: Linus Walleij <triad@df.lth.se>
index 99980aa..1c82d82 100644 (file)
@@ -1365,7 +1365,7 @@ static void panel_process_inputs(void)
                                break;
                        input->rise_timer = 0;
                        input->state = INPUT_ST_RISING;
-                       /* fall through */
+                       fallthrough;
                case INPUT_ST_RISING:
                        if ((phys_curr & input->mask) != input->value) {
                                input->state = INPUT_ST_LOW;
@@ -1378,11 +1378,11 @@ static void panel_process_inputs(void)
                        }
                        input->high_timer = 0;
                        input->state = INPUT_ST_HIGH;
-                       /* fall through */
+                       fallthrough;
                case INPUT_ST_HIGH:
                        if (input_state_high(input))
                                break;
-                       /* fall through */
+                       fallthrough;
                case INPUT_ST_FALLING:
                        input_state_falling(input);
                }
index ac1046a..bb5806a 100644 (file)
@@ -807,9 +807,7 @@ static void device_link_put_kref(struct device_link *link)
 void device_link_del(struct device_link *link)
 {
        device_links_write_lock();
-       device_pm_lock();
        device_link_put_kref(link);
-       device_pm_unlock();
        device_links_write_unlock();
 }
 EXPORT_SYMBOL_GPL(device_link_del);
@@ -830,7 +828,6 @@ void device_link_remove(void *consumer, struct device *supplier)
                return;
 
        device_links_write_lock();
-       device_pm_lock();
 
        list_for_each_entry(link, &supplier->links.consumers, s_node) {
                if (link->consumer == consumer) {
@@ -839,7 +836,6 @@ void device_link_remove(void *consumer, struct device *supplier)
                }
        }
 
-       device_pm_unlock();
        device_links_write_unlock();
 }
 EXPORT_SYMBOL_GPL(device_link_remove);
@@ -4237,10 +4233,10 @@ int dev_err_probe(const struct device *dev, int err, const char *fmt, ...)
        vaf.va = &args;
 
        if (err != -EPROBE_DEFER) {
-               dev_err(dev, "error %d: %pV", err, &vaf);
+               dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
        } else {
                device_set_deferred_probe_reason(dev, &vaf);
-               dev_dbg(dev, "error %d: %pV", err, &vaf);
+               dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
        }
 
        va_end(args);
@@ -4264,9 +4260,9 @@ static inline bool fwnode_is_primary(struct fwnode_handle *fwnode)
  */
 void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
 {
-       if (fwnode) {
-               struct fwnode_handle *fn = dev->fwnode;
+       struct fwnode_handle *fn = dev->fwnode;
 
+       if (fwnode) {
                if (fwnode_is_primary(fn))
                        fn = fn->secondary;
 
@@ -4276,8 +4272,12 @@ void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
                }
                dev->fwnode = fwnode;
        } else {
-               dev->fwnode = fwnode_is_primary(dev->fwnode) ?
-                       dev->fwnode->secondary : NULL;
+               if (fwnode_is_primary(fn)) {
+                       dev->fwnode = fn->secondary;
+                       fn->secondary = NULL;
+               } else {
+                       dev->fwnode = NULL;
+               }
        }
 }
 EXPORT_SYMBOL_GPL(set_primary_fwnode);
index 5327bfc..283ca2d 100644 (file)
@@ -289,10 +289,10 @@ static ssize_t firmware_loading_store(struct device *dev,
                        }
                        break;
                }
-               /* fallthrough */
+               fallthrough;
        default:
                dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
-               /* fallthrough */
+               fallthrough;
        case -1:
                fw_load_abort(fw_sysfs);
                break;
index 933e219..d08efc7 100644 (file)
@@ -142,10 +142,12 @@ int assign_fw(struct firmware *fw, struct device *device, u32 opt_flags);
 void fw_free_paged_buf(struct fw_priv *fw_priv);
 int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed);
 int fw_map_paged_buf(struct fw_priv *fw_priv);
+bool fw_is_paged_buf(struct fw_priv *fw_priv);
 #else
 static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {}
 static inline int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; }
 static inline int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; }
+static inline bool fw_is_paged_buf(struct fw_priv *fw_priv) { return false; }
 #endif
 
 #endif /* __FIRMWARE_LOADER_H */
index 9da0c9d..63b9714 100644 (file)
@@ -252,9 +252,11 @@ static void __free_fw_priv(struct kref *ref)
        list_del(&fw_priv->list);
        spin_unlock(&fwc->lock);
 
-       fw_free_paged_buf(fw_priv); /* free leftover pages */
-       if (!fw_priv->allocated_size)
+       if (fw_is_paged_buf(fw_priv))
+               fw_free_paged_buf(fw_priv);
+       else if (!fw_priv->allocated_size)
                vfree(fw_priv->data);
+
        kfree_const(fw_priv->fw_name);
        kfree(fw_priv);
 }
@@ -268,6 +270,11 @@ static void free_fw_priv(struct fw_priv *fw_priv)
 }
 
 #ifdef CONFIG_FW_LOADER_PAGED_BUF
+bool fw_is_paged_buf(struct fw_priv *fw_priv)
+{
+       return fw_priv->is_paged_buf;
+}
+
 void fw_free_paged_buf(struct fw_priv *fw_priv)
 {
        int i;
@@ -275,6 +282,8 @@ void fw_free_paged_buf(struct fw_priv *fw_priv)
        if (!fw_priv->pages)
                return;
 
+       vunmap(fw_priv->data);
+
        for (i = 0; i < fw_priv->nr_pages; i++)
                __free_page(fw_priv->pages[i]);
        kvfree(fw_priv->pages);
@@ -328,10 +337,6 @@ int fw_map_paged_buf(struct fw_priv *fw_priv)
        if (!fw_priv->data)
                return -ENOMEM;
 
-       /* page table is no longer needed after mapping, let's free */
-       kvfree(fw_priv->pages);
-       fw_priv->pages = NULL;
-
        return 0;
 }
 #endif
index 508b80f..50af16e 100644 (file)
@@ -761,14 +761,36 @@ static int __ref get_nid_for_pfn(unsigned long pfn)
        return pfn_to_nid(pfn);
 }
 
+static int do_register_memory_block_under_node(int nid,
+                                              struct memory_block *mem_blk)
+{
+       int ret;
+
+       /*
+        * If this memory block spans multiple nodes, we only indicate
+        * the last processed node.
+        */
+       mem_blk->nid = nid;
+
+       ret = sysfs_create_link_nowarn(&node_devices[nid]->dev.kobj,
+                                      &mem_blk->dev.kobj,
+                                      kobject_name(&mem_blk->dev.kobj));
+       if (ret)
+               return ret;
+
+       return sysfs_create_link_nowarn(&mem_blk->dev.kobj,
+                               &node_devices[nid]->dev.kobj,
+                               kobject_name(&node_devices[nid]->dev.kobj));
+}
+
 /* register memory section under specified node if it spans that node */
-static int register_mem_sect_under_node(struct memory_block *mem_blk,
-                                        void *arg)
+static int register_mem_block_under_node_early(struct memory_block *mem_blk,
+                                              void *arg)
 {
        unsigned long memory_block_pfns = memory_block_size_bytes() / PAGE_SIZE;
        unsigned long start_pfn = section_nr_to_pfn(mem_blk->start_section_nr);
        unsigned long end_pfn = start_pfn + memory_block_pfns - 1;
-       int ret, nid = *(int *)arg;
+       int nid = *(int *)arg;
        unsigned long pfn;
 
        for (pfn = start_pfn; pfn <= end_pfn; pfn++) {
@@ -785,39 +807,34 @@ static int register_mem_sect_under_node(struct memory_block *mem_blk,
                }
 
                /*
-                * We need to check if page belongs to nid only for the boot
-                * case, during hotplug we know that all pages in the memory
-                * block belong to the same node.
-                */
-               if (system_state == SYSTEM_BOOTING) {
-                       page_nid = get_nid_for_pfn(pfn);
-                       if (page_nid < 0)
-                               continue;
-                       if (page_nid != nid)
-                               continue;
-               }
-
-               /*
-                * If this memory block spans multiple nodes, we only indicate
-                * the last processed node.
+                * We need to check if page belongs to nid only at the boot
+                * case because node's ranges can be interleaved.
                 */
-               mem_blk->nid = nid;
-
-               ret = sysfs_create_link_nowarn(&node_devices[nid]->dev.kobj,
-                                       &mem_blk->dev.kobj,
-                                       kobject_name(&mem_blk->dev.kobj));
-               if (ret)
-                       return ret;
+               page_nid = get_nid_for_pfn(pfn);
+               if (page_nid < 0)
+                       continue;
+               if (page_nid != nid)
+                       continue;
 
-               return sysfs_create_link_nowarn(&mem_blk->dev.kobj,
-                               &node_devices[nid]->dev.kobj,
-                               kobject_name(&node_devices[nid]->dev.kobj));
+               return do_register_memory_block_under_node(nid, mem_blk);
        }
        /* mem section does not span the specified node */
        return 0;
 }
 
 /*
+ * During hotplug we know that all pages in the memory block belong to the same
+ * node.
+ */
+static int register_mem_block_under_node_hotplug(struct memory_block *mem_blk,
+                                                void *arg)
+{
+       int nid = *(int *)arg;
+
+       return do_register_memory_block_under_node(nid, mem_blk);
+}
+
+/*
  * Unregister a memory block device under the node it spans. Memory blocks
  * with multiple nodes cannot be offlined and therefore also never be removed.
  */
@@ -832,11 +849,19 @@ void unregister_memory_block_under_nodes(struct memory_block *mem_blk)
                          kobject_name(&node_devices[mem_blk->nid]->dev.kobj));
 }
 
-int link_mem_sections(int nid, unsigned long start_pfn, unsigned long end_pfn)
+int link_mem_sections(int nid, unsigned long start_pfn, unsigned long end_pfn,
+                     enum meminit_context context)
 {
+       walk_memory_blocks_func_t func;
+
+       if (context == MEMINIT_HOTPLUG)
+               func = register_mem_block_under_node_hotplug;
+       else
+               func = register_mem_block_under_node_early;
+
        return walk_memory_blocks(PFN_PHYS(start_pfn),
                                  PFN_PHYS(end_pfn - start_pfn), (void *)&nid,
-                                 register_mem_sect_under_node);
+                                 func);
 }
 
 #ifdef CONFIG_HUGETLBFS
index 9dd85be..205a067 100644 (file)
@@ -1606,13 +1606,17 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
        }
 
        /*
-        * If a device configured to wake up the system from sleep states
-        * has been suspended at run time and there's a resume request pending
-        * for it, this is equivalent to the device signaling wakeup, so the
-        * system suspend operation should be aborted.
+        * Wait for possible runtime PM transitions of the device in progress
+        * to complete and if there's a runtime resume request pending for it,
+        * resume it before proceeding with invoking the system-wide suspend
+        * callbacks for it.
+        *
+        * If the system-wide suspend callbacks below change the configuration
+        * of the device, they must disable runtime PM for it or otherwise
+        * ensure that its runtime-resume callbacks will not be confused by that
+        * change in case they are invoked going forward.
         */
-       if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
-               pm_wakeup_event(dev, 0);
+       pm_runtime_barrier(dev);
 
        if (pm_wakeup_pending()) {
                dev->power.direct_complete = false;
index 3d80c4b..7be2fcf 100644 (file)
@@ -217,7 +217,7 @@ struct regmap_field {
 
 #ifdef CONFIG_DEBUG_FS
 extern void regmap_debugfs_initcall(void);
-extern void regmap_debugfs_init(struct regmap *map, const char *name);
+extern void regmap_debugfs_init(struct regmap *map);
 extern void regmap_debugfs_exit(struct regmap *map);
 
 static inline void regmap_debugfs_disable(struct regmap *map)
@@ -227,7 +227,7 @@ static inline void regmap_debugfs_disable(struct regmap *map)
 
 #else
 static inline void regmap_debugfs_initcall(void) { }
-static inline void regmap_debugfs_init(struct regmap *map, const char *name) { }
+static inline void regmap_debugfs_init(struct regmap *map) { }
 static inline void regmap_debugfs_exit(struct regmap *map) { }
 static inline void regmap_debugfs_disable(struct regmap *map) { }
 #endif
@@ -259,7 +259,7 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
 int regcache_lookup_reg(struct regmap *map, unsigned int reg);
 
 int _regmap_raw_write(struct regmap *map, unsigned int reg,
-                     const void *val, size_t val_len);
+                     const void *val, size_t val_len, bool noinc);
 
 void regmap_async_complete_cb(struct regmap_async *async, int ret);
 
index a93cafd..7f4b3b6 100644 (file)
@@ -717,7 +717,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
 
        map->cache_bypass = true;
 
-       ret = _regmap_raw_write(map, base, *data, count * val_bytes);
+       ret = _regmap_raw_write(map, base, *data, count * val_bytes, false);
        if (ret)
                dev_err(map->dev, "Unable to sync registers %#x-%#x. %d\n",
                        base, cur - map->reg_stride, ret);
index f58baff..b6d63ef 100644 (file)
@@ -17,7 +17,6 @@
 
 struct regmap_debugfs_node {
        struct regmap *map;
-       const char *name;
        struct list_head link;
 };
 
@@ -544,11 +543,12 @@ static const struct file_operations regmap_cache_bypass_fops = {
        .write = regmap_cache_bypass_write_file,
 };
 
-void regmap_debugfs_init(struct regmap *map, const char *name)
+void regmap_debugfs_init(struct regmap *map)
 {
        struct rb_node *next;
        struct regmap_range_node *range_node;
        const char *devname = "dummy";
+       const char *name = map->name;
 
        /*
         * Userspace can initiate reads from the hardware over debugfs.
@@ -569,7 +569,6 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
                if (!node)
                        return;
                node->map = map;
-               node->name = name;
                mutex_lock(&regmap_debugfs_early_lock);
                list_add(&node->link, &regmap_debugfs_early_list);
                mutex_unlock(&regmap_debugfs_early_lock);
@@ -679,7 +678,7 @@ void regmap_debugfs_initcall(void)
 
        mutex_lock(&regmap_debugfs_early_lock);
        list_for_each_entry_safe(node, tmp, &regmap_debugfs_early_list, link) {
-               regmap_debugfs_init(node->map, node->name);
+               regmap_debugfs_init(node->map);
                list_del(&node->link);
                kfree(node);
        }
index e93700a..b71f9ec 100644 (file)
@@ -581,14 +581,34 @@ static void regmap_range_exit(struct regmap *map)
        kfree(map->selector_work_buf);
 }
 
+static int regmap_set_name(struct regmap *map, const struct regmap_config *config)
+{
+       if (config->name) {
+               const char *name = kstrdup_const(config->name, GFP_KERNEL);
+
+               if (!name)
+                       return -ENOMEM;
+
+               kfree_const(map->name);
+               map->name = name;
+       }
+
+       return 0;
+}
+
 int regmap_attach_dev(struct device *dev, struct regmap *map,
                      const struct regmap_config *config)
 {
        struct regmap **m;
+       int ret;
 
        map->dev = dev;
 
-       regmap_debugfs_init(map, config->name);
+       ret = regmap_set_name(map, config);
+       if (ret)
+               return ret;
+
+       regmap_debugfs_init(map);
 
        /* Add a devres resource for dev_get_regmap() */
        m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
@@ -687,13 +707,9 @@ struct regmap *__regmap_init(struct device *dev,
                goto err;
        }
 
-       if (config->name) {
-               map->name = kstrdup_const(config->name, GFP_KERNEL);
-               if (!map->name) {
-                       ret = -ENOMEM;
-                       goto err_map;
-               }
-       }
+       ret = regmap_set_name(map, config);
+       if (ret)
+               goto err_map;
 
        if (config->disable_locking) {
                map->lock = map->unlock = regmap_lock_unlock_none;
@@ -1137,7 +1153,7 @@ skip_format_initialization:
                if (ret != 0)
                        goto err_regcache;
        } else {
-               regmap_debugfs_init(map, config->name);
+               regmap_debugfs_init(map);
        }
 
        return map;
@@ -1297,6 +1313,8 @@ EXPORT_SYMBOL_GPL(regmap_field_free);
  */
 int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 {
+       int ret;
+
        regcache_exit(map);
        regmap_debugfs_exit(map);
 
@@ -1309,7 +1327,11 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
        map->readable_noinc_reg = config->readable_noinc_reg;
        map->cache_type = config->cache_type;
 
-       regmap_debugfs_init(map, config->name);
+       ret = regmap_set_name(map, config);
+       if (ret)
+               return ret;
+
+       regmap_debugfs_init(map);
 
        map->cache_bypass = false;
        map->cache_only = false;
@@ -1464,7 +1486,7 @@ static void regmap_set_work_buf_flag_mask(struct regmap *map, int max_bytes,
 }
 
 static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
-                                 const void *val, size_t val_len)
+                                 const void *val, size_t val_len, bool noinc)
 {
        struct regmap_range_node *range;
        unsigned long flags;
@@ -1523,7 +1545,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
                                win_residue, val_len / map->format.val_bytes);
                        ret = _regmap_raw_write_impl(map, reg, val,
                                                     win_residue *
-                                                    map->format.val_bytes);
+                                                    map->format.val_bytes, noinc);
                        if (ret != 0)
                                return ret;
 
@@ -1537,7 +1559,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
                        win_residue = range->window_len - win_offset;
                }
 
-               ret = _regmap_select_page(map, &reg, range, val_num);
+               ret = _regmap_select_page(map, &reg, range, noinc ? 1 : val_num);
                if (ret != 0)
                        return ret;
        }
@@ -1745,7 +1767,8 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
                                      map->work_buf +
                                      map->format.reg_bytes +
                                      map->format.pad_bytes,
-                                     map->format.val_bytes);
+                                     map->format.val_bytes,
+                                     false);
 }
 
 static inline void *_regmap_map_get_context(struct regmap *map)
@@ -1839,7 +1862,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val)
 EXPORT_SYMBOL_GPL(regmap_write_async);
 
 int _regmap_raw_write(struct regmap *map, unsigned int reg,
-                     const void *val, size_t val_len)
+                     const void *val, size_t val_len, bool noinc)
 {
        size_t val_bytes = map->format.val_bytes;
        size_t val_count = val_len / val_bytes;
@@ -1860,7 +1883,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
 
        /* Write as many bytes as possible with chunk_size */
        for (i = 0; i < chunk_count; i++) {
-               ret = _regmap_raw_write_impl(map, reg, val, chunk_bytes);
+               ret = _regmap_raw_write_impl(map, reg, val, chunk_bytes, noinc);
                if (ret)
                        return ret;
 
@@ -1871,7 +1894,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
 
        /* Write remaining bytes */
        if (val_len)
-               ret = _regmap_raw_write_impl(map, reg, val, val_len);
+               ret = _regmap_raw_write_impl(map, reg, val, val_len, noinc);
 
        return ret;
 }
@@ -1904,7 +1927,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
 
        map->lock(map->lock_arg);
 
-       ret = _regmap_raw_write(map, reg, val, val_len);
+       ret = _regmap_raw_write(map, reg, val, val_len, false);
 
        map->unlock(map->lock_arg);
 
@@ -1962,7 +1985,7 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
                        write_len = map->max_raw_write;
                else
                        write_len = val_len;
-               ret = _regmap_raw_write(map, reg, val, write_len);
+               ret = _regmap_raw_write(map, reg, val, write_len, true);
                if (ret)
                        goto out_unlock;
                val = ((u8 *)val) + write_len;
@@ -2439,7 +2462,7 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
 
        map->async = true;
 
-       ret = _regmap_raw_write(map, reg, val, val_len);
+       ret = _regmap_raw_write(map, reg, val, val_len, false);
 
        map->async = false;
 
@@ -2450,7 +2473,7 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
 EXPORT_SYMBOL_GPL(regmap_raw_write_async);
 
 static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
-                           unsigned int val_len)
+                           unsigned int val_len, bool noinc)
 {
        struct regmap_range_node *range;
        int ret;
@@ -2463,7 +2486,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
        range = _regmap_range_lookup(map, reg);
        if (range) {
                ret = _regmap_select_page(map, &reg, range,
-                                         val_len / map->format.val_bytes);
+                                         noinc ? 1 : val_len / map->format.val_bytes);
                if (ret != 0)
                        return ret;
        }
@@ -2501,7 +2524,7 @@ static int _regmap_bus_read(void *context, unsigned int reg,
        if (!map->format.parse_val)
                return -EINVAL;
 
-       ret = _regmap_raw_read(map, reg, work_val, map->format.val_bytes);
+       ret = _regmap_raw_read(map, reg, work_val, map->format.val_bytes, false);
        if (ret == 0)
                *val = map->format.parse_val(work_val);
 
@@ -2617,7 +2640,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 
                /* Read bytes that fit into whole chunks */
                for (i = 0; i < chunk_count; i++) {
-                       ret = _regmap_raw_read(map, reg, val, chunk_bytes);
+                       ret = _regmap_raw_read(map, reg, val, chunk_bytes, false);
                        if (ret != 0)
                                goto out;
 
@@ -2628,7 +2651,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 
                /* Read remaining bytes */
                if (val_len) {
-                       ret = _regmap_raw_read(map, reg, val, val_len);
+                       ret = _regmap_raw_read(map, reg, val, val_len, false);
                        if (ret != 0)
                                goto out;
                }
@@ -2703,7 +2726,7 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
                        read_len = map->max_raw_read;
                else
                        read_len = val_len;
-               ret = _regmap_raw_read(map, reg, val, read_len);
+               ret = _regmap_raw_read(map, reg, val, read_len, true);
                if (ret)
                        goto out_unlock;
                val = ((u8 *)val) + read_len;
index 3cf9bc5..6dba413 100644 (file)
@@ -1135,7 +1135,7 @@ noskb:            if (buf)
                        break;
                }
                bvcpy(skb, f->buf->bio, f->iter, n);
-               /* fall through */
+               fallthrough;
        case ATA_CMD_PIO_WRITE:
        case ATA_CMD_PIO_WRITE_EXT:
                spin_lock_irq(&d->lock);
index 1553d41..a50e13a 100644 (file)
@@ -1726,7 +1726,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
                /* MSch: invalidate default_params */
                default_params[drive].blocks  = 0;
                set_capacity(floppy->disk, MAX_DISK_SIZE * 2);
-               /* Fall through */
+               fallthrough;
        case FDFMTEND:
        case FDFLUSH:
                /* invalidate the buffer track to force a reread */
index fe6cb99..740e93b 100644 (file)
@@ -1733,7 +1733,7 @@ static inline void __drbd_chk_io_error_(struct drbd_device *device,
                                _drbd_set_state(_NS(device, disk, D_INCONSISTENT), CS_HARD, NULL);
                        break;
                }
-               /* fall through - for DRBD_META_IO_ERROR or DRBD_FORCE_DETACH */
+               fallthrough;    /* for DRBD_META_IO_ERROR or DRBD_FORCE_DETACH */
        case EP_DETACH:
        case EP_CALL_HELPER:
                /* Remember whether we saw a READ or WRITE error.
index cb687cc..573dbf6 100644 (file)
@@ -430,7 +430,7 @@ int drbd_thread_start(struct drbd_thread *thi)
                thi->t_state = RESTARTING;
                drbd_info(resource, "Restarting %s thread (from %s [%d])\n",
                                thi->name, current->comm, current->pid);
-               /* fall through */
+               fallthrough;
        case RUNNING:
        case RESTARTING:
        default:
@@ -1553,7 +1553,7 @@ static int _drbd_send_page(struct drbd_peer_device *peer_device, struct page *pa
         * put_page(); and would cause either a VM_BUG directly, or
         * __page_cache_release a page that would actually still be referenced
         * by someone, leading to some obscure delayed Oops somewhere else. */
-       if (drbd_disable_sendpage || (page_count(page) < 1) || PageSlab(page))
+       if (drbd_disable_sendpage || !sendpage_ok(page))
                return _drbd_no_send_page(peer_device, page, offset, size, msg_flags);
 
        msg_flags |= MSG_NOSIGNAL;
index 28eb078..43c8ae4 100644 (file)
@@ -3883,7 +3883,7 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
                        if (nla_put_u32(skb, T_helper_exit_code,
                                        sib->helper_exit_code))
                                goto nla_put_failure;
-                       /* fall through */
+                       fallthrough;
                case SIB_HELPER_PRE:
                        if (nla_put_string(skb, T_helper, sib->helper_name))
                                goto nla_put_failure;
index 1d17593..422363d 100644 (file)
@@ -1797,7 +1797,7 @@ static int receive_Barrier(struct drbd_connection *connection, struct packet_inf
                        break;
                else
                        drbd_warn(connection, "Allocation of an epoch failed, slowing down\n");
-                       /* Fall through */
+               fallthrough;
 
        case WO_BDEV_FLUSH:
        case WO_DRAIN_IO:
@@ -2917,7 +2917,7 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet
                   then we would do something smarter here than reading
                   the block... */
                peer_req->flags |= EE_RS_THIN_REQ;
-               /* fall through */
+               fallthrough;
        case P_RS_DATA_REQUEST:
                peer_req->w.cb = w_e_end_rsdata_req;
                fault_type = DRBD_FAULT_RS_RD;
@@ -3083,7 +3083,7 @@ static int drbd_asb_recover_0p(struct drbd_peer_device *peer_device) __must_hold
                        rv =  1;
                        break;
                }
-               /* Else fall through - to one of the other strategies... */
+               fallthrough;    /* to one of the other strategies */
        case ASB_DISCARD_OLDER_PRI:
                if (self == 0 && peer == 1) {
                        rv = 1;
@@ -3096,7 +3096,7 @@ static int drbd_asb_recover_0p(struct drbd_peer_device *peer_device) __must_hold
                /* Else fall through to one of the other strategies... */
                drbd_warn(device, "Discard younger/older primary did not find a decision\n"
                     "Using discard-least-changes instead\n");
-               /* fall through */
+               fallthrough;
        case ASB_DISCARD_ZERO_CHG:
                if (ch_peer == 0 && ch_self == 0) {
                        rv = test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags)
@@ -3108,7 +3108,7 @@ static int drbd_asb_recover_0p(struct drbd_peer_device *peer_device) __must_hold
                }
                if (after_sb_0p == ASB_DISCARD_ZERO_CHG)
                        break;
-               /* else, fall through */
+               fallthrough;
        case ASB_DISCARD_LEAST_CHG:
                if      (ch_self < ch_peer)
                        rv = -1;
@@ -3608,7 +3608,7 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_peer_device *peer_device,
                switch (rr_conflict) {
                case ASB_CALL_HELPER:
                        drbd_khelper(device, "pri-lost");
-                       /* fall through */
+                       fallthrough;
                case ASB_DISCONNECT:
                        drbd_err(device, "I shall become SyncTarget, but I am primary!\n");
                        return C_MASK;
index 674be09..5c975af 100644 (file)
@@ -611,7 +611,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
                drbd_set_out_of_sync(device, req->i.sector, req->i.size);
                drbd_report_io_error(device, req);
                __drbd_chk_io_error(device, DRBD_READ_ERROR);
-               /* fall through. */
+               fallthrough;
        case READ_AHEAD_COMPLETED_WITH_ERROR:
                /* it is legal to fail read-ahead, no __drbd_chk_io_error in that case. */
                mod_rq_state(req, m, RQ_LOCAL_PENDING, RQ_LOCAL_COMPLETED);
@@ -836,7 +836,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
                        } /* else: FIXME can this happen? */
                        break;
                }
-               /* else, fall through - to BARRIER_ACKED */
+               fallthrough;    /* to BARRIER_ACKED */
 
        case BARRIER_ACKED:
                /* barrier ack for READ requests does not make sense */
index 09079ae..a563b02 100644 (file)
@@ -1680,7 +1680,7 @@ static void recal_interrupt(void)
                        clear_bit(FD_DISK_NEWCHANGE_BIT,
                                  &drive_state[current_drive].flags);
                        drive_state[current_drive].select_date = jiffies;
-                       /* fall through */
+                       fallthrough;
                default:
                        debugt(__func__, "default");
                        /* Recalibrate moves the head by at
@@ -3592,7 +3592,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
                        return -EINTR;
                process_fd_request();
-               /* fall through */
+               fallthrough;
        case FDGETDRVSTAT:
                outparam = &drive_state[drive];
                break;
index 2f137d6..d339419 100644 (file)
@@ -878,6 +878,7 @@ static void loop_config_discard(struct loop_device *lo)
        struct file *file = lo->lo_backing_file;
        struct inode *inode = file->f_mapping->host;
        struct request_queue *q = lo->lo_queue;
+       u32 granularity, max_discard_sectors;
 
        /*
         * If the backing device is a block device, mirror its zeroing
@@ -890,11 +891,10 @@ static void loop_config_discard(struct loop_device *lo)
                struct request_queue *backingq;
 
                backingq = bdev_get_queue(inode->i_bdev);
-               blk_queue_max_discard_sectors(q,
-                       backingq->limits.max_write_zeroes_sectors);
 
-               blk_queue_max_write_zeroes_sectors(q,
-                       backingq->limits.max_write_zeroes_sectors);
+               max_discard_sectors = backingq->limits.max_write_zeroes_sectors;
+               granularity = backingq->limits.discard_granularity ?:
+                       queue_physical_block_size(backingq);
 
        /*
         * We use punch hole to reclaim the free space used by the
@@ -903,23 +903,26 @@ static void loop_config_discard(struct loop_device *lo)
         * useful information.
         */
        } else if (!file->f_op->fallocate || lo->lo_encrypt_key_size) {
-               q->limits.discard_granularity = 0;
-               q->limits.discard_alignment = 0;
-               blk_queue_max_discard_sectors(q, 0);
-               blk_queue_max_write_zeroes_sectors(q, 0);
+               max_discard_sectors = 0;
+               granularity = 0;
 
        } else {
-               q->limits.discard_granularity = inode->i_sb->s_blocksize;
-               q->limits.discard_alignment = 0;
-
-               blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
-               blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
+               max_discard_sectors = UINT_MAX >> 9;
+               granularity = inode->i_sb->s_blocksize;
        }
 
-       if (q->limits.max_write_zeroes_sectors)
+       if (max_discard_sectors) {
+               q->limits.discard_granularity = granularity;
+               blk_queue_max_discard_sectors(q, max_discard_sectors);
+               blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
                blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
-       else
+       } else {
+               q->limits.discard_granularity = 0;
+               blk_queue_max_discard_sectors(q, 0);
+               blk_queue_max_write_zeroes_sectors(q, 0);
                blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
+       }
+       q->limits.discard_alignment = 0;
 }
 
 static void loop_unprepare_queue(struct loop_device *lo)
@@ -1111,8 +1114,6 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
        mapping = file->f_mapping;
        inode = mapping->host;
 
-       size = get_loop_size(lo, file);
-
        if ((config->info.lo_flags & ~LOOP_CONFIGURE_SETTABLE_FLAGS) != 0) {
                error = -EINVAL;
                goto out_unlock;
@@ -1162,6 +1163,8 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
        loop_update_rotational(lo);
        loop_update_dio(lo);
        loop_sysfs_init(lo);
+
+       size = get_loop_size(lo, file);
        loop_set_size(lo, size);
 
        set_blocksize(bdev, S_ISBLK(inode->i_mode) ?
@@ -1719,7 +1722,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
        case LOOP_SET_BLOCK_SIZE:
                if (!(mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               /* Fall through */
+               fallthrough;
        default:
                err = lo_simple_ioctl(lo, cmd, arg);
                break;
@@ -1867,7 +1870,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
        case LOOP_SET_STATUS64:
        case LOOP_CONFIGURE:
                arg = (unsigned long) compat_ptr(arg);
-               /* fall through */
+               fallthrough;
        case LOOP_SET_FD:
        case LOOP_CHANGE_FD:
        case LOOP_SET_BLOCK_SIZE:
index 3ff4054..edf8b63 100644 (file)
@@ -1363,6 +1363,8 @@ static void nbd_set_cmd_timeout(struct nbd_device *nbd, u64 timeout)
        nbd->tag_set.timeout = timeout * HZ;
        if (timeout)
                blk_queue_rq_timeout(nbd->disk->queue, timeout * HZ);
+       else
+               blk_queue_rq_timeout(nbd->disk->queue, 30 * HZ);
 }
 
 /* Must be called with config_lock held */
index 47a9dad..d74443a 100644 (file)
@@ -1147,7 +1147,7 @@ static int null_handle_rq(struct nullb_cmd *cmd)
                len = bvec.bv_len;
                err = null_transfer(nullb, bvec.bv_page, len, bvec.bv_offset,
                                     op_is_write(req_op(rq)), sector,
-                                    req_op(rq) & REQ_FUA);
+                                    rq->cmd_flags & REQ_FUA);
                if (err) {
                        spin_unlock_irq(&nullb->lock);
                        return err;
index c096750..a7af4f2 100644 (file)
@@ -440,7 +440,7 @@ static void run_fsm(void)
                                pd_claimed = 1;
                                if (!pi_schedule_claimed(pi_current, run_fsm))
                                        return;
-                               /* fall through */
+                               fallthrough;
                        case 1:
                                pd_claimed = 2;
                                pi_current->proto->connect(pi_current);
@@ -465,7 +465,7 @@ static void run_fsm(void)
                                if (stop)
                                        return;
                                }
-                               /* fall through */
+                               fallthrough;
                        case Hold:
                                schedule_fsm();
                                return;
index 4becc1e..1034e44 100644 (file)
@@ -2641,7 +2641,7 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
                 */
                if (pd->refcnt == 1)
                        pkt_lock_door(pd, 0);
-               /* fall through */
+               fallthrough;
        /*
         * forward selected CDROM ioctls to CD-ROM, for UDF
         */
index d9c0e7d..e77eaab 100644 (file)
@@ -3293,7 +3293,7 @@ again:
        case __RBD_OBJ_COPYUP_OBJECT_MAPS:
                if (!pending_result_dec(&obj_req->pending, result))
                        return false;
-               /* fall through */
+               fallthrough;
        case RBD_OBJ_COPYUP_OBJECT_MAPS:
                if (*result) {
                        rbd_warn(rbd_dev, "snap object map update failed: %d",
@@ -3312,7 +3312,7 @@ again:
        case __RBD_OBJ_COPYUP_WRITE_OBJECT:
                if (!pending_result_dec(&obj_req->pending, result))
                        return false;
-               /* fall through */
+               fallthrough;
        case RBD_OBJ_COPYUP_WRITE_OBJECT:
                return true;
        default:
@@ -3399,7 +3399,7 @@ again:
        case __RBD_OBJ_WRITE_COPYUP:
                if (!rbd_obj_advance_copyup(obj_req, result))
                        return false;
-               /* fall through */
+               fallthrough;
        case RBD_OBJ_WRITE_COPYUP:
                if (*result) {
                        rbd_warn(rbd_dev, "copyup failed: %d", *result);
@@ -3592,7 +3592,7 @@ again:
        case __RBD_IMG_OBJECT_REQUESTS:
                if (!pending_result_dec(&img_req->pending, result))
                        return false;
-               /* fall through */
+               fallthrough;
        case RBD_IMG_OBJECT_REQUESTS:
                return true;
        default:
@@ -5120,6 +5120,9 @@ static ssize_t rbd_config_info_show(struct device *dev,
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        return sprintf(buf, "%s\n", rbd_dev->config_info);
 }
 
@@ -5231,6 +5234,9 @@ static ssize_t rbd_image_refresh(struct device *dev,
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
        int ret;
 
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        ret = rbd_dev_refresh(rbd_dev);
        if (ret)
                return ret;
@@ -7059,6 +7065,9 @@ static ssize_t do_rbd_add(struct bus_type *bus,
        struct rbd_client *rbdc;
        int rc;
 
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        if (!try_module_get(THIS_MODULE))
                return -ENODEV;
 
@@ -7209,6 +7218,9 @@ static ssize_t do_rbd_remove(struct bus_type *bus,
        bool force = false;
        int ret;
 
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        dev_id = -1;
        opt_buf[0] = '\0';
        sscanf(buf, "%d %5s", &dev_id, opt_buf);
index 0fb9484..e1bc8b4 100644 (file)
@@ -148,7 +148,8 @@ static int process_rdma(struct rtrs_srv *sess,
        /* Generate bio with pages pointing to the rdma buffer */
        bio = rnbd_bio_map_kern(data, sess_dev->rnbd_dev->ibd_bio_set, datalen, GFP_KERNEL);
        if (IS_ERR(bio)) {
-               rnbd_srv_err(sess_dev, "Failed to generate bio, err: %ld\n", PTR_ERR(bio));
+               err = PTR_ERR(bio);
+               rnbd_srv_err(sess_dev, "Failed to generate bio, err: %d\n", err);
                goto sess_dev_put;
        }
 
index 7e26122..8799e3b 100644 (file)
@@ -425,7 +425,7 @@ static void card_state_change(struct rsxx_cardinfo *card,
                 * Fall through so the DMA devices can be attached and
                 * the user can attempt to pull off their data.
                 */
-               /* fall through */
+               fallthrough;
        case CARD_STATE_GOOD:
                st = rsxx_get_card_size8(card, &card->size8);
                if (st)
index 3a476dc..ae6454c 100644 (file)
@@ -1436,7 +1436,7 @@ static void skd_resolve_req_exception(struct skd_device *skdev,
                        blk_mq_requeue_request(req, true);
                        break;
                }
-               /* fall through */
+               fallthrough;
 
        case SKD_CHECK_STATUS_REPORT_ERROR:
        default:
index 63b213e..b2e48da 100644 (file)
@@ -126,16 +126,31 @@ static int virtblk_setup_discard_write_zeroes(struct request *req, bool unmap)
        if (!range)
                return -ENOMEM;
 
-       __rq_for_each_bio(bio, req) {
-               u64 sector = bio->bi_iter.bi_sector;
-               u32 num_sectors = bio->bi_iter.bi_size >> SECTOR_SHIFT;
-
-               range[n].flags = cpu_to_le32(flags);
-               range[n].num_sectors = cpu_to_le32(num_sectors);
-               range[n].sector = cpu_to_le64(sector);
-               n++;
+       /*
+        * Single max discard segment means multi-range discard isn't
+        * supported, and block layer only runs contiguity merge like
+        * normal RW request. So we can't reply on bio for retrieving
+        * each range info.
+        */
+       if (queue_max_discard_segments(req->q) == 1) {
+               range[0].flags = cpu_to_le32(flags);
+               range[0].num_sectors = cpu_to_le32(blk_rq_sectors(req));
+               range[0].sector = cpu_to_le64(blk_rq_pos(req));
+               n = 1;
+       } else {
+               __rq_for_each_bio(bio, req) {
+                       u64 sector = bio->bi_iter.bi_sector;
+                       u32 num_sectors = bio->bi_iter.bi_size >> SECTOR_SHIFT;
+
+                       range[n].flags = cpu_to_le32(flags);
+                       range[n].num_sectors = cpu_to_le32(num_sectors);
+                       range[n].sector = cpu_to_le64(sector);
+                       n++;
+               }
        }
 
+       WARN_ON_ONCE(n != segments);
+
        req->special_vec.bv_page = virt_to_page(range);
        req->special_vec.bv_offset = offset_in_page(range);
        req->special_vec.bv_len = sizeof(*range) * segments;
index c2f7126..adfc935 100644 (file)
@@ -1260,7 +1260,7 @@ static int dispatch_rw_block_io(struct xen_blkif_ring *ring,
                break;
        case BLKIF_OP_WRITE_BARRIER:
                drain = true;
-               /* fall through */
+               fallthrough;
        case BLKIF_OP_FLUSH_DISKCACHE:
                ring->st_f_req++;
                operation = REQ_OP_WRITE;
index 42944d4..b9aa5d1 100644 (file)
@@ -843,7 +843,7 @@ static void frontend_changed(struct xenbus_device *dev,
                xenbus_switch_state(dev, XenbusStateClosed);
                if (xenbus_dev_is_online(dev))
                        break;
-               /* fall through */
+               fallthrough;
                /* if not online */
        case XenbusStateUnknown:
                /* implies xen_blkif_disconnect() via xen_blkbk_remove() */
index 3bb3dd8..91de2e0 100644 (file)
@@ -1403,7 +1403,6 @@ static enum blk_req_status blkif_rsp_to_req_status(int rsp)
        case BLKIF_RSP_EOPNOTSUPP:
                return REQ_EOPNOTSUPP;
        case BLKIF_RSP_ERROR:
-               /* Fallthrough. */
        default:
                return REQ_ERROR;
        }
@@ -1643,7 +1642,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                                info->feature_flush = 0;
                                xlvbd_flush(info);
                        }
-                       /* fall through */
+                       fallthrough;
                case BLKIF_OP_READ:
                case BLKIF_OP_WRITE:
                        if (unlikely(bret->status != BLKIF_RSP_OKAY))
@@ -2484,7 +2483,7 @@ static void blkback_changed(struct xenbus_device *dev,
        case XenbusStateClosed:
                if (dev->state == XenbusStateClosed)
                        break;
-               /* fall through */
+               fallthrough;
        case XenbusStateClosing:
                if (info)
                        blkfront_closing(info);
index fb5a901..efb088d 100644 (file)
@@ -1849,7 +1849,7 @@ static int sysc_clockdomain_init(struct sysc *ddata)
        switch (ddata->nr_clocks) {
        case 2:
                ick = ddata->clocks[SYSC_ICK];
-               /* fallthrough */
+               fallthrough;
        case 1:
                fck = ddata->clocks[SYSC_FCK];
                break;
index 89527ba..760d9a9 100644 (file)
@@ -357,7 +357,7 @@ found:
                default:
                        break;
                }
-               /*FALLTHROUGH*/
+               fallthrough;
        default:
                bridge->driver = &ali_generic_bridge;
        }
index f976a49..e92c4d9 100644 (file)
@@ -282,6 +282,20 @@ config HW_RANDOM_INGENIC_RNG
 
          If unsure, say Y.
 
+config HW_RANDOM_INGENIC_TRNG
+       tristate "Ingenic True Random Number Generator support"
+       depends on HW_RANDOM
+       depends on MACH_X1830
+       default HW_RANDOM
+       help
+         This driver provides kernel-side support for the True Random Number Generator
+         hardware found in ingenic X1830 SoC. YSH & ATIL CU1830-Neo uses X1830 SoC.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ingenic-trng.
+
+         If unsure, say Y.
+
 config HW_RANDOM_NOMADIK
        tristate "ST-Ericsson Nomadik Random Number Generator support"
        depends on ARCH_NOMADIK
@@ -512,6 +526,16 @@ config HW_RANDOM_CCTRNG
          will be called cctrng.
          If unsure, say 'N'.
 
+config HW_RANDOM_XIPHERA
+       tristate "Xiphera FPGA based True Random Number Generator support"
+       depends on HAS_IOMEM
+       help
+         This driver provides kernel-side support for Xiphera True Random
+         Number Generator Intellectual Property Core.
+
+         To compile this driver as a module, choose M here: the
+         module will be called xiphera-trng.
+
 endif # HW_RANDOM
 
 config UML_RANDOM
index 26ae068..5da3445 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
 obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
 obj-$(CONFIG_HW_RANDOM_IMX_RNGC) += imx-rngc.o
 obj-$(CONFIG_HW_RANDOM_INGENIC_RNG) += ingenic-rng.o
+obj-$(CONFIG_HW_RANDOM_INGENIC_TRNG) += ingenic-trng.o
 obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
 obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
 obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
@@ -44,3 +45,4 @@ obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
 obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
 obj-$(CONFIG_HW_RANDOM_NPCM) += npcm-rng.o
 obj-$(CONFIG_HW_RANDOM_CCTRNG) += cctrng.o
+obj-$(CONFIG_HW_RANDOM_XIPHERA) += xiphera-trng.o
index 619148f..7a293f2 100644 (file)
@@ -463,11 +463,10 @@ static int cc_trng_clk_init(struct cctrng_drvdata *drvdata)
        int rc = 0;
 
        clk = devm_clk_get_optional(dev, NULL);
-       if (IS_ERR(clk)) {
-               if (PTR_ERR(clk) != -EPROBE_DEFER)
-                       dev_err(dev, "Error getting clock: %pe\n", clk);
-               return PTR_ERR(clk);
-       }
+       if (IS_ERR(clk))
+               return dev_err_probe(dev, PTR_ERR(clk),
+                                    "Error getting clock\n");
+
        drvdata->clk = clk;
 
        rc = clk_prepare_enable(drvdata->clk);
index 9c47e43..61c844b 100644 (file)
@@ -285,6 +285,7 @@ static int imx_rngc_probe(struct platform_device *pdev)
        rngc->rng.init = imx_rngc_init;
        rngc->rng.read = imx_rngc_read;
        rngc->rng.cleanup = imx_rngc_cleanup;
+       rngc->rng.quality = 19;
 
        rngc->dev = &pdev->dev;
        platform_set_drvdata(pdev, rngc);
index d704cef..055cfe5 100644 (file)
@@ -92,8 +92,7 @@ static int ingenic_rng_probe(struct platform_device *pdev)
        priv->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->base)) {
                pr_err("%s: Failed to map RNG registers\n", __func__);
-               ret = PTR_ERR(priv->base);
-               goto err_free_rng;
+               return PTR_ERR(priv->base);
        }
 
        priv->version = (enum ingenic_rng_version)of_device_get_match_data(&pdev->dev);
@@ -106,17 +105,13 @@ static int ingenic_rng_probe(struct platform_device *pdev)
        ret = hwrng_register(&priv->rng);
        if (ret) {
                dev_err(&pdev->dev, "Failed to register hwrng\n");
-               goto err_free_rng;
+               return ret;
        }
 
        platform_set_drvdata(pdev, priv);
 
        dev_info(&pdev->dev, "Ingenic RNG driver registered\n");
        return 0;
-
-err_free_rng:
-       kfree(priv);
-       return ret;
 }
 
 static int ingenic_rng_remove(struct platform_device *pdev)
diff --git a/drivers/char/hw_random/ingenic-trng.c b/drivers/char/hw_random/ingenic-trng.c
new file mode 100644 (file)
index 0000000..954a841
--- /dev/null
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ingenic True Random Number Generator driver
+ * Copyright (c) 2019 漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>
+ * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* DTRNG register offsets */
+#define TRNG_REG_CFG_OFFSET                    0x00
+#define TRNG_REG_RANDOMNUM_OFFSET      0x04
+#define TRNG_REG_STATUS_OFFSET         0x08
+
+/* bits within the CFG register */
+#define CFG_RDY_CLR                                    BIT(12)
+#define CFG_INT_MASK                           BIT(11)
+#define CFG_GEN_EN                                     BIT(0)
+
+/* bits within the STATUS register */
+#define STATUS_RANDOM_RDY                      BIT(0)
+
+struct ingenic_trng {
+       void __iomem *base;
+       struct clk *clk;
+       struct hwrng rng;
+};
+
+static int ingenic_trng_init(struct hwrng *rng)
+{
+       struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng);
+       unsigned int ctrl;
+
+       ctrl = readl(trng->base + TRNG_REG_CFG_OFFSET);
+       ctrl |= CFG_GEN_EN;
+       writel(ctrl, trng->base + TRNG_REG_CFG_OFFSET);
+
+       return 0;
+}
+
+static void ingenic_trng_cleanup(struct hwrng *rng)
+{
+       struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng);
+       unsigned int ctrl;
+
+       ctrl = readl(trng->base + TRNG_REG_CFG_OFFSET);
+       ctrl &= ~CFG_GEN_EN;
+       writel(ctrl, trng->base + TRNG_REG_CFG_OFFSET);
+}
+
+static int ingenic_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+       struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng);
+       u32 *data = buf;
+       u32 status;
+       int ret;
+
+       ret = readl_poll_timeout(trng->base + TRNG_REG_STATUS_OFFSET, status,
+                                status & STATUS_RANDOM_RDY, 10, 1000);
+       if (ret == -ETIMEDOUT) {
+               pr_err("%s: Wait for DTRNG data ready timeout\n", __func__);
+               return ret;
+       }
+
+       *data = readl(trng->base + TRNG_REG_RANDOMNUM_OFFSET);
+
+       return 4;
+}
+
+static int ingenic_trng_probe(struct platform_device *pdev)
+{
+       struct ingenic_trng *trng;
+       int ret;
+
+       trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
+       if (!trng)
+               return -ENOMEM;
+
+       trng->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(trng->base)) {
+               pr_err("%s: Failed to map DTRNG registers\n", __func__);
+               ret = PTR_ERR(trng->base);
+               return PTR_ERR(trng->base);
+       }
+
+       trng->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(trng->clk)) {
+               ret = PTR_ERR(trng->clk);
+               pr_crit("%s: Cannot get DTRNG clock\n", __func__);
+               return PTR_ERR(trng->clk);
+       }
+
+       ret = clk_prepare_enable(trng->clk);
+       if (ret) {
+               pr_crit("%s: Unable to enable DTRNG clock\n", __func__);
+               return ret;
+       }
+
+       trng->rng.name = pdev->name;
+       trng->rng.init = ingenic_trng_init;
+       trng->rng.cleanup = ingenic_trng_cleanup;
+       trng->rng.read = ingenic_trng_read;
+
+       ret = hwrng_register(&trng->rng);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register hwrng\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, trng);
+
+       dev_info(&pdev->dev, "Ingenic DTRNG driver registered\n");
+       return 0;
+}
+
+static int ingenic_trng_remove(struct platform_device *pdev)
+{
+       struct ingenic_trng *trng = platform_get_drvdata(pdev);
+       unsigned int ctrl;
+
+       hwrng_unregister(&trng->rng);
+
+       ctrl = readl(trng->base + TRNG_REG_CFG_OFFSET);
+       ctrl &= ~CFG_GEN_EN;
+       writel(ctrl, trng->base + TRNG_REG_CFG_OFFSET);
+
+       clk_disable_unprepare(trng->clk);
+
+       return 0;
+}
+
+static const struct of_device_id ingenic_trng_of_match[] = {
+       { .compatible = "ingenic,x1830-dtrng" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ingenic_trng_of_match);
+
+static struct platform_driver ingenic_trng_driver = {
+       .probe          = ingenic_trng_probe,
+       .remove         = ingenic_trng_remove,
+       .driver         = {
+               .name   = "ingenic-trng",
+               .of_match_table = ingenic_trng_of_match,
+       },
+};
+
+module_platform_driver(ingenic_trng_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>");
+MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
+MODULE_DESCRIPTION("Ingenic True Random Number Generator driver");
index 9f205bd..eb7db27 100644 (file)
@@ -330,7 +330,7 @@ static int __init mod_init(void)
        int err = -ENODEV;
        int i;
        struct pci_dev *dev = NULL;
-       void __iomem *mem = mem;
+       void __iomem *mem;
        u8 hw_status;
        struct intel_rng_hw *intel_rng_hw;
 
index 32d9fe6..01583fa 100644 (file)
@@ -195,10 +195,10 @@ static int iproc_rng200_probe(struct platform_device *pdev)
                return PTR_ERR(priv->base);
        }
 
-       priv->rng.name = "iproc-rng200",
-       priv->rng.read = iproc_rng200_read,
-       priv->rng.init = iproc_rng200_init,
-       priv->rng.cleanup = iproc_rng200_cleanup,
+       priv->rng.name = "iproc-rng200";
+       priv->rng.read = iproc_rng200_read;
+       priv->rng.init = iproc_rng200_init;
+       priv->rng.cleanup = iproc_rng200_cleanup;
 
        /* Register driver */
        ret = devm_hwrng_register(dev, &priv->rng);
index 025083c..008763c 100644 (file)
@@ -143,9 +143,9 @@ static int __init mxc_rnga_probe(struct platform_device *pdev)
        mxc_rng->dev = &pdev->dev;
        mxc_rng->rng.name = "mxc-rnga";
        mxc_rng->rng.init = mxc_rnga_init;
-       mxc_rng->rng.cleanup = mxc_rnga_cleanup,
-       mxc_rng->rng.data_present = mxc_rnga_data_present,
-       mxc_rng->rng.data_read = mxc_rnga_data_read,
+       mxc_rng->rng.cleanup = mxc_rnga_cleanup;
+       mxc_rng->rng.data_present = mxc_rnga_data_present;
+       mxc_rng->rng.data_read = mxc_rnga_data_read;
 
        mxc_rng->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(mxc_rng->clk)) {
index 5d0d13f..1ec5f26 100644 (file)
@@ -58,24 +58,24 @@ static int npcm_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
 
        pm_runtime_get_sync((struct device *)priv->rng.priv);
 
-       while (max >= sizeof(u32)) {
+       while (max) {
                if (wait) {
-                       if (readl_poll_timeout(priv->base + NPCM_RNGCS_REG,
+                       if (readb_poll_timeout(priv->base + NPCM_RNGCS_REG,
                                               ready,
                                               ready & NPCM_RNG_DATA_VALID,
                                               NPCM_RNG_POLL_USEC,
                                               NPCM_RNG_TIMEOUT_USEC))
                                break;
                } else {
-                       if ((readl(priv->base + NPCM_RNGCS_REG) &
+                       if ((readb(priv->base + NPCM_RNGCS_REG) &
                            NPCM_RNG_DATA_VALID) == 0)
                                break;
                }
 
-               *(u32 *)buf = readl(priv->base + NPCM_RNGD_REG);
-               retval += sizeof(u32);
-               buf += sizeof(u32);
-               max -= sizeof(u32);
+               *(u8 *)buf = readb(priv->base + NPCM_RNGD_REG);
+               retval++;
+               buf++;
+               max--;
        }
 
        pm_runtime_mark_last_busy((struct device *)priv->rng.priv);
index 49b2e02..a99d829 100644 (file)
@@ -122,14 +122,14 @@ static int optee_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
        if (max > MAX_ENTROPY_REQ_SZ)
                max = MAX_ENTROPY_REQ_SZ;
 
-       while (read == 0) {
+       while (read < max) {
                rng_size = get_optee_rng_data(pvt_data, data, (max - read));
 
                data += rng_size;
                read += rng_size;
 
-               if (wait) {
-                       if (timeout-- == 0)
+               if (wait && pvt_data->data_rate) {
+                       if ((timeout-- == 0) || (read == max))
                                return read;
                        msleep((1000 * (max - read)) / pvt_data->data_rate);
                } else {
index 38324c2..bc22178 100644 (file)
@@ -145,12 +145,12 @@ static int stm32_rng_probe(struct platform_device *ofdev)
 
        dev_set_drvdata(dev, priv);
 
-       priv->rng.name = dev_driver_string(dev),
+       priv->rng.name = dev_driver_string(dev);
 #ifndef CONFIG_PM
-       priv->rng.init = stm32_rng_init,
-       priv->rng.cleanup = stm32_rng_cleanup,
+       priv->rng.init = stm32_rng_init;
+       priv->rng.cleanup = stm32_rng_cleanup;
 #endif
-       priv->rng.read = stm32_rng_read,
+       priv->rng.read = stm32_rng_read;
        priv->rng.priv = (unsigned long) dev;
        priv->rng.quality = 900;
 
diff --git a/drivers/char/hw_random/xiphera-trng.c b/drivers/char/hw_random/xiphera-trng.c
new file mode 100644 (file)
index 0000000..7bdab8c
--- /dev/null
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2020 Xiphera Ltd. */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/hw_random.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#define CONTROL_REG                    0x00000000
+#define STATUS_REG                     0x00000004
+#define RAND_REG                       0x00000000
+
+#define HOST_TO_TRNG_RESET             0x00000001
+#define HOST_TO_TRNG_RELEASE_RESET     0x00000002
+#define HOST_TO_TRNG_ENABLE            0x80000000
+#define HOST_TO_TRNG_ZEROIZE           0x80000004
+#define HOST_TO_TRNG_ACK_ZEROIZE       0x80000008
+#define HOST_TO_TRNG_READ              0x8000000F
+
+/* trng statuses */
+#define TRNG_ACK_RESET                 0x000000AC
+#define TRNG_SUCCESSFUL_STARTUP                0x00000057
+#define TRNG_FAILED_STARTUP            0x000000FA
+#define TRNG_NEW_RAND_AVAILABLE                0x000000ED
+
+struct xiphera_trng {
+       void __iomem *mem;
+       struct hwrng rng;
+};
+
+static int xiphera_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+       struct xiphera_trng *trng = container_of(rng, struct xiphera_trng, rng);
+       int ret = 0;
+
+       while (max >= sizeof(u32)) {
+               /* check for data */
+               if (readl(trng->mem + STATUS_REG) == TRNG_NEW_RAND_AVAILABLE) {
+                       *(u32 *)buf = readl(trng->mem + RAND_REG);
+                       /*
+                        * Inform the trng of the read
+                        * and re-enable it to produce a new random number
+                        */
+                       writel(HOST_TO_TRNG_READ, trng->mem + CONTROL_REG);
+                       writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG);
+                       ret += sizeof(u32);
+                       buf += sizeof(u32);
+                       max -= sizeof(u32);
+               } else {
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int xiphera_trng_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct xiphera_trng *trng;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+
+       trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL);
+       if (!trng)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       trng->mem = devm_ioremap_resource(dev, res);
+       if (IS_ERR(trng->mem))
+               return PTR_ERR(trng->mem);
+
+       /*
+        * the trng needs to be reset first which might not happen in time,
+        * hence we incorporate a small delay to ensure proper behaviour
+        */
+       writel(HOST_TO_TRNG_RESET, trng->mem + CONTROL_REG);
+       usleep_range(100, 200);
+
+       if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) {
+               /*
+                * there is a small chance the trng is just not ready yet,
+                * so we try one more time. If the second time fails, we give up
+                */
+               usleep_range(100, 200);
+               if (readl(trng->mem + STATUS_REG) != TRNG_ACK_RESET) {
+                       dev_err(dev, "failed to reset the trng ip\n");
+                       return -ENODEV;
+               }
+       }
+
+       /*
+        * once again, to ensure proper behaviour we sleep
+        * for a while after zeroizing the trng
+        */
+       writel(HOST_TO_TRNG_RELEASE_RESET, trng->mem + CONTROL_REG);
+       writel(HOST_TO_TRNG_ENABLE, trng->mem + CONTROL_REG);
+       writel(HOST_TO_TRNG_ZEROIZE, trng->mem + CONTROL_REG);
+       msleep(20);
+
+       if (readl(trng->mem + STATUS_REG) != TRNG_SUCCESSFUL_STARTUP) {
+               /* diagnose the reason for the failure */
+               if (readl(trng->mem + STATUS_REG) == TRNG_FAILED_STARTUP) {
+                       dev_err(dev, "trng ip startup-tests failed\n");
+                       return -ENODEV;
+               }
+               dev_err(dev, "startup-tests yielded no response\n");
+               return -ENODEV;
+       }
+
+       writel(HOST_TO_TRNG_ACK_ZEROIZE, trng->mem + CONTROL_REG);
+
+       trng->rng.name = pdev->name;
+       trng->rng.read = xiphera_trng_read;
+       trng->rng.quality = 900;
+
+       ret = devm_hwrng_register(dev, &trng->rng);
+       if (ret) {
+               dev_err(dev, "failed to register rng device: %d\n", ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, trng);
+
+       return 0;
+}
+
+static const struct of_device_id xiphera_trng_of_match[] = {
+       { .compatible = "xiphera,xip8001b-trng", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xiphera_trng_of_match);
+
+static struct platform_driver xiphera_trng_driver = {
+       .driver = {
+               .name = "xiphera-trng",
+               .of_match_table = xiphera_trng_of_match,
+       },
+       .probe = xiphera_trng_probe,
+};
+
+module_platform_driver(xiphera_trng_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Atte Tommiska");
+MODULE_DESCRIPTION("Xiphera FPGA-based true random number generator driver");
index ed4dc3b..f292e74 100644 (file)
@@ -99,7 +99,7 @@ static void kcs_bmc_handle_data(struct kcs_bmc *kcs_bmc)
        switch (kcs_bmc->phase) {
        case KCS_PHASE_WRITE_START:
                kcs_bmc->phase = KCS_PHASE_WRITE_DATA;
-               /* fall through */
+               fallthrough;
 
        case KCS_PHASE_WRITE_DATA:
                if (kcs_bmc->data_in_idx < KCS_MSG_BUFSIZ) {
index bd95aba..45932f0 100644 (file)
@@ -734,7 +734,7 @@ static long lp_ioctl(struct file *file, unsigned int cmd,
                        ret = lp_set_timeout32(minor, (void __user *)arg);
                        break;
                }
-               /* fall through - for 64-bit */
+               fallthrough;    /* for 64-bit */
        case LPSETTIMEOUT_NEW:
                ret = lp_set_timeout64(minor, (void __user *)arg);
                break;
@@ -762,7 +762,7 @@ static long lp_compat_ioctl(struct file *file, unsigned int cmd,
                        ret = lp_set_timeout32(minor, (void __user *)arg);
                        break;
                }
-               /* fall through - for x32 mode */
+               fallthrough;    /* for x32 mode */
        case LPSETTIMEOUT_NEW:
                ret = lp_set_timeout64(minor, (void __user *)arg);
                break;
index 687d4af..abd4ffd 100644 (file)
@@ -791,7 +791,7 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
        switch (orig) {
        case SEEK_CUR:
                offset += file->f_pos;
-               /* fall through */
+               fallthrough;
        case SEEK_SET:
                /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */
                if ((unsigned long long)offset >= -MAX_ERRNO) {
index 8206412..e9f694b 100644 (file)
@@ -286,7 +286,7 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
 #ifdef CONFIG_PPC
        case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
                pr_warn("nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
-               /* fall through */
+               fallthrough;
        case IOC_NVRAM_GET_OFFSET:
                ret = -EINVAL;
 #ifdef CONFIG_PPC_PMAC
index 58b4c57..a18c314 100644 (file)
@@ -74,6 +74,18 @@ config TCG_TIS_SPI_CR50
          If you have a H1 secure module running Cr50 firmware on SPI bus,
          say Yes and it will be accessible from within Linux.
 
+config TCG_TIS_SYNQUACER
+       tristate "TPM Interface Specification 1.2 Interface / TPM 2.0 FIFO Interface (MMIO - SynQuacer)"
+       depends on ARCH_SYNQUACER
+       select TCG_TIS_CORE
+       help
+         If you have a TPM security chip that is compliant with the
+         TCG TIS 1.2 TPM specification (TPM1.2) or the TCG PTP FIFO
+         specification (TPM2.0) say Yes and it will be accessible from
+         within Linux on Socionext SynQuacer platform.
+         To compile this driver as a module, choose  M here;
+         the module will be called tpm_tis_synquacer.
+
 config TCG_TIS_I2C_ATMEL
        tristate "TPM Interface Specification 1.2 Interface (I2C - Atmel)"
        depends on I2C
index 9567e51..84db4fb 100644 (file)
@@ -21,6 +21,7 @@ tpm-$(CONFIG_EFI) += eventlog/efi.o
 tpm-$(CONFIG_OF) += eventlog/of.o
 obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
 obj-$(CONFIG_TCG_TIS) += tpm_tis.o
+obj-$(CONFIG_TCG_TIS_SYNQUACER) += tpm_tis_synquacer.o
 
 obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o
 tpm_tis_spi-y := tpm_tis_spi_main.o
index d52bf4d..e2ff0b2 100644 (file)
@@ -56,31 +56,20 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
        out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
        str +=
            sprintf(str,
-                   "Algorithm: %02X %02X %02X %02X\n"
-                   "Encscheme: %02X %02X\n"
-                   "Sigscheme: %02X %02X\n"
-                   "Parameters: %02X %02X %02X %02X "
-                   "%02X %02X %02X %02X "
-                   "%02X %02X %02X %02X\n"
+                   "Algorithm: %4ph\n"
+                   "Encscheme: %2ph\n"
+                   "Sigscheme: %2ph\n"
+                   "Parameters: %12ph\n"
                    "Modulus length: %d\n"
                    "Modulus:\n",
-                   out->algorithm[0], out->algorithm[1], out->algorithm[2],
-                   out->algorithm[3],
-                   out->encscheme[0], out->encscheme[1],
-                   out->sigscheme[0], out->sigscheme[1],
-                   out->parameters[0], out->parameters[1],
-                   out->parameters[2], out->parameters[3],
-                   out->parameters[4], out->parameters[5],
-                   out->parameters[6], out->parameters[7],
-                   out->parameters[8], out->parameters[9],
-                   out->parameters[10], out->parameters[11],
+                   out->algorithm,
+                   out->encscheme,
+                   out->sigscheme,
+                   out->parameters,
                    be32_to_cpu(out->keysize));
 
-       for (i = 0; i < 256; i++) {
-               str += sprintf(str, "%02X ", out->modulus[i]);
-               if ((i + 1) % 16 == 0)
-                       str += sprintf(str, "\n");
-       }
+       for (i = 0; i < 256; i += 16)
+               str += sprintf(str, "%16ph\n", &out->modulus[i]);
 
 out_buf:
        tpm_buf_destroy(&tpm_buf);
index 65ab1b0..92c51c6 100644 (file)
@@ -239,6 +239,17 @@ static u8 tpm_tis_status(struct tpm_chip *chip)
        if (rc < 0)
                return 0;
 
+       if (unlikely((status & TPM_STS_READ_ZERO) != 0)) {
+               /*
+                * If this trips, the chances are the read is
+                * returning 0xff because the locality hasn't been
+                * acquired.  Usually because tpm_try_get_ops() hasn't
+                * been called before doing a TPM operation.
+                */
+               WARN_ONCE(1, "TPM returned invalid status\n");
+               return 0;
+       }
+
        return status;
 }
 
index 7337819..9b2d32a 100644 (file)
@@ -34,6 +34,7 @@ enum tis_status {
        TPM_STS_GO = 0x20,
        TPM_STS_DATA_AVAIL = 0x10,
        TPM_STS_DATA_EXPECT = 0x08,
+       TPM_STS_READ_ZERO = 0x23, /* bits that must be zero on read */
 };
 
 enum tis_int_flags {
diff --git a/drivers/char/tpm/tpm_tis_synquacer.c b/drivers/char/tpm/tpm_tis_synquacer.c
new file mode 100644 (file)
index 0000000..e47bdd2
--- /dev/null
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 Linaro Ltd.
+ *
+ * This device driver implements MMIO TPM on SynQuacer Platform.
+ */
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/kernel.h>
+#include "tpm.h"
+#include "tpm_tis_core.h"
+
+/*
+ * irq > 0 means: use irq $irq;
+ * irq = 0 means: autoprobe for an irq;
+ * irq = -1 means: no irq support
+ */
+struct tpm_tis_synquacer_info {
+       struct resource res;
+       int irq;
+};
+
+struct tpm_tis_synquacer_phy {
+       struct tpm_tis_data priv;
+       void __iomem *iobase;
+};
+
+static inline struct tpm_tis_synquacer_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *data)
+{
+       return container_of(data, struct tpm_tis_synquacer_phy, priv);
+}
+
+static int tpm_tis_synquacer_read_bytes(struct tpm_tis_data *data, u32 addr,
+                                       u16 len, u8 *result)
+{
+       struct tpm_tis_synquacer_phy *phy = to_tpm_tis_tcg_phy(data);
+
+       while (len--)
+               *result++ = ioread8(phy->iobase + addr);
+
+       return 0;
+}
+
+static int tpm_tis_synquacer_write_bytes(struct tpm_tis_data *data, u32 addr,
+                                        u16 len, const u8 *value)
+{
+       struct tpm_tis_synquacer_phy *phy = to_tpm_tis_tcg_phy(data);
+
+       while (len--)
+               iowrite8(*value++, phy->iobase + addr);
+
+       return 0;
+}
+
+static int tpm_tis_synquacer_read16_bw(struct tpm_tis_data *data,
+                                      u32 addr, u16 *result)
+{
+       struct tpm_tis_synquacer_phy *phy = to_tpm_tis_tcg_phy(data);
+
+       /*
+        * Due to the limitation of SPI controller on SynQuacer,
+        * 16/32 bits access must be done in byte-wise and descending order.
+        */
+       *result = (ioread8(phy->iobase + addr + 1) << 8) |
+                 (ioread8(phy->iobase + addr));
+
+       return 0;
+}
+
+static int tpm_tis_synquacer_read32_bw(struct tpm_tis_data *data,
+                                      u32 addr, u32 *result)
+{
+       struct tpm_tis_synquacer_phy *phy = to_tpm_tis_tcg_phy(data);
+
+       /*
+        * Due to the limitation of SPI controller on SynQuacer,
+        * 16/32 bits access must be done in byte-wise and descending order.
+        */
+       *result = (ioread8(phy->iobase + addr + 3) << 24) |
+                 (ioread8(phy->iobase + addr + 2) << 16) |
+                 (ioread8(phy->iobase + addr + 1) << 8) |
+                 (ioread8(phy->iobase + addr));
+
+       return 0;
+}
+
+static int tpm_tis_synquacer_write32_bw(struct tpm_tis_data *data,
+                                       u32 addr, u32 value)
+{
+       struct tpm_tis_synquacer_phy *phy = to_tpm_tis_tcg_phy(data);
+
+       /*
+        * Due to the limitation of SPI controller on SynQuacer,
+        * 16/32 bits access must be done in byte-wise and descending order.
+        */
+       iowrite8(value >> 24, phy->iobase + addr + 3);
+       iowrite8(value >> 16, phy->iobase + addr + 2);
+       iowrite8(value >> 8, phy->iobase + addr + 1);
+       iowrite8(value, phy->iobase + addr);
+
+       return 0;
+}
+
+static const struct tpm_tis_phy_ops tpm_tcg_bw = {
+       .read_bytes     = tpm_tis_synquacer_read_bytes,
+       .write_bytes    = tpm_tis_synquacer_write_bytes,
+       .read16         = tpm_tis_synquacer_read16_bw,
+       .read32         = tpm_tis_synquacer_read32_bw,
+       .write32        = tpm_tis_synquacer_write32_bw,
+};
+
+static int tpm_tis_synquacer_init(struct device *dev,
+                                 struct tpm_tis_synquacer_info *tpm_info)
+{
+       struct tpm_tis_synquacer_phy *phy;
+
+       phy = devm_kzalloc(dev, sizeof(struct tpm_tis_synquacer_phy), GFP_KERNEL);
+       if (phy == NULL)
+               return -ENOMEM;
+
+       phy->iobase = devm_ioremap_resource(dev, &tpm_info->res);
+       if (IS_ERR(phy->iobase))
+               return PTR_ERR(phy->iobase);
+
+       return tpm_tis_core_init(dev, &phy->priv, tpm_info->irq, &tpm_tcg_bw,
+                                ACPI_HANDLE(dev));
+}
+
+static SIMPLE_DEV_PM_OPS(tpm_tis_synquacer_pm, tpm_pm_suspend, tpm_tis_resume);
+
+static int tpm_tis_synquacer_probe(struct platform_device *pdev)
+{
+       struct tpm_tis_synquacer_info tpm_info = {};
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no memory resource defined\n");
+               return -ENODEV;
+       }
+       tpm_info.res = *res;
+
+       tpm_info.irq = -1;
+
+       return tpm_tis_synquacer_init(&pdev->dev, &tpm_info);
+}
+
+static int tpm_tis_synquacer_remove(struct platform_device *pdev)
+{
+       struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
+
+       tpm_chip_unregister(chip);
+       tpm_tis_remove(chip);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id tis_synquacer_of_platform_match[] = {
+       {.compatible = "socionext,synquacer-tpm-mmio"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, tis_synquacer_of_platform_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id tpm_synquacer_acpi_tbl[] = {
+       { "SCX0009" },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, tpm_synquacer_acpi_tbl);
+#endif
+
+static struct platform_driver tis_synquacer_drv = {
+       .probe = tpm_tis_synquacer_probe,
+       .remove = tpm_tis_synquacer_remove,
+       .driver = {
+               .name           = "tpm_tis_synquacer",
+               .pm             = &tpm_tis_synquacer_pm,
+               .of_match_table = of_match_ptr(tis_synquacer_of_platform_match),
+               .acpi_match_table = ACPI_PTR(tpm_synquacer_acpi_tbl),
+       },
+};
+
+static int __init tpm_tis_synquacer_module_init(void)
+{
+       int rc;
+
+       rc = platform_driver_register(&tis_synquacer_drv);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static void __exit tpm_tis_synquacer_module_exit(void)
+{
+       platform_driver_unregister(&tis_synquacer_drv);
+}
+
+module_init(tpm_tis_synquacer_module_init);
+module_exit(tpm_tis_synquacer_module_exit);
+MODULE_DESCRIPTION("TPM MMIO Driver for Socionext SynQuacer platform");
+MODULE_LICENSE("GPL");
index 784f12c..ec738f7 100644 (file)
@@ -5,6 +5,7 @@ config CLK_BCM2711_DVP
        depends on ARCH_BCM2835 ||COMPILE_TEST
        depends on COMMON_CLK
        default ARCH_BCM2835
+       select RESET_CONTROLLER
        select RESET_SIMPLE
        help
          Enable common clock framework support for the Broadcom BCM2711
index 6c35e4b..0d75043 100644 (file)
@@ -491,7 +491,7 @@ struct clk *davinci_pll_clk_register(struct device *dev,
                parent_name = postdiv_name;
        }
 
-       pllen = kzalloc(sizeof(*pllout), GFP_KERNEL);
+       pllen = kzalloc(sizeof(*pllen), GFP_KERNEL);
        if (!pllen) {
                ret = -ENOMEM;
                goto err_unregister_postdiv;
index d4c1864..228d08f 100644 (file)
@@ -420,17 +420,18 @@ static int lpass_core_sc7180_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        ret = pm_clk_create(&pdev->dev);
        if (ret)
-               return ret;
+               goto disable_pm_runtime;
 
        ret = pm_clk_add(&pdev->dev, "iface");
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to acquire iface clock\n");
-               goto disable_pm_runtime;
+               goto destroy_pm_clk;
        }
 
+       ret = -EINVAL;
        clk_probe = of_device_get_match_data(&pdev->dev);
        if (!clk_probe)
-               return -EINVAL;
+               goto destroy_pm_clk;
 
        ret = clk_probe(pdev);
        if (ret)
index d7243c0..47d6482 100644 (file)
@@ -137,7 +137,7 @@ PNAME(mux_usb480m_p)                = { "usb480m_phy", "xin24m" };
 PNAME(mux_hdmiphy_p)           = { "hdmiphy_phy", "xin24m" };
 PNAME(mux_aclk_cpu_src_p)      = { "cpll_aclk_cpu", "gpll_aclk_cpu", "hdmiphy_aclk_cpu" };
 
-PNAME(mux_pll_src_4plls_p)     = { "cpll", "gpll", "hdmiphy" "usb480m" };
+PNAME(mux_pll_src_4plls_p)     = { "cpll", "gpll", "hdmiphy", "usb480m" };
 PNAME(mux_pll_src_3plls_p)     = { "cpll", "gpll", "hdmiphy" };
 PNAME(mux_pll_src_2plls_p)     = { "cpll", "gpll" };
 PNAME(mux_sclk_hdmi_cec_p)     = { "cpll", "gpll", "xin24m" };
index 51564fc..f408628 100644 (file)
@@ -927,7 +927,7 @@ static const struct samsung_gate_clock exynos4210_gate_clks[] __initconst = {
        GATE(CLK_PCIE, "pcie", "aclk133", GATE_IP_FSYS, 14, 0, 0),
        GATE(CLK_SMMU_PCIE, "smmu_pcie", "aclk133", GATE_IP_FSYS, 18, 0, 0),
        GATE(CLK_MODEMIF, "modemif", "aclk100", GATE_IP_PERIL, 28, 0, 0),
-       GATE(CLK_CHIPID, "chipid", "aclk100", E4210_GATE_IP_PERIR, 0, 0, 0),
+       GATE(CLK_CHIPID, "chipid", "aclk100", E4210_GATE_IP_PERIR, 0, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SYSREG, "sysreg", "aclk100", E4210_GATE_IP_PERIR, 0,
                        CLK_IGNORE_UNUSED, 0),
        GATE(CLK_HDMI_CEC, "hdmi_cec", "aclk100", E4210_GATE_IP_PERIR, 11, 0,
@@ -969,7 +969,7 @@ static const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = {
                0),
        GATE(CLK_TSADC, "tsadc", "aclk133", E4X12_GATE_BUS_FSYS1, 16, 0, 0),
        GATE(CLK_MIPI_HSI, "mipi_hsi", "aclk133", GATE_IP_FSYS, 10, 0, 0),
-       GATE(CLK_CHIPID, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, 0, 0),
+       GATE(CLK_CHIPID, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, CLK_IGNORE_UNUSED, 0),
        GATE(CLK_SYSREG, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1,
                        CLK_IGNORE_UNUSED, 0),
        GATE(CLK_HDMI_CEC, "hdmi_cec", "aclk100", E4X12_GATE_IP_PERIR, 11, 0,
index fea3339..bd62087 100644 (file)
@@ -1655,6 +1655,11 @@ static void __init exynos5x_clk_init(struct device_node *np,
         * main G3D clock enablement status.
         */
        clk_prepare_enable(__clk_lookup("mout_sw_aclk_g3d"));
+       /*
+        * Keep top BPLL mux enabled permanently to ensure that DRAM operates
+        * properly.
+        */
+       clk_prepare_enable(__clk_lookup("mout_bpll"));
 
        samsung_clk_of_add_provider(np, ctx);
 }
index c1dfc9b..661a8e9 100644 (file)
@@ -209,7 +209,7 @@ static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = {
        { STRATIX10_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux, ARRAY_SIZE(emacb_free_mux),
          0, 0, 2, 0xB0, 1},
        { STRATIX10_EMAC_PTP_FREE_CLK, "emac_ptp_free_clk", NULL, emac_ptp_free_mux,
-         ARRAY_SIZE(emac_ptp_free_mux), 0, 0, 4, 0xB0, 2},
+         ARRAY_SIZE(emac_ptp_free_mux), 0, 0, 2, 0xB0, 2},
        { STRATIX10_GPIO_DB_FREE_CLK, "gpio_db_free_clk", NULL, gpio_db_free_mux,
          ARRAY_SIZE(gpio_db_free_mux), 0, 0, 0, 0xB0, 3},
        { STRATIX10_SDMMC_FREE_CLK, "sdmmc_free_clk", NULL, sdmmc_free_mux,
index f180c05..c5cc0a2 100644 (file)
@@ -1611,9 +1611,6 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
        unsigned long flags = 0;
        unsigned long input_rate;
 
-       if (clk_pll_is_enabled(hw))
-               return 0;
-
        input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
 
        if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
@@ -1673,7 +1670,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
        pll_writel(val, PLLE_SS_CTRL, pll);
        udelay(1);
 
-       /* Enable hw control of xusb brick pll */
+       /* Enable HW control of XUSB brick PLL */
        val = pll_readl_misc(pll);
        val &= ~PLLE_MISC_IDDQ_SW_CTRL;
        pll_writel_misc(val, pll);
@@ -1696,7 +1693,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
        val |= XUSBIO_PLL_CFG0_SEQ_ENABLE;
        pll_writel(val, XUSBIO_PLL_CFG0, pll);
 
-       /* Enable hw control of SATA pll */
+       /* Enable HW control of SATA PLL */
        val = pll_readl(SATA_PLL_CFG0, pll);
        val &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL;
        val |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET;
index 352a2c3..51fd0ec 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 
+#include "clk.h"
+
 #define CLK_SOURCE_EMC 0x19c
 #define  CLK_SOURCE_EMC_2X_CLK_SRC GENMASK(31, 29)
 #define  CLK_SOURCE_EMC_MC_EMC_SAME_FREQ BIT(16)
index ca79824..85c395d 100644 (file)
@@ -109,8 +109,10 @@ static int integrator_impd1_clk_probe(struct platform_device *pdev)
 
        for_each_available_child_of_node(np, child) {
                ret = integrator_impd1_clk_spawn(dev, np, child);
-               if (ret)
+               if (ret) {
+                       of_node_put(child);
                        break;
+               }
        }
 
        return ret;
index 1d740a8..47114c2 100644 (file)
@@ -169,7 +169,7 @@ static int __init h8300_8timer_init(struct device_node *node)
                return PTR_ERR(clk);
        }
 
-       ret = ENXIO;
+       ret = -ENXIO;
        base = of_iomap(node, 0);
        if (!base) {
                pr_err("failed to map registers for clockevent\n");
index 2e64d98..efe8cad 100644 (file)
@@ -149,9 +149,9 @@ static int __init mps2_clockevent_init(struct device_node *np)
        ce->clkevt.rating = 200;
        ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
        ce->clkevt.cpumask = cpu_possible_mask;
-       ce->clkevt.set_state_shutdown   = mps2_timer_shutdown,
-       ce->clkevt.set_state_periodic   = mps2_timer_set_periodic,
-       ce->clkevt.set_state_oneshot    = mps2_timer_shutdown,
+       ce->clkevt.set_state_shutdown   = mps2_timer_shutdown;
+       ce->clkevt.set_state_periodic   = mps2_timer_set_periodic;
+       ce->clkevt.set_state_oneshot    = mps2_timer_shutdown;
        ce->clkevt.set_next_event       = mps2_timer_set_next_event;
 
        /* Ensure timer is disabled */
index edf1a46..e3acc3c 100644 (file)
@@ -181,12 +181,12 @@ static int armada_370_xp_timer_starting_cpu(unsigned int cpu)
                clr = TIMER0_25MHZ;
        local_timer_ctrl_clrset(clr, set);
 
-       evt->name               = "armada_370_xp_per_cpu_tick",
+       evt->name               = "armada_370_xp_per_cpu_tick";
        evt->features           = CLOCK_EVT_FEAT_ONESHOT |
                                  CLOCK_EVT_FEAT_PERIODIC;
-       evt->shift              = 32,
-       evt->rating             = 300,
-       evt->set_next_event     = armada_370_xp_clkevt_next_event,
+       evt->shift              = 32;
+       evt->rating             = 300;
+       evt->set_next_event     = armada_370_xp_clkevt_next_event;
        evt->set_state_shutdown = armada_370_xp_clkevt_shutdown;
        evt->set_state_periodic = armada_370_xp_clkevt_set_periodic;
        evt->set_state_oneshot  = armada_370_xp_clkevt_shutdown;
index 38858e1..80e9606 100644 (file)
@@ -309,7 +309,7 @@ static int ttc_rate_change_clocksource_cb(struct notifier_block *nb,
                /* restore original register value */
                writel_relaxed(ttccs->scale_clk_ctrl_reg_old,
                               ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
-               /* fall through */
+               fallthrough;
        default:
                return NOTIFY_DONE;
        }
@@ -392,7 +392,7 @@ static int ttc_rate_change_clockevent_cb(struct notifier_block *nb,
 
                clockevents_update_freq(&ttcce->ce, ndata->new_rate / PRESCALE);
 
-               /* fall through */
+               fallthrough;
        case PRE_RATE_CHANGE:
        case ABORT_RATE_CHANGE:
        default:
index 8eeafa8..6cfe2ab 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/of_irq.h>
 #include <linux/smp.h>
+#include <linux/timex.h>
+
+#ifndef CONFIG_RISCV_M_MODE
+#include <asm/clint.h>
+#endif
 
 #define CLINT_IPI_OFF          0
 #define CLINT_TIMER_CMP_OFF    0x4000
@@ -31,6 +36,11 @@ static u64 __iomem *clint_timer_val;
 static unsigned long clint_timer_freq;
 static unsigned int clint_timer_irq;
 
+#ifdef CONFIG_RISCV_M_MODE
+u64 __iomem *clint_time_val;
+EXPORT_SYMBOL(clint_time_val);
+#endif
+
 static void clint_send_ipi(const struct cpumask *target)
 {
        unsigned int cpu;
@@ -184,6 +194,14 @@ static int __init clint_timer_init_dt(struct device_node *np)
        clint_timer_val = base + CLINT_TIMER_VAL_OFF;
        clint_timer_freq = riscv_timebase;
 
+#ifdef CONFIG_RISCV_M_MODE
+       /*
+        * Yes, that's an odd naming scheme.  time_val is public, but hopefully
+        * will die in favor of something cleaner.
+        */
+       clint_time_val = clint_timer_val;
+#endif
+
        pr_info("%pOFP: timer running at %ld Hz\n", np, clint_timer_freq);
 
        rc = clocksource_register_hz(&clint_clocksource, clint_timer_freq);
index 80d0939..8d386ad 100644 (file)
@@ -28,6 +28,7 @@ static irqreturn_t gx6605s_timer_interrupt(int irq, void *dev)
        void __iomem *base = timer_of_base(to_timer_of(ce));
 
        writel_relaxed(GX6605S_STATUS_CLR, base + TIMER_STATUS);
+       writel_relaxed(0, base + TIMER_INI);
 
        ce->event_handler(ce);
 
index b2037eb..811f840 100644 (file)
@@ -10,6 +10,7 @@
  *
  * Every SP804 contains two identical timers.
  */
+#define NR_TIMERS      2
 #define TIMER_1_BASE   0x00
 #define TIMER_2_BASE   0x20
 
 #define TIMER_RIS      0x10                    /*  CVR ro */
 #define TIMER_MIS      0x14                    /*  CVR ro */
 #define TIMER_BGLOAD   0x18                    /*  CVR rw */
+
+struct sp804_timer {
+       int load;
+       int load_h;
+       int value;
+       int value_h;
+       int ctrl;
+       int intclr;
+       int ris;
+       int mis;
+       int bgload;
+       int bgload_h;
+       int timer_base[NR_TIMERS];
+       int width;
+};
+
+struct sp804_clkevt {
+       void __iomem *base;
+       void __iomem *load;
+       void __iomem *load_h;
+       void __iomem *value;
+       void __iomem *value_h;
+       void __iomem *ctrl;
+       void __iomem *intclr;
+       void __iomem *ris;
+       void __iomem *mis;
+       void __iomem *bgload;
+       void __iomem *bgload_h;
+       unsigned long reload;
+       int width;
+};
index 5cd0abf..6e8ad4a 100644 (file)
 #include <linux/of_irq.h>
 #include <linux/sched_clock.h>
 
-#include <clocksource/timer-sp804.h>
-
 #include "timer-sp.h"
 
-static long __init sp804_get_clock_rate(struct clk *clk)
+/* Hisilicon 64-bit timer(a variant of ARM SP804) */
+#define HISI_TIMER_1_BASE      0x00
+#define HISI_TIMER_2_BASE      0x40
+#define HISI_TIMER_LOAD                0x00
+#define HISI_TIMER_LOAD_H      0x04
+#define HISI_TIMER_VALUE       0x08
+#define HISI_TIMER_VALUE_H     0x0c
+#define HISI_TIMER_CTRL                0x10
+#define HISI_TIMER_INTCLR      0x14
+#define HISI_TIMER_RIS         0x18
+#define HISI_TIMER_MIS         0x1c
+#define HISI_TIMER_BGLOAD      0x20
+#define HISI_TIMER_BGLOAD_H    0x24
+
+
+struct sp804_timer __initdata arm_sp804_timer = {
+       .load           = TIMER_LOAD,
+       .value          = TIMER_VALUE,
+       .ctrl           = TIMER_CTRL,
+       .intclr         = TIMER_INTCLR,
+       .timer_base     = {TIMER_1_BASE, TIMER_2_BASE},
+       .width          = 32,
+};
+
+struct sp804_timer __initdata hisi_sp804_timer = {
+       .load           = HISI_TIMER_LOAD,
+       .load_h         = HISI_TIMER_LOAD_H,
+       .value          = HISI_TIMER_VALUE,
+       .value_h        = HISI_TIMER_VALUE_H,
+       .ctrl           = HISI_TIMER_CTRL,
+       .intclr         = HISI_TIMER_INTCLR,
+       .timer_base     = {HISI_TIMER_1_BASE, HISI_TIMER_2_BASE},
+       .width          = 64,
+};
+
+static struct sp804_clkevt sp804_clkevt[NR_TIMERS];
+
+static long __init sp804_get_clock_rate(struct clk *clk, const char *name)
 {
        long rate;
        int err;
 
+       if (!clk)
+               clk = clk_get_sys("sp804", name);
+       if (IS_ERR(clk)) {
+               pr_err("sp804: %s clock not found: %ld\n", name, PTR_ERR(clk));
+               return PTR_ERR(clk);
+       }
+
        err = clk_prepare(clk);
        if (err) {
                pr_err("sp804: clock failed to prepare: %d\n", err);
@@ -53,50 +95,57 @@ static long __init sp804_get_clock_rate(struct clk *clk)
        return rate;
 }
 
-static void __iomem *sched_clock_base;
-
-static u64 notrace sp804_read(void)
+static struct sp804_clkevt * __init sp804_clkevt_get(void __iomem *base)
 {
-       return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
+       int i;
+
+       for (i = 0; i < NR_TIMERS; i++) {
+               if (sp804_clkevt[i].base == base)
+                       return &sp804_clkevt[i];
+       }
+
+       /* It's impossible to reach here */
+       WARN_ON(1);
+
+       return NULL;
 }
 
-void __init sp804_timer_disable(void __iomem *base)
+static struct sp804_clkevt *sched_clkevt;
+
+static u64 notrace sp804_read(void)
 {
-       writel(0, base + TIMER_CTRL);
+       return ~readl_relaxed(sched_clkevt->value);
 }
 
-int  __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
-                                                    const char *name,
-                                                    struct clk *clk,
-                                                    int use_sched_clock)
+int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
+                                                 const char *name,
+                                                 struct clk *clk,
+                                                 int use_sched_clock)
 {
        long rate;
+       struct sp804_clkevt *clkevt;
 
-       if (!clk) {
-               clk = clk_get_sys("sp804", name);
-               if (IS_ERR(clk)) {
-                       pr_err("sp804: clock not found: %d\n",
-                              (int)PTR_ERR(clk));
-                       return PTR_ERR(clk);
-               }
-       }
-
-       rate = sp804_get_clock_rate(clk);
+       rate = sp804_get_clock_rate(clk, name);
        if (rate < 0)
                return -EINVAL;
 
-       /* setup timer 0 as free-running clocksource */
-       writel(0, base + TIMER_CTRL);
-       writel(0xffffffff, base + TIMER_LOAD);
-       writel(0xffffffff, base + TIMER_VALUE);
+       clkevt = sp804_clkevt_get(base);
+
+       writel(0, clkevt->ctrl);
+       writel(0xffffffff, clkevt->load);
+       writel(0xffffffff, clkevt->value);
+       if (clkevt->width == 64) {
+               writel(0xffffffff, clkevt->load_h);
+               writel(0xffffffff, clkevt->value_h);
+       }
        writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
-               base + TIMER_CTRL);
+               clkevt->ctrl);
 
-       clocksource_mmio_init(base + TIMER_VALUE, name,
+       clocksource_mmio_init(clkevt->value, name,
                rate, 200, 32, clocksource_mmio_readl_down);
 
        if (use_sched_clock) {
-               sched_clock_base = base;
+               sched_clkevt = clkevt;
                sched_clock_register(sp804_read, 32, rate);
        }
 
@@ -104,8 +153,7 @@ int  __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
 }
 
 
-static void __iomem *clkevt_base;
-static unsigned long clkevt_reload;
+static struct sp804_clkevt *common_clkevt;
 
 /*
  * IRQ handler for the timer
@@ -115,7 +163,7 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
        struct clock_event_device *evt = dev_id;
 
        /* clear the interrupt */
-       writel(1, clkevt_base + TIMER_INTCLR);
+       writel(1, common_clkevt->intclr);
 
        evt->event_handler(evt);
 
@@ -124,7 +172,7 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
 
 static inline void timer_shutdown(struct clock_event_device *evt)
 {
-       writel(0, clkevt_base + TIMER_CTRL);
+       writel(0, common_clkevt->ctrl);
 }
 
 static int sp804_shutdown(struct clock_event_device *evt)
@@ -139,8 +187,8 @@ static int sp804_set_periodic(struct clock_event_device *evt)
                             TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
 
        timer_shutdown(evt);
-       writel(clkevt_reload, clkevt_base + TIMER_LOAD);
-       writel(ctrl, clkevt_base + TIMER_CTRL);
+       writel(common_clkevt->reload, common_clkevt->load);
+       writel(ctrl, common_clkevt->ctrl);
        return 0;
 }
 
@@ -150,8 +198,8 @@ static int sp804_set_next_event(unsigned long next,
        unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
                             TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE;
 
-       writel(next, clkevt_base + TIMER_LOAD);
-       writel(ctrl, clkevt_base + TIMER_CTRL);
+       writel(next, common_clkevt->load);
+       writel(ctrl, common_clkevt->ctrl);
 
        return 0;
 }
@@ -168,30 +216,23 @@ static struct clock_event_device sp804_clockevent = {
        .rating                 = 300,
 };
 
-int __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name)
+int __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
+                                 struct clk *clk, const char *name)
 {
        struct clock_event_device *evt = &sp804_clockevent;
        long rate;
 
-       if (!clk)
-               clk = clk_get_sys("sp804", name);
-       if (IS_ERR(clk)) {
-               pr_err("sp804: %s clock not found: %d\n", name,
-                       (int)PTR_ERR(clk));
-               return PTR_ERR(clk);
-       }
-
-       rate = sp804_get_clock_rate(clk);
+       rate = sp804_get_clock_rate(clk, name);
        if (rate < 0)
                return -EINVAL;
 
-       clkevt_base = base;
-       clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
+       common_clkevt = sp804_clkevt_get(base);
+       common_clkevt->reload = DIV_ROUND_CLOSEST(rate, HZ);
        evt->name = name;
        evt->irq = irq;
        evt->cpumask = cpu_possible_mask;
 
-       writel(0, base + TIMER_CTRL);
+       writel(0, common_clkevt->ctrl);
 
        if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
                        "timer", &sp804_clockevent))
@@ -201,10 +242,33 @@ int __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct
        return 0;
 }
 
-static int __init sp804_of_init(struct device_node *np)
+static void __init sp804_clkevt_init(struct sp804_timer *timer, void __iomem *base)
+{
+       int i;
+
+       for (i = 0; i < NR_TIMERS; i++) {
+               void __iomem *timer_base;
+               struct sp804_clkevt *clkevt;
+
+               timer_base = base + timer->timer_base[i];
+               clkevt = &sp804_clkevt[i];
+               clkevt->base    = timer_base;
+               clkevt->load    = timer_base + timer->load;
+               clkevt->load_h  = timer_base + timer->load_h;
+               clkevt->value   = timer_base + timer->value;
+               clkevt->value_h = timer_base + timer->value_h;
+               clkevt->ctrl    = timer_base + timer->ctrl;
+               clkevt->intclr  = timer_base + timer->intclr;
+               clkevt->width   = timer->width;
+       }
+}
+
+static int __init sp804_of_init(struct device_node *np, struct sp804_timer *timer)
 {
        static bool initialized = false;
        void __iomem *base;
+       void __iomem *timer1_base;
+       void __iomem *timer2_base;
        int irq, ret = -EINVAL;
        u32 irq_num = 0;
        struct clk *clk1, *clk2;
@@ -214,9 +278,12 @@ static int __init sp804_of_init(struct device_node *np)
        if (!base)
                return -ENXIO;
 
+       timer1_base = base + timer->timer_base[0];
+       timer2_base = base + timer->timer_base[1];
+
        /* Ensure timers are disabled */
-       writel(0, base + TIMER_CTRL);
-       writel(0, base + TIMER_2_BASE + TIMER_CTRL);
+       writel(0, timer1_base + timer->ctrl);
+       writel(0, timer2_base + timer->ctrl);
 
        if (initialized || !of_device_is_available(np)) {
                ret = -EINVAL;
@@ -242,24 +309,27 @@ static int __init sp804_of_init(struct device_node *np)
        if (irq <= 0)
                goto err;
 
+       sp804_clkevt_init(timer, base);
+
        of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
        if (irq_num == 2) {
 
-               ret = __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name);
+               ret = sp804_clockevents_init(timer2_base, irq, clk2, name);
                if (ret)
                        goto err;
 
-               ret = __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1);
+               ret = sp804_clocksource_and_sched_clock_init(timer1_base,
+                                                            name, clk1, 1);
                if (ret)
                        goto err;
        } else {
 
-               ret = __sp804_clockevents_init(base, irq, clk1 , name);
+               ret = sp804_clockevents_init(timer1_base, irq, clk1, name);
                if (ret)
                        goto err;
 
-               ret =__sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE,
-                                                             name, clk2, 1);
+               ret = sp804_clocksource_and_sched_clock_init(timer2_base,
+                                                            name, clk2, 1);
                if (ret)
                        goto err;
        }
@@ -270,7 +340,18 @@ err:
        iounmap(base);
        return ret;
 }
-TIMER_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
+
+static int __init arm_sp804_of_init(struct device_node *np)
+{
+       return sp804_of_init(np, &arm_sp804_timer);
+}
+TIMER_OF_DECLARE(sp804, "arm,sp804", arm_sp804_of_init);
+
+static int __init hisi_sp804_of_init(struct device_node *np)
+{
+       return sp804_of_init(np, &hisi_sp804_timer);
+}
+TIMER_OF_DECLARE(hisi_sp804, "hisilicon,sp804", hisi_sp804_of_init);
 
 static int __init integrator_cp_of_init(struct device_node *np)
 {
@@ -293,13 +374,16 @@ static int __init integrator_cp_of_init(struct device_node *np)
        }
 
        /* Ensure timer is disabled */
-       writel(0, base + TIMER_CTRL);
+       writel(0, base + arm_sp804_timer.ctrl);
 
        if (init_count == 2 || !of_device_is_available(np))
                goto err;
 
+       sp804_clkevt_init(&arm_sp804_timer, base);
+
        if (!init_count) {
-               ret = __sp804_clocksource_and_sched_clock_init(base, name, clk, 0);
+               ret = sp804_clocksource_and_sched_clock_init(base,
+                                                            name, clk, 0);
                if (ret)
                        goto err;
        } else {
@@ -307,7 +391,7 @@ static int __init integrator_cp_of_init(struct device_node *np)
                if (irq <= 0)
                        goto err;
 
-               ret = __sp804_clockevents_init(base, irq, clk, name);
+               ret = sp804_clockevents_init(base, irq, clk, name);
                if (ret)
                        goto err;
        }
index f6fd1c1..33b3e8a 100644 (file)
@@ -69,12 +69,33 @@ static bool dmtimer_systimer_revision1(struct dmtimer_systimer *t)
        return !(tidr >> 16);
 }
 
+static void dmtimer_systimer_enable(struct dmtimer_systimer *t)
+{
+       u32 val;
+
+       if (dmtimer_systimer_revision1(t))
+               val = DMTIMER_TYPE1_ENABLE;
+       else
+               val = DMTIMER_TYPE2_ENABLE;
+
+       writel_relaxed(val, t->base + t->sysc);
+}
+
+static void dmtimer_systimer_disable(struct dmtimer_systimer *t)
+{
+       if (!dmtimer_systimer_revision1(t))
+               return;
+
+       writel_relaxed(DMTIMER_TYPE1_DISABLE, t->base + t->sysc);
+}
+
 static int __init dmtimer_systimer_type1_reset(struct dmtimer_systimer *t)
 {
        void __iomem *syss = t->base + OMAP_TIMER_V1_SYS_STAT_OFFSET;
        int ret;
        u32 l;
 
+       dmtimer_systimer_enable(t);
        writel_relaxed(BIT(1) | BIT(2), t->base + t->ifctrl);
        ret = readl_poll_timeout_atomic(syss, l, l & BIT(0), 100,
                                        DMTIMER_RESET_WAIT);
@@ -88,6 +109,7 @@ static int __init dmtimer_systimer_type2_reset(struct dmtimer_systimer *t)
        void __iomem *sysc = t->base + t->sysc;
        u32 l;
 
+       dmtimer_systimer_enable(t);
        l = readl_relaxed(sysc);
        l |= BIT(0);
        writel_relaxed(l, sysc);
@@ -336,26 +358,6 @@ static int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t,
        return 0;
 }
 
-static void dmtimer_systimer_enable(struct dmtimer_systimer *t)
-{
-       u32 val;
-
-       if (dmtimer_systimer_revision1(t))
-               val = DMTIMER_TYPE1_ENABLE;
-       else
-               val = DMTIMER_TYPE2_ENABLE;
-
-       writel_relaxed(val, t->base + t->sysc);
-}
-
-static void dmtimer_systimer_disable(struct dmtimer_systimer *t)
-{
-       if (!dmtimer_systimer_revision1(t))
-               return;
-
-       writel_relaxed(DMTIMER_TYPE1_DISABLE, t->base + t->sysc);
-}
-
 static int __init dmtimer_systimer_setup(struct device_node *np,
                                         struct dmtimer_systimer *t)
 {
@@ -409,8 +411,8 @@ static int __init dmtimer_systimer_setup(struct device_node *np,
        t->wakeup = regbase + _OMAP_TIMER_WAKEUP_EN_OFFSET;
        t->ifctrl = regbase + _OMAP_TIMER_IF_CTRL_OFFSET;
 
-       dmtimer_systimer_enable(t);
        dmtimer_systimer_reset(t);
+       dmtimer_systimer_enable(t);
        pr_debug("dmtimer rev %08x sysc %08x\n", readl_relaxed(t->base),
                 readl_relaxed(t->base + t->sysc));
 
index f7b7743..b7b252c 100644 (file)
@@ -320,8 +320,8 @@ static int mchp_tc_probe(struct platform_device *pdev)
        }
 
        regmap = syscon_node_to_regmap(np->parent);
-       if (IS_ERR(priv->regmap))
-               return PTR_ERR(priv->regmap);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
 
        /* max. channels number is 2 when in QDEC mode */
        priv->num_channels = of_property_count_u32_elems(np, "reg");
index 02ab56b..47aa90f 100644 (file)
@@ -703,8 +703,7 @@ static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf)
        freq = arch_freq_get_on_cpu(policy->cpu);
        if (freq)
                ret = sprintf(buf, "%u\n", freq);
-       else if (cpufreq_driver && cpufreq_driver->setpolicy &&
-                       cpufreq_driver->get)
+       else if (cpufreq_driver->setpolicy && cpufreq_driver->get)
                ret = sprintf(buf, "%u\n", cpufreq_driver->get(policy->cpu));
        else
                ret = sprintf(buf, "%u\n", policy->cur);
index e0220a6..9a515c4 100644 (file)
@@ -219,14 +219,13 @@ struct global_params {
  * @epp_policy:                Last saved policy used to set EPP/EPB
  * @epp_default:       Power on default HWP energy performance
  *                     preference/bias
- * @epp_saved:         Saved EPP/EPB during system suspend or CPU offline
- *                     operation
  * @epp_cached         Cached HWP energy-performance preference value
  * @hwp_req_cached:    Cached value of the last HWP Request MSR
  * @hwp_cap_cached:    Cached value of the last HWP Capabilities MSR
  * @last_io_update:    Last time when IO wake flag was set
  * @sched_flags:       Store scheduler flags for possible cross CPU update
  * @hwp_boost_min:     Last HWP boosted min performance
+ * @suspended:         Whether or not the driver has been suspended.
  *
  * This structure stores per CPU instance data for all CPUs.
  */
@@ -258,13 +257,13 @@ struct cpudata {
        s16 epp_powersave;
        s16 epp_policy;
        s16 epp_default;
-       s16 epp_saved;
        s16 epp_cached;
        u64 hwp_req_cached;
        u64 hwp_cap_cached;
        u64 last_io_update;
        unsigned int sched_flags;
        u32 hwp_boost_min;
+       bool suspended;
 };
 
 static struct cpudata **all_cpu_data;
@@ -644,6 +643,8 @@ static int intel_pstate_get_energy_pref_index(struct cpudata *cpu_data, int *raw
 
 static int intel_pstate_set_epp(struct cpudata *cpu, u32 epp)
 {
+       int ret;
+
        /*
         * Use the cached HWP Request MSR value, because in the active mode the
         * register itself may be updated by intel_pstate_hwp_boost_up() or
@@ -659,7 +660,11 @@ static int intel_pstate_set_epp(struct cpudata *cpu, u32 epp)
         * function, so it cannot run in parallel with the update below.
         */
        WRITE_ONCE(cpu->hwp_req_cached, value);
-       return wrmsrl_on_cpu(cpu->cpu, MSR_HWP_REQUEST, value);
+       ret = wrmsrl_on_cpu(cpu->cpu, MSR_HWP_REQUEST, value);
+       if (!ret)
+               cpu->epp_cached = epp;
+
+       return ret;
 }
 
 static int intel_pstate_set_energy_pref_index(struct cpudata *cpu_data,
@@ -678,6 +683,14 @@ static int intel_pstate_set_energy_pref_index(struct cpudata *cpu_data,
                else if (epp == -EINVAL)
                        epp = epp_values[pref_index - 1];
 
+               /*
+                * To avoid confusion, refuse to set EPP to any values different
+                * from 0 (performance) if the current policy is "performance",
+                * because those values would be overridden.
+                */
+               if (epp > 0 && cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE)
+                       return -EBUSY;
+
                ret = intel_pstate_set_epp(cpu_data, epp);
        } else {
                if (epp == -EINVAL)
@@ -762,10 +775,8 @@ static ssize_t store_energy_performance_preference(
                        cpufreq_stop_governor(policy);
                        ret = intel_pstate_set_epp(cpu, epp);
                        err = cpufreq_start_governor(policy);
-                       if (!ret) {
-                               cpu->epp_cached = epp;
+                       if (!ret)
                                ret = err;
-                       }
                }
        }
 
@@ -825,7 +836,7 @@ static void intel_pstate_get_hwp_max(unsigned int cpu, int *phy_max,
 
        rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap);
        WRITE_ONCE(all_cpu_data[cpu]->hwp_cap_cached, cap);
-       if (global.no_turbo)
+       if (global.no_turbo || global.turbo_disabled)
                *current_max = HWP_GUARANTEED_PERF(cap);
        else
                *current_max = HWP_HIGHEST_PERF(cap);
@@ -859,12 +870,6 @@ static void intel_pstate_hwp_set(unsigned int cpu)
 
        cpu_data->epp_policy = cpu_data->policy;
 
-       if (cpu_data->epp_saved >= 0) {
-               epp = cpu_data->epp_saved;
-               cpu_data->epp_saved = -EINVAL;
-               goto update_epp;
-       }
-
        if (cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE) {
                epp = intel_pstate_get_epp(cpu_data, value);
                cpu_data->epp_powersave = epp;
@@ -891,7 +896,6 @@ static void intel_pstate_hwp_set(unsigned int cpu)
 
                epp = cpu_data->epp_powersave;
        }
-update_epp:
        if (boot_cpu_has(X86_FEATURE_HWP_EPP)) {
                value &= ~GENMASK_ULL(31, 24);
                value |= (u64)epp << 24;
@@ -903,14 +907,24 @@ skip_epp:
        wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value);
 }
 
-static void intel_pstate_hwp_force_min_perf(int cpu)
+static void intel_pstate_hwp_offline(struct cpudata *cpu)
 {
-       u64 value;
+       u64 value = READ_ONCE(cpu->hwp_req_cached);
        int min_perf;
 
-       value = all_cpu_data[cpu]->hwp_req_cached;
+       if (boot_cpu_has(X86_FEATURE_HWP_EPP)) {
+               /*
+                * In case the EPP has been set to "performance" by the
+                * active mode "performance" scaling algorithm, replace that
+                * temporary value with the cached EPP one.
+                */
+               value &= ~GENMASK_ULL(31, 24);
+               value |= HWP_ENERGY_PERF_PREFERENCE(cpu->epp_cached);
+               WRITE_ONCE(cpu->hwp_req_cached, value);
+       }
+
        value &= ~GENMASK_ULL(31, 0);
-       min_perf = HWP_LOWEST_PERF(all_cpu_data[cpu]->hwp_cap_cached);
+       min_perf = HWP_LOWEST_PERF(cpu->hwp_cap_cached);
 
        /* Set hwp_max = hwp_min */
        value |= HWP_MAX_PERF(min_perf);
@@ -920,19 +934,7 @@ static void intel_pstate_hwp_force_min_perf(int cpu)
        if (boot_cpu_has(X86_FEATURE_HWP_EPP))
                value |= HWP_ENERGY_PERF_PREFERENCE(HWP_EPP_POWERSAVE);
 
-       wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value);
-}
-
-static int intel_pstate_hwp_save_state(struct cpufreq_policy *policy)
-{
-       struct cpudata *cpu_data = all_cpu_data[policy->cpu];
-
-       if (!hwp_active)
-               return 0;
-
-       cpu_data->epp_saved = intel_pstate_get_epp(cpu_data, 0);
-
-       return 0;
+       wrmsrl_on_cpu(cpu->cpu, MSR_HWP_REQUEST, value);
 }
 
 #define POWER_CTL_EE_ENABLE    1
@@ -959,8 +961,28 @@ static void set_power_ctl_ee_state(bool input)
 
 static void intel_pstate_hwp_enable(struct cpudata *cpudata);
 
+static void intel_pstate_hwp_reenable(struct cpudata *cpu)
+{
+       intel_pstate_hwp_enable(cpu);
+       wrmsrl_on_cpu(cpu->cpu, MSR_HWP_REQUEST, READ_ONCE(cpu->hwp_req_cached));
+}
+
+static int intel_pstate_suspend(struct cpufreq_policy *policy)
+{
+       struct cpudata *cpu = all_cpu_data[policy->cpu];
+
+       pr_debug("CPU %d suspending\n", cpu->cpu);
+
+       cpu->suspended = true;
+
+       return 0;
+}
+
 static int intel_pstate_resume(struct cpufreq_policy *policy)
 {
+       struct cpudata *cpu = all_cpu_data[policy->cpu];
+
+       pr_debug("CPU %d resuming\n", cpu->cpu);
 
        /* Only restore if the system default is changed */
        if (power_ctl_ee_state == POWER_CTL_EE_ENABLE)
@@ -968,18 +990,16 @@ static int intel_pstate_resume(struct cpufreq_policy *policy)
        else if (power_ctl_ee_state == POWER_CTL_EE_DISABLE)
                set_power_ctl_ee_state(false);
 
-       if (!hwp_active)
-               return 0;
-
-       mutex_lock(&intel_pstate_limits_lock);
+       if (cpu->suspended && hwp_active) {
+               mutex_lock(&intel_pstate_limits_lock);
 
-       if (policy->cpu == 0)
-               intel_pstate_hwp_enable(all_cpu_data[policy->cpu]);
+               /* Re-enable HWP, because "online" has not done that. */
+               intel_pstate_hwp_reenable(cpu);
 
-       all_cpu_data[policy->cpu]->epp_policy = 0;
-       intel_pstate_hwp_set(policy->cpu);
+               mutex_unlock(&intel_pstate_limits_lock);
+       }
 
-       mutex_unlock(&intel_pstate_limits_lock);
+       cpu->suspended = false;
 
        return 0;
 }
@@ -1428,7 +1448,6 @@ static void intel_pstate_hwp_enable(struct cpudata *cpudata)
                wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00);
 
        wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1);
-       cpudata->epp_policy = 0;
        if (cpudata->epp_default == -EINVAL)
                cpudata->epp_default = intel_pstate_get_epp(cpudata, 0);
 }
@@ -2097,25 +2116,31 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
 
                all_cpu_data[cpunum] = cpu;
 
-               cpu->epp_default = -EINVAL;
-               cpu->epp_powersave = -EINVAL;
-               cpu->epp_saved = -EINVAL;
-       }
+               cpu->cpu = cpunum;
 
-       cpu = all_cpu_data[cpunum];
+               cpu->epp_default = -EINVAL;
 
-       cpu->cpu = cpunum;
+               if (hwp_active) {
+                       const struct x86_cpu_id *id;
 
-       if (hwp_active) {
-               const struct x86_cpu_id *id;
+                       intel_pstate_hwp_enable(cpu);
 
-               intel_pstate_hwp_enable(cpu);
-
-               id = x86_match_cpu(intel_pstate_hwp_boost_ids);
-               if (id && intel_pstate_acpi_pm_profile_server())
-                       hwp_boost = true;
+                       id = x86_match_cpu(intel_pstate_hwp_boost_ids);
+                       if (id && intel_pstate_acpi_pm_profile_server())
+                               hwp_boost = true;
+               }
+       } else if (hwp_active) {
+               /*
+                * Re-enable HWP in case this happens after a resume from ACPI
+                * S3 if the CPU was offline during the whole system/resume
+                * cycle.
+                */
+               intel_pstate_hwp_reenable(cpu);
        }
 
+       cpu->epp_powersave = -EINVAL;
+       cpu->epp_policy = 0;
+
        intel_pstate_get_cpu_pstates(cpu);
 
        pr_debug("controlling: cpu %d\n", cpunum);
@@ -2296,28 +2321,61 @@ static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy)
        return 0;
 }
 
-static void intel_cpufreq_stop_cpu(struct cpufreq_policy *policy)
+static int intel_pstate_cpu_offline(struct cpufreq_policy *policy)
 {
+       struct cpudata *cpu = all_cpu_data[policy->cpu];
+
+       pr_debug("CPU %d going offline\n", cpu->cpu);
+
+       if (cpu->suspended)
+               return 0;
+
+       /*
+        * If the CPU is an SMT thread and it goes offline with the performance
+        * settings different from the minimum, it will prevent its sibling
+        * from getting to lower performance levels, so force the minimum
+        * performance on CPU offline to prevent that from happening.
+        */
        if (hwp_active)
-               intel_pstate_hwp_force_min_perf(policy->cpu);
+               intel_pstate_hwp_offline(cpu);
        else
-               intel_pstate_set_min_pstate(all_cpu_data[policy->cpu]);
+               intel_pstate_set_min_pstate(cpu);
+
+       intel_pstate_exit_perf_limits(policy);
+
+       return 0;
+}
+
+static int intel_pstate_cpu_online(struct cpufreq_policy *policy)
+{
+       struct cpudata *cpu = all_cpu_data[policy->cpu];
+
+       pr_debug("CPU %d going online\n", cpu->cpu);
+
+       intel_pstate_init_acpi_perf_limits(policy);
+
+       if (hwp_active) {
+               /*
+                * Re-enable HWP and clear the "suspended" flag to let "resume"
+                * know that it need not do that.
+                */
+               intel_pstate_hwp_reenable(cpu);
+               cpu->suspended = false;
+       }
+
+       return 0;
 }
 
 static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
 {
-       pr_debug("CPU %d exiting\n", policy->cpu);
+       pr_debug("CPU %d stopping\n", policy->cpu);
 
        intel_pstate_clear_update_util_hook(policy->cpu);
-       if (hwp_active)
-               intel_pstate_hwp_save_state(policy);
-
-       intel_cpufreq_stop_cpu(policy);
 }
 
 static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
 {
-       intel_pstate_exit_perf_limits(policy);
+       pr_debug("CPU %d exiting\n", policy->cpu);
 
        policy->fast_switch_possible = false;
 
@@ -2378,6 +2436,12 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
         */
        policy->policy = CPUFREQ_POLICY_POWERSAVE;
 
+       if (hwp_active) {
+               struct cpudata *cpu = all_cpu_data[policy->cpu];
+
+               cpu->epp_cached = intel_pstate_get_epp(cpu, 0);
+       }
+
        return 0;
 }
 
@@ -2385,11 +2449,13 @@ static struct cpufreq_driver intel_pstate = {
        .flags          = CPUFREQ_CONST_LOOPS,
        .verify         = intel_pstate_verify_policy,
        .setpolicy      = intel_pstate_set_policy,
-       .suspend        = intel_pstate_hwp_save_state,
+       .suspend        = intel_pstate_suspend,
        .resume         = intel_pstate_resume,
        .init           = intel_pstate_cpu_init,
        .exit           = intel_pstate_cpu_exit,
        .stop_cpu       = intel_pstate_stop_cpu,
+       .offline        = intel_pstate_cpu_offline,
+       .online         = intel_pstate_cpu_online,
        .update_limits  = intel_pstate_update_limits,
        .name           = "intel_pstate",
 };
@@ -2585,7 +2651,7 @@ static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy)
                policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY_HWP;
                rdmsrl_on_cpu(cpu->cpu, MSR_HWP_REQUEST, &value);
                WRITE_ONCE(cpu->hwp_req_cached, value);
-               cpu->epp_cached = (value & GENMASK_ULL(31, 24)) >> 24;
+               cpu->epp_cached = intel_pstate_get_epp(cpu, value);
        } else {
                turbo_max = cpu->pstate.turbo_pstate;
                policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY;
@@ -2644,7 +2710,10 @@ static struct cpufreq_driver intel_cpufreq = {
        .fast_switch    = intel_cpufreq_fast_switch,
        .init           = intel_cpufreq_cpu_init,
        .exit           = intel_cpufreq_cpu_exit,
-       .stop_cpu       = intel_cpufreq_stop_cpu,
+       .offline        = intel_pstate_cpu_offline,
+       .online         = intel_pstate_cpu_online,
+       .suspend        = intel_pstate_suspend,
+       .resume         = intel_pstate_resume,
        .update_limits  = intel_pstate_update_limits,
        .name           = "intel_cpufreq",
 };
@@ -2667,9 +2736,6 @@ static void intel_pstate_driver_cleanup(void)
        }
        put_online_cpus();
 
-       if (intel_pstate_driver == &intel_pstate)
-               intel_pstate_sysfs_hide_hwp_dynamic_boost();
-
        intel_pstate_driver = NULL;
 }
 
@@ -2695,14 +2761,6 @@ static int intel_pstate_register_driver(struct cpufreq_driver *driver)
        return 0;
 }
 
-static int intel_pstate_unregister_driver(void)
-{
-       cpufreq_unregister_driver(intel_pstate_driver);
-       intel_pstate_driver_cleanup();
-
-       return 0;
-}
-
 static ssize_t intel_pstate_show_status(char *buf)
 {
        if (!intel_pstate_driver)
@@ -2714,20 +2772,24 @@ static ssize_t intel_pstate_show_status(char *buf)
 
 static int intel_pstate_update_status(const char *buf, size_t size)
 {
-       int ret;
+       if (size == 3 && !strncmp(buf, "off", size)) {
+               if (!intel_pstate_driver)
+                       return -EINVAL;
+
+               if (hwp_active)
+                       return -EBUSY;
 
-       if (size == 3 && !strncmp(buf, "off", size))
-               return intel_pstate_driver ?
-                       intel_pstate_unregister_driver() : -EINVAL;
+               cpufreq_unregister_driver(intel_pstate_driver);
+               intel_pstate_driver_cleanup();
+               return 0;
+       }
 
        if (size == 6 && !strncmp(buf, "active", size)) {
                if (intel_pstate_driver) {
                        if (intel_pstate_driver == &intel_pstate)
                                return 0;
 
-                       ret = intel_pstate_unregister_driver();
-                       if (ret)
-                               return ret;
+                       cpufreq_unregister_driver(intel_pstate_driver);
                }
 
                return intel_pstate_register_driver(&intel_pstate);
@@ -2738,9 +2800,8 @@ static int intel_pstate_update_status(const char *buf, size_t size)
                        if (intel_pstate_driver == &intel_cpufreq)
                                return 0;
 
-                       ret = intel_pstate_unregister_driver();
-                       if (ret)
-                               return ret;
+                       cpufreq_unregister_driver(intel_pstate_driver);
+                       intel_pstate_sysfs_hide_hwp_dynamic_boost();
                }
 
                return intel_pstate_register_driver(&intel_cpufreq);
index bb61677..ef0a321 100644 (file)
@@ -129,7 +129,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
                        return speedstep_get_frequency(SPEEDSTEP_CPU_PCORE);
                case 0x0D: /* Pentium M (Dothan) */
                        p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
-                       /* fall through */
+                       fallthrough;
                case 0x09: /* Pentium M (Banias) */
                        return speedstep_get_frequency(SPEEDSTEP_CPU_PM);
                }
index 5c4f8f0..a13a2d1 100644 (file)
@@ -366,7 +366,7 @@ enum speedstep_processor speedstep_detect_processor(void)
                        } else
                                return SPEEDSTEP_CPU_PIII_C;
                }
-               /* fall through */
+               fallthrough;
        default:
                return 0;
        }
index bae527e..e1d931c 100644 (file)
@@ -56,9 +56,11 @@ struct read_counters_work {
 
 static struct workqueue_struct *read_counters_wq;
 
-static enum cluster get_cpu_cluster(u8 cpu)
+static void get_cpu_cluster(void *cluster)
 {
-       return MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 1);
+       u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
+
+       *((uint32_t *)cluster) = MPIDR_AFFINITY_LEVEL(mpidr, 1);
 }
 
 /*
@@ -186,8 +188,10 @@ static unsigned int tegra194_get_speed(u32 cpu)
 static int tegra194_cpufreq_init(struct cpufreq_policy *policy)
 {
        struct tegra194_cpufreq_data *data = cpufreq_get_driver_data();
-       int cl = get_cpu_cluster(policy->cpu);
        u32 cpu;
+       u32 cl;
+
+       smp_call_function_single(policy->cpu, get_cpu_cluster, &cl, true);
 
        if (cl >= data->num_clusters)
                return -EINVAL;
index ab0de27..8f9fdd8 100644 (file)
@@ -86,11 +86,11 @@ static unsigned long dra7_efuse_xlate(struct ti_cpufreq_data *opp_data,
        case DRA76_EFUSE_HAS_PLUS_MPU_OPP:
        case DRA76_EFUSE_HAS_ALL_MPU_OPP:
                calculated_efuse |= DRA76_EFUSE_PLUS_MPU_OPP;
-               /* Fall through */
+               fallthrough;
        case DRA7_EFUSE_HAS_ALL_MPU_OPP:
        case DRA7_EFUSE_HAS_HIGH_MPU_OPP:
                calculated_efuse |= DRA7_EFUSE_HIGH_MPU_OPP;
-               /* Fall through */
+               fallthrough;
        case DRA7_EFUSE_HAS_OD_MPU_OPP:
                calculated_efuse |= DRA7_EFUSE_OD_MPU_OPP;
        }
index 7446384..d928b37 100644 (file)
@@ -66,7 +66,7 @@ static int psci_enter_domain_idle_state(struct cpuidle_device *dev,
                return -1;
 
        /* Do runtime PM to manage a hierarchical CPU toplogy. */
-       pm_runtime_put_sync_suspend(pd_dev);
+       RCU_NONIDLE(pm_runtime_put_sync_suspend(pd_dev));
 
        state = psci_get_domain_state();
        if (!state)
@@ -74,7 +74,7 @@ static int psci_enter_domain_idle_state(struct cpuidle_device *dev,
 
        ret = psci_cpu_suspend_enter(state) ? -1 : idx;
 
-       pm_runtime_get_sync(pd_dev);
+       RCU_NONIDLE(pm_runtime_get_sync(pd_dev));
 
        cpu_pm_exit();
 
index ff6d99e..a2b5c6f 100644 (file)
@@ -361,7 +361,10 @@ static void __init fixup_cede0_latency(void)
        for (i = 0; i < nr_xcede_records; i++) {
                struct xcede_latency_record *record = &payload->records[i];
                u64 latency_tb = be64_to_cpu(record->latency_ticks);
-               u64 latency_us = tb_to_ns(latency_tb) / NSEC_PER_USEC;
+               u64 latency_us = DIV_ROUND_UP_ULL(tb_to_ns(latency_tb), NSEC_PER_USEC);
+
+               if (latency_us == 0)
+                       pr_warn("cpuidle: xcede record %d has an unrealistic latency of 0us.\n", i);
 
                if (latency_us < min_latency_us)
                        min_latency_us = latency_us;
@@ -378,10 +381,14 @@ static void __init fixup_cede0_latency(void)
         * Perform the fix-up.
         */
        if (min_latency_us < dedicated_states[1].exit_latency) {
-               u64 cede0_latency = min_latency_us - 1;
+               /*
+                * We set a minimum of 1us wakeup latency for cede0 to
+                * distinguish it from snooze
+                */
+               u64 cede0_latency = 1;
 
-               if (cede0_latency <= 0)
-                       cede0_latency = min_latency_us;
+               if (min_latency_us > cede0_latency)
+                       cede0_latency = min_latency_us - 1;
 
                dedicated_states[1].exit_latency = cede0_latency;
                dedicated_states[1].target_residency = 10 * (cede0_latency);
index 8719731..29e8468 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/suspend.h>
 #include <linux/tick.h>
+#include <linux/mmu_context.h>
 #include <trace/events/power.h>
 
 #include "cpuidle.h"
@@ -137,29 +138,25 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv,
                                struct cpuidle_device *dev, int index)
 {
        ktime_t time_start, time_end;
+       struct cpuidle_state *target_state = &drv->states[index];
 
        time_start = ns_to_ktime(local_clock());
 
-       /*
-        * trace_suspend_resume() called by tick_freeze() for the last CPU
-        * executing it contains RCU usage regarded as invalid in the idle
-        * context, so tell RCU about that.
-        */
-       RCU_NONIDLE(tick_freeze());
+       tick_freeze();
        /*
         * The state used here cannot be a "coupled" one, because the "coupled"
         * cpuidle mechanism enables interrupts and doing that with timekeeping
         * suspended is generally unsafe.
         */
        stop_critical_timings();
-       drv->states[index].enter_s2idle(dev, drv, index);
-       WARN_ON(!irqs_disabled());
-       /*
-        * timekeeping_resume() that will be called by tick_unfreeze() for the
-        * first CPU executing it calls functions containing RCU read-side
-        * critical sections, so tell RCU about that.
-        */
-       RCU_NONIDLE(tick_unfreeze());
+       if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
+               rcu_idle_enter();
+       target_state->enter_s2idle(dev, drv, index);
+       if (WARN_ON_ONCE(!irqs_disabled()))
+               local_irq_disable();
+       if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
+               rcu_idle_exit();
+       tick_unfreeze();
        start_critical_timings();
 
        time_end = ns_to_ktime(local_clock());
@@ -225,19 +222,26 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
                broadcast = false;
        }
 
+       if (target_state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
+               leave_mm(dev->cpu);
+
        /* Take note of the planned idle state. */
        sched_idle_set_state(target_state);
 
-       trace_cpu_idle_rcuidle(index, dev->cpu);
+       trace_cpu_idle(index, dev->cpu);
        time_start = ns_to_ktime(local_clock());
 
        stop_critical_timings();
+       if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
+               rcu_idle_enter();
        entered_state = target_state->enter(dev, drv, index);
+       if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
+               rcu_idle_exit();
        start_critical_timings();
 
        sched_clock_idle_wakeup_event();
        time_end = ns_to_ktime(local_clock());
-       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
+       trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
 
        /* The cpu is no longer idle or about to enter idle. */
        sched_idle_set_state(NULL);
index aa3a4ed..3759338 100644 (file)
@@ -873,6 +873,10 @@ config CRYPTO_DEV_SA2UL
        select CRYPTO_AES
        select CRYPTO_AES_ARM64
        select CRYPTO_ALGAPI
+       select CRYPTO_AUTHENC
+       select CRYPTO_SHA1
+       select CRYPTO_SHA256
+       select CRYPTO_SHA512
        select HW_RANDOM
        select SG_SPLIT
        help
index 12e7c6a..0cdfe0e 100644 (file)
@@ -59,6 +59,32 @@ config CRYPTO_DEV_SUN8I_CE_DEBUG
          This will create /sys/kernel/debug/sun8i-ce/stats for displaying
          the number of requests per flow and per algorithm.
 
+config CRYPTO_DEV_SUN8I_CE_HASH
+       bool "Enable support for hash on sun8i-ce"
+       depends on CRYPTO_DEV_SUN8I_CE
+       select MD5
+       select SHA1
+       select SHA256
+       select SHA512
+       help
+         Say y to enable support for hash algorithms.
+
+config CRYPTO_DEV_SUN8I_CE_PRNG
+       bool "Support for Allwinner Crypto Engine PRNG"
+       depends on CRYPTO_DEV_SUN8I_CE
+       select CRYPTO_RNG
+       help
+         Select this option if you want to provide kernel-side support for
+         the Pseudo-Random Number Generator found in the Crypto Engine.
+
+config CRYPTO_DEV_SUN8I_CE_TRNG
+       bool "Support for Allwinner Crypto Engine TRNG"
+       depends on CRYPTO_DEV_SUN8I_CE
+       select HW_RANDOM
+       help
+         Select this option if you want to provide kernel-side support for
+         the True Random Number Generator found in the Crypto Engine.
+
 config CRYPTO_DEV_SUN8I_SS
        tristate "Support for Allwinner Security System cryptographic offloader"
        select CRYPTO_SKCIPHER
@@ -85,3 +111,20 @@ config CRYPTO_DEV_SUN8I_SS_DEBUG
          Say y to enable sun8i-ss debug stats.
          This will create /sys/kernel/debug/sun8i-ss/stats for displaying
          the number of requests per flow and per algorithm.
+
+config CRYPTO_DEV_SUN8I_SS_PRNG
+       bool "Support for Allwinner Security System PRNG"
+       depends on CRYPTO_DEV_SUN8I_SS
+       select CRYPTO_RNG
+       help
+         Select this option if you want to provide kernel-side support for
+         the Pseudo-Random Number Generator found in the Security System.
+
+config CRYPTO_DEV_SUN8I_SS_HASH
+       bool "Enable support for hash on sun8i-ss"
+       depends on CRYPTO_DEV_SUN8I_SS
+       select MD5
+       select SHA1
+       select SHA256
+       help
+         Say y to enable support for hash algorithms.
index dc35edd..1dff485 100644 (file)
@@ -9,6 +9,7 @@
  * You could find the datasheet in Documentation/arm/sunxi.rst
  */
 #include "sun4i-ss.h"
+#include <asm/unaligned.h>
 #include <linux/scatterlist.h>
 
 /* This is a totally arbitrary value */
@@ -196,7 +197,7 @@ static int sun4i_hash(struct ahash_request *areq)
        struct sg_mapping_iter mi;
        int in_r, err = 0;
        size_t copied = 0;
-       __le32 wb = 0;
+       u32 wb = 0;
 
        dev_dbg(ss->dev, "%s %s bc=%llu len=%u mode=%x wl=%u h0=%0x",
                __func__, crypto_tfm_alg_name(areq->base.tfm),
@@ -408,7 +409,7 @@ hash_final:
 
                nbw = op->len - 4 * nwait;
                if (nbw) {
-                       wb = cpu_to_le32(*(u32 *)(op->buf + nwait * 4));
+                       wb = le32_to_cpup((__le32 *)(op->buf + nwait * 4));
                        wb &= GENMASK((nbw * 8) - 1, 0);
 
                        op->byte_count += nbw;
@@ -417,7 +418,7 @@ hash_final:
 
        /* write the remaining bytes of the nbw buffer */
        wb |= ((1 << 7) << (nbw * 8));
-       bf[j++] = le32_to_cpu(wb);
+       ((__le32 *)bf)[j++] = cpu_to_le32(wb);
 
        /*
         * number of space to pad to obtain 64o minus 8(size) minus 4 (final 1)
@@ -479,16 +480,16 @@ hash_final:
        /* Get the hash from the device */
        if (op->mode == SS_OP_SHA1) {
                for (i = 0; i < 5; i++) {
+                       v = readl(ss->base + SS_MD0 + i * 4);
                        if (ss->variant->sha1_in_be)
-                               v = cpu_to_le32(readl(ss->base + SS_MD0 + i * 4));
+                               put_unaligned_le32(v, areq->result + i * 4);
                        else
-                               v = cpu_to_be32(readl(ss->base + SS_MD0 + i * 4));
-                       memcpy(areq->result + i * 4, &v, 4);
+                               put_unaligned_be32(v, areq->result + i * 4);
                }
        } else {
                for (i = 0; i < 4; i++) {
-                       v = cpu_to_le32(readl(ss->base + SS_MD0 + i * 4));
-                       memcpy(areq->result + i * 4, &v, 4);
+                       v = readl(ss->base + SS_MD0 + i * 4);
+                       put_unaligned_le32(v, areq->result + i * 4);
                }
        }
 
index 08b68c3..0842eb2 100644 (file)
@@ -1,2 +1,5 @@
 obj-$(CONFIG_CRYPTO_DEV_SUN8I_CE) += sun8i-ce.o
 sun8i-ce-y += sun8i-ce-core.o sun8i-ce-cipher.o
+sun8i-ce-$(CONFIG_CRYPTO_DEV_SUN8I_CE_HASH) += sun8i-ce-hash.o
+sun8i-ce-$(CONFIG_CRYPTO_DEV_SUN8I_CE_PRNG) += sun8i-ce-prng.o
+sun8i-ce-$(CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG) += sun8i-ce-trng.o
index b4d5fea..33707a2 100644 (file)
@@ -75,8 +75,9 @@ static int sun8i_ce_cipher_fallback(struct skcipher_request *areq)
        return err;
 }
 
-static int sun8i_ce_cipher(struct skcipher_request *areq)
+static int sun8i_ce_cipher_prepare(struct crypto_engine *engine, void *async_req)
 {
+       struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base);
        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
        struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
        struct sun8i_ce_dev *ce = op->ce;
@@ -87,8 +88,6 @@ static int sun8i_ce_cipher(struct skcipher_request *areq)
        struct ce_task *cet;
        struct scatterlist *sg;
        unsigned int todo, len, offset, ivsize;
-       dma_addr_t addr_iv = 0, addr_key = 0;
-       void *backup_iv = NULL;
        u32 common, sym;
        int flow, i;
        int nr_sgs = 0;
@@ -119,7 +118,7 @@ static int sun8i_ce_cipher(struct skcipher_request *areq)
        common |= rctx->op_dir | CE_COMM_INT;
        cet->t_common_ctl = cpu_to_le32(common);
        /* CTS and recent CE (H6) need length in bytes, in word otherwise */
-       if (ce->variant->has_t_dlen_in_bytes)
+       if (ce->variant->cipher_t_dlen_in_bytes)
                cet->t_dlen = cpu_to_le32(areq->cryptlen);
        else
                cet->t_dlen = cpu_to_le32(areq->cryptlen / 4);
@@ -141,41 +140,41 @@ static int sun8i_ce_cipher(struct skcipher_request *areq)
        cet->t_sym_ctl = cpu_to_le32(sym);
        cet->t_asym_ctl = 0;
 
-       addr_key = dma_map_single(ce->dev, op->key, op->keylen, DMA_TO_DEVICE);
-       cet->t_key = cpu_to_le32(addr_key);
-       if (dma_mapping_error(ce->dev, addr_key)) {
+       rctx->addr_key = dma_map_single(ce->dev, op->key, op->keylen, DMA_TO_DEVICE);
+       if (dma_mapping_error(ce->dev, rctx->addr_key)) {
                dev_err(ce->dev, "Cannot DMA MAP KEY\n");
                err = -EFAULT;
                goto theend;
        }
+       cet->t_key = cpu_to_le32(rctx->addr_key);
 
        ivsize = crypto_skcipher_ivsize(tfm);
        if (areq->iv && crypto_skcipher_ivsize(tfm) > 0) {
-               chan->ivlen = ivsize;
-               chan->bounce_iv = kzalloc(ivsize, GFP_KERNEL | GFP_DMA);
-               if (!chan->bounce_iv) {
+               rctx->ivlen = ivsize;
+               rctx->bounce_iv = kzalloc(ivsize, GFP_KERNEL | GFP_DMA);
+               if (!rctx->bounce_iv) {
                        err = -ENOMEM;
                        goto theend_key;
                }
                if (rctx->op_dir & CE_DECRYPTION) {
-                       backup_iv = kzalloc(ivsize, GFP_KERNEL);
-                       if (!backup_iv) {
+                       rctx->backup_iv = kzalloc(ivsize, GFP_KERNEL);
+                       if (!rctx->backup_iv) {
                                err = -ENOMEM;
                                goto theend_key;
                        }
                        offset = areq->cryptlen - ivsize;
-                       scatterwalk_map_and_copy(backup_iv, areq->src, offset,
-                                                ivsize, 0);
+                       scatterwalk_map_and_copy(rctx->backup_iv, areq->src,
+                                                offset, ivsize, 0);
                }
-               memcpy(chan->bounce_iv, areq->iv, ivsize);
-               addr_iv = dma_map_single(ce->dev, chan->bounce_iv, chan->ivlen,
-                                        DMA_TO_DEVICE);
-               cet->t_iv = cpu_to_le32(addr_iv);
-               if (dma_mapping_error(ce->dev, addr_iv)) {
+               memcpy(rctx->bounce_iv, areq->iv, ivsize);
+               rctx->addr_iv = dma_map_single(ce->dev, rctx->bounce_iv, rctx->ivlen,
+                                              DMA_TO_DEVICE);
+               if (dma_mapping_error(ce->dev, rctx->addr_iv)) {
                        dev_err(ce->dev, "Cannot DMA MAP IV\n");
                        err = -ENOMEM;
                        goto theend_iv;
                }
+               cet->t_iv = cpu_to_le32(rctx->addr_iv);
        }
 
        if (areq->src == areq->dst) {
@@ -235,7 +234,9 @@ static int sun8i_ce_cipher(struct skcipher_request *areq)
        }
 
        chan->timeout = areq->cryptlen;
-       err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(areq->base.tfm));
+       rctx->nr_sgs = nr_sgs;
+       rctx->nr_sgd = nr_sgd;
+       return 0;
 
 theend_sgs:
        if (areq->src == areq->dst) {
@@ -248,34 +249,83 @@ theend_sgs:
 
 theend_iv:
        if (areq->iv && ivsize > 0) {
-               if (addr_iv)
-                       dma_unmap_single(ce->dev, addr_iv, chan->ivlen,
-                                        DMA_TO_DEVICE);
+               if (rctx->addr_iv)
+                       dma_unmap_single(ce->dev, rctx->addr_iv, rctx->ivlen, DMA_TO_DEVICE);
                offset = areq->cryptlen - ivsize;
                if (rctx->op_dir & CE_DECRYPTION) {
-                       memcpy(areq->iv, backup_iv, ivsize);
-                       kfree_sensitive(backup_iv);
+                       memcpy(areq->iv, rctx->backup_iv, ivsize);
+                       kfree_sensitive(rctx->backup_iv);
                } else {
                        scatterwalk_map_and_copy(areq->iv, areq->dst, offset,
                                                 ivsize, 0);
                }
-               kfree(chan->bounce_iv);
+               kfree(rctx->bounce_iv);
        }
 
 theend_key:
-       dma_unmap_single(ce->dev, addr_key, op->keylen, DMA_TO_DEVICE);
+       dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE);
 
 theend:
        return err;
 }
 
-static int sun8i_ce_handle_cipher_request(struct crypto_engine *engine, void *areq)
+static int sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq)
 {
-       int err;
        struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(breq);
+       struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+       struct sun8i_ce_dev *ce = op->ce;
+       struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(breq);
+       int flow, err;
 
-       err = sun8i_ce_cipher(breq);
+       flow = rctx->flow;
+       err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm));
        crypto_finalize_skcipher_request(engine, breq, err);
+       return 0;
+}
+
+static int sun8i_ce_cipher_unprepare(struct crypto_engine *engine, void *async_req)
+{
+       struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base);
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+       struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+       struct sun8i_ce_dev *ce = op->ce;
+       struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
+       struct sun8i_ce_flow *chan;
+       struct ce_task *cet;
+       unsigned int ivsize, offset;
+       int nr_sgs = rctx->nr_sgs;
+       int nr_sgd = rctx->nr_sgd;
+       int flow;
+
+       flow = rctx->flow;
+       chan = &ce->chanlist[flow];
+       cet = chan->tl;
+       ivsize = crypto_skcipher_ivsize(tfm);
+
+       if (areq->src == areq->dst) {
+               dma_unmap_sg(ce->dev, areq->src, nr_sgs, DMA_BIDIRECTIONAL);
+       } else {
+               if (nr_sgs > 0)
+                       dma_unmap_sg(ce->dev, areq->src, nr_sgs, DMA_TO_DEVICE);
+               dma_unmap_sg(ce->dev, areq->dst, nr_sgd, DMA_FROM_DEVICE);
+       }
+
+       if (areq->iv && ivsize > 0) {
+               if (cet->t_iv)
+                       dma_unmap_single(ce->dev, rctx->addr_iv, rctx->ivlen, DMA_TO_DEVICE);
+               offset = areq->cryptlen - ivsize;
+               if (rctx->op_dir & CE_DECRYPTION) {
+                       memcpy(areq->iv, rctx->backup_iv, ivsize);
+                       kfree_sensitive(rctx->backup_iv);
+               } else {
+                       scatterwalk_map_and_copy(areq->iv, areq->dst, offset,
+                                                ivsize, 0);
+               }
+               kfree(rctx->bounce_iv);
+       }
+
+       dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE);
 
        return 0;
 }
@@ -347,9 +397,9 @@ int sun8i_ce_cipher_init(struct crypto_tfm *tfm)
                 crypto_tfm_alg_driver_name(&sktfm->base),
                 crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)));
 
-       op->enginectx.op.do_one_request = sun8i_ce_handle_cipher_request;
-       op->enginectx.op.prepare_request = NULL;
-       op->enginectx.op.unprepare_request = NULL;
+       op->enginectx.op.do_one_request = sun8i_ce_cipher_run;
+       op->enginectx.op.prepare_request = sun8i_ce_cipher_prepare;
+       op->enginectx.op.unprepare_request = sun8i_ce_cipher_unprepare;
 
        err = pm_runtime_get_sync(op->ce->dev);
        if (err < 0)
@@ -366,10 +416,7 @@ void sun8i_ce_cipher_exit(struct crypto_tfm *tfm)
 {
        struct sun8i_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
 
-       if (op->key) {
-               memzero_explicit(op->key, op->keylen);
-               kfree(op->key);
-       }
+       kfree_sensitive(op->key);
        crypto_free_skcipher(op->fallback_tfm);
        pm_runtime_put_sync_suspend(op->ce->dev);
 }
@@ -391,10 +438,7 @@ int sun8i_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
                dev_dbg(ce->dev, "ERROR: Invalid keylen %u\n", keylen);
                return -EINVAL;
        }
-       if (op->key) {
-               memzero_explicit(op->key, op->keylen);
-               kfree(op->key);
-       }
+       kfree_sensitive(op->key);
        op->keylen = keylen;
        op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
        if (!op->key)
@@ -416,10 +460,7 @@ int sun8i_ce_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
        if (err)
                return err;
 
-       if (op->key) {
-               memzero_explicit(op->key, op->keylen);
-               kfree(op->key);
-       }
+       kfree_sensitive(op->key);
        op->keylen = keylen;
        op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
        if (!op->key)
index 138759d..158422f 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/reset.h>
+#include <crypto/internal/rng.h>
 #include <crypto/internal/skcipher.h>
 
 #include "sun8i-ce.h"
 static const struct ce_variant ce_h3_variant = {
        .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,
        },
+       .alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,
+               CE_ALG_SHA384, CE_ALG_SHA512
+       },
        .op_mode = { CE_OP_ECB, CE_OP_CBC
        },
        .ce_clks = {
                { "bus", 0, 200000000 },
                { "mod", 50000000, 0 },
-               }
+               },
+       .esr = ESR_H3,
+       .prng = CE_ALG_PRNG,
+       .trng = CE_ID_NOTSUPP,
 };
 
 static const struct ce_variant ce_h5_variant = {
        .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,
        },
+       .alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,
+               CE_ID_NOTSUPP, CE_ID_NOTSUPP
+       },
        .op_mode = { CE_OP_ECB, CE_OP_CBC
        },
        .ce_clks = {
                { "bus", 0, 200000000 },
                { "mod", 300000000, 0 },
-               }
+               },
+       .esr = ESR_H5,
+       .prng = CE_ALG_PRNG,
+       .trng = CE_ID_NOTSUPP,
 };
 
 static const struct ce_variant ce_h6_variant = {
        .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,
        },
+       .alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,
+               CE_ALG_SHA384, CE_ALG_SHA512
+       },
        .op_mode = { CE_OP_ECB, CE_OP_CBC
        },
-       .has_t_dlen_in_bytes = true,
+       .cipher_t_dlen_in_bytes = true,
+       .hash_t_dlen_in_bits = true,
+       .prng_t_dlen_in_bytes = true,
+       .trng_t_dlen_in_bytes = true,
        .ce_clks = {
                { "bus", 0, 200000000 },
                { "mod", 300000000, 0 },
                { "ram", 0, 400000000 },
-               }
+               },
+       .esr = ESR_H6,
+       .prng = CE_ALG_PRNG_V2,
+       .trng = CE_ALG_TRNG_V2,
 };
 
 static const struct ce_variant ce_a64_variant = {
        .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,
        },
+       .alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,
+               CE_ID_NOTSUPP, CE_ID_NOTSUPP
+       },
        .op_mode = { CE_OP_ECB, CE_OP_CBC
        },
        .ce_clks = {
                { "bus", 0, 200000000 },
                { "mod", 300000000, 0 },
-               }
+               },
+       .esr = ESR_A64,
+       .prng = CE_ALG_PRNG,
+       .trng = CE_ID_NOTSUPP,
 };
 
 static const struct ce_variant ce_r40_variant = {
        .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES,
        },
+       .alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256,
+               CE_ID_NOTSUPP, CE_ID_NOTSUPP
+       },
        .op_mode = { CE_OP_ECB, CE_OP_CBC
        },
        .ce_clks = {
                { "bus", 0, 200000000 },
                { "mod", 300000000, 0 },
-               }
+               },
+       .esr = ESR_R40,
+       .prng = CE_ALG_PRNG,
+       .trng = CE_ID_NOTSUPP,
 };
 
 /*
  * sun8i_ce_get_engine_number() get the next channel slot
  * This is a simple round-robin way of getting the next channel
+ * The flow 3 is reserve for xRNG operations
  */
 int sun8i_ce_get_engine_number(struct sun8i_ce_dev *ce)
 {
-       return atomic_inc_return(&ce->flow) % MAXFLOW;
+       return atomic_inc_return(&ce->flow) % (MAXFLOW - 1);
 }
 
 int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name)
 {
        u32 v;
        int err = 0;
+       struct ce_task *cet = ce->chanlist[flow].tl;
 
 #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
        ce->chanlist[flow].stat_req++;
@@ -120,7 +156,10 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name)
        /* Be sure all data is written before enabling the task */
        wmb();
 
-       v = 1 | (ce->chanlist[flow].tl->t_common_ctl & 0x7F) << 8;
+       /* Only H6 needs to write a part of t_common_ctl along with "1", but since it is ignored
+        * on older SoCs, we have no reason to complicate things.
+        */
+       v = 1 | ((le32_to_cpu(ce->chanlist[flow].tl->t_common_ctl) & 0x7F) << 8);
        writel(v, ce->base + CE_TLR);
        mutex_unlock(&ce->mlock);
 
@@ -128,19 +167,56 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name)
                        msecs_to_jiffies(ce->chanlist[flow].timeout));
 
        if (ce->chanlist[flow].status == 0) {
-               dev_err(ce->dev, "DMA timeout for %s\n", name);
+               dev_err(ce->dev, "DMA timeout for %s (tm=%d) on flow %d\n", name,
+                       ce->chanlist[flow].timeout, flow);
                err = -EFAULT;
        }
        /* No need to lock for this read, the channel is locked so
         * nothing could modify the error value for this channel
         */
        v = readl(ce->base + CE_ESR);
-       if (v) {
+       switch (ce->variant->esr) {
+       case ESR_H3:
+               /* Sadly, the error bit is not per flow */
+               if (v) {
+                       dev_err(ce->dev, "CE ERROR: %x for flow %x\n", v, flow);
+                       err = -EFAULT;
+                       print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4,
+                                      cet, sizeof(struct ce_task), false);
+               }
+               if (v & CE_ERR_ALGO_NOTSUP)
+                       dev_err(ce->dev, "CE ERROR: algorithm not supported\n");
+               if (v & CE_ERR_DATALEN)
+                       dev_err(ce->dev, "CE ERROR: data length error\n");
+               if (v & CE_ERR_KEYSRAM)
+                       dev_err(ce->dev, "CE ERROR: keysram access error for AES\n");
+               break;
+       case ESR_A64:
+       case ESR_H5:
+       case ESR_R40:
                v >>= (flow * 4);
+               v &= 0xF;
+               if (v) {
+                       dev_err(ce->dev, "CE ERROR: %x for flow %x\n", v, flow);
+                       err = -EFAULT;
+                       print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4,
+                                      cet, sizeof(struct ce_task), false);
+               }
+               if (v & CE_ERR_ALGO_NOTSUP)
+                       dev_err(ce->dev, "CE ERROR: algorithm not supported\n");
+               if (v & CE_ERR_DATALEN)
+                       dev_err(ce->dev, "CE ERROR: data length error\n");
+               if (v & CE_ERR_KEYSRAM)
+                       dev_err(ce->dev, "CE ERROR: keysram access error for AES\n");
+               break;
+       case ESR_H6:
+               v >>= (flow * 8);
                v &= 0xFF;
                if (v) {
                        dev_err(ce->dev, "CE ERROR: %x for flow %x\n", v, flow);
                        err = -EFAULT;
+                       print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4,
+                                      cet, sizeof(struct ce_task), false);
                }
                if (v & CE_ERR_ALGO_NOTSUP)
                        dev_err(ce->dev, "CE ERROR: algorithm not supported\n");
@@ -150,7 +226,10 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name)
                        dev_err(ce->dev, "CE ERROR: keysram access error for AES\n");
                if (v & CE_ERR_ADDR_INVALID)
                        dev_err(ce->dev, "CE ERROR: address invalid\n");
-               }
+               if (v & CE_ERR_KEYLADDER)
+                       dev_err(ce->dev, "CE ERROR: key ladder configuration error\n");
+               break;
+       }
 
        return err;
 }
@@ -280,13 +359,214 @@ static struct sun8i_ce_alg_template ce_algs[] = {
                .decrypt        = sun8i_ce_skdecrypt,
        }
 },
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_HASH
+{      .type = CRYPTO_ALG_TYPE_AHASH,
+       .ce_algo_id = CE_ID_HASH_MD5,
+       .alg.hash = {
+               .init = sun8i_ce_hash_init,
+               .update = sun8i_ce_hash_update,
+               .final = sun8i_ce_hash_final,
+               .finup = sun8i_ce_hash_finup,
+               .digest = sun8i_ce_hash_digest,
+               .export = sun8i_ce_hash_export,
+               .import = sun8i_ce_hash_import,
+               .halg = {
+                       .digestsize = MD5_DIGEST_SIZE,
+                       .statesize = sizeof(struct md5_state),
+                       .base = {
+                               .cra_name = "md5",
+                               .cra_driver_name = "md5-sun8i-ce",
+                               .cra_priority = 300,
+                               .cra_alignmask = 3,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
+                               .cra_module = THIS_MODULE,
+                               .cra_init = sun8i_ce_hash_crainit,
+                               .cra_exit = sun8i_ce_hash_craexit,
+                       }
+               }
+       }
+},
+{      .type = CRYPTO_ALG_TYPE_AHASH,
+       .ce_algo_id = CE_ID_HASH_SHA1,
+       .alg.hash = {
+               .init = sun8i_ce_hash_init,
+               .update = sun8i_ce_hash_update,
+               .final = sun8i_ce_hash_final,
+               .finup = sun8i_ce_hash_finup,
+               .digest = sun8i_ce_hash_digest,
+               .export = sun8i_ce_hash_export,
+               .import = sun8i_ce_hash_import,
+               .halg = {
+                       .digestsize = SHA1_DIGEST_SIZE,
+                       .statesize = sizeof(struct sha1_state),
+                       .base = {
+                               .cra_name = "sha1",
+                               .cra_driver_name = "sha1-sun8i-ce",
+                               .cra_priority = 300,
+                               .cra_alignmask = 3,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA1_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
+                               .cra_module = THIS_MODULE,
+                               .cra_init = sun8i_ce_hash_crainit,
+                               .cra_exit = sun8i_ce_hash_craexit,
+                       }
+               }
+       }
+},
+{      .type = CRYPTO_ALG_TYPE_AHASH,
+       .ce_algo_id = CE_ID_HASH_SHA224,
+       .alg.hash = {
+               .init = sun8i_ce_hash_init,
+               .update = sun8i_ce_hash_update,
+               .final = sun8i_ce_hash_final,
+               .finup = sun8i_ce_hash_finup,
+               .digest = sun8i_ce_hash_digest,
+               .export = sun8i_ce_hash_export,
+               .import = sun8i_ce_hash_import,
+               .halg = {
+                       .digestsize = SHA224_DIGEST_SIZE,
+                       .statesize = sizeof(struct sha256_state),
+                       .base = {
+                               .cra_name = "sha224",
+                               .cra_driver_name = "sha224-sun8i-ce",
+                               .cra_priority = 300,
+                               .cra_alignmask = 3,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA224_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
+                               .cra_module = THIS_MODULE,
+                               .cra_init = sun8i_ce_hash_crainit,
+                               .cra_exit = sun8i_ce_hash_craexit,
+                       }
+               }
+       }
+},
+{      .type = CRYPTO_ALG_TYPE_AHASH,
+       .ce_algo_id = CE_ID_HASH_SHA256,
+       .alg.hash = {
+               .init = sun8i_ce_hash_init,
+               .update = sun8i_ce_hash_update,
+               .final = sun8i_ce_hash_final,
+               .finup = sun8i_ce_hash_finup,
+               .digest = sun8i_ce_hash_digest,
+               .export = sun8i_ce_hash_export,
+               .import = sun8i_ce_hash_import,
+               .halg = {
+                       .digestsize = SHA256_DIGEST_SIZE,
+                       .statesize = sizeof(struct sha256_state),
+                       .base = {
+                               .cra_name = "sha256",
+                               .cra_driver_name = "sha256-sun8i-ce",
+                               .cra_priority = 300,
+                               .cra_alignmask = 3,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA256_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
+                               .cra_module = THIS_MODULE,
+                               .cra_init = sun8i_ce_hash_crainit,
+                               .cra_exit = sun8i_ce_hash_craexit,
+                       }
+               }
+       }
+},
+{      .type = CRYPTO_ALG_TYPE_AHASH,
+       .ce_algo_id = CE_ID_HASH_SHA384,
+       .alg.hash = {
+               .init = sun8i_ce_hash_init,
+               .update = sun8i_ce_hash_update,
+               .final = sun8i_ce_hash_final,
+               .finup = sun8i_ce_hash_finup,
+               .digest = sun8i_ce_hash_digest,
+               .export = sun8i_ce_hash_export,
+               .import = sun8i_ce_hash_import,
+               .halg = {
+                       .digestsize = SHA384_DIGEST_SIZE,
+                       .statesize = sizeof(struct sha512_state),
+                       .base = {
+                               .cra_name = "sha384",
+                               .cra_driver_name = "sha384-sun8i-ce",
+                               .cra_priority = 300,
+                               .cra_alignmask = 3,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA384_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
+                               .cra_module = THIS_MODULE,
+                               .cra_init = sun8i_ce_hash_crainit,
+                               .cra_exit = sun8i_ce_hash_craexit,
+                       }
+               }
+       }
+},
+{      .type = CRYPTO_ALG_TYPE_AHASH,
+       .ce_algo_id = CE_ID_HASH_SHA512,
+       .alg.hash = {
+               .init = sun8i_ce_hash_init,
+               .update = sun8i_ce_hash_update,
+               .final = sun8i_ce_hash_final,
+               .finup = sun8i_ce_hash_finup,
+               .digest = sun8i_ce_hash_digest,
+               .export = sun8i_ce_hash_export,
+               .import = sun8i_ce_hash_import,
+               .halg = {
+                       .digestsize = SHA512_DIGEST_SIZE,
+                       .statesize = sizeof(struct sha512_state),
+                       .base = {
+                               .cra_name = "sha512",
+                               .cra_driver_name = "sha512-sun8i-ce",
+                               .cra_priority = 300,
+                               .cra_alignmask = 3,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA512_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
+                               .cra_module = THIS_MODULE,
+                               .cra_init = sun8i_ce_hash_crainit,
+                               .cra_exit = sun8i_ce_hash_craexit,
+                       }
+               }
+       }
+},
+#endif
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_PRNG
+{
+       .type = CRYPTO_ALG_TYPE_RNG,
+       .alg.rng = {
+               .base = {
+                       .cra_name               = "stdrng",
+                       .cra_driver_name        = "sun8i-ce-prng",
+                       .cra_priority           = 300,
+                       .cra_ctxsize            = sizeof(struct sun8i_ce_rng_tfm_ctx),
+                       .cra_module             = THIS_MODULE,
+                       .cra_init               = sun8i_ce_prng_init,
+                       .cra_exit               = sun8i_ce_prng_exit,
+               },
+               .generate               = sun8i_ce_prng_generate,
+               .seed                   = sun8i_ce_prng_seed,
+               .seedsize               = PRNG_SEED_SIZE,
+       }
+},
+#endif
 };
 
 #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
-static int sun8i_ce_dbgfs_read(struct seq_file *seq, void *v)
+static int sun8i_ce_debugfs_show(struct seq_file *seq, void *v)
 {
        struct sun8i_ce_dev *ce = seq->private;
-       int i;
+       unsigned int i;
 
        for (i = 0; i < MAXFLOW; i++)
                seq_printf(seq, "Channel %d: nreq %lu\n", i, ce->chanlist[i].stat_req);
@@ -301,23 +581,28 @@ static int sun8i_ce_dbgfs_read(struct seq_file *seq, void *v)
                                   ce_algs[i].alg.skcipher.base.cra_name,
                                   ce_algs[i].stat_req, ce_algs[i].stat_fb);
                        break;
+               case CRYPTO_ALG_TYPE_AHASH:
+                       seq_printf(seq, "%s %s %lu %lu\n",
+                                  ce_algs[i].alg.hash.halg.base.cra_driver_name,
+                                  ce_algs[i].alg.hash.halg.base.cra_name,
+                                  ce_algs[i].stat_req, ce_algs[i].stat_fb);
+                       break;
+               case CRYPTO_ALG_TYPE_RNG:
+                       seq_printf(seq, "%s %s %lu %lu\n",
+                                  ce_algs[i].alg.rng.base.cra_driver_name,
+                                  ce_algs[i].alg.rng.base.cra_name,
+                                  ce_algs[i].stat_req, ce_algs[i].stat_bytes);
+                       break;
                }
        }
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG
+       seq_printf(seq, "HWRNG %lu %lu\n",
+                  ce->hwrng_stat_req, ce->hwrng_stat_bytes);
+#endif
        return 0;
 }
 
-static int sun8i_ce_dbgfs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, sun8i_ce_dbgfs_read, inode->i_private);
-}
-
-static const struct file_operations sun8i_ce_debugfs_fops = {
-       .owner = THIS_MODULE,
-       .open = sun8i_ce_dbgfs_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(sun8i_ce_debugfs);
 #endif
 
 static void sun8i_ce_free_chanlist(struct sun8i_ce_dev *ce, int i)
@@ -482,7 +767,8 @@ static int sun8i_ce_get_clks(struct sun8i_ce_dev *ce)
 
 static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce)
 {
-       int ce_method, err, id, i;
+       int ce_method, err, id;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
                ce_algs[i].ce = ce;
@@ -515,6 +801,43 @@ static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce)
                                return err;
                        }
                        break;
+               case CRYPTO_ALG_TYPE_AHASH:
+                       id = ce_algs[i].ce_algo_id;
+                       ce_method = ce->variant->alg_hash[id];
+                       if (ce_method == CE_ID_NOTSUPP) {
+                               dev_info(ce->dev,
+                                        "DEBUG: Algo of %s not supported\n",
+                                        ce_algs[i].alg.hash.halg.base.cra_name);
+                               ce_algs[i].ce = NULL;
+                               break;
+                       }
+                       dev_info(ce->dev, "Register %s\n",
+                                ce_algs[i].alg.hash.halg.base.cra_name);
+                       err = crypto_register_ahash(&ce_algs[i].alg.hash);
+                       if (err) {
+                               dev_err(ce->dev, "ERROR: Fail to register %s\n",
+                                       ce_algs[i].alg.hash.halg.base.cra_name);
+                               ce_algs[i].ce = NULL;
+                               return err;
+                       }
+                       break;
+               case CRYPTO_ALG_TYPE_RNG:
+                       if (ce->variant->prng == CE_ID_NOTSUPP) {
+                               dev_info(ce->dev,
+                                        "DEBUG: Algo of %s not supported\n",
+                                        ce_algs[i].alg.rng.base.cra_name);
+                               ce_algs[i].ce = NULL;
+                               break;
+                       }
+                       dev_info(ce->dev, "Register %s\n",
+                                ce_algs[i].alg.rng.base.cra_name);
+                       err = crypto_register_rng(&ce_algs[i].alg.rng);
+                       if (err) {
+                               dev_err(ce->dev, "Fail to register %s\n",
+                                       ce_algs[i].alg.rng.base.cra_name);
+                               ce_algs[i].ce = NULL;
+                       }
+                       break;
                default:
                        ce_algs[i].ce = NULL;
                        dev_err(ce->dev, "ERROR: tried to register an unknown algo\n");
@@ -525,7 +848,7 @@ static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce)
 
 static void sun8i_ce_unregister_algs(struct sun8i_ce_dev *ce)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
                if (!ce_algs[i].ce)
@@ -536,6 +859,16 @@ static void sun8i_ce_unregister_algs(struct sun8i_ce_dev *ce)
                                 ce_algs[i].alg.skcipher.base.cra_name);
                        crypto_unregister_skcipher(&ce_algs[i].alg.skcipher);
                        break;
+               case CRYPTO_ALG_TYPE_AHASH:
+                       dev_info(ce->dev, "Unregister %d %s\n", i,
+                                ce_algs[i].alg.hash.halg.base.cra_name);
+                       crypto_unregister_ahash(&ce_algs[i].alg.hash);
+                       break;
+               case CRYPTO_ALG_TYPE_RNG:
+                       dev_info(ce->dev, "Unregister %d %s\n", i,
+                                ce_algs[i].alg.rng.base.cra_name);
+                       crypto_unregister_rng(&ce_algs[i].alg.rng);
+                       break;
                }
        }
 }
@@ -573,14 +906,12 @@ static int sun8i_ce_probe(struct platform_device *pdev)
                return irq;
 
        ce->reset = devm_reset_control_get(&pdev->dev, NULL);
-       if (IS_ERR(ce->reset)) {
-               if (PTR_ERR(ce->reset) == -EPROBE_DEFER)
-                       return PTR_ERR(ce->reset);
-               dev_err(&pdev->dev, "No reset control found\n");
-               return PTR_ERR(ce->reset);
-       }
+       if (IS_ERR(ce->reset))
+               return dev_err_probe(&pdev->dev, PTR_ERR(ce->reset),
+                                    "No reset control found\n");
 
        mutex_init(&ce->mlock);
+       mutex_init(&ce->rnglock);
 
        err = sun8i_ce_allocate_chanlist(ce);
        if (err)
@@ -605,6 +936,10 @@ static int sun8i_ce_probe(struct platform_device *pdev)
        if (err < 0)
                goto error_alg;
 
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG
+       sun8i_ce_hwrng_register(ce);
+#endif
+
        v = readl(ce->base + CE_CTR);
        v >>= CE_DIE_ID_SHIFT;
        v &= CE_DIE_ID_MASK;
@@ -634,6 +969,10 @@ static int sun8i_ce_remove(struct platform_device *pdev)
 {
        struct sun8i_ce_dev *ce = platform_get_drvdata(pdev);
 
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG
+       sun8i_ce_hwrng_unregister(ce);
+#endif
+
        sun8i_ce_unregister_algs(ce);
 
 #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c
new file mode 100644 (file)
index 0000000..fa2f1b4
--- /dev/null
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sun8i-ce-hash.c - hardware cryptographic offloader for
+ * Allwinner H3/A64/H5/H2+/H6/R40 SoC
+ *
+ * Copyright (C) 2015-2020 Corentin Labbe <clabbe@baylibre.com>
+ *
+ * This file add support for MD5 and SHA1/SHA224/SHA256/SHA384/SHA512.
+ *
+ * You could find the datasheet in Documentation/arm/sunxi/README
+ */
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <crypto/md5.h>
+#include "sun8i-ce.h"
+
+int sun8i_ce_hash_crainit(struct crypto_tfm *tfm)
+{
+       struct sun8i_ce_hash_tfm_ctx *op = crypto_tfm_ctx(tfm);
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
+       struct sun8i_ce_alg_template *algt;
+       int err;
+
+       memset(op, 0, sizeof(struct sun8i_ce_hash_tfm_ctx));
+
+       algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
+       op->ce = algt->ce;
+
+       op->enginectx.op.do_one_request = sun8i_ce_hash_run;
+       op->enginectx.op.prepare_request = NULL;
+       op->enginectx.op.unprepare_request = NULL;
+
+       /* FALLBACK */
+       op->fallback_tfm = crypto_alloc_ahash(crypto_tfm_alg_name(tfm), 0,
+                                             CRYPTO_ALG_NEED_FALLBACK);
+       if (IS_ERR(op->fallback_tfm)) {
+               dev_err(algt->ce->dev, "Fallback driver could no be loaded\n");
+               return PTR_ERR(op->fallback_tfm);
+       }
+
+       if (algt->alg.hash.halg.statesize < crypto_ahash_statesize(op->fallback_tfm))
+               algt->alg.hash.halg.statesize = crypto_ahash_statesize(op->fallback_tfm);
+
+       crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+                                sizeof(struct sun8i_ce_hash_reqctx) +
+                                crypto_ahash_reqsize(op->fallback_tfm));
+
+       dev_info(op->ce->dev, "Fallback for %s is %s\n",
+                crypto_tfm_alg_driver_name(tfm),
+                crypto_tfm_alg_driver_name(&op->fallback_tfm->base));
+       err = pm_runtime_get_sync(op->ce->dev);
+       if (err < 0)
+               goto error_pm;
+       return 0;
+error_pm:
+       pm_runtime_put_noidle(op->ce->dev);
+       crypto_free_ahash(op->fallback_tfm);
+       return err;
+}
+
+void sun8i_ce_hash_craexit(struct crypto_tfm *tfm)
+{
+       struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_ahash(tfmctx->fallback_tfm);
+       pm_runtime_put_sync_suspend(tfmctx->ce->dev);
+}
+
+int sun8i_ce_hash_init(struct ahash_request *areq)
+{
+       struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+
+       memset(rctx, 0, sizeof(struct sun8i_ce_hash_reqctx));
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       return crypto_ahash_init(&rctx->fallback_req);
+}
+
+int sun8i_ce_hash_export(struct ahash_request *areq, void *out)
+{
+       struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       return crypto_ahash_export(&rctx->fallback_req, out);
+}
+
+int sun8i_ce_hash_import(struct ahash_request *areq, const void *in)
+{
+       struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       return crypto_ahash_import(&rctx->fallback_req, in);
+}
+
+int sun8i_ce_hash_final(struct ahash_request *areq)
+{
+       struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+       struct sun8i_ce_alg_template *algt;
+#endif
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags &
+                                       CRYPTO_TFM_REQ_MAY_SLEEP;
+       rctx->fallback_req.result = areq->result;
+
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+       algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
+       algt->stat_fb++;
+#endif
+
+       return crypto_ahash_final(&rctx->fallback_req);
+}
+
+int sun8i_ce_hash_update(struct ahash_request *areq)
+{
+       struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags &
+                                       CRYPTO_TFM_REQ_MAY_SLEEP;
+       rctx->fallback_req.nbytes = areq->nbytes;
+       rctx->fallback_req.src = areq->src;
+
+       return crypto_ahash_update(&rctx->fallback_req);
+}
+
+int sun8i_ce_hash_finup(struct ahash_request *areq)
+{
+       struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+       struct sun8i_ce_alg_template *algt;
+#endif
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags &
+                                       CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       rctx->fallback_req.nbytes = areq->nbytes;
+       rctx->fallback_req.src = areq->src;
+       rctx->fallback_req.result = areq->result;
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+       algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
+       algt->stat_fb++;
+#endif
+
+       return crypto_ahash_finup(&rctx->fallback_req);
+}
+
+static int sun8i_ce_hash_digest_fb(struct ahash_request *areq)
+{
+       struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+       struct sun8i_ce_alg_template *algt;
+#endif
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags &
+                                       CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       rctx->fallback_req.nbytes = areq->nbytes;
+       rctx->fallback_req.src = areq->src;
+       rctx->fallback_req.result = areq->result;
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+       algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
+       algt->stat_fb++;
+#endif
+
+       return crypto_ahash_digest(&rctx->fallback_req);
+}
+
+static bool sun8i_ce_hash_need_fallback(struct ahash_request *areq)
+{
+       struct scatterlist *sg;
+
+       if (areq->nbytes == 0)
+               return true;
+       /* we need to reserve one SG for padding one */
+       if (sg_nents(areq->src) > MAX_SG - 1)
+               return true;
+       sg = areq->src;
+       while (sg) {
+               if (sg->length % 4 || !IS_ALIGNED(sg->offset, sizeof(u32)))
+                       return true;
+               sg = sg_next(sg);
+       }
+       return false;
+}
+
+int sun8i_ce_hash_digest(struct ahash_request *areq)
+{
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+       struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct sun8i_ce_alg_template *algt;
+       struct sun8i_ce_dev *ce;
+       struct crypto_engine *engine;
+       struct scatterlist *sg;
+       int nr_sgs, e, i;
+
+       if (sun8i_ce_hash_need_fallback(areq))
+               return sun8i_ce_hash_digest_fb(areq);
+
+       nr_sgs = sg_nents(areq->src);
+       if (nr_sgs > MAX_SG - 1)
+               return sun8i_ce_hash_digest_fb(areq);
+
+       for_each_sg(areq->src, sg, nr_sgs, i) {
+               if (sg->length % 4 || !IS_ALIGNED(sg->offset, sizeof(u32)))
+                       return sun8i_ce_hash_digest_fb(areq);
+       }
+
+       algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
+       ce = algt->ce;
+
+       e = sun8i_ce_get_engine_number(ce);
+       rctx->flow = e;
+       engine = ce->chanlist[e].engine;
+
+       return crypto_transfer_hash_request_to_engine(engine, areq);
+}
+
+int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
+{
+       struct ahash_request *areq = container_of(breq, struct ahash_request, base);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+       struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct sun8i_ce_alg_template *algt;
+       struct sun8i_ce_dev *ce;
+       struct sun8i_ce_flow *chan;
+       struct ce_task *cet;
+       struct scatterlist *sg;
+       int nr_sgs, flow, err;
+       unsigned int len;
+       u32 common;
+       u64 byte_count;
+       __le32 *bf;
+       void *buf;
+       int j, i, todo;
+       int nbw = 0;
+       u64 fill, min_fill;
+       __be64 *bebits;
+       __le64 *lebits;
+       void *result;
+       u64 bs;
+       int digestsize;
+       dma_addr_t addr_res, addr_pad;
+
+       algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
+       ce = algt->ce;
+
+       bs = algt->alg.hash.halg.base.cra_blocksize;
+       digestsize = algt->alg.hash.halg.digestsize;
+       if (digestsize == SHA224_DIGEST_SIZE)
+               digestsize = SHA256_DIGEST_SIZE;
+       if (digestsize == SHA384_DIGEST_SIZE)
+               digestsize = SHA512_DIGEST_SIZE;
+
+       /* the padding could be up to two block. */
+       buf = kzalloc(bs * 2, GFP_KERNEL | GFP_DMA);
+       if (!buf)
+               return -ENOMEM;
+       bf = (__le32 *)buf;
+
+       result = kzalloc(digestsize, GFP_KERNEL | GFP_DMA);
+       if (!result)
+               return -ENOMEM;
+
+       flow = rctx->flow;
+       chan = &ce->chanlist[flow];
+
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+       algt->stat_req++;
+#endif
+       dev_dbg(ce->dev, "%s %s len=%d\n", __func__, crypto_tfm_alg_name(areq->base.tfm), areq->nbytes);
+
+       cet = chan->tl;
+       memset(cet, 0, sizeof(struct ce_task));
+
+       cet->t_id = cpu_to_le32(flow);
+       common = ce->variant->alg_hash[algt->ce_algo_id];
+       common |= CE_COMM_INT;
+       cet->t_common_ctl = cpu_to_le32(common);
+
+       cet->t_sym_ctl = 0;
+       cet->t_asym_ctl = 0;
+
+       nr_sgs = dma_map_sg(ce->dev, areq->src, sg_nents(areq->src), DMA_TO_DEVICE);
+       if (nr_sgs <= 0 || nr_sgs > MAX_SG) {
+               dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
+               err = -EINVAL;
+               goto theend;
+       }
+
+       len = areq->nbytes;
+       for_each_sg(areq->src, sg, nr_sgs, i) {
+               cet->t_src[i].addr = cpu_to_le32(sg_dma_address(sg));
+               todo = min(len, sg_dma_len(sg));
+               cet->t_src[i].len = cpu_to_le32(todo / 4);
+               len -= todo;
+       }
+       if (len > 0) {
+               dev_err(ce->dev, "remaining len %d\n", len);
+               err = -EINVAL;
+               goto theend;
+       }
+       addr_res = dma_map_single(ce->dev, result, digestsize, DMA_FROM_DEVICE);
+       cet->t_dst[0].addr = cpu_to_le32(addr_res);
+       cet->t_dst[0].len = cpu_to_le32(digestsize / 4);
+       if (dma_mapping_error(ce->dev, addr_res)) {
+               dev_err(ce->dev, "DMA map dest\n");
+               err = -EINVAL;
+               goto theend;
+       }
+
+       byte_count = areq->nbytes;
+       j = 0;
+       bf[j++] = cpu_to_le32(0x80);
+
+       if (bs == 64) {
+               fill = 64 - (byte_count % 64);
+               min_fill = 2 * sizeof(u32) + (nbw ? 0 : sizeof(u32));
+       } else {
+               fill = 128 - (byte_count % 128);
+               min_fill = 4 * sizeof(u32) + (nbw ? 0 : sizeof(u32));
+       }
+
+       if (fill < min_fill)
+               fill += bs;
+
+       j += (fill - min_fill) / sizeof(u32);
+
+       switch (algt->ce_algo_id) {
+       case CE_ID_HASH_MD5:
+               lebits = (__le64 *)&bf[j];
+               *lebits = cpu_to_le64(byte_count << 3);
+               j += 2;
+               break;
+       case CE_ID_HASH_SHA1:
+       case CE_ID_HASH_SHA224:
+       case CE_ID_HASH_SHA256:
+               bebits = (__be64 *)&bf[j];
+               *bebits = cpu_to_be64(byte_count << 3);
+               j += 2;
+               break;
+       case CE_ID_HASH_SHA384:
+       case CE_ID_HASH_SHA512:
+               bebits = (__be64 *)&bf[j];
+               *bebits = cpu_to_be64(byte_count >> 61);
+               j += 2;
+               bebits = (__be64 *)&bf[j];
+               *bebits = cpu_to_be64(byte_count << 3);
+               j += 2;
+               break;
+       }
+
+       addr_pad = dma_map_single(ce->dev, buf, j * 4, DMA_TO_DEVICE);
+       cet->t_src[i].addr = cpu_to_le32(addr_pad);
+       cet->t_src[i].len = cpu_to_le32(j);
+       if (dma_mapping_error(ce->dev, addr_pad)) {
+               dev_err(ce->dev, "DMA error on padding SG\n");
+               err = -EINVAL;
+               goto theend;
+       }
+
+       if (ce->variant->hash_t_dlen_in_bits)
+               cet->t_dlen = cpu_to_le32((areq->nbytes + j * 4) * 8);
+       else
+               cet->t_dlen = cpu_to_le32(areq->nbytes / 4 + j);
+
+       chan->timeout = areq->nbytes;
+
+       err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(areq->base.tfm));
+
+       dma_unmap_single(ce->dev, addr_pad, j * 4, DMA_TO_DEVICE);
+       dma_unmap_sg(ce->dev, areq->src, nr_sgs, DMA_TO_DEVICE);
+       dma_unmap_single(ce->dev, addr_res, digestsize, DMA_FROM_DEVICE);
+
+       kfree(buf);
+
+       memcpy(areq->result, result, algt->alg.hash.halg.digestsize);
+       kfree(result);
+theend:
+       crypto_finalize_hash_request(engine, breq, err);
+       return 0;
+}
diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c
new file mode 100644 (file)
index 0000000..7850300
--- /dev/null
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sun8i-ce-prng.c - hardware cryptographic offloader for
+ * Allwinner H3/A64/H5/H2+/H6/R40 SoC
+ *
+ * Copyright (C) 2015-2020 Corentin Labbe <clabbe@baylibre.com>
+ *
+ * This file handle the PRNG
+ *
+ * You could find a link for the datasheet in Documentation/arm/sunxi/README
+ */
+#include "sun8i-ce.h"
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <crypto/internal/rng.h>
+
+int sun8i_ce_prng_init(struct crypto_tfm *tfm)
+{
+       struct sun8i_ce_rng_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       memset(ctx, 0, sizeof(struct sun8i_ce_rng_tfm_ctx));
+       return 0;
+}
+
+void sun8i_ce_prng_exit(struct crypto_tfm *tfm)
+{
+       struct sun8i_ce_rng_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       memzero_explicit(ctx->seed, ctx->slen);
+       kfree(ctx->seed);
+       ctx->seed = NULL;
+       ctx->slen = 0;
+}
+
+int sun8i_ce_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+                      unsigned int slen)
+{
+       struct sun8i_ce_rng_tfm_ctx *ctx = crypto_rng_ctx(tfm);
+
+       if (ctx->seed && ctx->slen != slen) {
+               memzero_explicit(ctx->seed, ctx->slen);
+               kfree(ctx->seed);
+               ctx->slen = 0;
+               ctx->seed = NULL;
+       }
+       if (!ctx->seed)
+               ctx->seed = kmalloc(slen, GFP_KERNEL | GFP_DMA);
+       if (!ctx->seed)
+               return -ENOMEM;
+
+       memcpy(ctx->seed, seed, slen);
+       ctx->slen = slen;
+
+       return 0;
+}
+
+int sun8i_ce_prng_generate(struct crypto_rng *tfm, const u8 *src,
+                          unsigned int slen, u8 *dst, unsigned int dlen)
+{
+       struct sun8i_ce_rng_tfm_ctx *ctx = crypto_rng_ctx(tfm);
+       struct rng_alg *alg = crypto_rng_alg(tfm);
+       struct sun8i_ce_alg_template *algt;
+       struct sun8i_ce_dev *ce;
+       dma_addr_t dma_iv, dma_dst;
+       int err = 0;
+       int flow = 3;
+       unsigned int todo;
+       struct sun8i_ce_flow *chan;
+       struct ce_task *cet;
+       u32 common, sym;
+       void *d;
+
+       algt = container_of(alg, struct sun8i_ce_alg_template, alg.rng);
+       ce = algt->ce;
+
+       if (ctx->slen == 0) {
+               dev_err(ce->dev, "not seeded\n");
+               return -EINVAL;
+       }
+
+       /* we want dlen + seedsize rounded up to a multiple of PRNG_DATA_SIZE */
+       todo = dlen + ctx->slen + PRNG_DATA_SIZE * 2;
+       todo -= todo % PRNG_DATA_SIZE;
+
+       d = kzalloc(todo, GFP_KERNEL | GFP_DMA);
+       if (!d) {
+               err = -ENOMEM;
+               goto err_mem;
+       }
+
+       dev_dbg(ce->dev, "%s PRNG slen=%u dlen=%u todo=%u multi=%u\n", __func__,
+               slen, dlen, todo, todo / PRNG_DATA_SIZE);
+
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+       algt->stat_req++;
+       algt->stat_bytes += todo;
+#endif
+
+       dma_iv = dma_map_single(ce->dev, ctx->seed, ctx->slen, DMA_TO_DEVICE);
+       if (dma_mapping_error(ce->dev, dma_iv)) {
+               dev_err(ce->dev, "Cannot DMA MAP IV\n");
+               goto err_iv;
+       }
+
+       dma_dst = dma_map_single(ce->dev, d, todo, DMA_FROM_DEVICE);
+       if (dma_mapping_error(ce->dev, dma_dst)) {
+               dev_err(ce->dev, "Cannot DMA MAP DST\n");
+               err = -EFAULT;
+               goto err_dst;
+       }
+
+       err = pm_runtime_get_sync(ce->dev);
+       if (err < 0) {
+               pm_runtime_put_noidle(ce->dev);
+               goto err_pm;
+       }
+
+       mutex_lock(&ce->rnglock);
+       chan = &ce->chanlist[flow];
+
+       cet = &chan->tl[0];
+       memset(cet, 0, sizeof(struct ce_task));
+
+       cet->t_id = cpu_to_le32(flow);
+       common = ce->variant->prng | CE_COMM_INT;
+       cet->t_common_ctl = cpu_to_le32(common);
+
+       /* recent CE (H6) need length in bytes, in word otherwise */
+       if (ce->variant->prng_t_dlen_in_bytes)
+               cet->t_dlen = cpu_to_le32(todo);
+       else
+               cet->t_dlen = cpu_to_le32(todo / 4);
+
+       sym = PRNG_LD;
+       cet->t_sym_ctl = cpu_to_le32(sym);
+       cet->t_asym_ctl = 0;
+
+       cet->t_key = cpu_to_le32(dma_iv);
+       cet->t_iv = cpu_to_le32(dma_iv);
+
+       cet->t_dst[0].addr = cpu_to_le32(dma_dst);
+       cet->t_dst[0].len = cpu_to_le32(todo / 4);
+       ce->chanlist[flow].timeout = 2000;
+
+       err = sun8i_ce_run_task(ce, 3, "PRNG");
+       mutex_unlock(&ce->rnglock);
+
+       pm_runtime_put(ce->dev);
+
+err_pm:
+       dma_unmap_single(ce->dev, dma_dst, todo, DMA_FROM_DEVICE);
+err_dst:
+       dma_unmap_single(ce->dev, dma_iv, ctx->slen, DMA_TO_DEVICE);
+
+       if (!err) {
+               memcpy(dst, d, dlen);
+               memcpy(ctx->seed, d + dlen, ctx->slen);
+       }
+       memzero_explicit(d, todo);
+err_iv:
+       kfree(d);
+err_mem:
+       return err;
+}
diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c
new file mode 100644 (file)
index 0000000..6543281
--- /dev/null
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sun8i-ce-trng.c - hardware cryptographic offloader for
+ * Allwinner H3/A64/H5/H2+/H6/R40 SoC
+ *
+ * Copyright (C) 2015-2020 Corentin Labbe <clabbe@baylibre.com>
+ *
+ * This file handle the TRNG
+ *
+ * You could find a link for the datasheet in Documentation/arm/sunxi/README
+ */
+#include "sun8i-ce.h"
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/hw_random.h>
+/*
+ * Note that according to the algorithm ID, 2 versions of the TRNG exists,
+ * The first present in H3/H5/R40/A64 and the second present in H6.
+ * This file adds support for both, but only the second is working
+ * reliabily according to rngtest.
+ **/
+
+static int sun8i_ce_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+       struct sun8i_ce_dev *ce;
+       dma_addr_t dma_dst;
+       int err = 0;
+       int flow = 3;
+       unsigned int todo;
+       struct sun8i_ce_flow *chan;
+       struct ce_task *cet;
+       u32 common;
+       void *d;
+
+       ce = container_of(rng, struct sun8i_ce_dev, trng);
+
+       /* round the data length to a multiple of 32*/
+       todo = max + 32;
+       todo -= todo % 32;
+
+       d = kzalloc(todo, GFP_KERNEL | GFP_DMA);
+       if (!d)
+               return -ENOMEM;
+
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+       ce->hwrng_stat_req++;
+       ce->hwrng_stat_bytes += todo;
+#endif
+
+       dma_dst = dma_map_single(ce->dev, d, todo, DMA_FROM_DEVICE);
+       if (dma_mapping_error(ce->dev, dma_dst)) {
+               dev_err(ce->dev, "Cannot DMA MAP DST\n");
+               err = -EFAULT;
+               goto err_dst;
+       }
+
+       err = pm_runtime_get_sync(ce->dev);
+       if (err < 0) {
+               pm_runtime_put_noidle(ce->dev);
+               goto err_pm;
+       }
+
+       mutex_lock(&ce->rnglock);
+       chan = &ce->chanlist[flow];
+
+       cet = &chan->tl[0];
+       memset(cet, 0, sizeof(struct ce_task));
+
+       cet->t_id = cpu_to_le32(flow);
+       common = ce->variant->trng | CE_COMM_INT;
+       cet->t_common_ctl = cpu_to_le32(common);
+
+       /* recent CE (H6) need length in bytes, in word otherwise */
+       if (ce->variant->trng_t_dlen_in_bytes)
+               cet->t_dlen = cpu_to_le32(todo);
+       else
+               cet->t_dlen = cpu_to_le32(todo / 4);
+
+       cet->t_sym_ctl = 0;
+       cet->t_asym_ctl = 0;
+
+       cet->t_dst[0].addr = cpu_to_le32(dma_dst);
+       cet->t_dst[0].len = cpu_to_le32(todo / 4);
+       ce->chanlist[flow].timeout = todo;
+
+       err = sun8i_ce_run_task(ce, 3, "TRNG");
+       mutex_unlock(&ce->rnglock);
+
+       pm_runtime_put(ce->dev);
+
+err_pm:
+       dma_unmap_single(ce->dev, dma_dst, todo, DMA_FROM_DEVICE);
+
+       if (!err) {
+               memcpy(data, d, max);
+               err = max;
+       }
+       memzero_explicit(d, todo);
+err_dst:
+       kfree(d);
+       return err;
+}
+
+int sun8i_ce_hwrng_register(struct sun8i_ce_dev *ce)
+{
+       int ret;
+
+       if (ce->variant->trng == CE_ID_NOTSUPP) {
+               dev_info(ce->dev, "TRNG not supported\n");
+               return 0;
+       }
+       ce->trng.name = "sun8i Crypto Engine TRNG";
+       ce->trng.read = sun8i_ce_trng_read;
+       ce->trng.quality = 1000;
+
+       ret = hwrng_register(&ce->trng);
+       if (ret)
+               dev_err(ce->dev, "Fail to register the TRNG\n");
+       return ret;
+}
+
+void sun8i_ce_hwrng_unregister(struct sun8i_ce_dev *ce)
+{
+       if (ce->variant->trng == CE_ID_NOTSUPP)
+               return;
+       hwrng_unregister(&ce->trng);
+}
index 963645f..5580275 100644 (file)
 #include <linux/atomic.h>
 #include <linux/debugfs.h>
 #include <linux/crypto.h>
+#include <linux/hw_random.h>
+#include <crypto/internal/hash.h>
+#include <crypto/md5.h>
+#include <crypto/rng.h>
+#include <crypto/sha.h>
 
 /* CE Registers */
 #define CE_TDQ 0x00
 #define CE_ALG_AES             0
 #define CE_ALG_DES             1
 #define CE_ALG_3DES            2
+#define CE_ALG_MD5              16
+#define CE_ALG_SHA1             17
+#define CE_ALG_SHA224           18
+#define CE_ALG_SHA256           19
+#define CE_ALG_SHA384           20
+#define CE_ALG_SHA512           21
+#define CE_ALG_TRNG            48
+#define CE_ALG_PRNG            49
+#define CE_ALG_TRNG_V2         0x1c
+#define CE_ALG_PRNG_V2         0x1d
 
 /* Used in ce_variant */
 #define CE_ID_NOTSUPP          0xFF
 #define CE_ID_CIPHER_DES3      2
 #define CE_ID_CIPHER_MAX       3
 
+#define CE_ID_HASH_MD5         0
+#define CE_ID_HASH_SHA1                1
+#define CE_ID_HASH_SHA224      2
+#define CE_ID_HASH_SHA256      3
+#define CE_ID_HASH_SHA384      4
+#define CE_ID_HASH_SHA512      5
+#define CE_ID_HASH_MAX         6
+
 #define CE_ID_OP_ECB   0
 #define CE_ID_OP_CBC   1
 #define CE_ID_OP_MAX   2
 #define CE_ERR_ADDR_INVALID    BIT(5)
 #define CE_ERR_KEYLADDER       BIT(6)
 
+#define ESR_H3 0
+#define ESR_A64        1
+#define ESR_R40        2
+#define ESR_H5 3
+#define ESR_H6 4
+
+#define PRNG_DATA_SIZE (160 / 8)
+#define PRNG_SEED_SIZE DIV_ROUND_UP(175, 8)
+#define PRNG_LD BIT(17)
+
 #define CE_DIE_ID_SHIFT        16
 #define CE_DIE_ID_MASK 0x07
 
@@ -90,16 +123,34 @@ struct ce_clock {
  * struct ce_variant - Describe CE capability for each variant hardware
  * @alg_cipher:        list of supported ciphers. for each CE_ID_ this will give the
  *              coresponding CE_ALG_XXX value
+ * @alg_hash:  list of supported hashes. for each CE_ID_ this will give the
+ *              corresponding CE_ALG_XXX value
  * @op_mode:   list of supported block modes
- * @has_t_dlen_in_bytes:       Does the request size for cipher is in
+ * @cipher_t_dlen_in_bytes:    Does the request size for cipher is in
+ *                             bytes or words
+ * @hash_t_dlen_in_bytes:      Does the request size for hash is in
+ *                             bits or words
+ * @prng_t_dlen_in_bytes:      Does the request size for PRNG is in
+ *                             bytes or words
+ * @trng_t_dlen_in_bytes:      Does the request size for TRNG is in
  *                             bytes or words
  * @ce_clks:   list of clocks needed by this variant
+ * @esr:       The type of error register
+ * @prng:      The CE_ALG_XXX value for the PRNG
+ * @trng:      The CE_ALG_XXX value for the TRNG
  */
 struct ce_variant {
        char alg_cipher[CE_ID_CIPHER_MAX];
+       char alg_hash[CE_ID_HASH_MAX];
        u32 op_mode[CE_ID_OP_MAX];
-       bool has_t_dlen_in_bytes;
+       bool cipher_t_dlen_in_bytes;
+       bool hash_t_dlen_in_bits;
+       bool prng_t_dlen_in_bytes;
+       bool trng_t_dlen_in_bytes;
        struct ce_clock ce_clks[CE_MAX_CLOCKS];
+       int esr;
+       unsigned char prng;
+       unsigned char trng;
 };
 
 struct sginfo {
@@ -129,8 +180,6 @@ struct ce_task {
 /*
  * struct sun8i_ce_flow - Information used by each flow
  * @engine:    ptr to the crypto_engine for this flow
- * @bounce_iv: buffer which contain the IV
- * @ivlen:     size of bounce_iv
  * @complete:  completion for the current task on this flow
  * @status:    set to 1 by interrupt if task is done
  * @t_phy:     Physical address of task
@@ -139,8 +188,6 @@ struct ce_task {
  */
 struct sun8i_ce_flow {
        struct crypto_engine *engine;
-       void *bounce_iv;
-       unsigned int ivlen;
        struct completion complete;
        int status;
        dma_addr_t t_phy;
@@ -158,6 +205,7 @@ struct sun8i_ce_flow {
  * @reset:     pointer to reset controller
  * @dev:       the platform device
  * @mlock:     Control access to device registers
+ * @rnglock:   Control access to the RNG (dedicated channel 3)
  * @chanlist:  array of all flow
  * @flow:      flow to use in next request
  * @variant:   pointer to variant specific data
@@ -170,6 +218,7 @@ struct sun8i_ce_dev {
        struct reset_control *reset;
        struct device *dev;
        struct mutex mlock;
+       struct mutex rnglock;
        struct sun8i_ce_flow *chanlist;
        atomic_t flow;
        const struct ce_variant *variant;
@@ -177,17 +226,38 @@ struct sun8i_ce_dev {
        struct dentry *dbgfs_dir;
        struct dentry *dbgfs_stats;
 #endif
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG
+       struct hwrng trng;
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+       unsigned long hwrng_stat_req;
+       unsigned long hwrng_stat_bytes;
+#endif
+#endif
 };
 
 /*
  * struct sun8i_cipher_req_ctx - context for a skcipher request
  * @op_dir:            direction (encrypt vs decrypt) for this request
  * @flow:              the flow to use for this request
+ * @backup_iv:         buffer which contain the next IV to store
+ * @bounce_iv:         buffer which contain the IV
+ * @ivlen:             size of bounce_iv
+ * @nr_sgs:            The number of source SG (as given by dma_map_sg())
+ * @nr_sgd:            The number of destination SG (as given by dma_map_sg())
+ * @addr_iv:           The IV addr returned by dma_map_single, need to unmap later
+ * @addr_key:          The key addr returned by dma_map_single, need to unmap later
  * @fallback_req:      request struct for invoking the fallback skcipher TFM
  */
 struct sun8i_cipher_req_ctx {
        u32 op_dir;
        int flow;
+       void *backup_iv;
+       void *bounce_iv;
+       unsigned int ivlen;
+       int nr_sgs;
+       int nr_sgd;
+       dma_addr_t addr_iv;
+       dma_addr_t addr_key;
        struct skcipher_request fallback_req;   // keep at the end
 };
 
@@ -208,6 +278,38 @@ struct sun8i_cipher_tfm_ctx {
 };
 
 /*
+ * struct sun8i_ce_hash_tfm_ctx - context for an ahash TFM
+ * @enginectx:         crypto_engine used by this TFM
+ * @ce:                        pointer to the private data of driver handling this TFM
+ * @fallback_tfm:      pointer to the fallback TFM
+ */
+struct sun8i_ce_hash_tfm_ctx {
+       struct crypto_engine_ctx enginectx;
+       struct sun8i_ce_dev *ce;
+       struct crypto_ahash *fallback_tfm;
+};
+
+/*
+ * struct sun8i_ce_hash_reqctx - context for an ahash request
+ * @fallback_req:      pre-allocated fallback request
+ * @flow:      the flow to use for this request
+ */
+struct sun8i_ce_hash_reqctx {
+       struct ahash_request fallback_req;
+       int flow;
+};
+
+/*
+ * struct sun8i_ce_prng_ctx - context for PRNG TFM
+ * @seed:      The seed to use
+ * @slen:      The size of the seed
+ */
+struct sun8i_ce_rng_tfm_ctx {
+       void *seed;
+       unsigned int slen;
+};
+
+/*
  * struct sun8i_ce_alg_template - crypto_alg template
  * @type:              the CRYPTO_ALG_TYPE for this template
  * @ce_algo_id:                the CE_ID for this template
@@ -217,6 +319,7 @@ struct sun8i_cipher_tfm_ctx {
  * @alg:               one of sub struct must be used
  * @stat_req:          number of request done on this template
  * @stat_fb:           number of request which has fallbacked
+ * @stat_bytes:                total data size done by this template
  */
 struct sun8i_ce_alg_template {
        u32 type;
@@ -225,10 +328,13 @@ struct sun8i_ce_alg_template {
        struct sun8i_ce_dev *ce;
        union {
                struct skcipher_alg skcipher;
+               struct ahash_alg hash;
+               struct rng_alg rng;
        } alg;
 #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
        unsigned long stat_req;
        unsigned long stat_fb;
+       unsigned long stat_bytes;
 #endif
 };
 
@@ -246,3 +352,24 @@ int sun8i_ce_skencrypt(struct skcipher_request *areq);
 int sun8i_ce_get_engine_number(struct sun8i_ce_dev *ce);
 
 int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name);
+
+int sun8i_ce_hash_crainit(struct crypto_tfm *tfm);
+void sun8i_ce_hash_craexit(struct crypto_tfm *tfm);
+int sun8i_ce_hash_init(struct ahash_request *areq);
+int sun8i_ce_hash_export(struct ahash_request *areq, void *out);
+int sun8i_ce_hash_import(struct ahash_request *areq, const void *in);
+int sun8i_ce_hash(struct ahash_request *areq);
+int sun8i_ce_hash_final(struct ahash_request *areq);
+int sun8i_ce_hash_update(struct ahash_request *areq);
+int sun8i_ce_hash_finup(struct ahash_request *areq);
+int sun8i_ce_hash_digest(struct ahash_request *areq);
+int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq);
+
+int sun8i_ce_prng_generate(struct crypto_rng *tfm, const u8 *src,
+                          unsigned int slen, u8 *dst, unsigned int dlen);
+int sun8i_ce_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);
+void sun8i_ce_prng_exit(struct crypto_tfm *tfm);
+int sun8i_ce_prng_init(struct crypto_tfm *tfm);
+
+int sun8i_ce_hwrng_register(struct sun8i_ce_dev *ce);
+void sun8i_ce_hwrng_unregister(struct sun8i_ce_dev *ce);
index add7b05..aabfd89 100644 (file)
@@ -1,2 +1,4 @@
 obj-$(CONFIG_CRYPTO_DEV_SUN8I_SS) += sun8i-ss.o
 sun8i-ss-y += sun8i-ss-core.o sun8i-ss-cipher.o
+sun8i-ss-$(CONFIG_CRYPTO_DEV_SUN8I_SS_PRNG) += sun8i-ss-prng.o
+sun8i-ss-$(CONFIG_CRYPTO_DEV_SUN8I_SS_HASH) += sun8i-ss-hash.o
index 7b39b44..ed2a69f 100644 (file)
@@ -248,7 +248,6 @@ theend_iv:
                        offset = areq->cryptlen - ivsize;
                        if (rctx->op_dir & SS_DECRYPTION) {
                                memcpy(areq->iv, backup_iv, ivsize);
-                               memzero_explicit(backup_iv, ivsize);
                                kfree_sensitive(backup_iv);
                        } else {
                                scatterwalk_map_and_copy(areq->iv, areq->dst, offset,
@@ -368,10 +367,7 @@ void sun8i_ss_cipher_exit(struct crypto_tfm *tfm)
 {
        struct sun8i_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
 
-       if (op->key) {
-               memzero_explicit(op->key, op->keylen);
-               kfree(op->key);
-       }
+       kfree_sensitive(op->key);
        crypto_free_skcipher(op->fallback_tfm);
        pm_runtime_put_sync(op->ss->dev);
 }
@@ -393,10 +389,7 @@ int sun8i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
                dev_dbg(ss->dev, "ERROR: Invalid keylen %u\n", keylen);
                return -EINVAL;
        }
-       if (op->key) {
-               memzero_explicit(op->key, op->keylen);
-               kfree(op->key);
-       }
+       kfree_sensitive(op->key);
        op->keylen = keylen;
        op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
        if (!op->key)
@@ -419,10 +412,7 @@ int sun8i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
                return -EINVAL;
        }
 
-       if (op->key) {
-               memzero_explicit(op->key, op->keylen);
-               kfree(op->key);
-       }
+       kfree_sensitive(op->key);
        op->keylen = keylen;
        op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
        if (!op->key)
index 9a23515..e0ddc68 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/reset.h>
+#include <crypto/internal/rng.h>
 #include <crypto/internal/skcipher.h>
 
 #include "sun8i-ss.h"
@@ -40,6 +41,8 @@ static const struct ss_variant ss_a80_variant = {
 static const struct ss_variant ss_a83t_variant = {
        .alg_cipher = { SS_ALG_AES, SS_ALG_DES, SS_ALG_3DES,
        },
+       .alg_hash = { SS_ALG_MD5, SS_ALG_SHA1, SS_ALG_SHA224, SS_ALG_SHA256,
+       },
        .op_mode = { SS_OP_ECB, SS_OP_CBC,
        },
        .ss_clks = {
@@ -61,7 +64,7 @@ int sun8i_ss_run_task(struct sun8i_ss_dev *ss, struct sun8i_cipher_req_ctx *rctx
                      const char *name)
 {
        int flow = rctx->flow;
-       u32 v = 1;
+       u32 v = SS_START;
        int i;
 
 #ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
@@ -264,13 +267,154 @@ static struct sun8i_ss_alg_template ss_algs[] = {
                .decrypt        = sun8i_ss_skdecrypt,
        }
 },
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_PRNG
+{
+       .type = CRYPTO_ALG_TYPE_RNG,
+       .alg.rng = {
+               .base = {
+                       .cra_name               = "stdrng",
+                       .cra_driver_name        = "sun8i-ss-prng",
+                       .cra_priority           = 300,
+                       .cra_ctxsize = sizeof(struct sun8i_ss_rng_tfm_ctx),
+                       .cra_module             = THIS_MODULE,
+                       .cra_init               = sun8i_ss_prng_init,
+                       .cra_exit               = sun8i_ss_prng_exit,
+               },
+               .generate               = sun8i_ss_prng_generate,
+               .seed                   = sun8i_ss_prng_seed,
+               .seedsize               = PRNG_SEED_SIZE,
+       }
+},
+#endif
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_HASH
+{      .type = CRYPTO_ALG_TYPE_AHASH,
+       .ss_algo_id = SS_ID_HASH_MD5,
+       .alg.hash = {
+               .init = sun8i_ss_hash_init,
+               .update = sun8i_ss_hash_update,
+               .final = sun8i_ss_hash_final,
+               .finup = sun8i_ss_hash_finup,
+               .digest = sun8i_ss_hash_digest,
+               .export = sun8i_ss_hash_export,
+               .import = sun8i_ss_hash_import,
+               .halg = {
+                       .digestsize = MD5_DIGEST_SIZE,
+                       .statesize = sizeof(struct md5_state),
+                       .base = {
+                               .cra_name = "md5",
+                               .cra_driver_name = "md5-sun8i-ss",
+                               .cra_priority = 300,
+                               .cra_alignmask = 3,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),
+                               .cra_module = THIS_MODULE,
+                               .cra_init = sun8i_ss_hash_crainit,
+                               .cra_exit = sun8i_ss_hash_craexit,
+                       }
+               }
+       }
+},
+{      .type = CRYPTO_ALG_TYPE_AHASH,
+       .ss_algo_id = SS_ID_HASH_SHA1,
+       .alg.hash = {
+               .init = sun8i_ss_hash_init,
+               .update = sun8i_ss_hash_update,
+               .final = sun8i_ss_hash_final,
+               .finup = sun8i_ss_hash_finup,
+               .digest = sun8i_ss_hash_digest,
+               .export = sun8i_ss_hash_export,
+               .import = sun8i_ss_hash_import,
+               .halg = {
+                       .digestsize = SHA1_DIGEST_SIZE,
+                       .statesize = sizeof(struct sha1_state),
+                       .base = {
+                               .cra_name = "sha1",
+                               .cra_driver_name = "sha1-sun8i-ss",
+                               .cra_priority = 300,
+                               .cra_alignmask = 3,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA1_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),
+                               .cra_module = THIS_MODULE,
+                               .cra_init = sun8i_ss_hash_crainit,
+                               .cra_exit = sun8i_ss_hash_craexit,
+                       }
+               }
+       }
+},
+{      .type = CRYPTO_ALG_TYPE_AHASH,
+       .ss_algo_id = SS_ID_HASH_SHA224,
+       .alg.hash = {
+               .init = sun8i_ss_hash_init,
+               .update = sun8i_ss_hash_update,
+               .final = sun8i_ss_hash_final,
+               .finup = sun8i_ss_hash_finup,
+               .digest = sun8i_ss_hash_digest,
+               .export = sun8i_ss_hash_export,
+               .import = sun8i_ss_hash_import,
+               .halg = {
+                       .digestsize = SHA224_DIGEST_SIZE,
+                       .statesize = sizeof(struct sha256_state),
+                       .base = {
+                               .cra_name = "sha224",
+                               .cra_driver_name = "sha224-sun8i-ss",
+                               .cra_priority = 300,
+                               .cra_alignmask = 3,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA224_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),
+                               .cra_module = THIS_MODULE,
+                               .cra_init = sun8i_ss_hash_crainit,
+                               .cra_exit = sun8i_ss_hash_craexit,
+                       }
+               }
+       }
+},
+{      .type = CRYPTO_ALG_TYPE_AHASH,
+       .ss_algo_id = SS_ID_HASH_SHA256,
+       .alg.hash = {
+               .init = sun8i_ss_hash_init,
+               .update = sun8i_ss_hash_update,
+               .final = sun8i_ss_hash_final,
+               .finup = sun8i_ss_hash_finup,
+               .digest = sun8i_ss_hash_digest,
+               .export = sun8i_ss_hash_export,
+               .import = sun8i_ss_hash_import,
+               .halg = {
+                       .digestsize = SHA256_DIGEST_SIZE,
+                       .statesize = sizeof(struct sha256_state),
+                       .base = {
+                               .cra_name = "sha256",
+                               .cra_driver_name = "sha256-sun8i-ss",
+                               .cra_priority = 300,
+                               .cra_alignmask = 3,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+                               .cra_blocksize = SHA256_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),
+                               .cra_module = THIS_MODULE,
+                               .cra_init = sun8i_ss_hash_crainit,
+                               .cra_exit = sun8i_ss_hash_craexit,
+                       }
+               }
+       }
+},
+#endif
 };
 
 #ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
-static int sun8i_ss_dbgfs_read(struct seq_file *seq, void *v)
+static int sun8i_ss_debugfs_show(struct seq_file *seq, void *v)
 {
        struct sun8i_ss_dev *ss = seq->private;
-       int i;
+       unsigned int i;
 
        for (i = 0; i < MAXFLOW; i++)
                seq_printf(seq, "Channel %d: nreq %lu\n", i, ss->flows[i].stat_req);
@@ -280,28 +424,29 @@ static int sun8i_ss_dbgfs_read(struct seq_file *seq, void *v)
                        continue;
                switch (ss_algs[i].type) {
                case CRYPTO_ALG_TYPE_SKCIPHER:
-                       seq_printf(seq, "%s %s %lu %lu\n",
+                       seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
                                   ss_algs[i].alg.skcipher.base.cra_driver_name,
                                   ss_algs[i].alg.skcipher.base.cra_name,
                                   ss_algs[i].stat_req, ss_algs[i].stat_fb);
                        break;
+               case CRYPTO_ALG_TYPE_RNG:
+                       seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",
+                                  ss_algs[i].alg.rng.base.cra_driver_name,
+                                  ss_algs[i].alg.rng.base.cra_name,
+                                  ss_algs[i].stat_req, ss_algs[i].stat_bytes);
+                       break;
+               case CRYPTO_ALG_TYPE_AHASH:
+                       seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
+                                  ss_algs[i].alg.hash.halg.base.cra_driver_name,
+                                  ss_algs[i].alg.hash.halg.base.cra_name,
+                                  ss_algs[i].stat_req, ss_algs[i].stat_fb);
+                       break;
                }
        }
        return 0;
 }
 
-static int sun8i_ss_dbgfs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, sun8i_ss_dbgfs_read, inode->i_private);
-}
-
-static const struct file_operations sun8i_ss_debugfs_fops = {
-       .owner = THIS_MODULE,
-       .open = sun8i_ss_dbgfs_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(sun8i_ss_debugfs);
 #endif
 
 static void sun8i_ss_free_flows(struct sun8i_ss_dev *ss, int i)
@@ -415,7 +560,8 @@ static void sun8i_ss_pm_exit(struct sun8i_ss_dev *ss)
 
 static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss)
 {
-       int ss_method, err, id, i;
+       int ss_method, err, id;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {
                ss_algs[i].ss = ss;
@@ -448,6 +594,34 @@ static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss)
                                return err;
                        }
                        break;
+               case CRYPTO_ALG_TYPE_RNG:
+                       err = crypto_register_rng(&ss_algs[i].alg.rng);
+                       if (err) {
+                               dev_err(ss->dev, "Fail to register %s\n",
+                                       ss_algs[i].alg.rng.base.cra_name);
+                               ss_algs[i].ss = NULL;
+                       }
+                       break;
+               case CRYPTO_ALG_TYPE_AHASH:
+                       id = ss_algs[i].ss_algo_id;
+                       ss_method = ss->variant->alg_hash[id];
+                       if (ss_method == SS_ID_NOTSUPP) {
+                               dev_info(ss->dev,
+                                       "DEBUG: Algo of %s not supported\n",
+                                       ss_algs[i].alg.hash.halg.base.cra_name);
+                               ss_algs[i].ss = NULL;
+                               break;
+                       }
+                       dev_info(ss->dev, "Register %s\n",
+                                ss_algs[i].alg.hash.halg.base.cra_name);
+                       err = crypto_register_ahash(&ss_algs[i].alg.hash);
+                       if (err) {
+                               dev_err(ss->dev, "ERROR: Fail to register %s\n",
+                                       ss_algs[i].alg.hash.halg.base.cra_name);
+                               ss_algs[i].ss = NULL;
+                               return err;
+                       }
+                       break;
                default:
                        ss_algs[i].ss = NULL;
                        dev_err(ss->dev, "ERROR: tried to register an unknown algo\n");
@@ -458,7 +632,7 @@ static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss)
 
 static void sun8i_ss_unregister_algs(struct sun8i_ss_dev *ss)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {
                if (!ss_algs[i].ss)
@@ -469,6 +643,16 @@ static void sun8i_ss_unregister_algs(struct sun8i_ss_dev *ss)
                                 ss_algs[i].alg.skcipher.base.cra_name);
                        crypto_unregister_skcipher(&ss_algs[i].alg.skcipher);
                        break;
+               case CRYPTO_ALG_TYPE_RNG:
+                       dev_info(ss->dev, "Unregister %d %s\n", i,
+                                ss_algs[i].alg.rng.base.cra_name);
+                       crypto_unregister_rng(&ss_algs[i].alg.rng);
+                       break;
+               case CRYPTO_ALG_TYPE_AHASH:
+                       dev_info(ss->dev, "Unregister %d %s\n", i,
+                                ss_algs[i].alg.hash.halg.base.cra_name);
+                       crypto_unregister_ahash(&ss_algs[i].alg.hash);
+                       break;
                }
        }
 }
@@ -545,12 +729,9 @@ static int sun8i_ss_probe(struct platform_device *pdev)
                return irq;
 
        ss->reset = devm_reset_control_get(&pdev->dev, NULL);
-       if (IS_ERR(ss->reset)) {
-               if (PTR_ERR(ss->reset) == -EPROBE_DEFER)
-                       return PTR_ERR(ss->reset);
-               dev_err(&pdev->dev, "No reset control found\n");
-               return PTR_ERR(ss->reset);
-       }
+       if (IS_ERR(ss->reset))
+               return dev_err_probe(&pdev->dev, PTR_ERR(ss->reset),
+                                    "No reset control found\n");
 
        mutex_init(&ss->mlock);
 
diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c
new file mode 100644 (file)
index 0000000..b6ab205
--- /dev/null
@@ -0,0 +1,444 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sun8i-ss-hash.c - hardware cryptographic offloader for
+ * Allwinner A80/A83T SoC
+ *
+ * Copyright (C) 2015-2020 Corentin Labbe <clabbe@baylibre.com>
+ *
+ * This file add support for MD5 and SHA1/SHA224/SHA256.
+ *
+ * You could find the datasheet in Documentation/arm/sunxi.rst
+ */
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <crypto/md5.h>
+#include "sun8i-ss.h"
+
+int sun8i_ss_hash_crainit(struct crypto_tfm *tfm)
+{
+       struct sun8i_ss_hash_tfm_ctx *op = crypto_tfm_ctx(tfm);
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
+       struct sun8i_ss_alg_template *algt;
+       int err;
+
+       memset(op, 0, sizeof(struct sun8i_ss_hash_tfm_ctx));
+
+       algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
+       op->ss = algt->ss;
+
+       op->enginectx.op.do_one_request = sun8i_ss_hash_run;
+       op->enginectx.op.prepare_request = NULL;
+       op->enginectx.op.unprepare_request = NULL;
+
+       /* FALLBACK */
+       op->fallback_tfm = crypto_alloc_ahash(crypto_tfm_alg_name(tfm), 0,
+                                             CRYPTO_ALG_NEED_FALLBACK);
+       if (IS_ERR(op->fallback_tfm)) {
+               dev_err(algt->ss->dev, "Fallback driver could no be loaded\n");
+               return PTR_ERR(op->fallback_tfm);
+       }
+
+       if (algt->alg.hash.halg.statesize < crypto_ahash_statesize(op->fallback_tfm))
+               algt->alg.hash.halg.statesize = crypto_ahash_statesize(op->fallback_tfm);
+
+       crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+                                sizeof(struct sun8i_ss_hash_reqctx) +
+                                crypto_ahash_reqsize(op->fallback_tfm));
+
+       dev_info(op->ss->dev, "Fallback for %s is %s\n",
+                crypto_tfm_alg_driver_name(tfm),
+                crypto_tfm_alg_driver_name(&op->fallback_tfm->base));
+       err = pm_runtime_get_sync(op->ss->dev);
+       if (err < 0)
+               goto error_pm;
+       return 0;
+error_pm:
+       pm_runtime_put_noidle(op->ss->dev);
+       crypto_free_ahash(op->fallback_tfm);
+       return err;
+}
+
+void sun8i_ss_hash_craexit(struct crypto_tfm *tfm)
+{
+       struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_ahash(tfmctx->fallback_tfm);
+       pm_runtime_put_sync_suspend(tfmctx->ss->dev);
+}
+
+int sun8i_ss_hash_init(struct ahash_request *areq)
+{
+       struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+
+       memset(rctx, 0, sizeof(struct sun8i_ss_hash_reqctx));
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       return crypto_ahash_init(&rctx->fallback_req);
+}
+
+int sun8i_ss_hash_export(struct ahash_request *areq, void *out)
+{
+       struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       return crypto_ahash_export(&rctx->fallback_req, out);
+}
+
+int sun8i_ss_hash_import(struct ahash_request *areq, const void *in)
+{
+       struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       return crypto_ahash_import(&rctx->fallback_req, in);
+}
+
+int sun8i_ss_hash_final(struct ahash_request *areq)
+{
+       struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+       struct sun8i_ss_alg_template *algt;
+#endif
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags &
+                                       CRYPTO_TFM_REQ_MAY_SLEEP;
+       rctx->fallback_req.result = areq->result;
+
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+       algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
+       algt->stat_fb++;
+#endif
+
+       return crypto_ahash_final(&rctx->fallback_req);
+}
+
+int sun8i_ss_hash_update(struct ahash_request *areq)
+{
+       struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags &
+                                       CRYPTO_TFM_REQ_MAY_SLEEP;
+       rctx->fallback_req.nbytes = areq->nbytes;
+       rctx->fallback_req.src = areq->src;
+
+       return crypto_ahash_update(&rctx->fallback_req);
+}
+
+int sun8i_ss_hash_finup(struct ahash_request *areq)
+{
+       struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+       struct sun8i_ss_alg_template *algt;
+#endif
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags &
+                                       CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       rctx->fallback_req.nbytes = areq->nbytes;
+       rctx->fallback_req.src = areq->src;
+       rctx->fallback_req.result = areq->result;
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+       algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
+       algt->stat_fb++;
+#endif
+
+       return crypto_ahash_finup(&rctx->fallback_req);
+}
+
+static int sun8i_ss_hash_digest_fb(struct ahash_request *areq)
+{
+       struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+       struct sun8i_ss_alg_template *algt;
+#endif
+
+       ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+       rctx->fallback_req.base.flags = areq->base.flags &
+                                       CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       rctx->fallback_req.nbytes = areq->nbytes;
+       rctx->fallback_req.src = areq->src;
+       rctx->fallback_req.result = areq->result;
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+       algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
+       algt->stat_fb++;
+#endif
+
+       return crypto_ahash_digest(&rctx->fallback_req);
+}
+
+static int sun8i_ss_run_hash_task(struct sun8i_ss_dev *ss,
+                                 struct sun8i_ss_hash_reqctx *rctx,
+                                 const char *name)
+{
+       int flow = rctx->flow;
+       u32 v = SS_START;
+       int i;
+
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+       ss->flows[flow].stat_req++;
+#endif
+
+       /* choose between stream0/stream1 */
+       if (flow)
+               v |= SS_FLOW1;
+       else
+               v |= SS_FLOW0;
+
+       v |= rctx->method;
+
+       for (i = 0; i < MAX_SG; i++) {
+               if (!rctx->t_dst[i].addr)
+                       break;
+
+               mutex_lock(&ss->mlock);
+               if (i > 0) {
+                       v |= BIT(17);
+                       writel(rctx->t_dst[i - 1].addr, ss->base + SS_KEY_ADR_REG);
+                       writel(rctx->t_dst[i - 1].addr, ss->base + SS_IV_ADR_REG);
+               }
+
+               dev_dbg(ss->dev,
+                       "Processing SG %d on flow %d %s ctl=%x %d to %d method=%x src=%x dst=%x\n",
+                       i, flow, name, v,
+                       rctx->t_src[i].len, rctx->t_dst[i].len,
+                       rctx->method, rctx->t_src[i].addr, rctx->t_dst[i].addr);
+
+               writel(rctx->t_src[i].addr, ss->base + SS_SRC_ADR_REG);
+               writel(rctx->t_dst[i].addr, ss->base + SS_DST_ADR_REG);
+               writel(rctx->t_src[i].len, ss->base + SS_LEN_ADR_REG);
+               writel(BIT(0) | BIT(1), ss->base + SS_INT_CTL_REG);
+
+               reinit_completion(&ss->flows[flow].complete);
+               ss->flows[flow].status = 0;
+               wmb();
+
+               writel(v, ss->base + SS_CTL_REG);
+               mutex_unlock(&ss->mlock);
+               wait_for_completion_interruptible_timeout(&ss->flows[flow].complete,
+                                                         msecs_to_jiffies(2000));
+               if (ss->flows[flow].status == 0) {
+                       dev_err(ss->dev, "DMA timeout for %s\n", name);
+                       return -EFAULT;
+               }
+       }
+
+       return 0;
+}
+
+static bool sun8i_ss_hash_need_fallback(struct ahash_request *areq)
+{
+       struct scatterlist *sg;
+
+       if (areq->nbytes == 0)
+               return true;
+       /* we need to reserve one SG for the padding one */
+       if (sg_nents(areq->src) > MAX_SG - 1)
+               return true;
+       sg = areq->src;
+       while (sg) {
+               /* SS can operate hash only on full block size
+                * since SS support only MD5,sha1,sha224 and sha256, blocksize
+                * is always 64
+                * TODO: handle request if last SG is not len%64
+                * but this will need to copy data on a new SG of size=64
+                */
+               if (sg->length % 64 || !IS_ALIGNED(sg->offset, sizeof(u32)))
+                       return true;
+               sg = sg_next(sg);
+       }
+       return false;
+}
+
+int sun8i_ss_hash_digest(struct ahash_request *areq)
+{
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+       struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct sun8i_ss_alg_template *algt;
+       struct sun8i_ss_dev *ss;
+       struct crypto_engine *engine;
+       struct scatterlist *sg;
+       int nr_sgs, e, i;
+
+       if (sun8i_ss_hash_need_fallback(areq))
+               return sun8i_ss_hash_digest_fb(areq);
+
+       nr_sgs = sg_nents(areq->src);
+       if (nr_sgs > MAX_SG - 1)
+               return sun8i_ss_hash_digest_fb(areq);
+
+       for_each_sg(areq->src, sg, nr_sgs, i) {
+               if (sg->length % 4 || !IS_ALIGNED(sg->offset, sizeof(u32)))
+                       return sun8i_ss_hash_digest_fb(areq);
+       }
+
+       algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
+       ss = algt->ss;
+
+       e = sun8i_ss_get_engine_number(ss);
+       rctx->flow = e;
+       engine = ss->flows[e].engine;
+
+       return crypto_transfer_hash_request_to_engine(engine, areq);
+}
+
+/* sun8i_ss_hash_run - run an ahash request
+ * Send the data of the request to the SS along with an extra SG with padding
+ */
+int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq)
+{
+       struct ahash_request *areq = container_of(breq, struct ahash_request, base);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+       struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+       struct sun8i_ss_alg_template *algt;
+       struct sun8i_ss_dev *ss;
+       struct scatterlist *sg;
+       int nr_sgs, err, digestsize;
+       unsigned int len;
+       u64 fill, min_fill, byte_count;
+       void *pad, *result;
+       int j, i, todo;
+       __be64 *bebits;
+       __le64 *lebits;
+       dma_addr_t addr_res, addr_pad;
+       __le32 *bf;
+
+       algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
+       ss = algt->ss;
+
+       digestsize = algt->alg.hash.halg.digestsize;
+       if (digestsize == SHA224_DIGEST_SIZE)
+               digestsize = SHA256_DIGEST_SIZE;
+
+       /* the padding could be up to two block. */
+       pad = kzalloc(algt->alg.hash.halg.base.cra_blocksize * 2, GFP_KERNEL | GFP_DMA);
+       if (!pad)
+               return -ENOMEM;
+       bf = (__le32 *)pad;
+
+       result = kzalloc(digestsize, GFP_KERNEL | GFP_DMA);
+       if (!result)
+               return -ENOMEM;
+
+       for (i = 0; i < MAX_SG; i++) {
+               rctx->t_dst[i].addr = 0;
+               rctx->t_dst[i].len = 0;
+       }
+
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+       algt->stat_req++;
+#endif
+
+       rctx->method = ss->variant->alg_hash[algt->ss_algo_id];
+
+       nr_sgs = dma_map_sg(ss->dev, areq->src, sg_nents(areq->src), DMA_TO_DEVICE);
+       if (nr_sgs <= 0 || nr_sgs > MAX_SG) {
+               dev_err(ss->dev, "Invalid sg number %d\n", nr_sgs);
+               err = -EINVAL;
+               goto theend;
+       }
+
+       addr_res = dma_map_single(ss->dev, result, digestsize, DMA_FROM_DEVICE);
+       if (dma_mapping_error(ss->dev, addr_res)) {
+               dev_err(ss->dev, "DMA map dest\n");
+               err = -EINVAL;
+               goto theend;
+       }
+
+       len = areq->nbytes;
+       for_each_sg(areq->src, sg, nr_sgs, i) {
+               rctx->t_src[i].addr = sg_dma_address(sg);
+               todo = min(len, sg_dma_len(sg));
+               rctx->t_src[i].len = todo / 4;
+               len -= todo;
+               rctx->t_dst[i].addr = addr_res;
+               rctx->t_dst[i].len = digestsize / 4;
+       }
+       if (len > 0) {
+               dev_err(ss->dev, "remaining len %d\n", len);
+               err = -EINVAL;
+               goto theend;
+       }
+
+       byte_count = areq->nbytes;
+       j = 0;
+       bf[j++] = cpu_to_le32(0x80);
+
+       fill = 64 - (byte_count % 64);
+       min_fill = 3 * sizeof(u32);
+
+       if (fill < min_fill)
+               fill += 64;
+
+       j += (fill - min_fill) / sizeof(u32);
+
+       switch (algt->ss_algo_id) {
+       case SS_ID_HASH_MD5:
+               lebits = (__le64 *)&bf[j];
+               *lebits = cpu_to_le64(byte_count << 3);
+               j += 2;
+               break;
+       case SS_ID_HASH_SHA1:
+       case SS_ID_HASH_SHA224:
+       case SS_ID_HASH_SHA256:
+               bebits = (__be64 *)&bf[j];
+               *bebits = cpu_to_be64(byte_count << 3);
+               j += 2;
+               break;
+       }
+
+       addr_pad = dma_map_single(ss->dev, pad, j * 4, DMA_TO_DEVICE);
+       rctx->t_src[i].addr = addr_pad;
+       rctx->t_src[i].len = j;
+       rctx->t_dst[i].addr = addr_res;
+       rctx->t_dst[i].len = digestsize / 4;
+       if (dma_mapping_error(ss->dev, addr_pad)) {
+               dev_err(ss->dev, "DMA error on padding SG\n");
+               err = -EINVAL;
+               goto theend;
+       }
+
+       err = sun8i_ss_run_hash_task(ss, rctx, crypto_tfm_alg_name(areq->base.tfm));
+
+       dma_unmap_single(ss->dev, addr_pad, j * 4, DMA_TO_DEVICE);
+       dma_unmap_sg(ss->dev, areq->src, nr_sgs, DMA_TO_DEVICE);
+       dma_unmap_single(ss->dev, addr_res, digestsize, DMA_FROM_DEVICE);
+
+       kfree(pad);
+
+       memcpy(areq->result, result, algt->alg.hash.halg.digestsize);
+       kfree(result);
+theend:
+       crypto_finalize_hash_request(engine, breq, err);
+       return 0;
+}
diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c
new file mode 100644 (file)
index 0000000..08a1473
--- /dev/null
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sun8i-ss-prng.c - hardware cryptographic offloader for
+ * Allwinner A80/A83T SoC
+ *
+ * Copyright (C) 2015-2020 Corentin Labbe <clabbe@baylibre.com>
+ *
+ * This file handle the PRNG found in the SS
+ *
+ * You could find a link for the datasheet in Documentation/arm/sunxi.rst
+ */
+#include "sun8i-ss.h"
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <crypto/internal/rng.h>
+
+int sun8i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+                      unsigned int slen)
+{
+       struct sun8i_ss_rng_tfm_ctx *ctx = crypto_rng_ctx(tfm);
+
+       if (ctx->seed && ctx->slen != slen) {
+               memzero_explicit(ctx->seed, ctx->slen);
+               kfree(ctx->seed);
+               ctx->slen = 0;
+               ctx->seed = NULL;
+       }
+       if (!ctx->seed)
+               ctx->seed = kmalloc(slen, GFP_KERNEL | GFP_DMA);
+       if (!ctx->seed)
+               return -ENOMEM;
+
+       memcpy(ctx->seed, seed, slen);
+       ctx->slen = slen;
+
+       return 0;
+}
+
+int sun8i_ss_prng_init(struct crypto_tfm *tfm)
+{
+       struct sun8i_ss_rng_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       memset(ctx, 0, sizeof(struct sun8i_ss_rng_tfm_ctx));
+       return 0;
+}
+
+void sun8i_ss_prng_exit(struct crypto_tfm *tfm)
+{
+       struct sun8i_ss_rng_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       memzero_explicit(ctx->seed, ctx->slen);
+       kfree(ctx->seed);
+       ctx->seed = NULL;
+       ctx->slen = 0;
+}
+
+int sun8i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+                          unsigned int slen, u8 *dst, unsigned int dlen)
+{
+       struct sun8i_ss_rng_tfm_ctx *ctx = crypto_rng_ctx(tfm);
+       struct rng_alg *alg = crypto_rng_alg(tfm);
+       struct sun8i_ss_alg_template *algt;
+       struct sun8i_ss_dev *ss;
+       dma_addr_t dma_iv, dma_dst;
+       unsigned int todo;
+       int err = 0;
+       int flow;
+       void *d;
+       u32 v;
+
+       algt = container_of(alg, struct sun8i_ss_alg_template, alg.rng);
+       ss = algt->ss;
+
+       if (ctx->slen == 0) {
+               dev_err(ss->dev, "The PRNG is not seeded\n");
+               return -EINVAL;
+       }
+
+       /* The SS does not give an updated seed, so we need to get a new one.
+        * So we will ask for an extra PRNG_SEED_SIZE data.
+        * We want dlen + seedsize rounded up to a multiple of PRNG_DATA_SIZE
+        */
+       todo = dlen + PRNG_SEED_SIZE + PRNG_DATA_SIZE;
+       todo -= todo % PRNG_DATA_SIZE;
+
+       d = kzalloc(todo, GFP_KERNEL | GFP_DMA);
+       if (!d)
+               return -ENOMEM;
+
+       flow = sun8i_ss_get_engine_number(ss);
+
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+       algt->stat_req++;
+       algt->stat_bytes += todo;
+#endif
+
+       v = SS_ALG_PRNG | SS_PRNG_CONTINUE | SS_START;
+       if (flow)
+               v |= SS_FLOW1;
+       else
+               v |= SS_FLOW0;
+
+       dma_iv = dma_map_single(ss->dev, ctx->seed, ctx->slen, DMA_TO_DEVICE);
+       if (dma_mapping_error(ss->dev, dma_iv)) {
+               dev_err(ss->dev, "Cannot DMA MAP IV\n");
+               return -EFAULT;
+       }
+
+       dma_dst = dma_map_single(ss->dev, d, todo, DMA_FROM_DEVICE);
+       if (dma_mapping_error(ss->dev, dma_dst)) {
+               dev_err(ss->dev, "Cannot DMA MAP DST\n");
+               err = -EFAULT;
+               goto err_iv;
+       }
+
+       err = pm_runtime_get_sync(ss->dev);
+       if (err < 0) {
+               pm_runtime_put_noidle(ss->dev);
+               goto err_pm;
+       }
+       err = 0;
+
+       mutex_lock(&ss->mlock);
+       writel(dma_iv, ss->base + SS_IV_ADR_REG);
+       /* the PRNG act badly (failing rngtest) without SS_KEY_ADR_REG set */
+       writel(dma_iv, ss->base + SS_KEY_ADR_REG);
+       writel(dma_dst, ss->base + SS_DST_ADR_REG);
+       writel(todo / 4, ss->base + SS_LEN_ADR_REG);
+
+       reinit_completion(&ss->flows[flow].complete);
+       ss->flows[flow].status = 0;
+       /* Be sure all data is written before enabling the task */
+       wmb();
+
+       writel(v, ss->base + SS_CTL_REG);
+
+       wait_for_completion_interruptible_timeout(&ss->flows[flow].complete,
+                                                 msecs_to_jiffies(todo));
+       if (ss->flows[flow].status == 0) {
+               dev_err(ss->dev, "DMA timeout for PRNG (size=%u)\n", todo);
+               err = -EFAULT;
+       }
+       /* Since cipher and hash use the linux/cryptoengine and that we have
+        * a cryptoengine per flow, we are sure that they will issue only one
+        * request per flow.
+        * Since the cryptoengine wait for completion before submitting a new
+        * one, the mlock could be left just after the final writel.
+        * But cryptoengine cannot handle crypto_rng, so we need to be sure
+        * nothing will use our flow.
+        * The easiest way is to grab mlock until the hardware end our requests.
+        * We could have used a per flow lock, but this would increase
+        * complexity.
+        * The drawback is that no request could be handled for the other flow.
+        */
+       mutex_unlock(&ss->mlock);
+
+       pm_runtime_put(ss->dev);
+
+err_pm:
+       dma_unmap_single(ss->dev, dma_dst, todo, DMA_FROM_DEVICE);
+err_iv:
+       dma_unmap_single(ss->dev, dma_iv, ctx->slen, DMA_TO_DEVICE);
+
+       if (!err) {
+               memcpy(dst, d, dlen);
+               /* Update seed */
+               memcpy(ctx->seed, d + dlen, ctx->slen);
+       }
+       memzero_explicit(d, todo);
+       kfree(d);
+
+       return err;
+}
index 0405767..1a66457 100644 (file)
@@ -8,10 +8,16 @@
 #include <crypto/aes.h>
 #include <crypto/des.h>
 #include <crypto/engine.h>
+#include <crypto/rng.h>
 #include <crypto/skcipher.h>
 #include <linux/atomic.h>
 #include <linux/debugfs.h>
 #include <linux/crypto.h>
+#include <crypto/internal/hash.h>
+#include <crypto/md5.h>
+#include <crypto/sha.h>
+
+#define SS_START       1
 
 #define SS_ENCRYPTION          0
 #define SS_DECRYPTION          BIT(6)
 #define SS_ALG_AES             0
 #define SS_ALG_DES             (1 << 2)
 #define SS_ALG_3DES            (2 << 2)
+#define SS_ALG_MD5             (3 << 2)
+#define SS_ALG_PRNG            (4 << 2)
+#define SS_ALG_SHA1            (6 << 2)
+#define SS_ALG_SHA224          (7 << 2)
+#define SS_ALG_SHA256          (8 << 2)
 
 #define SS_CTL_REG             0x00
 #define SS_INT_CTL_REG         0x04
 #define SS_OP_ECB      0
 #define SS_OP_CBC      (1 << 13)
 
+#define SS_ID_HASH_MD5 0
+#define SS_ID_HASH_SHA1        1
+#define SS_ID_HASH_SHA224      2
+#define SS_ID_HASH_SHA256      3
+#define SS_ID_HASH_MAX 4
+
 #define SS_FLOW0       BIT(30)
 #define SS_FLOW1       BIT(31)
 
+#define SS_PRNG_CONTINUE       BIT(18)
+
 #define MAX_SG 8
 
 #define MAXFLOW 2
@@ -59,6 +78,9 @@
 #define SS_DIE_ID_SHIFT        20
 #define SS_DIE_ID_MASK 0x07
 
+#define PRNG_DATA_SIZE (160 / 8)
+#define PRNG_SEED_SIZE DIV_ROUND_UP(175, 8)
+
 /*
  * struct ss_clock - Describe clocks used by sun8i-ss
  * @name:       Name of clock needed by this variant
@@ -75,11 +97,14 @@ struct ss_clock {
  * struct ss_variant - Describe SS capability for each variant hardware
  * @alg_cipher:        list of supported ciphers. for each SS_ID_ this will give the
  *              coresponding SS_ALG_XXX value
+ * @alg_hash:  list of supported hashes. for each SS_ID_ this will give the
+ *              corresponding SS_ALG_XXX value
  * @op_mode:   list of supported block modes
- * @ss_clks!   list of clock needed by this variant
+ * @ss_clks:   list of clock needed by this variant
  */
 struct ss_variant {
        char alg_cipher[SS_ID_CIPHER_MAX];
+       char alg_hash[SS_ID_HASH_MAX];
        u32 op_mode[SS_ID_OP_MAX];
        struct ss_clock ss_clks[SS_MAX_CLOCKS];
 };
@@ -170,6 +195,8 @@ struct sun8i_cipher_req_ctx {
  * @keylen:            len of the key
  * @ss:                        pointer to the private data of driver handling this TFM
  * @fallback_tfm:      pointer to the fallback TFM
+ *
+ * enginectx must be the first element
  */
 struct sun8i_cipher_tfm_ctx {
        struct crypto_engine_ctx enginectx;
@@ -180,6 +207,46 @@ struct sun8i_cipher_tfm_ctx {
 };
 
 /*
+ * struct sun8i_ss_prng_ctx - context for PRNG TFM
+ * @seed:      The seed to use
+ * @slen:      The size of the seed
+ */
+struct sun8i_ss_rng_tfm_ctx {
+       void *seed;
+       unsigned int slen;
+};
+
+/*
+ * struct sun8i_ss_hash_tfm_ctx - context for an ahash TFM
+ * @enginectx:         crypto_engine used by this TFM
+ * @fallback_tfm:      pointer to the fallback TFM
+ * @ss:                        pointer to the private data of driver handling this TFM
+ *
+ * enginectx must be the first element
+ */
+struct sun8i_ss_hash_tfm_ctx {
+       struct crypto_engine_ctx enginectx;
+       struct crypto_ahash *fallback_tfm;
+       struct sun8i_ss_dev *ss;
+};
+
+/*
+ * struct sun8i_ss_hash_reqctx - context for an ahash request
+ * @t_src:     list of DMA address and size for source SGs
+ * @t_dst:     list of DMA address and size for destination SGs
+ * @fallback_req:      pre-allocated fallback request
+ * @method:    the register value for the algorithm used by this request
+ * @flow:      the flow to use for this request
+ */
+struct sun8i_ss_hash_reqctx {
+       struct sginfo t_src[MAX_SG];
+       struct sginfo t_dst[MAX_SG];
+       struct ahash_request fallback_req;
+       u32 method;
+       int flow;
+};
+
+/*
  * struct sun8i_ss_alg_template - crypto_alg template
  * @type:              the CRYPTO_ALG_TYPE for this template
  * @ss_algo_id:                the SS_ID for this template
@@ -189,6 +256,7 @@ struct sun8i_cipher_tfm_ctx {
  * @alg:               one of sub struct must be used
  * @stat_req:          number of request done on this template
  * @stat_fb:           number of request which has fallbacked
+ * @stat_bytes:                total data size done by this template
  */
 struct sun8i_ss_alg_template {
        u32 type;
@@ -197,10 +265,13 @@ struct sun8i_ss_alg_template {
        struct sun8i_ss_dev *ss;
        union {
                struct skcipher_alg skcipher;
+               struct rng_alg rng;
+               struct ahash_alg hash;
        } alg;
 #ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
        unsigned long stat_req;
        unsigned long stat_fb;
+       unsigned long stat_bytes;
 #endif
 };
 
@@ -218,3 +289,19 @@ int sun8i_ss_skencrypt(struct skcipher_request *areq);
 int sun8i_ss_get_engine_number(struct sun8i_ss_dev *ss);
 
 int sun8i_ss_run_task(struct sun8i_ss_dev *ss, struct sun8i_cipher_req_ctx *rctx, const char *name);
+int sun8i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+                          unsigned int slen, u8 *dst, unsigned int dlen);
+int sun8i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);
+int sun8i_ss_prng_init(struct crypto_tfm *tfm);
+void sun8i_ss_prng_exit(struct crypto_tfm *tfm);
+
+int sun8i_ss_hash_crainit(struct crypto_tfm *tfm);
+void sun8i_ss_hash_craexit(struct crypto_tfm *tfm);
+int sun8i_ss_hash_init(struct ahash_request *areq);
+int sun8i_ss_hash_export(struct ahash_request *areq, void *out);
+int sun8i_ss_hash_import(struct ahash_request *areq, const void *in);
+int sun8i_ss_hash_final(struct ahash_request *areq);
+int sun8i_ss_hash_update(struct ahash_request *areq);
+int sun8i_ss_hash_finup(struct ahash_request *areq);
+int sun8i_ss_hash_digest(struct ahash_request *areq);
+int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq);
index f7fc0c4..7729a63 100644 (file)
@@ -55,7 +55,7 @@ static void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm,
        sa->sa_command_1.w = 0;
        sa->sa_command_1.bf.crypto_mode31 = (cm & 4) >> 2;
        sa->sa_command_1.bf.crypto_mode9_8 = cm & 3;
-       sa->sa_command_1.bf.feedback_mode = cfb,
+       sa->sa_command_1.bf.feedback_mode = cfb;
        sa->sa_command_1.bf.sa_rev = 1;
        sa->sa_command_1.bf.hmac_muting = hmac_mc;
        sa->sa_command_1.bf.extended_seq_num = esn;
index 6b68413..a4e25b4 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/ratelimit.h>
 #include <linux/mutex.h>
+#include <linux/scatterlist.h>
 #include <crypto/internal/hash.h>
 #include <crypto/internal/aead.h>
 #include <crypto/internal/rng.h>
index d932107..8b5e073 100644 (file)
@@ -99,7 +99,7 @@ static int meson_cipher(struct skcipher_request *areq)
        unsigned int keyivlen, ivsize, offset, tloffset;
        dma_addr_t phykeyiv;
        void *backup_iv = NULL, *bkeyiv;
-       __le32 v;
+       u32 v;
 
        algt = container_of(alg, struct meson_alg_template, alg.skcipher);
 
@@ -340,10 +340,7 @@ void meson_cipher_exit(struct crypto_tfm *tfm)
 {
        struct meson_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
 
-       if (op->key) {
-               memzero_explicit(op->key, op->keylen);
-               kfree(op->key);
-       }
+       kfree_sensitive(op->key);
        crypto_free_skcipher(op->fallback_tfm);
 }
 
@@ -367,10 +364,7 @@ int meson_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
                dev_dbg(mc->dev, "ERROR: Invalid keylen %u\n", keylen);
                return -EINVAL;
        }
-       if (op->key) {
-               memzero_explicit(op->key, op->keylen);
-               kfree(op->key);
-       }
+       kfree_sensitive(op->key);
        op->keylen = keylen;
        op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
        if (!op->key)
index 466552a..5bbeff4 100644 (file)
@@ -98,7 +98,7 @@ static struct meson_alg_template mc_algs[] = {
 };
 
 #ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
-static int meson_dbgfs_read(struct seq_file *seq, void *v)
+static int meson_debugfs_show(struct seq_file *seq, void *v)
 {
        struct meson_dev *mc = seq->private;
        int i;
@@ -118,19 +118,7 @@ static int meson_dbgfs_read(struct seq_file *seq, void *v)
        }
        return 0;
 }
-
-static int meson_dbgfs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, meson_dbgfs_read, inode->i_private);
-}
-
-static const struct file_operations meson_debugfs_fops = {
-       .owner = THIS_MODULE,
-       .open = meson_dbgfs_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(meson_debugfs);
 #endif
 
 static void meson_free_chanlist(struct meson_dev *mc, int i)
index a6e1449..b1d2860 100644 (file)
@@ -1539,7 +1539,7 @@ static int atmel_aes_gcm_length(struct atmel_aes_dev *dd)
 
        /* Write incr32(J0) into IV. */
        j0_lsw = j0[3];
-       j0[3] = cpu_to_be32(be32_to_cpu(j0[3]) + 1);
+       be32_add_cpu(&j0[3], 1);
        atmel_aes_write_block(dd, AES_IVR(0), j0);
        j0[3] = j0_lsw;
 
index ed40dbb..4d63cb1 100644 (file)
@@ -912,7 +912,7 @@ static void atmel_tdes_skcipher_alg_init(struct skcipher_alg *alg)
 {
        alg->base.cra_priority = ATMEL_TDES_PRIORITY;
        alg->base.cra_flags = CRYPTO_ALG_ASYNC;
-       alg->base.cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+       alg->base.cra_ctxsize = sizeof(struct atmel_tdes_ctx);
        alg->base.cra_module = THIS_MODULE;
 
        alg->init = atmel_tdes_init_tfm;
index 1a46eed..809c303 100644 (file)
@@ -2310,7 +2310,7 @@ static int artpec6_crypto_prepare_submit_hash(struct ahash_request *req)
 
        case ARTPEC6_CRYPTO_PREPARE_HASH_NO_START:
                ret = 0;
-               /* Fallthrough */
+               fallthrough;
 
        default:
                artpec6_crypto_common_destroy(&req_ctx->common);
index 8a7fa1a..50d169e 100644 (file)
@@ -165,10 +165,6 @@ spu_skcipher_rx_sg_create(struct brcm_message *mssg,
                return -EFAULT;
        }
 
-       if (ctx->cipher.alg == CIPHER_ALG_RC4)
-               /* Add buffer to catch 260-byte SUPDT field for RC4 */
-               sg_set_buf(sg++, rctx->msg_buf.c.supdt_tweak, SPU_SUPDT_LEN);
-
        if (stat_pad_len)
                sg_set_buf(sg++, rctx->msg_buf.rx_stat_pad, stat_pad_len);
 
@@ -317,7 +313,6 @@ static int handle_skcipher_req(struct iproc_reqctx_s *rctx)
        u8 local_iv_ctr[MAX_IV_SIZE];
        u32 stat_pad_len;       /* num bytes to align status field */
        u32 pad_len;            /* total length of all padding */
-       bool update_key = false;
        struct brcm_message *mssg;      /* mailbox message */
 
        /* number of entries in src and dst sg in mailbox message. */
@@ -391,28 +386,6 @@ static int handle_skcipher_req(struct iproc_reqctx_s *rctx)
                }
        }
 
-       if (ctx->cipher.alg == CIPHER_ALG_RC4) {
-               rx_frag_num++;
-               if (chunk_start) {
-                       /*
-                        * for non-first RC4 chunks, use SUPDT from previous
-                        * response as key for this chunk.
-                        */
-                       cipher_parms.key_buf = rctx->msg_buf.c.supdt_tweak;
-                       update_key = true;
-                       cipher_parms.type = CIPHER_TYPE_UPDT;
-               } else if (!rctx->is_encrypt) {
-                       /*
-                        * First RC4 chunk. For decrypt, key in pre-built msg
-                        * header may have been changed if encrypt required
-                        * multiple chunks. So revert the key to the
-                        * ctx->enckey value.
-                        */
-                       update_key = true;
-                       cipher_parms.type = CIPHER_TYPE_INIT;
-               }
-       }
-
        if (ctx->max_payload == SPU_MAX_PAYLOAD_INF)
                flow_log("max_payload infinite\n");
        else
@@ -425,14 +398,9 @@ static int handle_skcipher_req(struct iproc_reqctx_s *rctx)
        memcpy(rctx->msg_buf.bcm_spu_req_hdr, ctx->bcm_spu_req_hdr,
               sizeof(rctx->msg_buf.bcm_spu_req_hdr));
 
-       /*
-        * Pass SUPDT field as key. Key field in finish() call is only used
-        * when update_key has been set above for RC4. Will be ignored in
-        * all other cases.
-        */
        spu->spu_cipher_req_finish(rctx->msg_buf.bcm_spu_req_hdr + BCM_HDR_LEN,
                                   ctx->spu_req_hdr_len, !(rctx->is_encrypt),
-                                  &cipher_parms, update_key, chunksize);
+                                  &cipher_parms, chunksize);
 
        atomic64_add(chunksize, &iproc_priv.bytes_out);
 
@@ -527,9 +495,6 @@ static void handle_skcipher_resp(struct iproc_reqctx_s *rctx)
                 __func__, rctx->total_received, payload_len);
 
        dump_sg(req->dst, rctx->total_received, payload_len);
-       if (ctx->cipher.alg == CIPHER_ALG_RC4)
-               packet_dump("  supdt ", rctx->msg_buf.c.supdt_tweak,
-                           SPU_SUPDT_LEN);
 
        rctx->total_received += payload_len;
        if (rctx->total_received == rctx->total_todo) {
@@ -1853,26 +1818,6 @@ static int aes_setkey(struct crypto_skcipher *cipher, const u8 *key,
        return 0;
 }
 
-static int rc4_setkey(struct crypto_skcipher *cipher, const u8 *key,
-                     unsigned int keylen)
-{
-       struct iproc_ctx_s *ctx = crypto_skcipher_ctx(cipher);
-       int i;
-
-       ctx->enckeylen = ARC4_MAX_KEY_SIZE + ARC4_STATE_SIZE;
-
-       ctx->enckey[0] = 0x00;  /* 0x00 */
-       ctx->enckey[1] = 0x00;  /* i    */
-       ctx->enckey[2] = 0x00;  /* 0x00 */
-       ctx->enckey[3] = 0x00;  /* j    */
-       for (i = 0; i < ARC4_MAX_KEY_SIZE; i++)
-               ctx->enckey[i + ARC4_STATE_SIZE] = key[i % keylen];
-
-       ctx->cipher_type = CIPHER_TYPE_INIT;
-
-       return 0;
-}
-
 static int skcipher_setkey(struct crypto_skcipher *cipher, const u8 *key,
                             unsigned int keylen)
 {
@@ -1895,9 +1840,6 @@ static int skcipher_setkey(struct crypto_skcipher *cipher, const u8 *key,
        case CIPHER_ALG_AES:
                err = aes_setkey(cipher, key, keylen);
                break;
-       case CIPHER_ALG_RC4:
-               err = rc4_setkey(cipher, key, keylen);
-               break;
        default:
                pr_err("%s() Error: unknown cipher alg\n", __func__);
                err = -EINVAL;
@@ -1905,11 +1847,9 @@ static int skcipher_setkey(struct crypto_skcipher *cipher, const u8 *key,
        if (err)
                return err;
 
-       /* RC4 already populated ctx->enkey */
-       if (ctx->cipher.alg != CIPHER_ALG_RC4) {
-               memcpy(ctx->enckey, key, keylen);
-               ctx->enckeylen = keylen;
-       }
+       memcpy(ctx->enckey, key, keylen);
+       ctx->enckeylen = keylen;
+
        /* SPU needs XTS keys in the reverse order the crypto API presents */
        if ((ctx->cipher.alg == CIPHER_ALG_AES) &&
            (ctx->cipher.mode == CIPHER_MODE_XTS)) {
@@ -2872,9 +2812,6 @@ static int aead_authenc_setkey(struct crypto_aead *cipher,
                        goto badkey;
                }
                break;
-       case CIPHER_ALG_RC4:
-               ctx->cipher_type = CIPHER_TYPE_INIT;
-               break;
        default:
                pr_err("%s() Error: Unknown cipher alg\n", __func__);
                return -EINVAL;
@@ -2930,7 +2867,6 @@ static int aead_gcm_ccm_setkey(struct crypto_aead *cipher,
 
        ctx->enckeylen = keylen;
        ctx->authkeylen = 0;
-       memcpy(ctx->enckey, key, ctx->enckeylen);
 
        switch (ctx->enckeylen) {
        case AES_KEYSIZE_128:
@@ -2946,6 +2882,8 @@ static int aead_gcm_ccm_setkey(struct crypto_aead *cipher,
                goto badkey;
        }
 
+       memcpy(ctx->enckey, key, ctx->enckeylen);
+
        flow_log("  enckeylen:%u authkeylen:%u\n", ctx->enckeylen,
                 ctx->authkeylen);
        flow_dump("  enc: ", ctx->enckey, ctx->enckeylen);
@@ -3000,6 +2938,10 @@ static int aead_gcm_esp_setkey(struct crypto_aead *cipher,
        struct iproc_ctx_s *ctx = crypto_aead_ctx(cipher);
 
        flow_log("%s\n", __func__);
+
+       if (keylen < GCM_ESP_SALT_SIZE)
+               return -EINVAL;
+
        ctx->salt_len = GCM_ESP_SALT_SIZE;
        ctx->salt_offset = GCM_ESP_SALT_OFFSET;
        memcpy(ctx->salt, key + keylen - GCM_ESP_SALT_SIZE, GCM_ESP_SALT_SIZE);
@@ -3028,6 +2970,10 @@ static int rfc4543_gcm_esp_setkey(struct crypto_aead *cipher,
        struct iproc_ctx_s *ctx = crypto_aead_ctx(cipher);
 
        flow_log("%s\n", __func__);
+
+       if (keylen < GCM_ESP_SALT_SIZE)
+               return -EINVAL;
+
        ctx->salt_len = GCM_ESP_SALT_SIZE;
        ctx->salt_offset = GCM_ESP_SALT_OFFSET;
        memcpy(ctx->salt, key + keylen - GCM_ESP_SALT_SIZE, GCM_ESP_SALT_SIZE);
@@ -3057,6 +3003,10 @@ static int aead_ccm_esp_setkey(struct crypto_aead *cipher,
        struct iproc_ctx_s *ctx = crypto_aead_ctx(cipher);
 
        flow_log("%s\n", __func__);
+
+       if (keylen < CCM_ESP_SALT_SIZE)
+               return -EINVAL;
+
        ctx->salt_len = CCM_ESP_SALT_SIZE;
        ctx->salt_offset = CCM_ESP_SALT_OFFSET;
        memcpy(ctx->salt, key + keylen - CCM_ESP_SALT_SIZE, CCM_ESP_SALT_SIZE);
@@ -3606,25 +3556,6 @@ static struct iproc_alg_s driver_algs[] = {
        {
         .type = CRYPTO_ALG_TYPE_SKCIPHER,
         .alg.skcipher = {
-                       .base.cra_name = "ecb(arc4)",
-                       .base.cra_driver_name = "ecb-arc4-iproc",
-                       .base.cra_blocksize = ARC4_BLOCK_SIZE,
-                       .min_keysize = ARC4_MIN_KEY_SIZE,
-                       .max_keysize = ARC4_MAX_KEY_SIZE,
-                       .ivsize = 0,
-                       },
-        .cipher_info = {
-                        .alg = CIPHER_ALG_RC4,
-                        .mode = CIPHER_MODE_NONE,
-                        },
-        .auth_info = {
-                      .alg = HASH_ALG_NONE,
-                      .mode = HASH_MODE_NONE,
-                      },
-        },
-       {
-        .type = CRYPTO_ALG_TYPE_SKCIPHER,
-        .alg.skcipher = {
                        .base.cra_name = "ofb(des)",
                        .base.cra_driver_name = "ofb-des-iproc",
                        .base.cra_blocksize = DES_BLOCK_SIZE,
@@ -4526,15 +4457,9 @@ static void spu_counters_init(void)
 
 static int spu_register_skcipher(struct iproc_alg_s *driver_alg)
 {
-       struct spu_hw *spu = &iproc_priv.spu;
        struct skcipher_alg *crypto = &driver_alg->alg.skcipher;
        int err;
 
-       /* SPU2 does not support RC4 */
-       if ((driver_alg->cipher_info.alg == CIPHER_ALG_RC4) &&
-           (spu->spu_type == SPU_TYPE_SPU2))
-               return 0;
-
        crypto->base.cra_module = THIS_MODULE;
        crypto->base.cra_priority = cipher_pri;
        crypto->base.cra_alignmask = 0;
index b6d83e3..035c838 100644 (file)
@@ -388,7 +388,6 @@ struct spu_hw {
                                      u16 spu_req_hdr_len,
                                      unsigned int is_inbound,
                                      struct spu_cipher_parms *cipher_parms,
-                                     bool update_key,
                                      unsigned int data_size);
        void (*spu_request_pad)(u8 *pad_start, u32 gcm_padding,
                                u32 hash_pad_len, enum hash_alg auth_alg,
index e7562e9..fe126f9 100644 (file)
@@ -222,10 +222,6 @@ void spum_dump_msg_hdr(u8 *buf, unsigned int buf_len)
                                cipher_key_len = 24;
                                name = "3DES";
                                break;
-                       case CIPHER_ALG_RC4:
-                               cipher_key_len = 260;
-                               name = "ARC4";
-                               break;
                        case CIPHER_ALG_AES:
                                switch (cipher_type) {
                                case CIPHER_TYPE_AES128:
@@ -919,21 +915,16 @@ u16 spum_cipher_req_init(u8 *spu_hdr, struct spu_cipher_parms *cipher_parms)
  * @spu_req_hdr_len: Length in bytes of the SPU request header
  * @isInbound:       0 encrypt, 1 decrypt
  * @cipher_parms:    Parameters describing cipher operation to be performed
- * @update_key:      If true, rewrite the cipher key in SCTX
  * @data_size:       Length of the data in the BD field
  *
  * Assumes much of the header was already filled in at setkey() time in
  * spum_cipher_req_init().
- * spum_cipher_req_init() fills in the encryption key. For RC4, when submitting
- * a request for a non-first chunk, we use the 260-byte SUPDT field from the
- * previous response as the key. update_key is true for this case. Unused in all
- * other cases.
+ * spum_cipher_req_init() fills in the encryption key.
  */
 void spum_cipher_req_finish(u8 *spu_hdr,
                            u16 spu_req_hdr_len,
                            unsigned int is_inbound,
                            struct spu_cipher_parms *cipher_parms,
-                           bool update_key,
                            unsigned int data_size)
 {
        struct SPUHEADER *spuh;
@@ -948,11 +939,6 @@ void spum_cipher_req_finish(u8 *spu_hdr,
        flow_log(" in: %u\n", is_inbound);
        flow_log(" cipher alg: %u, cipher_type: %u\n", cipher_parms->alg,
                 cipher_parms->type);
-       if (update_key) {
-               flow_log(" cipher key len: %u\n", cipher_parms->key_len);
-               flow_dump("  key: ", cipher_parms->key_buf,
-                         cipher_parms->key_len);
-       }
 
        /*
         * In XTS mode, API puts "i" parameter (block tweak) in IV.  For
@@ -981,13 +967,6 @@ void spum_cipher_req_finish(u8 *spu_hdr,
        else
                cipher_bits &= ~CIPHER_INBOUND;
 
-       /* update encryption key for RC4 on non-first chunk */
-       if (update_key) {
-               spuh->sa.cipher_flags |=
-                       cipher_parms->type << CIPHER_TYPE_SHIFT;
-               memcpy(spuh + 1, cipher_parms->key_buf, cipher_parms->key_len);
-       }
-
        if (cipher_parms->alg && cipher_parms->iv_buf && cipher_parms->iv_len)
                /* cipher iv provided so put it in here */
                memcpy(bdesc_ptr - cipher_parms->iv_len, cipher_parms->iv_buf,
index b247bc5..dd13238 100644 (file)
@@ -251,7 +251,6 @@ void spum_cipher_req_finish(u8 *spu_hdr,
                            u16 spu_req_hdr_len,
                            unsigned int is_inbound,
                            struct spu_cipher_parms *cipher_parms,
-                           bool update_key,
                            unsigned int data_size);
 
 void spum_request_pad(u8 *pad_start,
index 59abb5e..c860ffb 100644 (file)
@@ -1170,21 +1170,16 @@ u16 spu2_cipher_req_init(u8 *spu_hdr, struct spu_cipher_parms *cipher_parms)
  * @spu_req_hdr_len: Length in bytes of the SPU request header
  * @isInbound:       0 encrypt, 1 decrypt
  * @cipher_parms:    Parameters describing cipher operation to be performed
- * @update_key:      If true, rewrite the cipher key in SCTX
  * @data_size:       Length of the data in the BD field
  *
  * Assumes much of the header was already filled in at setkey() time in
  * spu_cipher_req_init().
- * spu_cipher_req_init() fills in the encryption key. For RC4, when submitting a
- * request for a non-first chunk, we use the 260-byte SUPDT field from the
- * previous response as the key. update_key is true for this case. Unused in all
- * other cases.
+ * spu_cipher_req_init() fills in the encryption key.
  */
 void spu2_cipher_req_finish(u8 *spu_hdr,
                            u16 spu_req_hdr_len,
                            unsigned int is_inbound,
                            struct spu_cipher_parms *cipher_parms,
-                           bool update_key,
                            unsigned int data_size)
 {
        struct SPU2_FMD *fmd;
@@ -1196,11 +1191,6 @@ void spu2_cipher_req_finish(u8 *spu_hdr,
        flow_log(" in: %u\n", is_inbound);
        flow_log(" cipher alg: %u, cipher_type: %u\n", cipher_parms->alg,
                 cipher_parms->type);
-       if (update_key) {
-               flow_log(" cipher key len: %u\n", cipher_parms->key_len);
-               flow_dump("  key: ", cipher_parms->key_buf,
-                         cipher_parms->key_len);
-       }
        flow_log(" iv len: %d\n", cipher_parms->iv_len);
        flow_dump("    iv: ", cipher_parms->iv_buf, cipher_parms->iv_len);
        flow_log(" data_size: %u\n", data_size);
index 03af6c3..6e666bf 100644 (file)
@@ -200,7 +200,6 @@ void spu2_cipher_req_finish(u8 *spu_hdr,
                            u16 spu_req_hdr_len,
                            unsigned int is_inbound,
                            struct spu_cipher_parms *cipher_parms,
-                           bool update_key,
                            unsigned int data_size);
 void spu2_request_pad(u8 *pad_start, u32 gcm_padding, u32 hash_pad_len,
                      enum hash_alg auth_alg, enum hash_mode auth_mode,
index bc35aa0..84ea7cb 100644 (file)
@@ -101,6 +101,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
        select CRYPTO_AUTHENC
        select CRYPTO_SKCIPHER
        select CRYPTO_LIB_DES
+       select CRYPTO_XTS
        help
          Selecting this will offload crypto for users of the
          scatterlist crypto API (such as the linux native IPSec
@@ -114,6 +115,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI
        select CRYPTO_AUTHENC
        select CRYPTO_SKCIPHER
        select CRYPTO_DES
+       select CRYPTO_XTS
        help
          Selecting this will use CAAM Queue Interface (QI) for sending
          & receiving crypto jobs to/from CAAM. This gives better performance
@@ -165,6 +167,7 @@ config CRYPTO_DEV_FSL_DPAA2_CAAM
        select CRYPTO_AEAD
        select CRYPTO_HASH
        select CRYPTO_DES
+       select CRYPTO_XTS
        help
          CAAM driver for QorIQ Data Path Acceleration Architecture 2.
          It handles DPSECI DPAA2 objects that sit on the Management Complex
index 68d5cc0..3570286 100644 (file)
@@ -27,6 +27,8 @@ ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
        ccflags-y += -DCONFIG_CAAM_QI
 endif
 
+caam-$(CONFIG_DEBUG_FS) += debugfs.o
+
 obj-$(CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM) += dpaa2_caam.o
 
 dpaa2_caam-y    := caamalg_qi2.o dpseci.o
index 91feda5..cf5bd76 100644 (file)
@@ -57,6 +57,8 @@
 #include "key_gen.h"
 #include "caamalg_desc.h"
 #include <crypto/engine.h>
+#include <crypto/xts.h>
+#include <asm/unaligned.h>
 
 /*
  * crypto alg
@@ -114,10 +116,13 @@ struct caam_ctx {
        struct alginfo adata;
        struct alginfo cdata;
        unsigned int authsize;
+       bool xts_key_fallback;
+       struct crypto_skcipher *fallback;
 };
 
 struct caam_skcipher_req_ctx {
        struct skcipher_edesc *edesc;
+       struct skcipher_request fallback_req;
 };
 
 struct caam_aead_req_ctx {
@@ -829,11 +834,23 @@ static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
 {
        struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
        struct device *jrdev = ctx->jrdev;
+       struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
        u32 *desc;
+       int err;
 
-       if (keylen != 2 * AES_MIN_KEY_SIZE  && keylen != 2 * AES_MAX_KEY_SIZE) {
+       err = xts_verify_key(skcipher, key, keylen);
+       if (err) {
                dev_dbg(jrdev, "key size mismatch\n");
-               return -EINVAL;
+               return err;
+       }
+
+       if (keylen != 2 * AES_KEYSIZE_128 && keylen != 2 * AES_KEYSIZE_256)
+               ctx->xts_key_fallback = true;
+
+       if (ctrlpriv->era <= 8 || ctx->xts_key_fallback) {
+               err = crypto_skcipher_setkey(ctx->fallback, key, keylen);
+               if (err)
+                       return err;
        }
 
        ctx->cdata.keylen = keylen;
@@ -1755,6 +1772,14 @@ static int skcipher_do_one_req(struct crypto_engine *engine, void *areq)
        return ret;
 }
 
+static inline bool xts_skcipher_ivsize(struct skcipher_request *req)
+{
+       struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+       unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
+
+       return !!get_unaligned((u64 *)(req->iv + (ivsize / 2)));
+}
+
 static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt)
 {
        struct skcipher_edesc *edesc;
@@ -1762,12 +1787,34 @@ static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt)
        struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
        struct device *jrdev = ctx->jrdev;
        struct caam_drv_private_jr *jrpriv = dev_get_drvdata(jrdev);
+       struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
        u32 *desc;
        int ret = 0;
 
-       if (!req->cryptlen)
+       /*
+        * XTS is expected to return an error even for input length = 0
+        * Note that the case input length < block size will be caught during
+        * HW offloading and return an error.
+        */
+       if (!req->cryptlen && !ctx->fallback)
                return 0;
 
+       if (ctx->fallback && ((ctrlpriv->era <= 8 && xts_skcipher_ivsize(req)) ||
+                             ctx->xts_key_fallback)) {
+               struct caam_skcipher_req_ctx *rctx = skcipher_request_ctx(req);
+
+               skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback);
+               skcipher_request_set_callback(&rctx->fallback_req,
+                                             req->base.flags,
+                                             req->base.complete,
+                                             req->base.data);
+               skcipher_request_set_crypt(&rctx->fallback_req, req->src,
+                                          req->dst, req->cryptlen, req->iv);
+
+               return encrypt ? crypto_skcipher_encrypt(&rctx->fallback_req) :
+                                crypto_skcipher_decrypt(&rctx->fallback_req);
+       }
+
        /* allocate extended descriptor */
        edesc = skcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ);
        if (IS_ERR(edesc))
@@ -1905,6 +1952,7 @@ static struct caam_skcipher_alg driver_algs[] = {
                        .base = {
                                .cra_name = "xts(aes)",
                                .cra_driver_name = "xts-aes-caam",
+                               .cra_flags = CRYPTO_ALG_NEED_FALLBACK,
                                .cra_blocksize = AES_BLOCK_SIZE,
                        },
                        .setkey = xts_skcipher_setkey,
@@ -3344,13 +3392,35 @@ static int caam_cra_init(struct crypto_skcipher *tfm)
        struct caam_skcipher_alg *caam_alg =
                container_of(alg, typeof(*caam_alg), skcipher);
        struct caam_ctx *ctx = crypto_skcipher_ctx(tfm);
-
-       crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_skcipher_req_ctx));
+       u32 alg_aai = caam_alg->caam.class1_alg_type & OP_ALG_AAI_MASK;
+       int ret = 0;
 
        ctx->enginectx.op.do_one_request = skcipher_do_one_req;
 
-       return caam_init_common(crypto_skcipher_ctx(tfm), &caam_alg->caam,
-                               false);
+       if (alg_aai == OP_ALG_AAI_XTS) {
+               const char *tfm_name = crypto_tfm_alg_name(&tfm->base);
+               struct crypto_skcipher *fallback;
+
+               fallback = crypto_alloc_skcipher(tfm_name, 0,
+                                                CRYPTO_ALG_NEED_FALLBACK);
+               if (IS_ERR(fallback)) {
+                       dev_err(ctx->jrdev, "Failed to allocate %s fallback: %ld\n",
+                               tfm_name, PTR_ERR(fallback));
+                       return PTR_ERR(fallback);
+               }
+
+               ctx->fallback = fallback;
+               crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_skcipher_req_ctx) +
+                                           crypto_skcipher_reqsize(fallback));
+       } else {
+               crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_skcipher_req_ctx));
+       }
+
+       ret = caam_init_common(ctx, &caam_alg->caam, false);
+       if (ret && ctx->fallback)
+               crypto_free_skcipher(ctx->fallback);
+
+       return ret;
 }
 
 static int caam_aead_init(struct crypto_aead *tfm)
@@ -3378,7 +3448,11 @@ static void caam_exit_common(struct caam_ctx *ctx)
 
 static void caam_cra_exit(struct crypto_skcipher *tfm)
 {
-       caam_exit_common(crypto_skcipher_ctx(tfm));
+       struct caam_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+       if (ctx->fallback)
+               crypto_free_skcipher(ctx->fallback);
+       caam_exit_common(ctx);
 }
 
 static void caam_aead_exit(struct crypto_aead *tfm)
@@ -3412,8 +3486,8 @@ static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg)
        alg->base.cra_module = THIS_MODULE;
        alg->base.cra_priority = CAAM_CRA_PRIORITY;
        alg->base.cra_ctxsize = sizeof(struct caam_ctx);
-       alg->base.cra_flags CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
-                             CRYPTO_ALG_KERN_DRIVER_ONLY;
+       alg->base.cra_flags |= (CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
+                             CRYPTO_ALG_KERN_DRIVER_ONLY);
 
        alg->init = caam_cra_init;
        alg->exit = caam_cra_exit;
index d6c5818..7571e1a 100644 (file)
@@ -373,6 +373,7 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_encap);
  *         with OP_ALG_AAI_HMAC_PRECOMP.
  * @ivsize: initialization vector size
  * @icvsize: integrity check value (ICV) size (truncated or full)
+ * @geniv: whether to generate Encrypted Chain IV
  * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template
  * @nonce: pointer to rfc3686 nonce
  * @ctx1_iv_off: IV offset in CONTEXT1 register
@@ -1550,13 +1551,14 @@ void cnstr_shdsc_xts_skcipher_encap(u32 * const desc, struct alginfo *cdata)
        set_jump_tgt_here(desc, key_jump_cmd);
 
        /*
-        * create sequence for loading the sector index
-        * Upper 8B of IV - will be used as sector index
-        * Lower 8B of IV - will be discarded
+        * create sequence for loading the sector index / 16B tweak value
+        * Lower 8B of IV - sector index / tweak lower half
+        * Upper 8B of IV - upper half of 16B tweak
         */
        append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB |
                        (0x20 << LDST_OFFSET_SHIFT));
-       append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP);
+       append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB |
+                       (0x30 << LDST_OFFSET_SHIFT));
 
        /* Load operation */
        append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
@@ -1565,9 +1567,11 @@ void cnstr_shdsc_xts_skcipher_encap(u32 * const desc, struct alginfo *cdata)
        /* Perform operation */
        skcipher_append_src_dst(desc);
 
-       /* Store upper 8B of IV */
+       /* Store lower 8B and upper 8B of IV */
        append_seq_store(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB |
                         (0x20 << LDST_OFFSET_SHIFT));
+       append_seq_store(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB |
+                        (0x30 << LDST_OFFSET_SHIFT));
 
        print_hex_dump_debug("xts skcipher enc shdesc@" __stringify(__LINE__)
                             ": ", DUMP_PREFIX_ADDRESS, 16, 4,
@@ -1609,23 +1613,25 @@ void cnstr_shdsc_xts_skcipher_decap(u32 * const desc, struct alginfo *cdata)
        set_jump_tgt_here(desc, key_jump_cmd);
 
        /*
-        * create sequence for loading the sector index
-        * Upper 8B of IV - will be used as sector index
-        * Lower 8B of IV - will be discarded
+        * create sequence for loading the sector index / 16B tweak value
+        * Lower 8B of IV - sector index / tweak lower half
+        * Upper 8B of IV - upper half of 16B tweak
         */
        append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB |
                        (0x20 << LDST_OFFSET_SHIFT));
-       append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP);
-
+       append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB |
+                       (0x30 << LDST_OFFSET_SHIFT));
        /* Load operation */
        append_dec_op1(desc, cdata->algtype);
 
        /* Perform operation */
        skcipher_append_src_dst(desc);
 
-       /* Store upper 8B of IV */
+       /* Store lower 8B and upper 8B of IV */
        append_seq_store(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB |
                         (0x20 << LDST_OFFSET_SHIFT));
+       append_seq_store(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB |
+                        (0x30 << LDST_OFFSET_SHIFT));
 
        print_hex_dump_debug("xts skcipher dec shdesc@" __stringify(__LINE__)
                             ": ", DUMP_PREFIX_ADDRESS, 16, 4, desc,
index bb1c010..66f60d7 100644 (file)
@@ -18,6 +18,8 @@
 #include "qi.h"
 #include "jr.h"
 #include "caamalg_desc.h"
+#include <crypto/xts.h>
+#include <asm/unaligned.h>
 
 /*
  * crypto alg
@@ -67,6 +69,12 @@ struct caam_ctx {
        struct device *qidev;
        spinlock_t lock;        /* Protects multiple init of driver context */
        struct caam_drv_ctx *drv_ctx[NUM_OP];
+       bool xts_key_fallback;
+       struct crypto_skcipher *fallback;
+};
+
+struct caam_skcipher_req_ctx {
+       struct skcipher_request fallback_req;
 };
 
 static int aead_set_sh_desc(struct crypto_aead *aead)
@@ -725,11 +733,23 @@ static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
 {
        struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
        struct device *jrdev = ctx->jrdev;
+       struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent);
        int ret = 0;
+       int err;
 
-       if (keylen != 2 * AES_MIN_KEY_SIZE  && keylen != 2 * AES_MAX_KEY_SIZE) {
+       err = xts_verify_key(skcipher, key, keylen);
+       if (err) {
                dev_dbg(jrdev, "key size mismatch\n");
-               return -EINVAL;
+               return err;
+       }
+
+       if (keylen != 2 * AES_KEYSIZE_128 && keylen != 2 * AES_KEYSIZE_256)
+               ctx->xts_key_fallback = true;
+
+       if (ctrlpriv->era <= 8 || ctx->xts_key_fallback) {
+               err = crypto_skcipher_setkey(ctx->fallback, key, keylen);
+               if (err)
+                       return err;
        }
 
        ctx->cdata.keylen = keylen;
@@ -1373,16 +1393,46 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
        return edesc;
 }
 
+static inline bool xts_skcipher_ivsize(struct skcipher_request *req)
+{
+       struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+       unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
+
+       return !!get_unaligned((u64 *)(req->iv + (ivsize / 2)));
+}
+
 static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt)
 {
        struct skcipher_edesc *edesc;
        struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
        struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+       struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent);
        int ret;
 
-       if (!req->cryptlen)
+       /*
+        * XTS is expected to return an error even for input length = 0
+        * Note that the case input length < block size will be caught during
+        * HW offloading and return an error.
+        */
+       if (!req->cryptlen && !ctx->fallback)
                return 0;
 
+       if (ctx->fallback && ((ctrlpriv->era <= 8 && xts_skcipher_ivsize(req)) ||
+                             ctx->xts_key_fallback)) {
+               struct caam_skcipher_req_ctx *rctx = skcipher_request_ctx(req);
+
+               skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback);
+               skcipher_request_set_callback(&rctx->fallback_req,
+                                             req->base.flags,
+                                             req->base.complete,
+                                             req->base.data);
+               skcipher_request_set_crypt(&rctx->fallback_req, req->src,
+                                          req->dst, req->cryptlen, req->iv);
+
+               return encrypt ? crypto_skcipher_encrypt(&rctx->fallback_req) :
+                                crypto_skcipher_decrypt(&rctx->fallback_req);
+       }
+
        if (unlikely(caam_congested))
                return -EAGAIN;
 
@@ -1507,6 +1557,7 @@ static struct caam_skcipher_alg driver_algs[] = {
                        .base = {
                                .cra_name = "xts(aes)",
                                .cra_driver_name = "xts-aes-caam-qi",
+                               .cra_flags = CRYPTO_ALG_NEED_FALLBACK,
                                .cra_blocksize = AES_BLOCK_SIZE,
                        },
                        .setkey = xts_skcipher_setkey,
@@ -2440,9 +2491,32 @@ static int caam_cra_init(struct crypto_skcipher *tfm)
        struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
        struct caam_skcipher_alg *caam_alg =
                container_of(alg, typeof(*caam_alg), skcipher);
+       struct caam_ctx *ctx = crypto_skcipher_ctx(tfm);
+       u32 alg_aai = caam_alg->caam.class1_alg_type & OP_ALG_AAI_MASK;
+       int ret = 0;
+
+       if (alg_aai == OP_ALG_AAI_XTS) {
+               const char *tfm_name = crypto_tfm_alg_name(&tfm->base);
+               struct crypto_skcipher *fallback;
+
+               fallback = crypto_alloc_skcipher(tfm_name, 0,
+                                                CRYPTO_ALG_NEED_FALLBACK);
+               if (IS_ERR(fallback)) {
+                       dev_err(ctx->jrdev, "Failed to allocate %s fallback: %ld\n",
+                               tfm_name, PTR_ERR(fallback));
+                       return PTR_ERR(fallback);
+               }
+
+               ctx->fallback = fallback;
+               crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_skcipher_req_ctx) +
+                                           crypto_skcipher_reqsize(fallback));
+       }
+
+       ret = caam_init_common(ctx, &caam_alg->caam, false);
+       if (ret && ctx->fallback)
+               crypto_free_skcipher(ctx->fallback);
 
-       return caam_init_common(crypto_skcipher_ctx(tfm), &caam_alg->caam,
-                               false);
+       return ret;
 }
 
 static int caam_aead_init(struct crypto_aead *tfm)
@@ -2468,7 +2542,11 @@ static void caam_exit_common(struct caam_ctx *ctx)
 
 static void caam_cra_exit(struct crypto_skcipher *tfm)
 {
-       caam_exit_common(crypto_skcipher_ctx(tfm));
+       struct caam_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+       if (ctx->fallback)
+               crypto_free_skcipher(ctx->fallback);
+       caam_exit_common(ctx);
 }
 
 static void caam_aead_exit(struct crypto_aead *tfm)
@@ -2502,8 +2580,8 @@ static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg)
        alg->base.cra_module = THIS_MODULE;
        alg->base.cra_priority = CAAM_CRA_PRIORITY;
        alg->base.cra_ctxsize = sizeof(struct caam_ctx);
-       alg->base.cra_flags CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
-                             CRYPTO_ALG_KERN_DRIVER_ONLY;
+       alg->base.cra_flags |= (CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
+                               CRYPTO_ALG_KERN_DRIVER_ONLY);
 
        alg->init = caam_cra_init;
        alg->exit = caam_cra_exit;
index 66ae1d5..98c1ff1 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/fsl/mc.h>
 #include <soc/fsl/dpaa2-io.h>
 #include <soc/fsl/dpaa2-fd.h>
+#include <crypto/xts.h>
+#include <asm/unaligned.h>
 
 #define CAAM_CRA_PRIORITY      2000
 
@@ -59,7 +61,7 @@ struct caam_skcipher_alg {
 };
 
 /**
- * caam_ctx - per-session context
+ * struct caam_ctx - per-session context
  * @flc: Flow Contexts array
  * @key:  [authentication key], encryption key
  * @flc_dma: I/O virtual addresses of the Flow Contexts
@@ -80,6 +82,8 @@ struct caam_ctx {
        struct alginfo adata;
        struct alginfo cdata;
        unsigned int authsize;
+       bool xts_key_fallback;
+       struct crypto_skcipher *fallback;
 };
 
 static void *dpaa2_caam_iova_to_virt(struct dpaa2_caam_priv *priv,
@@ -1054,12 +1058,24 @@ static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
 {
        struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
        struct device *dev = ctx->dev;
+       struct dpaa2_caam_priv *priv = dev_get_drvdata(dev);
        struct caam_flc *flc;
        u32 *desc;
+       int err;
 
-       if (keylen != 2 * AES_MIN_KEY_SIZE  && keylen != 2 * AES_MAX_KEY_SIZE) {
+       err = xts_verify_key(skcipher, key, keylen);
+       if (err) {
                dev_dbg(dev, "key size mismatch\n");
-               return -EINVAL;
+               return err;
+       }
+
+       if (keylen != 2 * AES_KEYSIZE_128 && keylen != 2 * AES_KEYSIZE_256)
+               ctx->xts_key_fallback = true;
+
+       if (priv->sec_attr.era <= 8 || ctx->xts_key_fallback) {
+               err = crypto_skcipher_setkey(ctx->fallback, key, keylen);
+               if (err)
+                       return err;
        }
 
        ctx->cdata.keylen = keylen;
@@ -1443,17 +1459,44 @@ static void skcipher_decrypt_done(void *cbk_ctx, u32 status)
        skcipher_request_complete(req, ecode);
 }
 
+static inline bool xts_skcipher_ivsize(struct skcipher_request *req)
+{
+       struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+       unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
+
+       return !!get_unaligned((u64 *)(req->iv + (ivsize / 2)));
+}
+
 static int skcipher_encrypt(struct skcipher_request *req)
 {
        struct skcipher_edesc *edesc;
        struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
        struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
        struct caam_request *caam_req = skcipher_request_ctx(req);
+       struct dpaa2_caam_priv *priv = dev_get_drvdata(ctx->dev);
        int ret;
 
-       if (!req->cryptlen)
+       /*
+        * XTS is expected to return an error even for input length = 0
+        * Note that the case input length < block size will be caught during
+        * HW offloading and return an error.
+        */
+       if (!req->cryptlen && !ctx->fallback)
                return 0;
 
+       if (ctx->fallback && ((priv->sec_attr.era <= 8 && xts_skcipher_ivsize(req)) ||
+                             ctx->xts_key_fallback)) {
+               skcipher_request_set_tfm(&caam_req->fallback_req, ctx->fallback);
+               skcipher_request_set_callback(&caam_req->fallback_req,
+                                             req->base.flags,
+                                             req->base.complete,
+                                             req->base.data);
+               skcipher_request_set_crypt(&caam_req->fallback_req, req->src,
+                                          req->dst, req->cryptlen, req->iv);
+
+               return crypto_skcipher_encrypt(&caam_req->fallback_req);
+       }
+
        /* allocate extended descriptor */
        edesc = skcipher_edesc_alloc(req);
        if (IS_ERR(edesc))
@@ -1480,10 +1523,30 @@ static int skcipher_decrypt(struct skcipher_request *req)
        struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
        struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
        struct caam_request *caam_req = skcipher_request_ctx(req);
+       struct dpaa2_caam_priv *priv = dev_get_drvdata(ctx->dev);
        int ret;
 
-       if (!req->cryptlen)
+       /*
+        * XTS is expected to return an error even for input length = 0
+        * Note that the case input length < block size will be caught during
+        * HW offloading and return an error.
+        */
+       if (!req->cryptlen && !ctx->fallback)
                return 0;
+
+       if (ctx->fallback && ((priv->sec_attr.era <= 8 && xts_skcipher_ivsize(req)) ||
+                             ctx->xts_key_fallback)) {
+               skcipher_request_set_tfm(&caam_req->fallback_req, ctx->fallback);
+               skcipher_request_set_callback(&caam_req->fallback_req,
+                                             req->base.flags,
+                                             req->base.complete,
+                                             req->base.data);
+               skcipher_request_set_crypt(&caam_req->fallback_req, req->src,
+                                          req->dst, req->cryptlen, req->iv);
+
+               return crypto_skcipher_decrypt(&caam_req->fallback_req);
+       }
+
        /* allocate extended descriptor */
        edesc = skcipher_edesc_alloc(req);
        if (IS_ERR(edesc))
@@ -1537,9 +1600,34 @@ static int caam_cra_init_skcipher(struct crypto_skcipher *tfm)
        struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
        struct caam_skcipher_alg *caam_alg =
                container_of(alg, typeof(*caam_alg), skcipher);
+       struct caam_ctx *ctx = crypto_skcipher_ctx(tfm);
+       u32 alg_aai = caam_alg->caam.class1_alg_type & OP_ALG_AAI_MASK;
+       int ret = 0;
 
-       crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_request));
-       return caam_cra_init(crypto_skcipher_ctx(tfm), &caam_alg->caam, false);
+       if (alg_aai == OP_ALG_AAI_XTS) {
+               const char *tfm_name = crypto_tfm_alg_name(&tfm->base);
+               struct crypto_skcipher *fallback;
+
+               fallback = crypto_alloc_skcipher(tfm_name, 0,
+                                                CRYPTO_ALG_NEED_FALLBACK);
+               if (IS_ERR(fallback)) {
+                       dev_err(ctx->dev, "Failed to allocate %s fallback: %ld\n",
+                               tfm_name, PTR_ERR(fallback));
+                       return PTR_ERR(fallback);
+               }
+
+               ctx->fallback = fallback;
+               crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_request) +
+                                           crypto_skcipher_reqsize(fallback));
+       } else {
+               crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_request));
+       }
+
+       ret = caam_cra_init(ctx, &caam_alg->caam, false);
+       if (ret && ctx->fallback)
+               crypto_free_skcipher(ctx->fallback);
+
+       return ret;
 }
 
 static int caam_cra_init_aead(struct crypto_aead *tfm)
@@ -1562,7 +1650,11 @@ static void caam_exit_common(struct caam_ctx *ctx)
 
 static void caam_cra_exit(struct crypto_skcipher *tfm)
 {
-       caam_exit_common(crypto_skcipher_ctx(tfm));
+       struct caam_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+       if (ctx->fallback)
+               crypto_free_skcipher(ctx->fallback);
+       caam_exit_common(ctx);
 }
 
 static void caam_cra_exit_aead(struct crypto_aead *tfm)
@@ -1665,6 +1757,7 @@ static struct caam_skcipher_alg driver_algs[] = {
                        .base = {
                                .cra_name = "xts(aes)",
                                .cra_driver_name = "xts-aes-caam-qi2",
+                               .cra_flags = CRYPTO_ALG_NEED_FALLBACK,
                                .cra_blocksize = AES_BLOCK_SIZE,
                        },
                        .setkey = xts_skcipher_setkey,
@@ -2912,8 +3005,8 @@ static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg)
        alg->base.cra_module = THIS_MODULE;
        alg->base.cra_priority = CAAM_CRA_PRIORITY;
        alg->base.cra_ctxsize = sizeof(struct caam_ctx);
-       alg->base.cra_flags CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
-                             CRYPTO_ALG_KERN_DRIVER_ONLY;
+       alg->base.cra_flags |= (CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
+                             CRYPTO_ALG_KERN_DRIVER_ONLY);
 
        alg->init = caam_cra_init_skcipher;
        alg->exit = caam_cra_exit;
@@ -2951,7 +3044,7 @@ enum hash_optype {
 };
 
 /**
- * caam_hash_ctx - ahash per-session context
+ * struct caam_hash_ctx - ahash per-session context
  * @flc: Flow Contexts array
  * @key: authentication key
  * @flc_dma: I/O virtual addresses of the Flow Contexts
@@ -5115,8 +5208,7 @@ static int dpaa2_caam_probe(struct fsl_mc_device *dpseci_dev)
        /* DPIO */
        err = dpaa2_dpseci_dpio_setup(priv);
        if (err) {
-               if (err != -EPROBE_DEFER)
-                       dev_err(dev, "dpaa2_dpseci_dpio_setup() failed\n");
+               dev_err_probe(dev, err, "dpaa2_dpseci_dpio_setup() failed\n");
                goto err_dpio_setup;
        }
 
index f29cb7b..d352534 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/netdevice.h>
 #include "dpseci.h"
 #include "desc_constr.h"
+#include <crypto/skcipher.h>
 
 #define DPAA2_CAAM_STORE_SIZE  16
 /* NAPI weight *must* be a multiple of the store size. */
@@ -186,6 +187,7 @@ struct caam_request {
        void (*cbk)(void *ctx, u32 err);
        void *ctx;
        void *edesc;
+       struct skcipher_request fallback_req;
 };
 
 /**
index 94502f1..ca0361b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/fsl/mc.h>
 
 #include "compat.h"
+#include "debugfs.h"
 #include "regs.h"
 #include "intern.h"
 #include "jr.h"
@@ -332,11 +333,10 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask,
 
        kfree(desc);
 
-       if (!ret)
-               ret = devm_add_action_or_reset(ctrldev, devm_deinstantiate_rng,
-                                              ctrldev);
+       if (ret)
+               return ret;
 
-       return ret;
+       return devm_add_action_or_reset(ctrldev, devm_deinstantiate_rng, ctrldev);
 }
 
 /*
@@ -443,7 +443,9 @@ static int caam_get_era_from_hw(struct caam_ctrl __iomem *ctrl)
  * by u-boot.
  * In case this property is not passed an attempt to retrieve the CAAM
  * era via register reads will be made.
- **/
+ *
+ * @ctrl:      controller region
+ */
 static int caam_get_era(struct caam_ctrl __iomem *ctrl)
 {
        struct device_node *caam_node;
@@ -582,12 +584,10 @@ static int init_clocks(struct device *dev, const struct caam_imx_data *data)
        return devm_add_action_or_reset(dev, disable_clocks, ctrlpriv);
 }
 
-#ifdef CONFIG_DEBUG_FS
 static void caam_remove_debugfs(void *root)
 {
        debugfs_remove_recursive(root);
 }
-#endif
 
 #ifdef CONFIG_FSL_MC_BUS
 static bool check_version(struct fsl_mc_version *mc_version, u32 major,
@@ -619,10 +619,7 @@ static int caam_probe(struct platform_device *pdev)
        struct device_node *nprop, *np;
        struct caam_ctrl __iomem *ctrl;
        struct caam_drv_private *ctrlpriv;
-#ifdef CONFIG_DEBUG_FS
-       struct caam_perfmon *perfmon;
        struct dentry *dfs_root;
-#endif
        u32 scfgr, comp_params;
        u8 rng_vid;
        int pg_size;
@@ -777,21 +774,15 @@ static int caam_probe(struct platform_device *pdev)
        ctrlpriv->era = caam_get_era(ctrl);
        ctrlpriv->domain = iommu_get_domain_for_dev(dev);
 
-#ifdef CONFIG_DEBUG_FS
-       /*
-        * FIXME: needs better naming distinction, as some amalgamation of
-        * "caam" and nprop->full_name. The OF name isn't distinctive,
-        * but does separate instances
-        */
-       perfmon = (struct caam_perfmon __force *)&ctrl->perfmon;
-
        dfs_root = debugfs_create_dir(dev_name(dev), NULL);
-       ret = devm_add_action_or_reset(dev, caam_remove_debugfs, dfs_root);
-       if (ret)
-               return ret;
+       if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+               ret = devm_add_action_or_reset(dev, caam_remove_debugfs,
+                                              dfs_root);
+               if (ret)
+                       return ret;
+       }
 
-       ctrlpriv->ctl = debugfs_create_dir("ctl", dfs_root);
-#endif
+       caam_debugfs_init(ctrlpriv, dfs_root);
 
        /* Check to see if (DPAA 1.x) QI present. If so, enable */
        if (ctrlpriv->qi_present && !caam_dpaa2) {
@@ -912,57 +903,6 @@ static int caam_probe(struct platform_device *pdev)
        dev_info(dev, "job rings = %d, qi = %d\n",
                 ctrlpriv->total_jobrs, ctrlpriv->qi_present);
 
-#ifdef CONFIG_DEBUG_FS
-       debugfs_create_file("rq_dequeued", S_IRUSR | S_IRGRP | S_IROTH,
-                           ctrlpriv->ctl, &perfmon->req_dequeued,
-                           &caam_fops_u64_ro);
-       debugfs_create_file("ob_rq_encrypted", S_IRUSR | S_IRGRP | S_IROTH,
-                           ctrlpriv->ctl, &perfmon->ob_enc_req,
-                           &caam_fops_u64_ro);
-       debugfs_create_file("ib_rq_decrypted", S_IRUSR | S_IRGRP | S_IROTH,
-                           ctrlpriv->ctl, &perfmon->ib_dec_req,
-                           &caam_fops_u64_ro);
-       debugfs_create_file("ob_bytes_encrypted", S_IRUSR | S_IRGRP | S_IROTH,
-                           ctrlpriv->ctl, &perfmon->ob_enc_bytes,
-                           &caam_fops_u64_ro);
-       debugfs_create_file("ob_bytes_protected", S_IRUSR | S_IRGRP | S_IROTH,
-                           ctrlpriv->ctl, &perfmon->ob_prot_bytes,
-                           &caam_fops_u64_ro);
-       debugfs_create_file("ib_bytes_decrypted", S_IRUSR | S_IRGRP | S_IROTH,
-                           ctrlpriv->ctl, &perfmon->ib_dec_bytes,
-                           &caam_fops_u64_ro);
-       debugfs_create_file("ib_bytes_validated", S_IRUSR | S_IRGRP | S_IROTH,
-                           ctrlpriv->ctl, &perfmon->ib_valid_bytes,
-                           &caam_fops_u64_ro);
-
-       /* Controller level - global status values */
-       debugfs_create_file("fault_addr", S_IRUSR | S_IRGRP | S_IROTH,
-                           ctrlpriv->ctl, &perfmon->faultaddr,
-                           &caam_fops_u32_ro);
-       debugfs_create_file("fault_detail", S_IRUSR | S_IRGRP | S_IROTH,
-                           ctrlpriv->ctl, &perfmon->faultdetail,
-                           &caam_fops_u32_ro);
-       debugfs_create_file("fault_status", S_IRUSR | S_IRGRP | S_IROTH,
-                           ctrlpriv->ctl, &perfmon->status,
-                           &caam_fops_u32_ro);
-
-       /* Internal covering keys (useful in non-secure mode only) */
-       ctrlpriv->ctl_kek_wrap.data = (__force void *)&ctrlpriv->ctrl->kek[0];
-       ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
-       debugfs_create_blob("kek", S_IRUSR | S_IRGRP | S_IROTH, ctrlpriv->ctl,
-                           &ctrlpriv->ctl_kek_wrap);
-
-       ctrlpriv->ctl_tkek_wrap.data = (__force void *)&ctrlpriv->ctrl->tkek[0];
-       ctrlpriv->ctl_tkek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
-       debugfs_create_blob("tkek", S_IRUSR | S_IRGRP | S_IROTH, ctrlpriv->ctl,
-                           &ctrlpriv->ctl_tkek_wrap);
-
-       ctrlpriv->ctl_tdsk_wrap.data = (__force void *)&ctrlpriv->ctrl->tdsk[0];
-       ctrlpriv->ctl_tdsk_wrap.size = KEK_KEY_SIZE * sizeof(u32);
-       debugfs_create_blob("tdsk", S_IRUSR | S_IRGRP | S_IROTH, ctrlpriv->ctl,
-                           &ctrlpriv->ctl_tdsk_wrap);
-#endif
-
        ret = devm_of_platform_populate(dev);
        if (ret)
                dev_err(dev, "JR platform devices creation error\n");
diff --git a/drivers/crypto/caam/debugfs.c b/drivers/crypto/caam/debugfs.c
new file mode 100644 (file)
index 0000000..8ebf183
--- /dev/null
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2019 NXP */
+
+#include <linux/debugfs.h>
+#include "compat.h"
+#include "debugfs.h"
+#include "regs.h"
+#include "intern.h"
+
+static int caam_debugfs_u64_get(void *data, u64 *val)
+{
+       *val = caam64_to_cpu(*(u64 *)data);
+       return 0;
+}
+
+static int caam_debugfs_u32_get(void *data, u64 *val)
+{
+       *val = caam32_to_cpu(*(u32 *)data);
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u32_ro, caam_debugfs_u32_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u64_ro, caam_debugfs_u64_get, NULL, "%llu\n");
+
+#ifdef CONFIG_CAAM_QI
+/*
+ * This is a counter for the number of times the congestion group (where all
+ * the request and response queueus are) reached congestion. Incremented
+ * each time the congestion callback is called with congested == true.
+ */
+static u64 times_congested;
+
+void caam_debugfs_qi_congested(void)
+{
+       times_congested++;
+}
+
+void caam_debugfs_qi_init(struct caam_drv_private *ctrlpriv)
+{
+       debugfs_create_file("qi_congested", 0444, ctrlpriv->ctl,
+                           &times_congested, &caam_fops_u64_ro);
+}
+#endif
+
+void caam_debugfs_init(struct caam_drv_private *ctrlpriv, struct dentry *root)
+{
+       struct caam_perfmon *perfmon;
+
+       /*
+        * FIXME: needs better naming distinction, as some amalgamation of
+        * "caam" and nprop->full_name. The OF name isn't distinctive,
+        * but does separate instances
+        */
+       perfmon = (struct caam_perfmon __force *)&ctrlpriv->ctrl->perfmon;
+
+       ctrlpriv->ctl = debugfs_create_dir("ctl", root);
+
+       debugfs_create_file("rq_dequeued", 0444, ctrlpriv->ctl,
+                           &perfmon->req_dequeued, &caam_fops_u64_ro);
+       debugfs_create_file("ob_rq_encrypted", 0444, ctrlpriv->ctl,
+                           &perfmon->ob_enc_req, &caam_fops_u64_ro);
+       debugfs_create_file("ib_rq_decrypted", 0444, ctrlpriv->ctl,
+                           &perfmon->ib_dec_req, &caam_fops_u64_ro);
+       debugfs_create_file("ob_bytes_encrypted", 0444, ctrlpriv->ctl,
+                           &perfmon->ob_enc_bytes, &caam_fops_u64_ro);
+       debugfs_create_file("ob_bytes_protected", 0444, ctrlpriv->ctl,
+                           &perfmon->ob_prot_bytes, &caam_fops_u64_ro);
+       debugfs_create_file("ib_bytes_decrypted", 0444, ctrlpriv->ctl,
+                           &perfmon->ib_dec_bytes, &caam_fops_u64_ro);
+       debugfs_create_file("ib_bytes_validated", 0444, ctrlpriv->ctl,
+                           &perfmon->ib_valid_bytes, &caam_fops_u64_ro);
+
+       /* Controller level - global status values */
+       debugfs_create_file("fault_addr", 0444, ctrlpriv->ctl,
+                           &perfmon->faultaddr, &caam_fops_u32_ro);
+       debugfs_create_file("fault_detail", 0444, ctrlpriv->ctl,
+                           &perfmon->faultdetail, &caam_fops_u32_ro);
+       debugfs_create_file("fault_status", 0444, ctrlpriv->ctl,
+                           &perfmon->status, &caam_fops_u32_ro);
+
+       /* Internal covering keys (useful in non-secure mode only) */
+       ctrlpriv->ctl_kek_wrap.data = (__force void *)&ctrlpriv->ctrl->kek[0];
+       ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
+       debugfs_create_blob("kek", 0444, ctrlpriv->ctl,
+                           &ctrlpriv->ctl_kek_wrap);
+
+       ctrlpriv->ctl_tkek_wrap.data = (__force void *)&ctrlpriv->ctrl->tkek[0];
+       ctrlpriv->ctl_tkek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
+       debugfs_create_blob("tkek", 0444, ctrlpriv->ctl,
+                           &ctrlpriv->ctl_tkek_wrap);
+
+       ctrlpriv->ctl_tdsk_wrap.data = (__force void *)&ctrlpriv->ctrl->tdsk[0];
+       ctrlpriv->ctl_tdsk_wrap.size = KEK_KEY_SIZE * sizeof(u32);
+       debugfs_create_blob("tdsk", 0444, ctrlpriv->ctl,
+                           &ctrlpriv->ctl_tdsk_wrap);
+}
diff --git a/drivers/crypto/caam/debugfs.h b/drivers/crypto/caam/debugfs.h
new file mode 100644 (file)
index 0000000..661d768
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/* Copyright 2019 NXP */
+
+#ifndef CAAM_DEBUGFS_H
+#define CAAM_DEBUGFS_H
+
+struct dentry;
+struct caam_drv_private;
+
+#ifdef CONFIG_DEBUG_FS
+void caam_debugfs_init(struct caam_drv_private *ctrlpriv, struct dentry *root);
+#else
+static inline void caam_debugfs_init(struct caam_drv_private *ctrlpriv,
+                                    struct dentry *root)
+{}
+#endif
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_CAAM_QI)
+void caam_debugfs_qi_congested(void);
+void caam_debugfs_qi_init(struct caam_drv_private *ctrlpriv);
+#else
+static inline void caam_debugfs_qi_congested(void) {}
+static inline void caam_debugfs_qi_init(struct caam_drv_private *ctrlpriv) {}
+#endif
+
+#endif /* CAAM_DEBUGFS_H */
index c5bfc92..0eca8c2 100644 (file)
@@ -44,33 +44,14 @@ static int dpseci_dbg_fqs_show(struct seq_file *file, void *offset)
        return 0;
 }
 
-static int dpseci_dbg_fqs_open(struct inode *inode, struct file *file)
-{
-       int err;
-       struct dpaa2_caam_priv *priv;
-
-       priv = (struct dpaa2_caam_priv *)inode->i_private;
-
-       err = single_open(file, dpseci_dbg_fqs_show, priv);
-       if (err < 0)
-               dev_err(priv->dev, "single_open() failed\n");
-
-       return err;
-}
-
-static const struct file_operations dpseci_dbg_fq_ops = {
-       .open = dpseci_dbg_fqs_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(dpseci_dbg_fqs);
 
 void dpaa2_dpseci_debugfs_init(struct dpaa2_caam_priv *priv)
 {
        priv->dfs_root = debugfs_create_dir(dev_name(priv->dev), NULL);
 
        debugfs_create_file("fq_stats", 0444, priv->dfs_root, priv,
-                           &dpseci_dbg_fq_ops);
+                           &dpseci_dbg_fqs_fops);
 }
 
 void dpaa2_dpseci_debugfs_exit(struct dpaa2_caam_priv *priv)
index 402d6a3..9112279 100644 (file)
@@ -195,23 +195,6 @@ static inline void caam_qi_algapi_exit(void)
 
 #endif /* CONFIG_CAAM_QI */
 
-#ifdef CONFIG_DEBUG_FS
-static int caam_debugfs_u64_get(void *data, u64 *val)
-{
-       *val = caam64_to_cpu(*(u64 *)data);
-       return 0;
-}
-
-static int caam_debugfs_u32_get(void *data, u64 *val)
-{
-       *val = caam32_to_cpu(*(u32 *)data);
-       return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u32_ro, caam_debugfs_u32_get, NULL, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u64_ro, caam_debugfs_u64_get, NULL, "%llu\n");
-#endif
-
 static inline u64 caam_get_dma_mask(struct device *dev)
 {
        struct device_node *nprop = dev->of_node;
index bf6b03b..6f66996 100644 (file)
@@ -324,7 +324,7 @@ EXPORT_SYMBOL(caam_jr_alloc);
 
 /**
  * caam_jr_free() - Free the Job Ring
- * @rdev     - points to the dev that identifies the Job ring to
+ * @rdev:      points to the dev that identifies the Job ring to
  *             be released.
  **/
 void caam_jr_free(struct device *rdev)
@@ -349,15 +349,15 @@ EXPORT_SYMBOL(caam_jr_free);
  *        of this request. This has the form:
  *        callback(struct device *dev, u32 *desc, u32 stat, void *arg)
  *        where:
- *        @dev:    contains the job ring device that processed this
+ *        dev:     contains the job ring device that processed this
  *                 response.
- *        @desc:   descriptor that initiated the request, same as
+ *        desc:    descriptor that initiated the request, same as
  *                 "desc" being argued to caam_jr_enqueue().
- *        @status: untranslated status received from CAAM. See the
+ *        status:  untranslated status received from CAAM. See the
  *                 reference manual for a detailed description of
  *                 error meaning, or see the JRSTA definitions in the
  *                 register header file
- *        @areq:   optional pointer to an argument passed with the
+ *        areq:    optional pointer to an argument passed with the
  *                 original request
  * @areq: optional pointer to a user argument for use at callback
  *        time.
index b390b93..ec53528 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kthread.h>
 #include <soc/fsl/qman.h>
 
+#include "debugfs.h"
 #include "regs.h"
 #include "qi.h"
 #include "desc.h"
@@ -73,15 +74,6 @@ static struct caam_qi_priv qipriv ____cacheline_aligned;
 bool caam_congested __read_mostly;
 EXPORT_SYMBOL(caam_congested);
 
-#ifdef CONFIG_DEBUG_FS
-/*
- * This is a counter for the number of times the congestion group (where all
- * the request and response queueus are) reached congestion. Incremented
- * each time the congestion callback is called with congested == true.
- */
-static u64 times_congested;
-#endif
-
 /*
  * This is a a cache of buffers, from which the users of CAAM QI driver
  * can allocate short (CAAM_QI_MEMCACHE_SIZE) buffers. It's faster than
@@ -544,9 +536,8 @@ static void cgr_cb(struct qman_portal *qm, struct qman_cgr *cgr, int congested)
        caam_congested = congested;
 
        if (congested) {
-#ifdef CONFIG_DEBUG_FS
-               times_congested++;
-#endif
+               caam_debugfs_qi_congested();
+
                pr_debug_ratelimited("CAAM entered congestion\n");
 
        } else {
@@ -775,10 +766,7 @@ int caam_qi_init(struct platform_device *caam_pdev)
                return -ENOMEM;
        }
 
-#ifdef CONFIG_DEBUG_FS
-       debugfs_create_file("qi_congested", 0444, ctrlpriv->ctl,
-                           &times_congested, &caam_fops_u64_ro);
-#endif
+       caam_debugfs_qi_init(ctrlpriv);
 
        err = devm_add_action_or_reset(qidev, caam_qi_shutdown, ctrlpriv);
        if (err)
index 5af0dc2..ce3b91c 100644 (file)
@@ -451,13 +451,7 @@ static struct skcipher_alg algs[] = { {
 
 static inline int cav_register_algs(void)
 {
-       int err = 0;
-
-       err = crypto_register_skciphers(algs, ARRAY_SIZE(algs));
-       if (err)
-               return err;
-
-       return 0;
+       return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
 }
 
 static inline void cav_unregister_algs(void)
index dc5fda5..4fe7898 100644 (file)
@@ -90,11 +90,11 @@ static int setup_sgio_components(struct cpt_vf *cptvf, struct buf_ptr *list,
        case 3:
                sg_ptr->u.s.len2 = cpu_to_be16(list[i * 4 + 2].size);
                sg_ptr->ptr2 = cpu_to_be64(list[i * 4 + 2].dma_addr);
-               /* Fall through */
+               fallthrough;
        case 2:
                sg_ptr->u.s.len1 = cpu_to_be16(list[i * 4 + 1].size);
                sg_ptr->ptr1 = cpu_to_be64(list[i * 4 + 1].dma_addr);
-               /* Fall through */
+               fallthrough;
        case 1:
                sg_ptr->u.s.len0 = cpu_to_be16(list[i * 4 + 0].size);
                sg_ptr->ptr0 = cpu_to_be64(list[i * 4 + 0].dma_addr);
index cee2a27..9d14be9 100644 (file)
@@ -451,6 +451,7 @@ static int nitrox_probe(struct pci_dev *pdev,
        err = pci_request_mem_regions(pdev, nitrox_driver_name);
        if (err) {
                pci_disable_device(pdev);
+               dev_err(&pdev->dev, "Failed to request mem regions!\n");
                return err;
        }
        pci_set_master(pdev);
index 194624b..d35216e 100644 (file)
@@ -460,7 +460,7 @@ static void zip_unregister_compression_device(void)
 #include <linux/debugfs.h>
 
 /* Displays ZIP device statistics */
-static int zip_show_stats(struct seq_file *s, void *unused)
+static int zip_stats_show(struct seq_file *s, void *unused)
 {
        u64 val = 0ull;
        u64 avg_chunk = 0ull, avg_cr = 0ull;
@@ -523,7 +523,7 @@ static int zip_show_stats(struct seq_file *s, void *unused)
 }
 
 /* Clears stats data */
-static int zip_clear_stats(struct seq_file *s, void *unused)
+static int zip_clear_show(struct seq_file *s, void *unused)
 {
        int index = 0;
 
@@ -558,7 +558,7 @@ static struct zip_registers zipregs[64] = {
 };
 
 /* Prints registers' contents */
-static int zip_print_regs(struct seq_file *s, void *unused)
+static int zip_regs_show(struct seq_file *s, void *unused)
 {
        u64 val = 0;
        int i = 0, index = 0;
@@ -584,41 +584,9 @@ static int zip_print_regs(struct seq_file *s, void *unused)
        return 0;
 }
 
-static int zip_stats_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, zip_show_stats, NULL);
-}
-
-static const struct file_operations zip_stats_fops = {
-       .owner = THIS_MODULE,
-       .open  = zip_stats_open,
-       .read  = seq_read,
-       .release = single_release,
-};
-
-static int zip_clear_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, zip_clear_stats, NULL);
-}
-
-static const struct file_operations zip_clear_fops = {
-       .owner = THIS_MODULE,
-       .open  = zip_clear_open,
-       .read  = seq_read,
-       .release = single_release,
-};
-
-static int zip_regs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, zip_print_regs, NULL);
-}
-
-static const struct file_operations zip_regs_fops = {
-       .owner = THIS_MODULE,
-       .open  = zip_regs_open,
-       .read  = seq_read,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(zip_stats);
+DEFINE_SHOW_ATTRIBUTE(zip_clear);
+DEFINE_SHOW_ATTRIBUTE(zip_regs);
 
 /* Root directory for thunderx_zip debugfs entry */
 static struct dentry *zip_debugfs_root;
index bd270e6..d6a8f4e 100644 (file)
@@ -8,6 +8,7 @@
  * Author: Gary R Hook <gary.hook@amd.com>
  */
 
+#include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
@@ -1744,7 +1745,7 @@ ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
                        break;
                default:
                        ret = -EINVAL;
-                       goto e_ctx;
+                       goto e_data;
                }
        } else {
                /* Stash the context */
index d77ae98..dafa657 100644 (file)
@@ -75,8 +75,7 @@ static int validate_keys_sizes(struct cc_cipher_ctx *ctx_p, u32 size)
                switch (size) {
                case CC_AES_128_BIT_KEY_SIZE:
                case CC_AES_192_BIT_KEY_SIZE:
-                       if (ctx_p->cipher_mode != DRV_CIPHER_XTS &&
-                           ctx_p->cipher_mode != DRV_CIPHER_BITLOCKER)
+                       if (ctx_p->cipher_mode != DRV_CIPHER_XTS)
                                return 0;
                        break;
                case CC_AES_256_BIT_KEY_SIZE:
@@ -84,8 +83,7 @@ static int validate_keys_sizes(struct cc_cipher_ctx *ctx_p, u32 size)
                case (CC_AES_192_BIT_KEY_SIZE * 2):
                case (CC_AES_256_BIT_KEY_SIZE * 2):
                        if (ctx_p->cipher_mode == DRV_CIPHER_XTS ||
-                           ctx_p->cipher_mode == DRV_CIPHER_ESSIV ||
-                           ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER)
+                           ctx_p->cipher_mode == DRV_CIPHER_ESSIV)
                                return 0;
                        break;
                default:
@@ -122,7 +120,6 @@ static int validate_data_size(struct cc_cipher_ctx *ctx_p,
                case DRV_CIPHER_ECB:
                case DRV_CIPHER_CBC:
                case DRV_CIPHER_ESSIV:
-               case DRV_CIPHER_BITLOCKER:
                        if (IS_ALIGNED(size, AES_BLOCK_SIZE))
                                return 0;
                        break;
@@ -348,8 +345,7 @@ static int cc_cipher_sethkey(struct crypto_skcipher *sktfm, const u8 *key,
                }
 
                if (ctx_p->cipher_mode == DRV_CIPHER_XTS ||
-                   ctx_p->cipher_mode == DRV_CIPHER_ESSIV ||
-                   ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER) {
+                   ctx_p->cipher_mode == DRV_CIPHER_ESSIV) {
                        if (hki.hw_key1 == hki.hw_key2) {
                                dev_err(dev, "Illegal hw key numbers (%d,%d)\n",
                                        hki.hw_key1, hki.hw_key2);
@@ -547,7 +543,6 @@ static void cc_setup_readiv_desc(struct crypto_tfm *tfm,
                break;
        case DRV_CIPHER_XTS:
        case DRV_CIPHER_ESSIV:
-       case DRV_CIPHER_BITLOCKER:
                /*  IV */
                hw_desc_init(&desc[*seq_size]);
                set_setup_mode(&desc[*seq_size], SETUP_WRITE_STATE1);
@@ -602,7 +597,6 @@ static void cc_setup_state_desc(struct crypto_tfm *tfm,
                break;
        case DRV_CIPHER_XTS:
        case DRV_CIPHER_ESSIV:
-       case DRV_CIPHER_BITLOCKER:
                break;
        default:
                dev_err(dev, "Unsupported cipher mode (%d)\n", cipher_mode);
@@ -624,16 +618,8 @@ static void cc_setup_xex_state_desc(struct crypto_tfm *tfm,
        dma_addr_t key_dma_addr = ctx_p->user.key_dma_addr;
        unsigned int key_len = (ctx_p->keylen / 2);
        dma_addr_t iv_dma_addr = req_ctx->gen_ctx.iv_dma_addr;
-       unsigned int du_size = nbytes;
        unsigned int key_offset = key_len;
 
-       struct cc_crypto_alg *cc_alg =
-               container_of(tfm->__crt_alg, struct cc_crypto_alg,
-                            skcipher_alg.base);
-
-       if (cc_alg->data_unit)
-               du_size = cc_alg->data_unit;
-
        switch (cipher_mode) {
        case DRV_CIPHER_ECB:
                break;
@@ -644,7 +630,6 @@ static void cc_setup_xex_state_desc(struct crypto_tfm *tfm,
                break;
        case DRV_CIPHER_XTS:
        case DRV_CIPHER_ESSIV:
-       case DRV_CIPHER_BITLOCKER:
 
                if (cipher_mode == DRV_CIPHER_ESSIV)
                        key_len = SHA256_DIGEST_SIZE;
@@ -661,7 +646,7 @@ static void cc_setup_xex_state_desc(struct crypto_tfm *tfm,
                                     (key_dma_addr + key_offset),
                                     key_len, NS_BIT);
                }
-               set_xex_data_unit_size(&desc[*seq_size], du_size);
+               set_xex_data_unit_size(&desc[*seq_size], nbytes);
                set_flow_mode(&desc[*seq_size], S_DIN_to_AES2);
                set_key_size_aes(&desc[*seq_size], key_len);
                set_setup_mode(&desc[*seq_size], SETUP_LOAD_XEX_KEY);
@@ -758,7 +743,6 @@ static void cc_setup_key_desc(struct crypto_tfm *tfm,
                break;
        case DRV_CIPHER_XTS:
        case DRV_CIPHER_ESSIV:
-       case DRV_CIPHER_BITLOCKER:
                /* Load AES key */
                hw_desc_init(&desc[*seq_size]);
                set_cipher_mode(&desc[*seq_size], cipher_mode);
@@ -1039,44 +1023,6 @@ static const struct cc_alg_template skcipher_algs[] = {
                .sec_func = true,
        },
        {
-               .name = "xts512(paes)",
-               .driver_name = "xts-paes-du512-ccree",
-               .blocksize = 1,
-               .template_skcipher = {
-                       .setkey = cc_cipher_sethkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = CC_HW_KEY_SIZE,
-                       .max_keysize = CC_HW_KEY_SIZE,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_XTS,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 512,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-               .sec_func = true,
-       },
-       {
-               .name = "xts4096(paes)",
-               .driver_name = "xts-paes-du4096-ccree",
-               .blocksize = 1,
-               .template_skcipher = {
-                       .setkey = cc_cipher_sethkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = CC_HW_KEY_SIZE,
-                       .max_keysize = CC_HW_KEY_SIZE,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_XTS,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 4096,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-               .sec_func = true,
-       },
-       {
                .name = "essiv(cbc(paes),sha256)",
                .driver_name = "essiv-paes-ccree",
                .blocksize = AES_BLOCK_SIZE,
@@ -1095,100 +1041,6 @@ static const struct cc_alg_template skcipher_algs[] = {
                .sec_func = true,
        },
        {
-               .name = "essiv512(cbc(paes),sha256)",
-               .driver_name = "essiv-paes-du512-ccree",
-               .blocksize = AES_BLOCK_SIZE,
-               .template_skcipher = {
-                       .setkey = cc_cipher_sethkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = CC_HW_KEY_SIZE,
-                       .max_keysize = CC_HW_KEY_SIZE,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_ESSIV,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 512,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-               .sec_func = true,
-       },
-       {
-               .name = "essiv4096(cbc(paes),sha256)",
-               .driver_name = "essiv-paes-du4096-ccree",
-               .blocksize = AES_BLOCK_SIZE,
-               .template_skcipher = {
-                       .setkey = cc_cipher_sethkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = CC_HW_KEY_SIZE,
-                       .max_keysize = CC_HW_KEY_SIZE,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_ESSIV,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 4096,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-               .sec_func = true,
-       },
-       {
-               .name = "bitlocker(paes)",
-               .driver_name = "bitlocker-paes-ccree",
-               .blocksize = AES_BLOCK_SIZE,
-               .template_skcipher = {
-                       .setkey = cc_cipher_sethkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = CC_HW_KEY_SIZE,
-                       .max_keysize = CC_HW_KEY_SIZE,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_BITLOCKER,
-               .flow_mode = S_DIN_to_AES,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-               .sec_func = true,
-       },
-       {
-               .name = "bitlocker512(paes)",
-               .driver_name = "bitlocker-paes-du512-ccree",
-               .blocksize = AES_BLOCK_SIZE,
-               .template_skcipher = {
-                       .setkey = cc_cipher_sethkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = CC_HW_KEY_SIZE,
-                       .max_keysize = CC_HW_KEY_SIZE,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_BITLOCKER,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 512,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-               .sec_func = true,
-       },
-       {
-               .name = "bitlocker4096(paes)",
-               .driver_name = "bitlocker-paes-du4096-ccree",
-               .blocksize = AES_BLOCK_SIZE,
-               .template_skcipher = {
-                       .setkey = cc_cipher_sethkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = CC_HW_KEY_SIZE,
-                       .max_keysize =  CC_HW_KEY_SIZE,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_BITLOCKER,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 4096,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-               .sec_func = true,
-       },
-       {
                .name = "ecb(paes)",
                .driver_name = "ecb-paes-ccree",
                .blocksize = AES_BLOCK_SIZE,
@@ -1300,42 +1152,6 @@ static const struct cc_alg_template skcipher_algs[] = {
                .std_body = CC_STD_NIST,
        },
        {
-               .name = "xts512(aes)",
-               .driver_name = "xts-aes-du512-ccree",
-               .blocksize = 1,
-               .template_skcipher = {
-                       .setkey = cc_cipher_setkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = AES_MIN_KEY_SIZE * 2,
-                       .max_keysize = AES_MAX_KEY_SIZE * 2,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_XTS,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 512,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-       },
-       {
-               .name = "xts4096(aes)",
-               .driver_name = "xts-aes-du4096-ccree",
-               .blocksize = 1,
-               .template_skcipher = {
-                       .setkey = cc_cipher_setkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = AES_MIN_KEY_SIZE * 2,
-                       .max_keysize = AES_MAX_KEY_SIZE * 2,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_XTS,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 4096,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-       },
-       {
                .name = "essiv(cbc(aes),sha256)",
                .driver_name = "essiv-aes-ccree",
                .blocksize = AES_BLOCK_SIZE,
@@ -1353,95 +1169,6 @@ static const struct cc_alg_template skcipher_algs[] = {
                .std_body = CC_STD_NIST,
        },
        {
-               .name = "essiv512(cbc(aes),sha256)",
-               .driver_name = "essiv-aes-du512-ccree",
-               .blocksize = AES_BLOCK_SIZE,
-               .template_skcipher = {
-                       .setkey = cc_cipher_setkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = AES_MIN_KEY_SIZE,
-                       .max_keysize = AES_MAX_KEY_SIZE,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_ESSIV,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 512,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-       },
-       {
-               .name = "essiv4096(cbc(aes),sha256)",
-               .driver_name = "essiv-aes-du4096-ccree",
-               .blocksize = AES_BLOCK_SIZE,
-               .template_skcipher = {
-                       .setkey = cc_cipher_setkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = AES_MIN_KEY_SIZE,
-                       .max_keysize = AES_MAX_KEY_SIZE,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_ESSIV,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 4096,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-       },
-       {
-               .name = "bitlocker(aes)",
-               .driver_name = "bitlocker-aes-ccree",
-               .blocksize = AES_BLOCK_SIZE,
-               .template_skcipher = {
-                       .setkey = cc_cipher_setkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = AES_MIN_KEY_SIZE * 2,
-                       .max_keysize = AES_MAX_KEY_SIZE * 2,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_BITLOCKER,
-               .flow_mode = S_DIN_to_AES,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-       },
-       {
-               .name = "bitlocker512(aes)",
-               .driver_name = "bitlocker-aes-du512-ccree",
-               .blocksize = AES_BLOCK_SIZE,
-               .template_skcipher = {
-                       .setkey = cc_cipher_setkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = AES_MIN_KEY_SIZE * 2,
-                       .max_keysize = AES_MAX_KEY_SIZE * 2,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_BITLOCKER,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 512,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-       },
-       {
-               .name = "bitlocker4096(aes)",
-               .driver_name = "bitlocker-aes-du4096-ccree",
-               .blocksize = AES_BLOCK_SIZE,
-               .template_skcipher = {
-                       .setkey = cc_cipher_setkey,
-                       .encrypt = cc_cipher_encrypt,
-                       .decrypt = cc_cipher_decrypt,
-                       .min_keysize = AES_MIN_KEY_SIZE * 2,
-                       .max_keysize = AES_MAX_KEY_SIZE * 2,
-                       .ivsize = AES_BLOCK_SIZE,
-                       },
-               .cipher_mode = DRV_CIPHER_BITLOCKER,
-               .flow_mode = S_DIN_to_AES,
-               .data_unit = 4096,
-               .min_hw_rev = CC_HW_REV_712,
-               .std_body = CC_STD_NIST,
-       },
-       {
                .name = "ecb(aes)",
                .driver_name = "ecb-aes-ccree",
                .blocksize = AES_BLOCK_SIZE,
@@ -1712,7 +1439,6 @@ static struct cc_crypto_alg *cc_create_alg(const struct cc_alg_template *tmpl,
 
        t_alg->cipher_mode = tmpl->cipher_mode;
        t_alg->flow_mode = tmpl->flow_mode;
-       t_alg->data_unit = tmpl->data_unit;
 
        return t_alg;
 }
index ccf960a..bd9a1c0 100644 (file)
@@ -108,7 +108,6 @@ enum drv_cipher_mode {
        DRV_CIPHER_CBC_CTS = 11,
        DRV_CIPHER_GCTR = 12,
        DRV_CIPHER_ESSIV = 13,
-       DRV_CIPHER_BITLOCKER = 14,
        DRV_CIPHER_RESERVE32B = S32_MAX
 };
 
index 2d50991..6f519d3 100644 (file)
@@ -300,11 +300,8 @@ static int init_cc_resources(struct platform_device *plat_dev)
        new_drvdata->plat_dev = plat_dev;
 
        clk = devm_clk_get_optional(dev, NULL);
-       if (IS_ERR(clk)) {
-               if (PTR_ERR(clk) != -EPROBE_DEFER)
-                       dev_err(dev, "Error getting clock: %pe\n", clk);
-               return PTR_ERR(clk);
-       }
+       if (IS_ERR(clk))
+               return dev_err_probe(dev, PTR_ERR(clk), "Error getting clock\n");
        new_drvdata->clk = clk;
 
        new_drvdata->coherent = of_dma_is_coherent(np);
index d938886..af77b20 100644 (file)
@@ -162,7 +162,6 @@ struct cc_crypto_alg {
        int cipher_mode;
        int flow_mode; /* Note: currently, refers to the cipher mode only. */
        int auth_mode;
-       unsigned int data_unit;
        struct cc_drvdata *drvdata;
        struct skcipher_alg skcipher_alg;
        struct aead_alg aead_alg;
index d39e166..3c65bf0 100644 (file)
@@ -65,8 +65,12 @@ const struct dev_pm_ops ccree_pm = {
 int cc_pm_get(struct device *dev)
 {
        int rc = pm_runtime_get_sync(dev);
+       if (rc < 0) {
+               pm_runtime_put_noidle(dev);
+               return rc;
+       }
 
-       return (rc == 1 ? 0 : rc);
+       return 0;
 }
 
 void cc_pm_put_suspend(struct device *dev)
index bd8dac8..ed7989c 100644 (file)
@@ -148,7 +148,7 @@ static void chcr_dev_init(struct uld_ctx *u_ctx)
 
 static int chcr_dev_move(struct uld_ctx *u_ctx)
 {
-        mutex_lock(&drv_data.drv_mutex);
+       mutex_lock(&drv_data.drv_mutex);
        if (drv_data.last_dev == u_ctx) {
                if (list_is_last(&drv_data.last_dev->entry, &drv_data.act_dev))
                        drv_data.last_dev = list_first_entry(&drv_data.act_dev,
index 91dee61..c5cce02 100644 (file)
@@ -135,7 +135,7 @@ static int chcr_ktls_update_connection_state(struct chcr_ktls_info *tx_info,
                        break;
                /* update to the next state and also initialize TCB */
                tx_info->connection_state = new_state;
-               /* FALLTHRU */
+               fallthrough;
        case KTLS_CONN_ACT_OPEN_RPL:
                /* if we are stuck in this state, means tcb init might not
                 * received by HW, try sending it again.
@@ -150,7 +150,7 @@ static int chcr_ktls_update_connection_state(struct chcr_ktls_info *tx_info,
                        break;
                /* update to the next state and check if l2t_state is valid  */
                tx_info->connection_state = new_state;
-               /* FALLTHRU */
+               fallthrough;
        case KTLS_CONN_SET_TCB_RPL:
                /* Check if l2t state is valid, then move to ready state. */
                if (cxgb4_check_l2t_valid(tx_info->l2te)) {
index 3548364..7e7a8f0 100644 (file)
@@ -780,8 +780,8 @@ static int hifn_register_rng(struct hifn_device *dev)
                                                   dev->pk_clk_freq) * 256;
 
        dev->rng.name           = dev->name;
-       dev->rng.data_present   = hifn_rng_data_present,
-       dev->rng.data_read      = hifn_rng_data_read,
+       dev->rng.data_present   = hifn_rng_data_present;
+       dev->rng.data_read      = hifn_rng_data_read;
        dev->rng.priv           = (unsigned long)dev;
 
        return hwrng_register(&dev->rng);
@@ -1235,7 +1235,8 @@ static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page,
        int idx;
        dma_addr_t addr;
 
-       addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_TODEVICE);
+       addr = dma_map_page(&dev->pdev->dev, page, offset, size,
+                           DMA_TO_DEVICE);
 
        idx = dma->srci;
 
@@ -1293,7 +1294,8 @@ static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page,
        int idx;
        dma_addr_t addr;
 
-       addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_FROMDEVICE);
+       addr = dma_map_page(&dev->pdev->dev, page, offset, size,
+                           DMA_FROM_DEVICE);
 
        idx = dma->dsti;
        dma->dstr[idx].p = __cpu_to_le32(addr);
@@ -2470,7 +2472,7 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                return err;
        pci_set_master(pdev);
 
-       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
        if (err)
                goto err_out_disable_pci_device;
 
@@ -2514,8 +2516,9 @@ static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                }
        }
 
-       dev->desc_virt = pci_zalloc_consistent(pdev, sizeof(struct hifn_dma),
-                                              &dev->desc_dma);
+       dev->desc_virt = dma_alloc_coherent(&pdev->dev,
+                                           sizeof(struct hifn_dma),
+                                           &dev->desc_dma, GFP_KERNEL);
        if (!dev->desc_virt) {
                dev_err(&pdev->dev, "Failed to allocate descriptor rings.\n");
                err = -ENOMEM;
@@ -2572,8 +2575,8 @@ err_out_free_irq:
        free_irq(dev->irq, dev);
        tasklet_kill(&dev->tasklet);
 err_out_free_desc:
-       pci_free_consistent(pdev, sizeof(struct hifn_dma),
-                       dev->desc_virt, dev->desc_dma);
+       dma_free_coherent(&pdev->dev, sizeof(struct hifn_dma), dev->desc_virt,
+                         dev->desc_dma);
 
 err_out_unmap_bars:
        for (i = 0; i < 3; ++i)
@@ -2610,8 +2613,8 @@ static void hifn_remove(struct pci_dev *pdev)
 
                hifn_flush(dev);
 
-               pci_free_consistent(pdev, sizeof(struct hifn_dma),
-                               dev->desc_virt, dev->desc_dma);
+               dma_free_coherent(&pdev->dev, sizeof(struct hifn_dma),
+                                 dev->desc_virt, dev->desc_dma);
                for (i = 0; i < 3; ++i)
                        if (dev->bar[i])
                                iounmap(dev->bar[i]);
@@ -2642,9 +2645,6 @@ static int __init hifn_init(void)
        unsigned int freq;
        int err;
 
-       /* HIFN supports only 32-bit addresses */
-       BUILD_BUG_ON(sizeof(dma_addr_t) != 4);
-
        if (strncmp(hifn_pll_ref, "ext", 3) &&
            strncmp(hifn_pll_ref, "pci", 3)) {
                pr_err("hifn795x: invalid hifn_pll_ref clock, must be pci or ext");
index ed730d1..f69252b 100644 (file)
@@ -56,7 +56,6 @@ struct hpre_dfx {
  * Just relevant for PF.
  */
 struct hpre_debug {
-       struct dentry *debug_root;
        struct hpre_dfx dfx[HPRE_DFX_FILE_NUM];
        struct hpre_debugfs_file files[HPRE_DEBUGFS_FILE_NUM];
 };
index 7b5cb27..a87f990 100644 (file)
@@ -98,9 +98,6 @@ struct hpre_asym_request {
        struct timespec64 req_time;
 };
 
-static DEFINE_MUTEX(hpre_alg_lock);
-static unsigned int hpre_active_devs;
-
 static int hpre_alloc_req_id(struct hpre_ctx *ctx)
 {
        unsigned long flags;
@@ -191,8 +188,7 @@ static int hpre_get_data_dma_addr(struct hpre_asym_request *hpre_req,
                hpre_req->dst = NULL;
                dma_dir = DMA_FROM_DEVICE;
        }
-       *tmp = dma_map_single(dev, sg_virt(data),
-                             len, dma_dir);
+       *tmp = dma_map_single(dev, sg_virt(data), len, dma_dir);
        if (unlikely(dma_mapping_error(dev, *tmp))) {
                dev_err(dev, "dma map data err!\n");
                return -ENOMEM;
@@ -242,8 +238,8 @@ static int hpre_hw_data_init(struct hpre_asym_request *hpre_req,
            ((is_dh && !is_src) || !is_dh))
                ret = hpre_get_data_dma_addr(hpre_req, data, len, is_src, &tmp);
        else
-               ret = hpre_prepare_dma_buf(hpre_req, data, len,
-                                         is_src, &tmp);
+               ret = hpre_prepare_dma_buf(hpre_req, data, len, is_src, &tmp);
+
        if (unlikely(ret))
                return ret;
 
@@ -270,11 +266,9 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx,
 
        if (src) {
                if (req->src)
-                       dma_free_coherent(dev, ctx->key_sz,
-                                         req->src, tmp);
+                       dma_free_coherent(dev, ctx->key_sz, req->src, tmp);
                else
-                       dma_unmap_single(dev, tmp,
-                                        ctx->key_sz, DMA_TO_DEVICE);
+                       dma_unmap_single(dev, tmp, ctx->key_sz, DMA_TO_DEVICE);
        }
 
        tmp = le64_to_cpu(sqe->out);
@@ -477,7 +471,7 @@ static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa)
                h_req->areq.dh = kreq;
                msg = &h_req->req;
                memset(msg, 0, sizeof(*msg));
-               msg->key = cpu_to_le64((u64)ctx->dh.dma_xa_p);
+               msg->key = cpu_to_le64(ctx->dh.dma_xa_p);
        }
 
        msg->dw0 |= cpu_to_le32(0x1 << HPRE_SQE_DONE_SHIFT);
@@ -534,6 +528,8 @@ static int hpre_dh_compute_value(struct kpp_request *req)
                ret = hpre_hw_data_init(hpre_req, req->src, req->src_len, 1, 1);
                if (unlikely(ret))
                        goto clear_all;
+       } else {
+               msg->in = cpu_to_le64(ctx->dh.dma_g);
        }
 
        ret = hpre_hw_data_init(hpre_req, req->dst, req->dst_len, 0, 1);
@@ -743,7 +739,7 @@ static int hpre_rsa_enc(struct akcipher_request *req)
                return ret;
 
        msg->dw0 |= cpu_to_le32(HPRE_ALG_NC_NCRT);
-       msg->key = cpu_to_le64((u64)ctx->rsa.dma_pubkey);
+       msg->key = cpu_to_le64(ctx->rsa.dma_pubkey);
 
        ret = hpre_hw_data_init(hpre_req, req->src, req->src_len, 1, 0);
        if (unlikely(ret))
@@ -791,11 +787,11 @@ static int hpre_rsa_dec(struct akcipher_request *req)
                return ret;
 
        if (ctx->crt_g2_mode) {
-               msg->key = cpu_to_le64((u64)ctx->rsa.dma_crt_prikey);
+               msg->key = cpu_to_le64(ctx->rsa.dma_crt_prikey);
                msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) |
                                       HPRE_ALG_NC_CRT);
        } else {
-               msg->key = cpu_to_le64((u64)ctx->rsa.dma_prikey);
+               msg->key = cpu_to_le64(ctx->rsa.dma_prikey);
                msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) |
                                       HPRE_ALG_NC_NCRT);
        }
@@ -1160,36 +1156,25 @@ static struct kpp_alg dh = {
 
 int hpre_algs_register(void)
 {
-       int ret = 0;
-
-       mutex_lock(&hpre_alg_lock);
-       if (++hpre_active_devs == 1) {
-               rsa.base.cra_flags = 0;
-               ret = crypto_register_akcipher(&rsa);
-               if (ret)
-                       goto unlock;
+       int ret;
+
+       rsa.base.cra_flags = 0;
+       ret = crypto_register_akcipher(&rsa);
+       if (ret)
+               return ret;
 #ifdef CONFIG_CRYPTO_DH
-               ret = crypto_register_kpp(&dh);
-               if (ret) {
-                       crypto_unregister_akcipher(&rsa);
-                       goto unlock;
-               }
+       ret = crypto_register_kpp(&dh);
+       if (ret)
+               crypto_unregister_akcipher(&rsa);
 #endif
-       }
 
-unlock:
-       mutex_unlock(&hpre_alg_lock);
        return ret;
 }
 
 void hpre_algs_unregister(void)
 {
-       mutex_lock(&hpre_alg_lock);
-       if (--hpre_active_devs == 0) {
-               crypto_unregister_akcipher(&rsa);
+       crypto_unregister_akcipher(&rsa);
 #ifdef CONFIG_CRYPTO_DH
-               crypto_unregister_kpp(&dh);
+       crypto_unregister_kpp(&dh);
 #endif
-       }
-       mutex_unlock(&hpre_alg_lock);
 }
index b135c74..a33394d 100644 (file)
@@ -90,7 +90,6 @@
 #define HPRE_SQE_MASK_OFFSET           8
 #define HPRE_SQE_MASK_LEN              24
 
-static struct hisi_qm_list hpre_devices;
 static const char hpre_name[] = "hisi_hpre";
 static struct dentry *hpre_debugfs_root;
 static const struct pci_device_id hpre_dev_ids[] = {
@@ -106,6 +105,11 @@ struct hpre_hw_error {
        const char *msg;
 };
 
+static struct hisi_qm_list hpre_devices = {
+       .register_to_crypto     = hpre_algs_register,
+       .unregister_from_crypto = hpre_algs_unregister,
+};
+
 static const char * const hpre_debug_file_name[] = {
        [HPRE_CURRENT_QM]   = "current_qm",
        [HPRE_CLEAR_ENABLE] = "rdclr_en",
@@ -186,7 +190,7 @@ static const struct kernel_param_ops hpre_pf_q_num_ops = {
 
 static u32 pf_q_num = HPRE_PF_DEF_Q_NUM;
 module_param_cb(pf_q_num, &hpre_pf_q_num_ops, &pf_q_num, 0444);
-MODULE_PARM_DESC(pf_q_num, "Number of queues in PF of CS(1-1024)");
+MODULE_PARM_DESC(pf_q_num, "Number of queues in PF of CS(2-1024)");
 
 static const struct kernel_param_ops vfs_num_ops = {
        .set = vfs_num_set,
@@ -864,9 +868,7 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (ret)
                dev_warn(&pdev->dev, "init debugfs fail!\n");
 
-       hisi_qm_add_to_list(qm, &hpre_devices);
-
-       ret = hpre_algs_register();
+       ret = hisi_qm_alg_register(qm, &hpre_devices);
        if (ret < 0) {
                pci_err(pdev, "fail to register algs to crypto!\n");
                goto err_with_qm_start;
@@ -875,18 +877,17 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (qm->fun_type == QM_HW_PF && vfs_num) {
                ret = hisi_qm_sriov_enable(pdev, vfs_num);
                if (ret < 0)
-                       goto err_with_crypto_register;
+                       goto err_with_alg_register;
        }
 
        return 0;
 
-err_with_crypto_register:
-       hpre_algs_unregister();
+err_with_alg_register:
+       hisi_qm_alg_unregister(qm, &hpre_devices);
 
 err_with_qm_start:
-       hisi_qm_del_from_list(qm, &hpre_devices);
        hpre_debugfs_exit(qm);
-       hisi_qm_stop(qm);
+       hisi_qm_stop(qm, QM_NORMAL);
 
 err_with_err_init:
        hisi_qm_dev_err_uninit(qm);
@@ -899,14 +900,13 @@ err_with_qm_init:
 
 static void hpre_remove(struct pci_dev *pdev)
 {
-       struct hpre *hpre = pci_get_drvdata(pdev);
-       struct hisi_qm *qm = &hpre->qm;
+       struct hisi_qm *qm = pci_get_drvdata(pdev);
        int ret;
 
-       hpre_algs_unregister();
-       hisi_qm_del_from_list(qm, &hpre_devices);
+       hisi_qm_wait_task_finish(qm, &hpre_devices);
+       hisi_qm_alg_unregister(qm, &hpre_devices);
        if (qm->fun_type == QM_HW_PF && qm->vfs_num) {
-               ret = hisi_qm_sriov_disable(pdev);
+               ret = hisi_qm_sriov_disable(pdev, qm->is_frozen);
                if (ret) {
                        pci_err(pdev, "Disable SRIOV fail!\n");
                        return;
@@ -918,7 +918,7 @@ static void hpre_remove(struct pci_dev *pdev)
        }
 
        hpre_debugfs_exit(qm);
-       hisi_qm_stop(qm);
+       hisi_qm_stop(qm, QM_NORMAL);
        hisi_qm_dev_err_uninit(qm);
        hisi_qm_uninit(qm);
 }
@@ -939,6 +939,7 @@ static struct pci_driver hpre_pci_driver = {
        .sriov_configure        = IS_ENABLED(CONFIG_PCI_IOV) ?
                                  hisi_qm_sriov_configure : NULL,
        .err_handler            = &hpre_err_handler,
+       .shutdown               = hisi_qm_dev_shutdown,
 };
 
 static void hpre_register_debugfs(void)
index 6527c53..530f231 100644 (file)
 #define QM_DBG_TMP_BUF_LEN             22
 #define QM_PCI_COMMAND_INVALID         ~0
 
+#define WAIT_PERIOD                    20
+#define REMOVE_WAIT_DELAY              10
 #define QM_SQE_ADDR_MASK               GENMASK(7, 0)
+#define QM_EQ_DEPTH                    (1024 * 2)
 
 #define QM_MK_CQC_DW3_V1(hop_num, pg_sz, buf_sz, cqe_sz) \
        (((hop_num) << QM_CQ_HOP_NUM_SHIFT)     | \
@@ -652,7 +655,7 @@ static void qm_work_process(struct work_struct *work)
                qp = qm_to_hisi_qp(qm, eqe);
                qm_poll_qp(qp, qm);
 
-               if (qm->status.eq_head == QM_Q_DEPTH - 1) {
+               if (qm->status.eq_head == QM_EQ_DEPTH - 1) {
                        qm->status.eqc_phase = !qm->status.eqc_phase;
                        eqe = qm->eqe;
                        qm->status.eq_head = 0;
@@ -661,7 +664,7 @@ static void qm_work_process(struct work_struct *work)
                        qm->status.eq_head++;
                }
 
-               if (eqe_num == QM_Q_DEPTH / 2 - 1) {
+               if (eqe_num == QM_EQ_DEPTH / 2 - 1) {
                        eqe_num = 0;
                        qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0);
                }
@@ -754,7 +757,7 @@ static void qm_init_qp_status(struct hisi_qp *qp)
        qp_status->sq_tail = 0;
        qp_status->cq_head = 0;
        qp_status->cqc_phase = true;
-       atomic_set(&qp_status->flags, 0);
+       atomic_set(&qp_status->used, 0);
 }
 
 static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base,
@@ -1046,17 +1049,7 @@ static int qm_regs_show(struct seq_file *s, void *unused)
        return 0;
 }
 
-static int qm_regs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, qm_regs_show, inode->i_private);
-}
-
-static const struct file_operations qm_regs_fops = {
-       .owner = THIS_MODULE,
-       .open = qm_regs_open,
-       .read = seq_read,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(qm_regs);
 
 static ssize_t qm_cmd_read(struct file *filp, char __user *buffer,
                           size_t count, loff_t *pos)
@@ -1370,7 +1363,13 @@ static int qm_eq_aeq_dump(struct hisi_qm *qm, const char *s,
                return -EINVAL;
 
        ret = kstrtou32(s, 0, &xeqe_id);
-       if (ret || xeqe_id >= QM_Q_DEPTH) {
+       if (ret)
+               return -EINVAL;
+
+       if (!strcmp(name, "EQE") && xeqe_id >= QM_EQ_DEPTH) {
+               dev_err(dev, "Please input eqe num (0-%d)", QM_EQ_DEPTH - 1);
+               return -EINVAL;
+       } else if (!strcmp(name, "AEQE") && xeqe_id >= QM_Q_DEPTH) {
                dev_err(dev, "Please input aeqe num (0-%d)", QM_Q_DEPTH - 1);
                return -EINVAL;
        }
@@ -1420,17 +1419,18 @@ static int qm_dbg_help(struct hisi_qm *qm, char *s)
 static int qm_cmd_write_dump(struct hisi_qm *qm, const char *cmd_buf)
 {
        struct device *dev = &qm->pdev->dev;
-       char *presult, *s;
+       char *presult, *s, *s_tmp;
        int ret;
 
        s = kstrdup(cmd_buf, GFP_KERNEL);
        if (!s)
                return -ENOMEM;
 
+       s_tmp = s;
        presult = strsep(&s, " ");
        if (!presult) {
-               kfree(s);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_buffer_free;
        }
 
        if (!strcmp(presult, "sqc"))
@@ -1459,7 +1459,8 @@ static int qm_cmd_write_dump(struct hisi_qm *qm, const char *cmd_buf)
        if (ret)
                dev_info(dev, "Please echo help\n");
 
-       kfree(s);
+err_buffer_free:
+       kfree(s_tmp);
 
        return ret;
 }
@@ -1644,7 +1645,7 @@ static void *qm_get_avail_sqe(struct hisi_qp *qp)
        struct hisi_qp_status *qp_status = &qp->qp_status;
        u16 sq_tail = qp_status->sq_tail;
 
-       if (unlikely(atomic_read(&qp->qp_status.used) == QM_Q_DEPTH))
+       if (unlikely(atomic_read(&qp->qp_status.used) == QM_Q_DEPTH - 1))
                return NULL;
 
        return qp->sqe + sq_tail * qp->qm->sqe_size;
@@ -1981,7 +1982,7 @@ int hisi_qp_send(struct hisi_qp *qp, const void *msg)
        if (unlikely(atomic_read(&qp->qp_status.flags) == QP_STOP ||
                     atomic_read(&qp->qm->status.flags) == QM_STOP ||
                     qp->is_resetting)) {
-               dev_info(&qp->qm->pdev->dev, "QP is stopped or resetting\n");
+               dev_info_ratelimited(&qp->qm->pdev->dev, "QP is stopped or resetting\n");
                return -EAGAIN;
        }
 
@@ -2215,6 +2216,82 @@ static int qm_alloc_uacce(struct hisi_qm *qm)
 }
 
 /**
+ * qm_frozen() - Try to froze QM to cut continuous queue request. If
+ * there is user on the QM, return failure without doing anything.
+ * @qm: The qm needed to be fronzen.
+ *
+ * This function frozes QM, then we can do SRIOV disabling.
+ */
+static int qm_frozen(struct hisi_qm *qm)
+{
+       down_write(&qm->qps_lock);
+
+       if (qm->is_frozen) {
+               up_write(&qm->qps_lock);
+               return 0;
+       }
+
+       if (!qm->qp_in_used) {
+               qm->qp_in_used = qm->qp_num;
+               qm->is_frozen = true;
+               up_write(&qm->qps_lock);
+               return 0;
+       }
+
+       up_write(&qm->qps_lock);
+
+       return -EBUSY;
+}
+
+static int qm_try_frozen_vfs(struct pci_dev *pdev,
+                            struct hisi_qm_list *qm_list)
+{
+       struct hisi_qm *qm, *vf_qm;
+       struct pci_dev *dev;
+       int ret = 0;
+
+       if (!qm_list || !pdev)
+               return -EINVAL;
+
+       /* Try to frozen all the VFs as disable SRIOV */
+       mutex_lock(&qm_list->lock);
+       list_for_each_entry(qm, &qm_list->list, list) {
+               dev = qm->pdev;
+               if (dev == pdev)
+                       continue;
+               if (pci_physfn(dev) == pdev) {
+                       vf_qm = pci_get_drvdata(dev);
+                       ret = qm_frozen(vf_qm);
+                       if (ret)
+                               goto frozen_fail;
+               }
+       }
+
+frozen_fail:
+       mutex_unlock(&qm_list->lock);
+
+       return ret;
+}
+
+/**
+ * hisi_qm_wait_task_finish() - Wait until the task is finished
+ * when removing the driver.
+ * @qm: The qm needed to wait for the task to finish.
+ * @qm_list: The list of all available devices.
+ */
+void hisi_qm_wait_task_finish(struct hisi_qm *qm, struct hisi_qm_list *qm_list)
+{
+       while (qm_frozen(qm) ||
+              ((qm->fun_type == QM_HW_PF) &&
+              qm_try_frozen_vfs(qm->pdev, qm_list))) {
+               msleep(WAIT_PERIOD);
+       }
+
+       udelay(REMOVE_WAIT_DELAY);
+}
+EXPORT_SYMBOL_GPL(hisi_qm_wait_task_finish);
+
+/**
  * hisi_qm_get_free_qp_num() - Get free number of qp in qm.
  * @qm: The qm which want to get free qp.
  *
@@ -2282,7 +2359,7 @@ static int hisi_qm_memory_init(struct hisi_qm *qm)
 } while (0)
 
        idr_init(&qm->qp_idr);
-       qm->qdma.size = QMC_ALIGN(sizeof(struct qm_eqe) * QM_Q_DEPTH) +
+       qm->qdma.size = QMC_ALIGN(sizeof(struct qm_eqe) * QM_EQ_DEPTH) +
                        QMC_ALIGN(sizeof(struct qm_aeqe) * QM_Q_DEPTH) +
                        QMC_ALIGN(sizeof(struct qm_sqc) * qm->qp_num) +
                        QMC_ALIGN(sizeof(struct qm_cqc) * qm->qp_num);
@@ -2292,7 +2369,7 @@ static int hisi_qm_memory_init(struct hisi_qm *qm)
        if (!qm->qdma.va)
                return -ENOMEM;
 
-       QM_INIT_BUF(qm, eqe, QM_Q_DEPTH);
+       QM_INIT_BUF(qm, eqe, QM_EQ_DEPTH);
        QM_INIT_BUF(qm, aeqe, QM_Q_DEPTH);
        QM_INIT_BUF(qm, sqc, qm->qp_num);
        QM_INIT_BUF(qm, cqc, qm->qp_num);
@@ -2338,6 +2415,7 @@ static void hisi_qm_pre_init(struct hisi_qm *qm)
        mutex_init(&qm->mailbox_lock);
        init_rwsem(&qm->qps_lock);
        qm->qp_in_used = 0;
+       qm->is_frozen = false;
 }
 
 /**
@@ -2462,7 +2540,7 @@ static int qm_eq_ctx_cfg(struct hisi_qm *qm)
        eqc->base_h = cpu_to_le32(upper_32_bits(qm->eqe_dma));
        if (qm->ver == QM_HW_V1)
                eqc->dw3 = cpu_to_le32(QM_EQE_AEQE_SIZE);
-       eqc->dw6 = cpu_to_le32((QM_Q_DEPTH - 1) | (1 << QM_EQC_PHASE_SHIFT));
+       eqc->dw6 = cpu_to_le32((QM_EQ_DEPTH - 1) | (1 << QM_EQC_PHASE_SHIFT));
        ret = qm_mb(qm, QM_MB_CMD_EQC, eqc_dma, 0, 0);
        dma_unmap_single(dev, eqc_dma, sizeof(struct qm_eqc), DMA_TO_DEVICE);
        kfree(eqc);
@@ -2633,18 +2711,20 @@ static void qm_clear_queues(struct hisi_qm *qm)
 /**
  * hisi_qm_stop() - Stop a qm.
  * @qm: The qm which will be stopped.
+ * @r: The reason to stop qm.
  *
  * This function stops qm and its qps, then qm can not accept request.
  * Related resources are not released at this state, we can use hisi_qm_start
  * to let qm start again.
  */
-int hisi_qm_stop(struct hisi_qm *qm)
+int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r)
 {
        struct device *dev = &qm->pdev->dev;
        int ret = 0;
 
        down_write(&qm->qps_lock);
 
+       qm->status.stop_reason = r;
        if (!qm_avail_state(qm, QM_STOP)) {
                ret = -EPERM;
                goto err_unlock;
@@ -3081,11 +3161,12 @@ EXPORT_SYMBOL_GPL(hisi_qm_sriov_enable);
 
 /**
  * hisi_qm_sriov_disable - disable virtual functions
- * @pdev: the PCI device
+ * @pdev: the PCI device.
+ * @is_frozen: true when all the VFs are frozen.
  *
- * Return failure if there are VFs assigned already.
+ * Return failure if there are VFs assigned already or VF is in used.
  */
-int hisi_qm_sriov_disable(struct pci_dev *pdev)
+int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen)
 {
        struct hisi_qm *qm = pci_get_drvdata(pdev);
 
@@ -3094,7 +3175,12 @@ int hisi_qm_sriov_disable(struct pci_dev *pdev)
                return -EPERM;
        }
 
-       /* remove in hpre_pci_driver will be called to free VF resources */
+       /* While VF is in used, SRIOV cannot be disabled. */
+       if (!is_frozen && qm_try_frozen_vfs(pdev, qm->qm_list)) {
+               pci_err(pdev, "Task is using its VF!\n");
+               return -EBUSY;
+       }
+
        pci_disable_sriov(pdev);
        return qm_clear_vft_config(qm);
 }
@@ -3110,7 +3196,7 @@ EXPORT_SYMBOL_GPL(hisi_qm_sriov_disable);
 int hisi_qm_sriov_configure(struct pci_dev *pdev, int num_vfs)
 {
        if (num_vfs == 0)
-               return hisi_qm_sriov_disable(pdev);
+               return hisi_qm_sriov_disable(pdev, 0);
        else
                return hisi_qm_sriov_enable(pdev, num_vfs);
 }
@@ -3290,10 +3376,10 @@ static int qm_set_msi(struct hisi_qm *qm, bool set)
        return 0;
 }
 
-static int qm_vf_reset_prepare(struct hisi_qm *qm)
+static int qm_vf_reset_prepare(struct hisi_qm *qm,
+                              enum qm_stop_reason stop_reason)
 {
        struct hisi_qm_list *qm_list = qm->qm_list;
-       int stop_reason = qm->status.stop_reason;
        struct pci_dev *pdev = qm->pdev;
        struct pci_dev *virtfn;
        struct hisi_qm *vf_qm;
@@ -3306,8 +3392,10 @@ static int qm_vf_reset_prepare(struct hisi_qm *qm)
                        continue;
 
                if (pci_physfn(virtfn) == pdev) {
-                       vf_qm->status.stop_reason = stop_reason;
-                       ret = hisi_qm_stop(vf_qm);
+                       /* save VFs PCIE BAR configuration */
+                       pci_save_state(virtfn);
+
+                       ret = hisi_qm_stop(vf_qm, stop_reason);
                        if (ret)
                                goto stop_fail;
                }
@@ -3346,15 +3434,14 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm)
        }
 
        if (qm->vfs_num) {
-               ret = qm_vf_reset_prepare(qm);
+               ret = qm_vf_reset_prepare(qm, QM_SOFT_RESET);
                if (ret) {
                        pci_err(pdev, "Fails to stop VFs!\n");
                        return ret;
                }
        }
 
-       qm->status.stop_reason = QM_SOFT_RESET;
-       ret = hisi_qm_stop(qm);
+       ret = hisi_qm_stop(qm, QM_SOFT_RESET);
        if (ret) {
                pci_err(pdev, "Fails to stop QM!\n");
                return ret;
@@ -3471,6 +3558,9 @@ static int qm_vf_reset_done(struct hisi_qm *qm)
                        continue;
 
                if (pci_physfn(virtfn) == pdev) {
+                       /* enable VFs PCIE BAR configuration */
+                       pci_restore_state(virtfn);
+
                        ret = qm_restart(vf_qm);
                        if (ret)
                                goto restart_fail;
@@ -3695,7 +3785,7 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev)
        }
 
        if (qm->vfs_num) {
-               ret = qm_vf_reset_prepare(qm);
+               ret = qm_vf_reset_prepare(qm, QM_FLR);
                if (ret) {
                        pci_err(pdev, "Failed to prepare reset, ret = %d.\n",
                                ret);
@@ -3703,7 +3793,7 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev)
                }
        }
 
-       ret = hisi_qm_stop(qm);
+       ret = hisi_qm_stop(qm, QM_FLR);
        if (ret) {
                pci_err(pdev, "Failed to stop QM, ret = %d.\n", ret);
                return;
@@ -3821,6 +3911,23 @@ err_aeq_irq:
        return ret;
 }
 
+/**
+ * hisi_qm_dev_shutdown() - Shutdown device.
+ * @pdev: The device will be shutdown.
+ *
+ * This function will stop qm when OS shutdown or rebooting.
+ */
+void hisi_qm_dev_shutdown(struct pci_dev *pdev)
+{
+       struct hisi_qm *qm = pci_get_drvdata(pdev);
+       int ret;
+
+       ret = hisi_qm_stop(qm, QM_NORMAL);
+       if (ret)
+               dev_err(&pdev->dev, "Fail to stop qm in shutdown!\n");
+}
+EXPORT_SYMBOL_GPL(hisi_qm_dev_shutdown);
+
 static void hisi_qm_controller_reset(struct work_struct *rst_work)
 {
        struct hisi_qm *qm = container_of(rst_work, struct hisi_qm, rst_work);
@@ -3834,6 +3941,58 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work)
 }
 
 /**
+ * hisi_qm_alg_register() - Register alg to crypto and add qm to qm_list.
+ * @qm: The qm needs add.
+ * @qm_list: The qm list.
+ *
+ * This function adds qm to qm list, and will register algorithm to
+ * crypto when the qm list is empty.
+ */
+int hisi_qm_alg_register(struct hisi_qm *qm, struct hisi_qm_list *qm_list)
+{
+       int flag = 0;
+       int ret = 0;
+
+       mutex_lock(&qm_list->lock);
+       if (list_empty(&qm_list->list))
+               flag = 1;
+       list_add_tail(&qm->list, &qm_list->list);
+       mutex_unlock(&qm_list->lock);
+
+       if (flag) {
+               ret = qm_list->register_to_crypto();
+               if (ret) {
+                       mutex_lock(&qm_list->lock);
+                       list_del(&qm->list);
+                       mutex_unlock(&qm_list->lock);
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(hisi_qm_alg_register);
+
+/**
+ * hisi_qm_alg_unregister() - Unregister alg from crypto and delete qm from
+ * qm list.
+ * @qm: The qm needs delete.
+ * @qm_list: The qm list.
+ *
+ * This function deletes qm from qm list, and will unregister algorithm
+ * from crypto when the qm list is empty.
+ */
+void hisi_qm_alg_unregister(struct hisi_qm *qm, struct hisi_qm_list *qm_list)
+{
+       mutex_lock(&qm_list->lock);
+       list_del(&qm->list);
+       mutex_unlock(&qm_list->lock);
+
+       if (list_empty(&qm_list->list))
+               qm_list->unregister_from_crypto();
+}
+EXPORT_SYMBOL_GPL(hisi_qm_alg_unregister);
+
+/**
  * hisi_qm_init() - Initialize configures about qm.
  * @qm: The qm needing init.
  *
index 6c1d3c7..0420f4c 100644 (file)
@@ -79,7 +79,7 @@
 #define QM_BASE_CE                     QM_ECC_1BIT
 
 #define QM_Q_DEPTH                     1024
-
+#define QM_MIN_QNUM                     2
 #define HISI_ACC_SGL_SGE_NR_MAX                255
 
 /* page number for queue file region */
@@ -193,6 +193,8 @@ struct hisi_qm_err_ini {
 struct hisi_qm_list {
        struct mutex lock;
        struct list_head list;
+       int (*register_to_crypto)(void);
+       void (*unregister_from_crypto)(void);
 };
 
 struct hisi_qm {
@@ -243,6 +245,7 @@ struct hisi_qm {
 
        const char *algs;
        bool use_sva;
+       bool is_frozen;
        resource_size_t phys_base;
        resource_size_t phys_size;
        struct uacce_device *uacce;
@@ -306,7 +309,7 @@ static inline int q_num_set(const char *val, const struct kernel_param *kp,
        }
 
        ret = kstrtou32(val, 10, &n);
-       if (ret || !n || n > q_num)
+       if (ret || n < QM_MIN_QNUM || n > q_num)
                return -EINVAL;
 
        return param_set_int(val, kp);
@@ -336,26 +339,10 @@ static inline void hisi_qm_init_list(struct hisi_qm_list *qm_list)
        mutex_init(&qm_list->lock);
 }
 
-static inline void hisi_qm_add_to_list(struct hisi_qm *qm,
-                                      struct hisi_qm_list *qm_list)
-{
-       mutex_lock(&qm_list->lock);
-       list_add_tail(&qm->list, &qm_list->list);
-       mutex_unlock(&qm_list->lock);
-}
-
-static inline void hisi_qm_del_from_list(struct hisi_qm *qm,
-                                        struct hisi_qm_list *qm_list)
-{
-       mutex_lock(&qm_list->lock);
-       list_del(&qm->list);
-       mutex_unlock(&qm_list->lock);
-}
-
 int hisi_qm_init(struct hisi_qm *qm);
 void hisi_qm_uninit(struct hisi_qm *qm);
 int hisi_qm_start(struct hisi_qm *qm);
-int hisi_qm_stop(struct hisi_qm *qm);
+int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r);
 struct hisi_qp *hisi_qm_create_qp(struct hisi_qm *qm, u8 alg_type);
 int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg);
 int hisi_qm_stop_qp(struct hisi_qp *qp);
@@ -367,7 +354,7 @@ int hisi_qm_debug_init(struct hisi_qm *qm);
 enum qm_hw_ver hisi_qm_get_hw_version(struct pci_dev *pdev);
 void hisi_qm_debug_regs_clear(struct hisi_qm *qm);
 int hisi_qm_sriov_enable(struct pci_dev *pdev, int max_vfs);
-int hisi_qm_sriov_disable(struct pci_dev *pdev);
+int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen);
 int hisi_qm_sriov_configure(struct pci_dev *pdev, int num_vfs);
 void hisi_qm_dev_err_init(struct hisi_qm *qm);
 void hisi_qm_dev_err_uninit(struct hisi_qm *qm);
@@ -390,4 +377,8 @@ void hisi_acc_free_sgl_pool(struct device *dev,
 int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num,
                           u8 alg_type, int node, struct hisi_qp **qps);
 void hisi_qm_free_qps(struct hisi_qp **qps, int qp_num);
+void hisi_qm_dev_shutdown(struct pci_dev *pdev);
+void hisi_qm_wait_task_finish(struct hisi_qm *qm, struct hisi_qm_list *qm_list);
+int hisi_qm_alg_register(struct hisi_qm *qm, struct hisi_qm_list *qm_list);
+void hisi_qm_alg_unregister(struct hisi_qm *qm, struct hisi_qm_list *qm_list);
 #endif
index 497969a..bb49342 100644 (file)
@@ -66,8 +66,6 @@
 #define SEC_SQE_AEAD_FLAG      3
 #define SEC_SQE_DONE           0x1
 
-static atomic_t sec_active_devs;
-
 /* Get an en/de-cipher queue cyclically to balance load over queues of TFM */
 static inline int sec_alloc_queue_id(struct sec_ctx *ctx, struct sec_req *req)
 {
@@ -342,11 +340,14 @@ static int sec_alg_resource_alloc(struct sec_ctx *ctx,
                ret = sec_alloc_pbuf_resource(dev, res);
                if (ret) {
                        dev_err(dev, "fail to alloc pbuf dma resource!\n");
-                       goto alloc_fail;
+                       goto alloc_pbuf_fail;
                }
        }
 
        return 0;
+alloc_pbuf_fail:
+       if (ctx->alg_type == SEC_AEAD)
+               sec_free_mac_resource(dev, qp_ctx->res);
 alloc_fail:
        sec_free_civ_resource(dev, res);
 
@@ -457,8 +458,10 @@ static int sec_ctx_base_init(struct sec_ctx *ctx)
        ctx->fake_req_limit = QM_Q_DEPTH >> 1;
        ctx->qp_ctx = kcalloc(sec->ctx_q_num, sizeof(struct sec_qp_ctx),
                              GFP_KERNEL);
-       if (!ctx->qp_ctx)
-               return -ENOMEM;
+       if (!ctx->qp_ctx) {
+               ret = -ENOMEM;
+               goto err_destroy_qps;
+       }
 
        for (i = 0; i < sec->ctx_q_num; i++) {
                ret = sec_create_qp_ctx(&sec->qm, ctx, i, 0);
@@ -467,12 +470,15 @@ static int sec_ctx_base_init(struct sec_ctx *ctx)
        }
 
        return 0;
+
 err_sec_release_qp_ctx:
        for (i = i - 1; i >= 0; i--)
                sec_release_qp_ctx(ctx, &ctx->qp_ctx[i]);
 
-       sec_destroy_qps(ctx->qps, sec->ctx_q_num);
        kfree(ctx->qp_ctx);
+err_destroy_qps:
+       sec_destroy_qps(ctx->qps, sec->ctx_q_num);
+
        return ret;
 }
 
@@ -1633,33 +1639,24 @@ static struct aead_alg sec_aeads[] = {
 
 int sec_register_to_crypto(void)
 {
-       int ret = 0;
+       int ret;
 
        /* To avoid repeat register */
-       if (atomic_add_return(1, &sec_active_devs) == 1) {
-               ret = crypto_register_skciphers(sec_skciphers,
-                                               ARRAY_SIZE(sec_skciphers));
-               if (ret)
-                       return ret;
-
-               ret = crypto_register_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
-               if (ret)
-                       goto reg_aead_fail;
-       }
-
-       return ret;
-
-reg_aead_fail:
-       crypto_unregister_skciphers(sec_skciphers, ARRAY_SIZE(sec_skciphers));
+       ret = crypto_register_skciphers(sec_skciphers,
+                                       ARRAY_SIZE(sec_skciphers));
+       if (ret)
+               return ret;
 
+       ret = crypto_register_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
+       if (ret)
+               crypto_unregister_skciphers(sec_skciphers,
+                                           ARRAY_SIZE(sec_skciphers));
        return ret;
 }
 
 void sec_unregister_from_crypto(void)
 {
-       if (atomic_sub_return(1, &sec_active_devs) == 0) {
-               crypto_unregister_skciphers(sec_skciphers,
-                                           ARRAY_SIZE(sec_skciphers));
-               crypto_unregister_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
-       }
+       crypto_unregister_skciphers(sec_skciphers,
+                                   ARRAY_SIZE(sec_skciphers));
+       crypto_unregister_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
 }
index 2297425..5488963 100644 (file)
@@ -99,7 +99,11 @@ struct sec_dfx_item {
 
 static const char sec_name[] = "hisi_sec2";
 static struct dentry *sec_debugfs_root;
-static struct hisi_qm_list sec_devices;
+
+static struct hisi_qm_list sec_devices = {
+       .register_to_crypto     = sec_register_to_crypto,
+       .unregister_from_crypto = sec_unregister_from_crypto,
+};
 
 static const struct sec_hw_error sec_hw_errors[] = {
        {.int_msk = BIT(0), .msg = "sec_axi_rresp_err_rint"},
@@ -165,7 +169,7 @@ static const struct kernel_param_ops sec_pf_q_num_ops = {
 
 static u32 pf_q_num = SEC_PF_DEF_Q_NUM;
 module_param_cb(pf_q_num, &sec_pf_q_num_ops, &pf_q_num, 0444);
-MODULE_PARM_DESC(pf_q_num, "Number of queues in PF(v1 0-4096, v2 0-1024)");
+MODULE_PARM_DESC(pf_q_num, "Number of queues in PF(v1 2-4096, v2 2-1024)");
 
 static int sec_ctx_q_num_set(const char *val, const struct kernel_param *kp)
 {
@@ -879,29 +883,26 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (ret)
                pci_warn(pdev, "Failed to init debugfs!\n");
 
-       hisi_qm_add_to_list(qm, &sec_devices);
-
-       ret = sec_register_to_crypto();
+       ret = hisi_qm_alg_register(qm, &sec_devices);
        if (ret < 0) {
                pr_err("Failed to register driver to crypto.\n");
-               goto err_remove_from_list;
+               goto err_qm_stop;
        }
 
        if (qm->fun_type == QM_HW_PF && vfs_num) {
                ret = hisi_qm_sriov_enable(pdev, vfs_num);
                if (ret < 0)
-                       goto err_crypto_unregister;
+                       goto err_alg_unregister;
        }
 
        return 0;
 
-err_crypto_unregister:
-       sec_unregister_from_crypto();
+err_alg_unregister:
+       hisi_qm_alg_unregister(qm, &sec_devices);
 
-err_remove_from_list:
-       hisi_qm_del_from_list(qm, &sec_devices);
+err_qm_stop:
        sec_debugfs_exit(qm);
-       hisi_qm_stop(qm);
+       hisi_qm_stop(qm, QM_NORMAL);
 
 err_probe_uninit:
        sec_probe_uninit(qm);
@@ -914,19 +915,16 @@ err_qm_uninit:
 
 static void sec_remove(struct pci_dev *pdev)
 {
-       struct sec_dev *sec = pci_get_drvdata(pdev);
-       struct hisi_qm *qm = &sec->qm;
-
-       sec_unregister_from_crypto();
-
-       hisi_qm_del_from_list(qm, &sec_devices);
+       struct hisi_qm *qm = pci_get_drvdata(pdev);
 
+       hisi_qm_wait_task_finish(qm, &sec_devices);
+       hisi_qm_alg_unregister(qm, &sec_devices);
        if (qm->fun_type == QM_HW_PF && qm->vfs_num)
-               hisi_qm_sriov_disable(pdev);
+               hisi_qm_sriov_disable(pdev, qm->is_frozen);
 
        sec_debugfs_exit(qm);
 
-       (void)hisi_qm_stop(qm);
+       (void)hisi_qm_stop(qm, QM_NORMAL);
 
        if (qm->fun_type == QM_HW_PF)
                sec_debug_regs_clear(qm);
@@ -950,6 +948,7 @@ static struct pci_driver sec_pci_driver = {
        .remove = sec_remove,
        .err_handler = &sec_err_handler,
        .sriov_configure = hisi_qm_sriov_configure,
+       .shutdown = hisi_qm_dev_shutdown,
 };
 
 static void sec_register_debugfs(void)
index 4484be1..92397f9 100644 (file)
@@ -9,20 +9,6 @@
 #include <linux/list.h>
 #include "../qm.h"
 
-/* hisi_zip_sqe dw3 */
-#define HZIP_BD_STATUS_M                       GENMASK(7, 0)
-/* hisi_zip_sqe dw7 */
-#define HZIP_IN_SGE_DATA_OFFSET_M              GENMASK(23, 0)
-/* hisi_zip_sqe dw8 */
-#define HZIP_OUT_SGE_DATA_OFFSET_M             GENMASK(23, 0)
-/* hisi_zip_sqe dw9 */
-#define HZIP_REQ_TYPE_M                                GENMASK(7, 0)
-#define HZIP_ALG_TYPE_ZLIB                     0x02
-#define HZIP_ALG_TYPE_GZIP                     0x03
-#define HZIP_BUF_TYPE_M                                GENMASK(11, 8)
-#define HZIP_PBUFFER                           0x0
-#define HZIP_SGL                               0x1
-
 enum hisi_zip_error_type {
        /* negative compression */
        HZIP_NC_ERR = 0x0d,
@@ -39,7 +25,6 @@ struct hisi_zip_ctrl;
 
 struct hisi_zip {
        struct hisi_qm qm;
-       struct list_head list;
        struct hisi_zip_ctrl *ctrl;
        struct hisi_zip_dfx dfx;
 };
index 01fd6a7..08b4660 100644 (file)
@@ -6,6 +6,20 @@
 #include <linux/scatterlist.h>
 #include "zip.h"
 
+/* hisi_zip_sqe dw3 */
+#define HZIP_BD_STATUS_M                       GENMASK(7, 0)
+/* hisi_zip_sqe dw7 */
+#define HZIP_IN_SGE_DATA_OFFSET_M              GENMASK(23, 0)
+/* hisi_zip_sqe dw8 */
+#define HZIP_OUT_SGE_DATA_OFFSET_M             GENMASK(23, 0)
+/* hisi_zip_sqe dw9 */
+#define HZIP_REQ_TYPE_M                                GENMASK(7, 0)
+#define HZIP_ALG_TYPE_ZLIB                     0x02
+#define HZIP_ALG_TYPE_GZIP                     0x03
+#define HZIP_BUF_TYPE_M                                GENMASK(11, 8)
+#define HZIP_PBUFFER                           0x0
+#define HZIP_SGL                               0x1
+
 #define HZIP_ZLIB_HEAD_SIZE                    2
 #define HZIP_GZIP_HEAD_SIZE                    10
 
 
 #define GZIP_HEAD_FLG_SHIFT                    3
 #define GZIP_HEAD_FEXTRA_SHIFT                 10
-#define GZIP_HEAD_FEXTRA_XLEN                  2
+#define GZIP_HEAD_FEXTRA_XLEN                  2UL
 #define GZIP_HEAD_FHCRC_SIZE                   2
 
-#define HZIP_CTX_Q_NUM                         2
 #define HZIP_GZIP_HEAD_BUF                     256
 #define HZIP_ALG_PRIORITY                      300
 #define HZIP_SGL_SGE_NR                                10
 
 static const u8 zlib_head[HZIP_ZLIB_HEAD_SIZE] = {0x78, 0x9c};
-static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = {0x1f, 0x8b, 0x08, 0x0, 0x0,
-                                                 0x0, 0x0, 0x0, 0x0, 0x03};
+static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = {
+       0x1f, 0x8b, 0x08, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x03
+};
+
 enum hisi_zip_alg_type {
        HZIP_ALG_TYPE_COMP = 0,
        HZIP_ALG_TYPE_DECOMP = 1,
 };
 
+enum {
+       HZIP_QPC_COMP,
+       HZIP_QPC_DECOMP,
+       HZIP_CTX_Q_NUM
+};
+
 #define COMP_NAME_TO_TYPE(alg_name)                                    \
        (!strcmp((alg_name), "zlib-deflate") ? HZIP_ALG_TYPE_ZLIB :     \
         !strcmp((alg_name), "gzip") ? HZIP_ALG_TYPE_GZIP : 0)          \
@@ -46,13 +67,13 @@ enum hisi_zip_alg_type {
 
 struct hisi_zip_req {
        struct acomp_req *req;
-       int sskip;
-       int dskip;
+       u32 sskip;
+       u32 dskip;
        struct hisi_acc_hw_sgl *hw_src;
        struct hisi_acc_hw_sgl *hw_dst;
        dma_addr_t dma_src;
        dma_addr_t dma_dst;
-       int req_id;
+       u16 req_id;
 };
 
 struct hisi_zip_req_q {
@@ -71,8 +92,6 @@ struct hisi_zip_qp_ctx {
 };
 
 struct hisi_zip_ctx {
-#define QPC_COMP       0
-#define QPC_DECOMP     1
        struct hisi_zip_qp_ctx qp_ctx[HZIP_CTX_Q_NUM];
 };
 
@@ -116,7 +135,7 @@ static void hisi_zip_config_tag(struct hisi_zip_sqe *sqe, u32 tag)
 
 static void hisi_zip_fill_sqe(struct hisi_zip_sqe *sqe, u8 req_type,
                              dma_addr_t s_addr, dma_addr_t d_addr, u32 slen,
-                             u32 dlen, int sskip, int dskip)
+                             u32 dlen, u32 sskip, u32 dskip)
 {
        memset(sqe, 0, sizeof(struct hisi_zip_sqe));
 
@@ -143,7 +162,7 @@ static int hisi_zip_start_qp(struct hisi_qp *qp, struct hisi_zip_qp_ctx *ctx,
 
        ret = hisi_qm_start_qp(qp, 0);
        if (ret < 0) {
-               dev_err(dev, "start qp failed!\n");
+               dev_err(dev, "failed to start qp (%d)!\n", ret);
                return ret;
        }
 
@@ -166,7 +185,7 @@ static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int
 
        ret = zip_create_qps(qps, HZIP_CTX_Q_NUM, node);
        if (ret) {
-               pr_err("Can not create zip qps!\n");
+               pr_err("failed to create zip qps (%d)!\n", ret);
                return -ENODEV;
        }
 
@@ -264,11 +283,11 @@ static int hisi_zip_create_req_q(struct hisi_zip_ctx *ctx)
        return 0;
 
 err_free_loop1:
-       kfree(ctx->qp_ctx[QPC_DECOMP].req_q.req_bitmap);
+       kfree(ctx->qp_ctx[HZIP_QPC_DECOMP].req_q.req_bitmap);
 err_free_loop0:
-       kfree(ctx->qp_ctx[QPC_COMP].req_q.q);
+       kfree(ctx->qp_ctx[HZIP_QPC_COMP].req_q.q);
 err_free_bitmap:
-       kfree(ctx->qp_ctx[QPC_COMP].req_q.req_bitmap);
+       kfree(ctx->qp_ctx[HZIP_QPC_COMP].req_q.req_bitmap);
        return ret;
 }
 
@@ -303,8 +322,8 @@ static int hisi_zip_create_sgl_pool(struct hisi_zip_ctx *ctx)
        return 0;
 
 err_free_sgl_pool0:
-       hisi_acc_free_sgl_pool(&ctx->qp_ctx[QPC_COMP].qp->qm->pdev->dev,
-                              ctx->qp_ctx[QPC_COMP].sgl_pool);
+       hisi_acc_free_sgl_pool(&ctx->qp_ctx[HZIP_QPC_COMP].qp->qm->pdev->dev,
+                              ctx->qp_ctx[HZIP_QPC_COMP].sgl_pool);
        return -ENOMEM;
 }
 
@@ -342,7 +361,6 @@ static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data)
 
        atomic64_inc(&dfx->recv_cnt);
        status = sqe->dw3 & HZIP_BD_STATUS_M;
-
        if (status != 0 && status != HZIP_NC_ERR) {
                dev_err(dev, "%scompress fail in qp%u: %u, output: %u\n",
                        (qp->alg_type == 0) ? "" : "de", qp->qp_id, status,
@@ -377,19 +395,28 @@ static int hisi_zip_acomp_init(struct crypto_acomp *tfm)
 {
        const char *alg_name = crypto_tfm_alg_name(&tfm->base);
        struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base);
+       struct device *dev;
        int ret;
 
        ret = hisi_zip_ctx_init(ctx, COMP_NAME_TO_TYPE(alg_name), tfm->base.node);
-       if (ret)
+       if (ret) {
+               pr_err("failed to init ctx (%d)!\n", ret);
                return ret;
+       }
+
+       dev = &ctx->qp_ctx[0].qp->qm->pdev->dev;
 
        ret = hisi_zip_create_req_q(ctx);
-       if (ret)
+       if (ret) {
+               dev_err(dev, "failed to create request queue (%d)!\n", ret);
                goto err_ctx_exit;
+       }
 
        ret = hisi_zip_create_sgl_pool(ctx);
-       if (ret)
+       if (ret) {
+               dev_err(dev, "failed to create sgl pool (%d)!\n", ret);
                goto err_release_req_q;
+       }
 
        hisi_zip_set_acomp_cb(ctx, hisi_zip_acomp_cb);
 
@@ -419,13 +446,15 @@ static int add_comp_head(struct scatterlist *dst, u8 req_type)
        int ret;
 
        ret = sg_copy_from_buffer(dst, sg_nents(dst), head, head_size);
-       if (ret != head_size)
+       if (ret != head_size) {
+               pr_err("the head size of buffer is wrong (%d)!\n", ret);
                return -ENOMEM;
+       }
 
        return head_size;
 }
 
-static size_t get_gzip_head_size(struct scatterlist *sgl)
+static size_t __maybe_unused get_gzip_head_size(struct scatterlist *sgl)
 {
        char buf[HZIP_GZIP_HEAD_BUF];
 
@@ -434,13 +463,20 @@ static size_t get_gzip_head_size(struct scatterlist *sgl)
        return __get_gzip_head_size(buf);
 }
 
-static size_t get_comp_head_size(struct scatterlist *src, u8 req_type)
+static int  get_comp_head_size(struct acomp_req *acomp_req, u8 req_type)
 {
+       if (!acomp_req->src || !acomp_req->slen)
+               return -EINVAL;
+
+       if ((req_type == HZIP_ALG_TYPE_GZIP) &&
+           (acomp_req->slen < GZIP_HEAD_FEXTRA_SHIFT))
+               return -EINVAL;
+
        switch (req_type) {
        case HZIP_ALG_TYPE_ZLIB:
                return TO_HEAD_SIZE(HZIP_ALG_TYPE_ZLIB);
        case HZIP_ALG_TYPE_GZIP:
-               return get_gzip_head_size(src);
+               return TO_HEAD_SIZE(HZIP_ALG_TYPE_GZIP);
        default:
                pr_err("request type does not support!\n");
                return -EINVAL;
@@ -462,7 +498,7 @@ static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req,
        if (req_id >= req_q->size) {
                write_unlock(&req_q->req_lock);
                dev_dbg(&qp_ctx->qp->qm->pdev->dev, "req cache is full!\n");
-               return ERR_PTR(-EBUSY);
+               return ERR_PTR(-EAGAIN);
        }
        set_bit(req_id, req_q->req_bitmap);
 
@@ -492,8 +528,7 @@ static int hisi_zip_do_work(struct hisi_zip_req *req,
        struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool;
        struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx;
        struct hisi_zip_sqe zip_sqe;
-       dma_addr_t input;
-       dma_addr_t output;
+       dma_addr_t input, output;
        int ret;
 
        if (!a_req->src || !a_req->slen || !a_req->dst || !a_req->dlen)
@@ -501,8 +536,11 @@ static int hisi_zip_do_work(struct hisi_zip_req *req,
 
        req->hw_src = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->src, pool,
                                                    req->req_id << 1, &input);
-       if (IS_ERR(req->hw_src))
+       if (IS_ERR(req->hw_src)) {
+               dev_err(dev, "failed to map the src buffer to hw sgl (%ld)!\n",
+                       PTR_ERR(req->hw_src));
                return PTR_ERR(req->hw_src);
+       }
        req->dma_src = input;
 
        req->hw_dst = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->dst, pool,
@@ -510,6 +548,8 @@ static int hisi_zip_do_work(struct hisi_zip_req *req,
                                                    &output);
        if (IS_ERR(req->hw_dst)) {
                ret = PTR_ERR(req->hw_dst);
+               dev_err(dev, "failed to map the dst buffer to hw slg (%d)!\n",
+                       ret);
                goto err_unmap_input;
        }
        req->dma_dst = output;
@@ -524,6 +564,8 @@ static int hisi_zip_do_work(struct hisi_zip_req *req,
        ret = hisi_qp_send(qp, &zip_sqe);
        if (ret < 0) {
                atomic64_inc(&dfx->send_busy_cnt);
+               ret = -EAGAIN;
+               dev_dbg_ratelimited(dev, "failed to send request!\n");
                goto err_unmap_output;
        }
 
@@ -539,23 +581,29 @@ err_unmap_input:
 static int hisi_zip_acompress(struct acomp_req *acomp_req)
 {
        struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm);
-       struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[QPC_COMP];
+       struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_COMP];
+       struct device *dev = &qp_ctx->qp->qm->pdev->dev;
        struct hisi_zip_req *req;
        int head_size;
        int ret;
 
        /* let's output compression head now */
        head_size = add_comp_head(acomp_req->dst, qp_ctx->qp->req_type);
-       if (head_size < 0)
-               return -ENOMEM;
+       if (head_size < 0) {
+               dev_err_ratelimited(dev, "failed to add comp head (%d)!\n",
+                                   head_size);
+               return head_size;
+       }
 
-       req = hisi_zip_create_req(acomp_req, qp_ctx, (size_t)head_size, true);
+       req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, true);
        if (IS_ERR(req))
                return PTR_ERR(req);
 
        ret = hisi_zip_do_work(req, qp_ctx);
-       if (ret != -EINPROGRESS)
+       if (ret != -EINPROGRESS) {
+               dev_info_ratelimited(dev, "failed to do compress (%d)!\n", ret);
                hisi_zip_remove_req(qp_ctx, req);
+       }
 
        return ret;
 }
@@ -563,20 +611,28 @@ static int hisi_zip_acompress(struct acomp_req *acomp_req)
 static int hisi_zip_adecompress(struct acomp_req *acomp_req)
 {
        struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm);
-       struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[QPC_DECOMP];
+       struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[HZIP_QPC_DECOMP];
+       struct device *dev = &qp_ctx->qp->qm->pdev->dev;
        struct hisi_zip_req *req;
-       size_t head_size;
-       int ret;
+       int head_size, ret;
 
-       head_size = get_comp_head_size(acomp_req->src, qp_ctx->qp->req_type);
+       head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type);
+       if (head_size < 0) {
+               dev_err_ratelimited(dev, "failed to get comp head size (%d)!\n",
+                                   head_size);
+               return head_size;
+       }
 
        req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, false);
        if (IS_ERR(req))
                return PTR_ERR(req);
 
        ret = hisi_zip_do_work(req, qp_ctx);
-       if (ret != -EINPROGRESS)
+       if (ret != -EINPROGRESS) {
+               dev_info_ratelimited(dev, "failed to do decompress (%d)!\n",
+                                    ret);
                hisi_zip_remove_req(qp_ctx, req);
+       }
 
        return ret;
 }
@@ -611,17 +667,17 @@ static struct acomp_alg hisi_zip_acomp_gzip = {
 
 int hisi_zip_register_to_crypto(void)
 {
-       int ret = 0;
+       int ret;
 
        ret = crypto_register_acomp(&hisi_zip_acomp_zlib);
        if (ret) {
-               pr_err("Zlib acomp algorithm registration failed\n");
+               pr_err("failed to register to zlib (%d)!\n", ret);
                return ret;
        }
 
        ret = crypto_register_acomp(&hisi_zip_acomp_gzip);
        if (ret) {
-               pr_err("Gzip acomp algorithm registration failed\n");
+               pr_err("failed to register to gzip (%d)!\n", ret);
                crypto_unregister_acomp(&hisi_zip_acomp_zlib);
        }
 
index e2845b2..4bd2c81 100644 (file)
@@ -17,7 +17,6 @@
 #define PCI_DEVICE_ID_ZIP_PF           0xa250
 #define PCI_DEVICE_ID_ZIP_VF           0xa251
 
-#define HZIP_VF_NUM                    63
 #define HZIP_QUEUE_NUM_V1              4096
 #define HZIP_QUEUE_NUM_V2              1024
 
 #define DECOMP3_ENABLE                 BIT(5)
 #define DECOMP4_ENABLE                 BIT(6)
 #define DECOMP5_ENABLE                 BIT(7)
-#define ALL_COMP_DECOMP_EN             (COMP0_ENABLE | COMP1_ENABLE |  \
+#define HZIP_ALL_COMP_DECOMP_EN                (COMP0_ENABLE | COMP1_ENABLE | \
                                         DECOMP0_ENABLE | DECOMP1_ENABLE | \
                                         DECOMP2_ENABLE | DECOMP3_ENABLE | \
                                         DECOMP4_ENABLE | DECOMP5_ENABLE)
-#define DECOMP_CHECK_ENABLE            BIT(16)
+#define HZIP_DECOMP_CHECK_ENABLE       BIT(16)
 #define HZIP_FSM_MAX_CNT               0x301008
 
 #define HZIP_PORT_ARCA_CHE_0           0x301040
 #define HZIP_PORT_ARCA_CHE_1           0x301044
 #define HZIP_PORT_AWCA_CHE_0           0x301060
 #define HZIP_PORT_AWCA_CHE_1           0x301064
-#define CACHE_ALL_EN                   0xffffffff
+#define HZIP_CACHE_ALL_EN              0xffffffff
 
 #define HZIP_BD_RUSER_32_63            0x301110
 #define HZIP_SGL_RUSER_32_63           0x30111c
@@ -83,7 +82,7 @@
 #define HZIP_PF_DEF_Q_BASE             0
 
 #define HZIP_SOFT_CTRL_CNT_CLR_CE      0x301000
-#define SOFT_CTRL_CNT_CLR_CE_BIT       BIT(0)
+#define HZIP_SOFT_CTRL_CNT_CLR_CE_BIT  BIT(0)
 #define HZIP_SOFT_CTRL_ZIP_CONTROL     0x30100C
 #define HZIP_AXI_SHUTDOWN_ENABLE       BIT(14)
 #define HZIP_WR_PORT                   BIT(11)
 #define HZIP_SQE_MASK_OFFSET           64
 #define HZIP_SQE_MASK_LEN              48
 
+#define HZIP_CNT_CLR_CE_EN             BIT(0)
+#define HZIP_RO_CNT_CLR_CE_EN          BIT(2)
+#define HZIP_RD_CNT_CLR_CE_EN          (HZIP_CNT_CLR_CE_EN | \
+                                        HZIP_RO_CNT_CLR_CE_EN)
+
 static const char hisi_zip_name[] = "hisi_zip";
 static struct dentry *hzip_debugfs_root;
-static struct hisi_qm_list zip_devices;
 
 struct hisi_zip_hw_error {
        u32 int_msk;
@@ -106,6 +109,11 @@ struct zip_dfx_item {
        u32 offset;
 };
 
+static struct hisi_qm_list zip_devices = {
+       .register_to_crypto     = hisi_zip_register_to_crypto,
+       .unregister_from_crypto = hisi_zip_unregister_from_crypto,
+};
+
 static struct zip_dfx_item zip_dfx_files[] = {
        {"send_cnt", offsetof(struct hisi_zip_dfx, send_cnt)},
        {"recv_cnt", offsetof(struct hisi_zip_dfx, recv_cnt)},
@@ -153,7 +161,6 @@ struct ctrl_debug_file {
  */
 struct hisi_zip_ctrl {
        struct hisi_zip *hisi_zip;
-       struct dentry *debug_root;
        struct ctrl_debug_file files[HZIP_DEBUG_FILE_NUM];
 };
 
@@ -216,7 +223,7 @@ static const struct kernel_param_ops pf_q_num_ops = {
 
 static u32 pf_q_num = HZIP_PF_DEF_Q_NUM;
 module_param_cb(pf_q_num, &pf_q_num_ops, &pf_q_num, 0444);
-MODULE_PARM_DESC(pf_q_num, "Number of queues in PF(v1 1-4096, v2 1-1024)");
+MODULE_PARM_DESC(pf_q_num, "Number of queues in PF(v1 2-4096, v2 2-1024)");
 
 static const struct kernel_param_ops vfs_num_ops = {
        .set = vfs_num_set,
@@ -256,15 +263,16 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm)
        /* qm cache */
        writel(AXI_M_CFG, base + QM_AXI_M_CFG);
        writel(AXI_M_CFG_ENABLE, base + QM_AXI_M_CFG_ENABLE);
+
        /* disable FLR triggered by BME(bus master enable) */
        writel(PEH_AXUSER_CFG, base + QM_PEH_AXUSER_CFG);
        writel(PEH_AXUSER_CFG_ENABLE, base + QM_PEH_AXUSER_CFG_ENABLE);
 
        /* cache */
-       writel(CACHE_ALL_EN, base + HZIP_PORT_ARCA_CHE_0);
-       writel(CACHE_ALL_EN, base + HZIP_PORT_ARCA_CHE_1);
-       writel(CACHE_ALL_EN, base + HZIP_PORT_AWCA_CHE_0);
-       writel(CACHE_ALL_EN, base + HZIP_PORT_AWCA_CHE_1);
+       writel(HZIP_CACHE_ALL_EN, base + HZIP_PORT_ARCA_CHE_0);
+       writel(HZIP_CACHE_ALL_EN, base + HZIP_PORT_ARCA_CHE_1);
+       writel(HZIP_CACHE_ALL_EN, base + HZIP_PORT_AWCA_CHE_0);
+       writel(HZIP_CACHE_ALL_EN, base + HZIP_PORT_AWCA_CHE_1);
 
        /* user domain configurations */
        writel(AXUSER_BASE, base + HZIP_BD_RUSER_32_63);
@@ -280,10 +288,10 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm)
        }
 
        /* let's open all compression/decompression cores */
-       writel(DECOMP_CHECK_ENABLE | ALL_COMP_DECOMP_EN,
+       writel(HZIP_DECOMP_CHECK_ENABLE | HZIP_ALL_COMP_DECOMP_EN,
               base + HZIP_CLOCK_GATE_CTRL);
 
-       /* enable sqc writeback */
+       /* enable sqc,cqc writeback */
        writel(SQC_CACHE_ENABLE | CQC_CACHE_ENABLE | SQC_CACHE_WB_ENABLE |
               CQC_CACHE_WB_ENABLE | FIELD_PREP(SQC_CACHE_WB_THRD, 1) |
               FIELD_PREP(CQC_CACHE_WB_THRD, 1), base + QM_CACHE_CTL);
@@ -309,7 +317,7 @@ static void hisi_zip_hw_error_enable(struct hisi_qm *qm)
        writel(0x1, qm->io_base + HZIP_CORE_INT_RAS_CE_ENB);
        writel(0x0, qm->io_base + HZIP_CORE_INT_RAS_FE_ENB);
        writel(HZIP_CORE_INT_RAS_NFE_ENABLE,
-               qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB);
+              qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB);
 
        /* enable ZIP hw error interrupts */
        writel(0, qm->io_base + HZIP_CORE_INT_MASK_REG);
@@ -356,7 +364,7 @@ static int current_qm_write(struct ctrl_debug_file *file, u32 val)
        if (val > qm->vfs_num)
                return -EINVAL;
 
-       /* Calculate curr_qm_qp_num and store */
+       /* According PF or VF Dev ID to calculation curr_qm_qp_num and store */
        if (val == 0) {
                qm->debug.curr_qm_qp_num = qm->qp_num;
        } else {
@@ -387,7 +395,7 @@ static u32 clear_enable_read(struct ctrl_debug_file *file)
        struct hisi_qm *qm = file_to_qm(file);
 
        return readl(qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE) &
-              SOFT_CTRL_CNT_CLR_CE_BIT;
+                    HZIP_SOFT_CTRL_CNT_CLR_CE_BIT;
 }
 
 static int clear_enable_write(struct ctrl_debug_file *file, u32 val)
@@ -399,14 +407,14 @@ static int clear_enable_write(struct ctrl_debug_file *file, u32 val)
                return -EINVAL;
 
        tmp = (readl(qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE) &
-              ~SOFT_CTRL_CNT_CLR_CE_BIT) | val;
+              ~HZIP_SOFT_CTRL_CNT_CLR_CE_BIT) | val;
        writel(tmp, qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE);
 
        return  0;
 }
 
-static ssize_t ctrl_debug_read(struct file *filp, char __user *buf,
-                              size_t count, loff_t *pos)
+static ssize_t hisi_zip_ctrl_debug_read(struct file *filp, char __user *buf,
+                                       size_t count, loff_t *pos)
 {
        struct ctrl_debug_file *file = filp->private_data;
        char tbuf[HZIP_BUF_SIZE];
@@ -426,12 +434,13 @@ static ssize_t ctrl_debug_read(struct file *filp, char __user *buf,
                return -EINVAL;
        }
        spin_unlock_irq(&file->lock);
-       ret = sprintf(tbuf, "%u\n", val);
+       ret = scnprintf(tbuf, sizeof(tbuf), "%u\n", val);
        return simple_read_from_buffer(buf, count, pos, tbuf, ret);
 }
 
-static ssize_t ctrl_debug_write(struct file *filp, const char __user *buf,
-                               size_t count, loff_t *pos)
+static ssize_t hisi_zip_ctrl_debug_write(struct file *filp,
+                                        const char __user *buf,
+                                        size_t count, loff_t *pos)
 {
        struct ctrl_debug_file *file = filp->private_data;
        char tbuf[HZIP_BUF_SIZE];
@@ -480,11 +489,10 @@ err_input:
 static const struct file_operations ctrl_debug_fops = {
        .owner = THIS_MODULE,
        .open = simple_open,
-       .read = ctrl_debug_read,
-       .write = ctrl_debug_write,
+       .read = hisi_zip_ctrl_debug_read,
+       .write = hisi_zip_ctrl_debug_write,
 };
 
-
 static int zip_debugfs_atomic64_set(void *data, u64 val)
 {
        if (val)
@@ -505,10 +513,8 @@ static int zip_debugfs_atomic64_get(void *data, u64 *val)
 DEFINE_DEBUGFS_ATTRIBUTE(zip_atomic64_ops, zip_debugfs_atomic64_get,
                         zip_debugfs_atomic64_set, "%llu\n");
 
-static int hisi_zip_core_debug_init(struct hisi_zip_ctrl *ctrl)
+static int hisi_zip_core_debug_init(struct hisi_qm *qm)
 {
-       struct hisi_zip *hisi_zip = ctrl->hisi_zip;
-       struct hisi_qm *qm = &hisi_zip->qm;
        struct device *dev = &qm->pdev->dev;
        struct debugfs_regset32 *regset;
        struct dentry *tmp_d;
@@ -517,9 +523,10 @@ static int hisi_zip_core_debug_init(struct hisi_zip_ctrl *ctrl)
 
        for (i = 0; i < HZIP_CORE_NUM; i++) {
                if (i < HZIP_COMP_CORE_NUM)
-                       sprintf(buf, "comp_core%d", i);
+                       scnprintf(buf, sizeof(buf), "comp_core%d", i);
                else
-                       sprintf(buf, "decomp_core%d", i - HZIP_COMP_CORE_NUM);
+                       scnprintf(buf, sizeof(buf), "decomp_core%d",
+                                 i - HZIP_COMP_CORE_NUM);
 
                regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
                if (!regset)
@@ -529,7 +536,7 @@ static int hisi_zip_core_debug_init(struct hisi_zip_ctrl *ctrl)
                regset->nregs = ARRAY_SIZE(hzip_dfx_regs);
                regset->base = qm->io_base + core_offsets[i];
 
-               tmp_d = debugfs_create_dir(buf, ctrl->debug_root);
+               tmp_d = debugfs_create_dir(buf, qm->debug.debug_root);
                debugfs_create_regset32("regs", 0444, tmp_d, regset);
        }
 
@@ -548,33 +555,32 @@ static void hisi_zip_dfx_debug_init(struct hisi_qm *qm)
        for (i = 0; i < ARRAY_SIZE(zip_dfx_files); i++) {
                data = (atomic64_t *)((uintptr_t)dfx + zip_dfx_files[i].offset);
                debugfs_create_file(zip_dfx_files[i].name,
-                       0644,
-                       tmp_dir,
-                       data,
-                       &zip_atomic64_ops);
+                                   0644, tmp_dir, data,
+                                   &zip_atomic64_ops);
        }
 }
 
-static int hisi_zip_ctrl_debug_init(struct hisi_zip_ctrl *ctrl)
+static int hisi_zip_ctrl_debug_init(struct hisi_qm *qm)
 {
+       struct hisi_zip *zip = container_of(qm, struct hisi_zip, qm);
        int i;
 
        for (i = HZIP_CURRENT_QM; i < HZIP_DEBUG_FILE_NUM; i++) {
-               spin_lock_init(&ctrl->files[i].lock);
-               ctrl->files[i].ctrl = ctrl;
-               ctrl->files[i].index = i;
+               spin_lock_init(&zip->ctrl->files[i].lock);
+               zip->ctrl->files[i].ctrl = zip->ctrl;
+               zip->ctrl->files[i].index = i;
 
                debugfs_create_file(ctrl_debug_file_name[i], 0600,
-                                   ctrl->debug_root, ctrl->files + i,
+                                   qm->debug.debug_root,
+                                   zip->ctrl->files + i,
                                    &ctrl_debug_fops);
        }
 
-       return hisi_zip_core_debug_init(ctrl);
+       return hisi_zip_core_debug_init(qm);
 }
 
-static int hisi_zip_debugfs_init(struct hisi_zip *hisi_zip)
+static int hisi_zip_debugfs_init(struct hisi_qm *qm)
 {
-       struct hisi_qm *qm = &hisi_zip->qm;
        struct device *dev = &qm->pdev->dev;
        struct dentry *dev_d;
        int ret;
@@ -589,8 +595,7 @@ static int hisi_zip_debugfs_init(struct hisi_zip *hisi_zip)
                goto failed_to_create;
 
        if (qm->fun_type == QM_HW_PF) {
-               hisi_zip->ctrl->debug_root = dev_d;
-               ret = hisi_zip_ctrl_debug_init(hisi_zip->ctrl);
+               ret = hisi_zip_ctrl_debug_init(qm);
                if (ret)
                        goto failed_to_create;
        }
@@ -604,25 +609,36 @@ failed_to_create:
        return ret;
 }
 
-static void hisi_zip_debug_regs_clear(struct hisi_zip *hisi_zip)
+/* hisi_zip_debug_regs_clear() - clear the zip debug regs */
+static void hisi_zip_debug_regs_clear(struct hisi_qm *qm)
 {
-       struct hisi_qm *qm = &hisi_zip->qm;
+       int i, j;
 
+       /* clear current_qm */
        writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF);
        writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF);
+
+       /* enable register read_clear bit */
+       writel(HZIP_RD_CNT_CLR_CE_EN, qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE);
+       for (i = 0; i < ARRAY_SIZE(core_offsets); i++)
+               for (j = 0; j < ARRAY_SIZE(hzip_dfx_regs); j++)
+                       readl(qm->io_base + core_offsets[i] +
+                             hzip_dfx_regs[j].offset);
+
+       /* disable register read_clear bit */
        writel(0x0, qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE);
 
        hisi_qm_debug_regs_clear(qm);
 }
 
-static void hisi_zip_debugfs_exit(struct hisi_zip *hisi_zip)
+static void hisi_zip_debugfs_exit(struct hisi_qm *qm)
 {
-       struct hisi_qm *qm = &hisi_zip->qm;
-
        debugfs_remove_recursive(qm->debug.debug_root);
 
-       if (qm->fun_type == QM_HW_PF)
-               hisi_zip_debug_regs_clear(hisi_zip);
+       if (qm->fun_type == QM_HW_PF) {
+               hisi_zip_debug_regs_clear(qm);
+               qm->debug.curr_qm_qp_num = 0;
+       }
 }
 
 static void hisi_zip_log_hw_error(struct hisi_qm *qm, u32 err_sts)
@@ -634,7 +650,7 @@ static void hisi_zip_log_hw_error(struct hisi_qm *qm, u32 err_sts)
        while (err->msg) {
                if (err->int_msk & err_sts) {
                        dev_err(dev, "%s [error status=0x%x] found\n",
-                                err->msg, err->int_msk);
+                               err->msg, err->int_msk);
 
                        if (err->int_msk & HZIP_CORE_INT_STATUS_M_ECC) {
                                err_val = readl(qm->io_base +
@@ -642,9 +658,6 @@ static void hisi_zip_log_hw_error(struct hisi_qm *qm, u32 err_sts)
                                dev_err(dev, "hisi-zip multi ecc sram num=0x%x\n",
                                        ((err_val >>
                                        HZIP_SRAM_ECC_ERR_NUM_SHIFT) & 0xFF));
-                               dev_err(dev, "hisi-zip multi ecc sram addr=0x%x\n",
-                                       (err_val >>
-                                       HZIP_SRAM_ECC_ERR_ADDR_SHIFT));
                        }
                }
                err++;
@@ -729,7 +742,7 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip)
 
        hisi_zip_set_user_domain_and_cache(qm);
        hisi_qm_dev_err_init(qm);
-       hisi_zip_debug_regs_clear(hisi_zip);
+       hisi_zip_debug_regs_clear(qm);
 
        return 0;
 }
@@ -747,6 +760,7 @@ static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev)
        if (qm->fun_type == QM_HW_PF) {
                qm->qp_base = HZIP_PF_DEF_Q_BASE;
                qm->qp_num = pf_q_num;
+               qm->debug.curr_qm_qp_num = pf_q_num;
                qm->qm_list = &zip_devices;
        } else if (qm->fun_type == QM_HW_VF && qm->ver == QM_HW_V1) {
                /*
@@ -803,32 +817,44 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ret = hisi_qm_start(qm);
        if (ret)
-               goto err_qm_uninit;
+               goto err_dev_err_uninit;
 
-       ret = hisi_zip_debugfs_init(hisi_zip);
+       ret = hisi_zip_debugfs_init(qm);
        if (ret)
-               dev_err(&pdev->dev, "Failed to init debugfs (%d)!\n", ret);
+               pci_err(pdev, "failed to init debugfs (%d)!\n", ret);
 
-       hisi_qm_add_to_list(qm, &zip_devices);
+       ret = hisi_qm_alg_register(qm, &zip_devices);
+       if (ret < 0) {
+               pci_err(pdev, "failed to register driver to crypto!\n");
+               goto err_qm_stop;
+       }
 
        if (qm->uacce) {
                ret = uacce_register(qm->uacce);
-               if (ret)
-                       goto err_qm_uninit;
+               if (ret) {
+                       pci_err(pdev, "failed to register uacce (%d)!\n", ret);
+                       goto err_qm_alg_unregister;
+               }
        }
 
        if (qm->fun_type == QM_HW_PF && vfs_num > 0) {
                ret = hisi_qm_sriov_enable(pdev, vfs_num);
                if (ret < 0)
-                       goto err_remove_from_list;
+                       goto err_qm_alg_unregister;
        }
 
        return 0;
 
-err_remove_from_list:
-       hisi_qm_del_from_list(qm, &zip_devices);
-       hisi_zip_debugfs_exit(hisi_zip);
-       hisi_qm_stop(qm);
+err_qm_alg_unregister:
+       hisi_qm_alg_unregister(qm, &zip_devices);
+
+err_qm_stop:
+       hisi_zip_debugfs_exit(qm);
+       hisi_qm_stop(qm, QM_NORMAL);
+
+err_dev_err_uninit:
+       hisi_qm_dev_err_uninit(qm);
+
 err_qm_uninit:
        hisi_qm_uninit(qm);
 
@@ -837,18 +863,18 @@ err_qm_uninit:
 
 static void hisi_zip_remove(struct pci_dev *pdev)
 {
-       struct hisi_zip *hisi_zip = pci_get_drvdata(pdev);
-       struct hisi_qm *qm = &hisi_zip->qm;
+       struct hisi_qm *qm = pci_get_drvdata(pdev);
 
-       if (qm->fun_type == QM_HW_PF && qm->vfs_num)
-               hisi_qm_sriov_disable(pdev);
+       hisi_qm_wait_task_finish(qm, &zip_devices);
+       hisi_qm_alg_unregister(qm, &zip_devices);
 
-       hisi_zip_debugfs_exit(hisi_zip);
-       hisi_qm_stop(qm);
+       if (qm->fun_type == QM_HW_PF && qm->vfs_num)
+               hisi_qm_sriov_disable(pdev, qm->is_frozen);
 
+       hisi_zip_debugfs_exit(qm);
+       hisi_qm_stop(qm, QM_NORMAL);
        hisi_qm_dev_err_uninit(qm);
        hisi_qm_uninit(qm);
-       hisi_qm_del_from_list(qm, &zip_devices);
 }
 
 static const struct pci_error_handlers hisi_zip_err_handler = {
@@ -866,6 +892,7 @@ static struct pci_driver hisi_zip_pci_driver = {
        .sriov_configure        = IS_ENABLED(CONFIG_PCI_IOV) ?
                                        hisi_qm_sriov_configure : NULL,
        .err_handler            = &hisi_zip_err_handler,
+       .shutdown               = hisi_qm_dev_shutdown,
 };
 
 static void hisi_zip_register_debugfs(void)
@@ -890,29 +917,15 @@ static int __init hisi_zip_init(void)
 
        ret = pci_register_driver(&hisi_zip_pci_driver);
        if (ret < 0) {
+               hisi_zip_unregister_debugfs();
                pr_err("Failed to register pci driver.\n");
-               goto err_pci;
        }
 
-       ret = hisi_zip_register_to_crypto();
-       if (ret < 0) {
-               pr_err("Failed to register driver to crypto.\n");
-               goto err_crypto;
-       }
-
-       return 0;
-
-err_crypto:
-       pci_unregister_driver(&hisi_zip_pci_driver);
-err_pci:
-       hisi_zip_unregister_debugfs();
-
        return ret;
 }
 
 static void __exit hisi_zip_exit(void)
 {
-       hisi_zip_unregister_from_crypto();
        pci_unregister_driver(&hisi_zip_pci_driver);
        hisi_zip_unregister_debugfs();
 }
index 87226b7..91f555c 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
index fa7398e..eb24184 100644 (file)
@@ -304,6 +304,11 @@ static void eip197_init_firmware(struct safexcel_crypto_priv *priv)
                /* Enable access to all IFPP program memories */
                writel(EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN,
                       EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe));
+
+               /* bypass the OCE, if present */
+               if (priv->flags & EIP197_OCE)
+                       writel(EIP197_DEBUG_OCE_BYPASS, EIP197_PE(priv) +
+                                                       EIP197_PE_DEBUG(pe));
        }
 
 }
@@ -1495,6 +1500,9 @@ static int safexcel_probe_generic(void *pdev,
        hwopt = readl(EIP197_GLOBAL(priv) + EIP197_OPTIONS);
        hiaopt = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_OPTIONS);
 
+       priv->hwconfig.icever = 0;
+       priv->hwconfig.ocever = 0;
+       priv->hwconfig.psever = 0;
        if (priv->flags & SAFEXCEL_HW_EIP197) {
                /* EIP197 */
                peopt = readl(EIP197_PE(priv) + EIP197_PE_OPTIONS(0));
@@ -1513,8 +1521,37 @@ static int safexcel_probe_generic(void *pdev,
                                            EIP197_N_RINGS_MASK;
                if (hiaopt & EIP197_HIA_OPT_HAS_PE_ARB)
                        priv->flags |= EIP197_PE_ARB;
-               if (EIP206_OPT_ICE_TYPE(peopt) == 1)
+               if (EIP206_OPT_ICE_TYPE(peopt) == 1) {
                        priv->flags |= EIP197_ICE;
+                       /* Detect ICE EIP207 class. engine and version */
+                       version = readl(EIP197_PE(priv) +
+                                 EIP197_PE_ICE_VERSION(0));
+                       if (EIP197_REG_LO16(version) != EIP207_VERSION_LE) {
+                               dev_err(dev, "EIP%d: ICE EIP207 not detected.\n",
+                                       peid);
+                               return -ENODEV;
+                       }
+                       priv->hwconfig.icever = EIP197_VERSION_MASK(version);
+               }
+               if (EIP206_OPT_OCE_TYPE(peopt) == 1) {
+                       priv->flags |= EIP197_OCE;
+                       /* Detect EIP96PP packet stream editor and version */
+                       version = readl(EIP197_PE(priv) + EIP197_PE_PSE_VERSION(0));
+                       if (EIP197_REG_LO16(version) != EIP96_VERSION_LE) {
+                               dev_err(dev, "EIP%d: EIP96PP not detected.\n", peid);
+                               return -ENODEV;
+                       }
+                       priv->hwconfig.psever = EIP197_VERSION_MASK(version);
+                       /* Detect OCE EIP207 class. engine and version */
+                       version = readl(EIP197_PE(priv) +
+                                 EIP197_PE_ICE_VERSION(0));
+                       if (EIP197_REG_LO16(version) != EIP207_VERSION_LE) {
+                               dev_err(dev, "EIP%d: OCE EIP207 not detected.\n",
+                                       peid);
+                               return -ENODEV;
+                       }
+                       priv->hwconfig.ocever = EIP197_VERSION_MASK(version);
+               }
                /* If not a full TRC, then assume simple TRC */
                if (!(hwopt & EIP197_OPT_HAS_TRC))
                        priv->flags |= EIP197_SIMPLE_TRC;
@@ -1552,13 +1589,14 @@ static int safexcel_probe_generic(void *pdev,
                                    EIP197_PE_EIP96_OPTIONS(0));
 
        /* Print single info line describing what we just detected */
-       dev_info(priv->dev, "EIP%d:%x(%d,%d,%d,%d)-HIA:%x(%d,%d,%d),PE:%x/%x,alg:%08x\n",
+       dev_info(priv->dev, "EIP%d:%x(%d,%d,%d,%d)-HIA:%x(%d,%d,%d),PE:%x/%x(alg:%08x)/%x/%x/%x\n",
                 peid, priv->hwconfig.hwver, hwctg, priv->hwconfig.hwnumpes,
                 priv->hwconfig.hwnumrings, priv->hwconfig.hwnumraic,
                 priv->hwconfig.hiaver, priv->hwconfig.hwdataw,
                 priv->hwconfig.hwcfsize, priv->hwconfig.hwrfsize,
                 priv->hwconfig.ppver, priv->hwconfig.pever,
-                priv->hwconfig.algo_flags);
+                priv->hwconfig.algo_flags, priv->hwconfig.icever,
+                priv->hwconfig.ocever, priv->hwconfig.psever);
 
        safexcel_configure(priv);
 
index 7c5fe38..9045f2d 100644 (file)
@@ -12,7 +12,9 @@
 #include <crypto/algapi.h>
 #include <crypto/internal/hash.h>
 #include <crypto/sha.h>
+#include <crypto/sha3.h>
 #include <crypto/skcipher.h>
+#include <linux/types.h>
 
 #define EIP197_HIA_VERSION_BE                  0xca35
 #define EIP197_HIA_VERSION_LE                  0x35ca
@@ -22,6 +24,7 @@
 #define EIP96_VERSION_LE                       0x9f60
 #define EIP201_VERSION_LE                      0x36c9
 #define EIP206_VERSION_LE                      0x31ce
+#define EIP207_VERSION_LE                      0x30cf
 #define EIP197_REG_LO16(reg)                   (reg & 0xffff)
 #define EIP197_REG_HI16(reg)                   ((reg >> 16) & 0xffff)
 #define EIP197_VERSION_MASK(reg)               ((reg >> 16) & 0xfff)
@@ -34,6 +37,7 @@
 
 /* EIP206 OPTIONS ENCODING */
 #define EIP206_OPT_ICE_TYPE(n)                 ((n>>8)&3)
+#define EIP206_OPT_OCE_TYPE(n)                 ((n>>10)&3)
 
 /* EIP197 OPTIONS ENCODING */
 #define EIP197_OPT_HAS_TRC                     BIT(31)
 #define EIP197_PE_ICE_FPP_CTRL(n)              (0x0d80 + (0x2000 * (n)))
 #define EIP197_PE_ICE_PPTF_CTRL(n)             (0x0e00 + (0x2000 * (n)))
 #define EIP197_PE_ICE_RAM_CTRL(n)              (0x0ff0 + (0x2000 * (n)))
+#define EIP197_PE_ICE_VERSION(n)               (0x0ffc + (0x2000 * (n)))
 #define EIP197_PE_EIP96_TOKEN_CTRL(n)          (0x1000 + (0x2000 * (n)))
 #define EIP197_PE_EIP96_FUNCTION_EN(n)         (0x1004 + (0x2000 * (n)))
 #define EIP197_PE_EIP96_CONTEXT_CTRL(n)                (0x1008 + (0x2000 * (n)))
 #define EIP197_PE_EIP96_FUNCTION2_EN(n)                (0x1030 + (0x2000 * (n)))
 #define EIP197_PE_EIP96_OPTIONS(n)             (0x13f8 + (0x2000 * (n)))
 #define EIP197_PE_EIP96_VERSION(n)             (0x13fc + (0x2000 * (n)))
+#define EIP197_PE_OCE_VERSION(n)               (0x1bfc + (0x2000 * (n)))
 #define EIP197_PE_OUT_DBUF_THRES(n)            (0x1c00 + (0x2000 * (n)))
 #define EIP197_PE_OUT_TBUF_THRES(n)            (0x1d00 + (0x2000 * (n)))
+#define EIP197_PE_PSE_VERSION(n)               (0x1efc + (0x2000 * (n)))
+#define EIP197_PE_DEBUG(n)                     (0x1ff4 + (0x2000 * (n)))
 #define EIP197_PE_OPTIONS(n)                   (0x1ff8 + (0x2000 * (n)))
 #define EIP197_PE_VERSION(n)                   (0x1ffc + (0x2000 * (n)))
 #define EIP197_MST_CTRL                                0xfff4
 /* EIP197_PE_EIP96_TOKEN_CTRL2 */
 #define EIP197_PE_EIP96_TOKEN_CTRL2_CTX_DONE   BIT(3)
 
+/* EIP197_PE_DEBUG */
+#define EIP197_DEBUG_OCE_BYPASS                        BIT(1)
+
 /* EIP197_STRC_CONFIG */
 #define EIP197_STRC_CONFIG_INIT                        BIT(31)
 #define EIP197_STRC_CONFIG_LARGE_REC(s)                (s<<8)
@@ -776,6 +787,7 @@ enum safexcel_flags {
        EIP197_PE_ARB           = BIT(2),
        EIP197_ICE              = BIT(3),
        EIP197_SIMPLE_TRC       = BIT(4),
+       EIP197_OCE              = BIT(5),
 };
 
 struct safexcel_hwconfig {
@@ -783,7 +795,10 @@ struct safexcel_hwconfig {
        int hwver;
        int hiaver;
        int ppver;
+       int icever;
        int pever;
+       int ocever;
+       int psever;
        int hwdataw;
        int hwcfsize;
        int hwrfsize;
@@ -819,8 +834,16 @@ struct safexcel_context {
                             struct crypto_async_request *req, bool *complete,
                             int *ret);
        struct safexcel_context_record *ctxr;
+       struct safexcel_crypto_priv *priv;
        dma_addr_t ctxr_dma;
 
+       union {
+               __le32 le[SHA3_512_BLOCK_SIZE / 4];
+               __be32 be[SHA3_512_BLOCK_SIZE / 4];
+               u32 word[SHA3_512_BLOCK_SIZE / 4];
+               u8 byte[SHA3_512_BLOCK_SIZE];
+       } ipad, opad;
+
        int ring;
        bool needs_inv;
        bool exit_inv;
@@ -898,8 +921,9 @@ void safexcel_rdr_req_set(struct safexcel_crypto_priv *priv,
 inline struct crypto_async_request *
 safexcel_rdr_req_get(struct safexcel_crypto_priv *priv, int ring);
 void safexcel_inv_complete(struct crypto_async_request *req, int error);
-int safexcel_hmac_setkey(const char *alg, const u8 *key, unsigned int keylen,
-                        void *istate, void *ostate);
+int safexcel_hmac_setkey(struct safexcel_context *base, const u8 *key,
+                        unsigned int keylen, const char *alg,
+                        unsigned int state_sz);
 
 /* available algorithms */
 extern struct safexcel_alg_template safexcel_alg_ecb_des;
index 1ac3253..9bcfb79 100644 (file)
@@ -61,8 +61,6 @@ struct safexcel_cipher_ctx {
        /* All the below is AEAD specific */
        u32 hash_alg;
        u32 state_sz;
-       __be32 ipad[SHA512_DIGEST_SIZE / sizeof(u32)];
-       __be32 opad[SHA512_DIGEST_SIZE / sizeof(u32)];
 
        struct crypto_cipher *hkaes;
        struct crypto_aead *fback;
@@ -375,7 +373,7 @@ static int safexcel_skcipher_aes_setkey(struct crypto_skcipher *ctfm,
 {
        struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm);
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        struct crypto_aes_ctx aes;
        int ret, i;
 
@@ -406,11 +404,11 @@ static int safexcel_aead_setkey(struct crypto_aead *ctfm, const u8 *key,
 {
        struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_ahash_export_state istate, ostate;
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        struct crypto_authenc_keys keys;
        struct crypto_aes_ctx aes;
        int err = -EINVAL, i;
+       const char *alg;
 
        if (unlikely(crypto_authenc_extractkeys(&keys, key, len)))
                goto badkey;
@@ -465,53 +463,37 @@ static int safexcel_aead_setkey(struct crypto_aead *ctfm, const u8 *key,
        /* Auth key */
        switch (ctx->hash_alg) {
        case CONTEXT_CONTROL_CRYPTO_ALG_SHA1:
-               if (safexcel_hmac_setkey("safexcel-sha1", keys.authkey,
-                                        keys.authkeylen, &istate, &ostate))
-                       goto badkey;
+               alg = "safexcel-sha1";
                break;
        case CONTEXT_CONTROL_CRYPTO_ALG_SHA224:
-               if (safexcel_hmac_setkey("safexcel-sha224", keys.authkey,
-                                        keys.authkeylen, &istate, &ostate))
-                       goto badkey;
+               alg = "safexcel-sha224";
                break;
        case CONTEXT_CONTROL_CRYPTO_ALG_SHA256:
-               if (safexcel_hmac_setkey("safexcel-sha256", keys.authkey,
-                                        keys.authkeylen, &istate, &ostate))
-                       goto badkey;
+               alg = "safexcel-sha256";
                break;
        case CONTEXT_CONTROL_CRYPTO_ALG_SHA384:
-               if (safexcel_hmac_setkey("safexcel-sha384", keys.authkey,
-                                        keys.authkeylen, &istate, &ostate))
-                       goto badkey;
+               alg = "safexcel-sha384";
                break;
        case CONTEXT_CONTROL_CRYPTO_ALG_SHA512:
-               if (safexcel_hmac_setkey("safexcel-sha512", keys.authkey,
-                                        keys.authkeylen, &istate, &ostate))
-                       goto badkey;
+               alg = "safexcel-sha512";
                break;
        case CONTEXT_CONTROL_CRYPTO_ALG_SM3:
-               if (safexcel_hmac_setkey("safexcel-sm3", keys.authkey,
-                                        keys.authkeylen, &istate, &ostate))
-                       goto badkey;
+               alg = "safexcel-sm3";
                break;
        default:
                dev_err(priv->dev, "aead: unsupported hash algorithm\n");
                goto badkey;
        }
 
-       if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma &&
-           (memcmp(ctx->ipad, istate.state, ctx->state_sz) ||
-            memcmp(ctx->opad, ostate.state, ctx->state_sz)))
-               ctx->base.needs_inv = true;
+       if (safexcel_hmac_setkey(&ctx->base, keys.authkey, keys.authkeylen,
+                                alg, ctx->state_sz))
+               goto badkey;
 
        /* Now copy the keys into the context */
        for (i = 0; i < keys.enckeylen / sizeof(u32); i++)
                ctx->key[i] = cpu_to_le32(((u32 *)keys.enckey)[i]);
        ctx->key_len = keys.enckeylen;
 
-       memcpy(ctx->ipad, &istate.state, ctx->state_sz);
-       memcpy(ctx->opad, &ostate.state, ctx->state_sz);
-
        memzero_explicit(&keys, sizeof(keys));
        return 0;
 
@@ -525,7 +507,7 @@ static int safexcel_context_control(struct safexcel_cipher_ctx *ctx,
                                    struct safexcel_cipher_req *sreq,
                                    struct safexcel_command_desc *cdesc)
 {
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ctrl_size = ctx->key_len / sizeof(u32);
 
        cdesc->control_data.control1 = ctx->mode;
@@ -692,7 +674,7 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring,
        struct skcipher_request *areq = skcipher_request_cast(base);
        struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(areq);
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        struct safexcel_command_desc *cdesc;
        struct safexcel_command_desc *first_cdesc = NULL;
        struct safexcel_result_desc *rdesc, *first_rdesc = NULL;
@@ -718,10 +700,10 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring,
                        totlen_dst += digestsize;
 
                memcpy(ctx->base.ctxr->data + ctx->key_len / sizeof(u32),
-                      ctx->ipad, ctx->state_sz);
+                      &ctx->base.ipad, ctx->state_sz);
                if (!ctx->xcm)
                        memcpy(ctx->base.ctxr->data + (ctx->key_len +
-                              ctx->state_sz) / sizeof(u32), ctx->opad,
+                              ctx->state_sz) / sizeof(u32), &ctx->base.opad,
                               ctx->state_sz);
        } else if ((ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) &&
                   (sreq->direction == SAFEXCEL_DECRYPT)) {
@@ -1020,7 +1002,7 @@ static int safexcel_cipher_send_inv(struct crypto_async_request *base,
                                    int ring, int *commands, int *results)
 {
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ret;
 
        ret = safexcel_invalidate_cache(base, priv, ctx->base.ctxr_dma, ring);
@@ -1039,7 +1021,7 @@ static int safexcel_skcipher_send(struct crypto_async_request *async, int ring,
        struct skcipher_request *req = skcipher_request_cast(async);
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
        struct safexcel_cipher_req *sreq = skcipher_request_ctx(req);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ret;
 
        BUG_ON(!(priv->flags & EIP197_TRC_CACHE) && sreq->needs_inv);
@@ -1072,7 +1054,7 @@ static int safexcel_aead_send(struct crypto_async_request *async, int ring,
        struct crypto_aead *tfm = crypto_aead_reqtfm(req);
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
        struct safexcel_cipher_req *sreq = aead_request_ctx(req);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ret;
 
        BUG_ON(!(priv->flags & EIP197_TRC_CACHE) && sreq->needs_inv);
@@ -1094,7 +1076,7 @@ static int safexcel_cipher_exit_inv(struct crypto_tfm *tfm,
                                    struct safexcel_inv_result *result)
 {
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ring = ctx->base.ring;
 
        init_completion(&result->completion);
@@ -1157,7 +1139,7 @@ static int safexcel_queue_req(struct crypto_async_request *base,
                        enum safexcel_cipher_direction dir)
 {
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ret, ring;
 
        sreq->needs_inv = false;
@@ -1211,7 +1193,7 @@ static int safexcel_skcipher_cra_init(struct crypto_tfm *tfm)
        crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm),
                                    sizeof(struct safexcel_cipher_req));
 
-       ctx->priv = tmpl->priv;
+       ctx->base.priv = tmpl->priv;
 
        ctx->base.send = safexcel_skcipher_send;
        ctx->base.handle_result = safexcel_skcipher_handle_result;
@@ -1237,7 +1219,7 @@ static int safexcel_cipher_cra_exit(struct crypto_tfm *tfm)
 static void safexcel_skcipher_cra_exit(struct crypto_tfm *tfm)
 {
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ret;
 
        if (safexcel_cipher_cra_exit(tfm))
@@ -1257,7 +1239,7 @@ static void safexcel_skcipher_cra_exit(struct crypto_tfm *tfm)
 static void safexcel_aead_cra_exit(struct crypto_tfm *tfm)
 {
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ret;
 
        if (safexcel_cipher_cra_exit(tfm))
@@ -1431,7 +1413,7 @@ static int safexcel_skcipher_aesctr_setkey(struct crypto_skcipher *ctfm,
 {
        struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm);
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        struct crypto_aes_ctx aes;
        int ret, i;
        unsigned int keylen;
@@ -1505,7 +1487,7 @@ static int safexcel_des_setkey(struct crypto_skcipher *ctfm, const u8 *key,
                               unsigned int len)
 {
        struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(ctfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ret;
 
        ret = verify_skcipher_des_key(ctfm, key);
@@ -1604,7 +1586,7 @@ static int safexcel_des3_ede_setkey(struct crypto_skcipher *ctfm,
                                   const u8 *key, unsigned int len)
 {
        struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(ctfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int err;
 
        err = verify_skcipher_des3_key(ctfm, key);
@@ -1723,7 +1705,7 @@ static int safexcel_aead_cra_init(struct crypto_tfm *tfm)
        crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
                                sizeof(struct safexcel_cipher_req));
 
-       ctx->priv = tmpl->priv;
+       ctx->base.priv = tmpl->priv;
 
        ctx->alg  = SAFEXCEL_AES; /* default */
        ctx->blocksz = AES_BLOCK_SIZE;
@@ -2466,7 +2448,7 @@ static int safexcel_skcipher_aesxts_setkey(struct crypto_skcipher *ctfm,
 {
        struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm);
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        struct crypto_aes_ctx aes;
        int ret, i;
        unsigned int keylen;
@@ -2580,7 +2562,7 @@ static int safexcel_aead_gcm_setkey(struct crypto_aead *ctfm, const u8 *key,
 {
        struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        struct crypto_aes_ctx aes;
        u32 hashkey[AES_BLOCK_SIZE >> 2];
        int ret, i;
@@ -2618,7 +2600,7 @@ static int safexcel_aead_gcm_setkey(struct crypto_aead *ctfm, const u8 *key,
 
        if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
                for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++) {
-                       if (be32_to_cpu(ctx->ipad[i]) != hashkey[i]) {
+                       if (be32_to_cpu(ctx->base.ipad.be[i]) != hashkey[i]) {
                                ctx->base.needs_inv = true;
                                break;
                        }
@@ -2626,7 +2608,7 @@ static int safexcel_aead_gcm_setkey(struct crypto_aead *ctfm, const u8 *key,
        }
 
        for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++)
-               ctx->ipad[i] = cpu_to_be32(hashkey[i]);
+               ctx->base.ipad.be[i] = cpu_to_be32(hashkey[i]);
 
        memzero_explicit(hashkey, AES_BLOCK_SIZE);
        memzero_explicit(&aes, sizeof(aes));
@@ -2693,7 +2675,7 @@ static int safexcel_aead_ccm_setkey(struct crypto_aead *ctfm, const u8 *key,
 {
        struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        struct crypto_aes_ctx aes;
        int ret, i;
 
@@ -2714,7 +2696,7 @@ static int safexcel_aead_ccm_setkey(struct crypto_aead *ctfm, const u8 *key,
 
        for (i = 0; i < len / sizeof(u32); i++) {
                ctx->key[i] = cpu_to_le32(aes.key_enc[i]);
-               ctx->ipad[i + 2 * AES_BLOCK_SIZE / sizeof(u32)] =
+               ctx->base.ipad.be[i + 2 * AES_BLOCK_SIZE / sizeof(u32)] =
                        cpu_to_be32(aes.key_enc[i]);
        }
 
@@ -2815,7 +2797,7 @@ struct safexcel_alg_template safexcel_alg_ccm = {
 static void safexcel_chacha20_setkey(struct safexcel_cipher_ctx *ctx,
                                     const u8 *key)
 {
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
 
        if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma)
                if (memcmp(ctx->key, key, CHACHA_KEY_SIZE))
@@ -3084,7 +3066,7 @@ static int safexcel_skcipher_sm4_setkey(struct crypto_skcipher *ctfm,
 {
        struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm);
        struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
 
        if (len != SM4_KEY_SIZE)
                return -EINVAL;
index 16a4679..56d5ccb 100644 (file)
@@ -20,7 +20,6 @@
 
 struct safexcel_ahash_ctx {
        struct safexcel_context base;
-       struct safexcel_crypto_priv *priv;
 
        u32 alg;
        u8  key_sz;
@@ -29,9 +28,6 @@ struct safexcel_ahash_ctx {
        bool fb_init_done;
        bool fb_do_setkey;
 
-       __le32 ipad[SHA3_512_BLOCK_SIZE / sizeof(__le32)];
-       __le32 opad[SHA3_512_BLOCK_SIZE / sizeof(__le32)];
-
        struct crypto_cipher *kaes;
        struct crypto_ahash *fback;
        struct crypto_shash *shpre;
@@ -111,7 +107,7 @@ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx,
                                     struct safexcel_ahash_req *req,
                                     struct safexcel_command_desc *cdesc)
 {
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        u64 count = 0;
 
        cdesc->control_data.control0 = ctx->alg;
@@ -124,7 +120,7 @@ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx,
         */
        if (unlikely(req->digest == CONTEXT_CONTROL_DIGEST_XCM)) {
                if (req->xcbcmac)
-                       memcpy(ctx->base.ctxr->data, ctx->ipad, ctx->key_sz);
+                       memcpy(ctx->base.ctxr->data, &ctx->base.ipad, ctx->key_sz);
                else
                        memcpy(ctx->base.ctxr->data, req->state, req->state_sz);
 
@@ -206,7 +202,7 @@ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx,
                } else { /* HMAC */
                        /* Need outer digest for HMAC finalization */
                        memcpy(ctx->base.ctxr->data + (req->state_sz >> 2),
-                              ctx->opad, req->state_sz);
+                              &ctx->base.opad, req->state_sz);
 
                        /* Single pass HMAC - no digest count */
                        cdesc->control_data.control0 |=
@@ -275,7 +271,7 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv,
                        memcpy(sreq->cache, sreq->state,
                               crypto_ahash_digestsize(ahash));
 
-                       memcpy(sreq->state, ctx->opad, sreq->digest_sz);
+                       memcpy(sreq->state, &ctx->base.opad, sreq->digest_sz);
 
                        sreq->len = sreq->block_sz +
                                    crypto_ahash_digestsize(ahash);
@@ -316,7 +312,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring,
        struct ahash_request *areq = ahash_request_cast(async);
        struct safexcel_ahash_req *req = ahash_request_ctx(areq);
        struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        struct safexcel_command_desc *cdesc, *first_cdesc = NULL;
        struct safexcel_result_desc *rdesc;
        struct scatterlist *sg;
@@ -379,10 +375,14 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring,
                                // 10- padding for XCBCMAC & CMAC
                                req->cache[cache_len + skip] = 0x80;
                                // HW will use K2 iso K3 - compensate!
-                               for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++)
-                                       ((__be32 *)req->cache)[i] ^=
-                                         cpu_to_be32(le32_to_cpu(
-                                           ctx->ipad[i] ^ ctx->ipad[i + 4]));
+                               for (i = 0; i < AES_BLOCK_SIZE / 4; i++) {
+                                       u32 *cache = (void *)req->cache;
+                                       u32 *ipad = ctx->base.ipad.word;
+                                       u32 x;
+
+                                       x = ipad[i] ^ ipad[i + 4];
+                                       cache[i] ^= swab(x);
+                               }
                        }
                        cache_len = AES_BLOCK_SIZE;
                        queued = queued + extra;
@@ -591,7 +591,7 @@ static int safexcel_ahash_send_inv(struct crypto_async_request *async,
        struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
        int ret;
 
-       ret = safexcel_invalidate_cache(async, ctx->priv,
+       ret = safexcel_invalidate_cache(async, ctx->base.priv,
                                        ctx->base.ctxr_dma, ring);
        if (unlikely(ret))
                return ret;
@@ -620,7 +620,7 @@ static int safexcel_ahash_send(struct crypto_async_request *async,
 static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm)
 {
        struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        EIP197_REQUEST_ON_STACK(req, ahash, EIP197_AHASH_REQ_SIZE);
        struct safexcel_ahash_req *rctx = ahash_request_ctx(req);
        struct safexcel_inv_result result = {};
@@ -688,7 +688,7 @@ static int safexcel_ahash_enqueue(struct ahash_request *areq)
 {
        struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
        struct safexcel_ahash_req *req = ahash_request_ctx(areq);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ret, ring;
 
        req->needs_inv = false;
@@ -702,7 +702,7 @@ static int safexcel_ahash_enqueue(struct ahash_request *areq)
                     /* invalidate for HMAC finish with odigest changed */
                     (req->finish && req->hmac &&
                      memcmp(ctx->base.ctxr->data + (req->state_sz>>2),
-                            ctx->opad, req->state_sz))))
+                            &ctx->base.opad, req->state_sz))))
                        /*
                         * We're still setting needs_inv here, even though it is
                         * cleared right away, because the needs_inv flag can be
@@ -803,7 +803,7 @@ static int safexcel_ahash_final(struct ahash_request *areq)
                            ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_MD5 &&
                            req->len == sizeof(u32) && !areq->nbytes)) {
                /* Zero length CRC32 */
-               memcpy(areq->result, ctx->ipad, sizeof(u32));
+               memcpy(areq->result, &ctx->base.ipad, sizeof(u32));
                return 0;
        } else if (unlikely(ctx->cbcmac && req->len == AES_BLOCK_SIZE &&
                            !areq->nbytes)) {
@@ -815,9 +815,12 @@ static int safexcel_ahash_final(struct ahash_request *areq)
                /* Zero length (X)CBC/CMAC */
                int i;
 
-               for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++)
-                       ((__be32 *)areq->result)[i] =
-                               cpu_to_be32(le32_to_cpu(ctx->ipad[i + 4]));//K3
+               for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++) {
+                       u32 *result = (void *)areq->result;
+
+                       /* K3 */
+                       result[i] = swab(ctx->base.ipad.word[i + 4]);
+               }
                areq->result[0] ^= 0x80;                        // 10- padding
                crypto_cipher_encrypt_one(ctx->kaes, areq->result, areq->result);
                return 0;
@@ -917,7 +920,7 @@ static int safexcel_ahash_cra_init(struct crypto_tfm *tfm)
                container_of(__crypto_ahash_alg(tfm->__crt_alg),
                             struct safexcel_alg_template, alg.ahash);
 
-       ctx->priv = tmpl->priv;
+       ctx->base.priv = tmpl->priv;
        ctx->base.send = safexcel_ahash_send;
        ctx->base.handle_result = safexcel_handle_result;
        ctx->fb_do_setkey = false;
@@ -956,7 +959,7 @@ static int safexcel_sha1_digest(struct ahash_request *areq)
 static void safexcel_ahash_cra_exit(struct crypto_tfm *tfm)
 {
        struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = ctx->base.priv;
        int ret;
 
        /* context not allocated, skip invalidation */
@@ -1012,7 +1015,7 @@ static int safexcel_hmac_sha1_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Start from ipad precompute */
-       memcpy(req->state, ctx->ipad, SHA1_DIGEST_SIZE);
+       memcpy(req->state, &ctx->base.ipad, SHA1_DIGEST_SIZE);
        /* Already processed the key^ipad part now! */
        req->len        = SHA1_BLOCK_SIZE;
        req->processed  = SHA1_BLOCK_SIZE;
@@ -1082,8 +1085,7 @@ static int safexcel_hmac_init_pad(struct ahash_request *areq,
                }
 
                /* Avoid leaking */
-               memzero_explicit(keydup, keylen);
-               kfree(keydup);
+               kfree_sensitive(keydup);
 
                if (ret)
                        return ret;
@@ -1135,8 +1137,9 @@ static int safexcel_hmac_init_iv(struct ahash_request *areq,
        return crypto_ahash_export(areq, state);
 }
 
-int safexcel_hmac_setkey(const char *alg, const u8 *key, unsigned int keylen,
-                        void *istate, void *ostate)
+static int __safexcel_hmac_setkey(const char *alg, const u8 *key,
+                                 unsigned int keylen,
+                                 void *istate, void *ostate)
 {
        struct ahash_request *areq;
        struct crypto_ahash *tfm;
@@ -1185,30 +1188,38 @@ free_ahash:
        return ret;
 }
 
-static int safexcel_hmac_alg_setkey(struct crypto_ahash *tfm, const u8 *key,
-                                   unsigned int keylen, const char *alg,
-                                   unsigned int state_sz)
+int safexcel_hmac_setkey(struct safexcel_context *base, const u8 *key,
+                        unsigned int keylen, const char *alg,
+                        unsigned int state_sz)
 {
-       struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
-       struct safexcel_crypto_priv *priv = ctx->priv;
+       struct safexcel_crypto_priv *priv = base->priv;
        struct safexcel_ahash_export_state istate, ostate;
        int ret;
 
-       ret = safexcel_hmac_setkey(alg, key, keylen, &istate, &ostate);
+       ret = __safexcel_hmac_setkey(alg, key, keylen, &istate, &ostate);
        if (ret)
                return ret;
 
-       if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr &&
-           (memcmp(ctx->ipad, istate.state, state_sz) ||
-            memcmp(ctx->opad, ostate.state, state_sz)))
-               ctx->base.needs_inv = true;
+       if (priv->flags & EIP197_TRC_CACHE && base->ctxr &&
+           (memcmp(&base->ipad, istate.state, state_sz) ||
+            memcmp(&base->opad, ostate.state, state_sz)))
+               base->needs_inv = true;
 
-       memcpy(ctx->ipad, &istate.state, state_sz);
-       memcpy(ctx->opad, &ostate.state, state_sz);
+       memcpy(&base->ipad, &istate.state, state_sz);
+       memcpy(&base->opad, &ostate.state, state_sz);
 
        return 0;
 }
 
+static int safexcel_hmac_alg_setkey(struct crypto_ahash *tfm, const u8 *key,
+                                   unsigned int keylen, const char *alg,
+                                   unsigned int state_sz)
+{
+       struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+       return safexcel_hmac_setkey(&ctx->base, key, keylen, alg, state_sz);
+}
+
 static int safexcel_hmac_sha1_setkey(struct crypto_ahash *tfm, const u8 *key,
                                     unsigned int keylen)
 {
@@ -1377,7 +1388,7 @@ static int safexcel_hmac_sha224_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Start from ipad precompute */
-       memcpy(req->state, ctx->ipad, SHA256_DIGEST_SIZE);
+       memcpy(req->state, &ctx->base.ipad, SHA256_DIGEST_SIZE);
        /* Already processed the key^ipad part now! */
        req->len        = SHA256_BLOCK_SIZE;
        req->processed  = SHA256_BLOCK_SIZE;
@@ -1449,7 +1460,7 @@ static int safexcel_hmac_sha256_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Start from ipad precompute */
-       memcpy(req->state, ctx->ipad, SHA256_DIGEST_SIZE);
+       memcpy(req->state, &ctx->base.ipad, SHA256_DIGEST_SIZE);
        /* Already processed the key^ipad part now! */
        req->len        = SHA256_BLOCK_SIZE;
        req->processed  = SHA256_BLOCK_SIZE;
@@ -1635,7 +1646,7 @@ static int safexcel_hmac_sha512_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Start from ipad precompute */
-       memcpy(req->state, ctx->ipad, SHA512_DIGEST_SIZE);
+       memcpy(req->state, &ctx->base.ipad, SHA512_DIGEST_SIZE);
        /* Already processed the key^ipad part now! */
        req->len        = SHA512_BLOCK_SIZE;
        req->processed  = SHA512_BLOCK_SIZE;
@@ -1707,7 +1718,7 @@ static int safexcel_hmac_sha384_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Start from ipad precompute */
-       memcpy(req->state, ctx->ipad, SHA512_DIGEST_SIZE);
+       memcpy(req->state, &ctx->base.ipad, SHA512_DIGEST_SIZE);
        /* Already processed the key^ipad part now! */
        req->len        = SHA512_BLOCK_SIZE;
        req->processed  = SHA512_BLOCK_SIZE;
@@ -1829,7 +1840,7 @@ static int safexcel_hmac_md5_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Start from ipad precompute */
-       memcpy(req->state, ctx->ipad, MD5_DIGEST_SIZE);
+       memcpy(req->state, &ctx->base.ipad, MD5_DIGEST_SIZE);
        /* Already processed the key^ipad part now! */
        req->len        = MD5_HMAC_BLOCK_SIZE;
        req->processed  = MD5_HMAC_BLOCK_SIZE;
@@ -1900,7 +1911,7 @@ static int safexcel_crc32_cra_init(struct crypto_tfm *tfm)
        int ret = safexcel_ahash_cra_init(tfm);
 
        /* Default 'key' is all zeroes */
-       memset(ctx->ipad, 0, sizeof(u32));
+       memset(&ctx->base.ipad, 0, sizeof(u32));
        return ret;
 }
 
@@ -1912,7 +1923,7 @@ static int safexcel_crc32_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Start from loaded key */
-       req->state[0]   = (__force __le32)le32_to_cpu(~ctx->ipad[0]);
+       req->state[0]   = cpu_to_le32(~ctx->base.ipad.word[0]);
        /* Set processed to non-zero to enable invalidation detection */
        req->len        = sizeof(u32);
        req->processed  = sizeof(u32);
@@ -1934,7 +1945,7 @@ static int safexcel_crc32_setkey(struct crypto_ahash *tfm, const u8 *key,
        if (keylen != sizeof(u32))
                return -EINVAL;
 
-       memcpy(ctx->ipad, key, sizeof(u32));
+       memcpy(&ctx->base.ipad, key, sizeof(u32));
        return 0;
 }
 
@@ -1984,7 +1995,7 @@ static int safexcel_cbcmac_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Start from loaded keys */
-       memcpy(req->state, ctx->ipad, ctx->key_sz);
+       memcpy(req->state, &ctx->base.ipad, ctx->key_sz);
        /* Set processed to non-zero to enable invalidation detection */
        req->len        = AES_BLOCK_SIZE;
        req->processed  = AES_BLOCK_SIZE;
@@ -2009,9 +2020,9 @@ static int safexcel_cbcmac_setkey(struct crypto_ahash *tfm, const u8 *key,
        if (ret)
                return ret;
 
-       memset(ctx->ipad, 0, 2 * AES_BLOCK_SIZE);
+       memset(&ctx->base.ipad, 0, 2 * AES_BLOCK_SIZE);
        for (i = 0; i < len / sizeof(u32); i++)
-               ctx->ipad[i + 8] = (__force __le32)cpu_to_be32(aes.key_enc[i]);
+               ctx->base.ipad.be[i + 8] = cpu_to_be32(aes.key_enc[i]);
 
        if (len == AES_KEYSIZE_192) {
                ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC192;
@@ -2093,8 +2104,7 @@ static int safexcel_xcbcmac_setkey(struct crypto_ahash *tfm, const u8 *key,
        crypto_cipher_encrypt_one(ctx->kaes, (u8 *)key_tmp + AES_BLOCK_SIZE,
                "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3");
        for (i = 0; i < 3 * AES_BLOCK_SIZE / sizeof(u32); i++)
-               ctx->ipad[i] =
-                       cpu_to_le32((__force u32)cpu_to_be32(key_tmp[i]));
+               ctx->base.ipad.word[i] = swab(key_tmp[i]);
 
        crypto_cipher_clear_flags(ctx->kaes, CRYPTO_TFM_REQ_MASK);
        crypto_cipher_set_flags(ctx->kaes, crypto_ahash_get_flags(tfm) &
@@ -2177,8 +2187,7 @@ static int safexcel_cmac_setkey(struct crypto_ahash *tfm, const u8 *key,
                return ret;
 
        for (i = 0; i < len / sizeof(u32); i++)
-               ctx->ipad[i + 8] =
-                       cpu_to_le32((__force u32)cpu_to_be32(aes.key_enc[i]));
+               ctx->base.ipad.word[i + 8] = swab(aes.key_enc[i]);
 
        /* precompute the CMAC key material */
        crypto_cipher_clear_flags(ctx->kaes, CRYPTO_TFM_REQ_MASK);
@@ -2209,7 +2218,7 @@ static int safexcel_cmac_setkey(struct crypto_ahash *tfm, const u8 *key,
        /* end of code borrowed from crypto/cmac.c */
 
        for (i = 0; i < 2 * AES_BLOCK_SIZE / sizeof(u32); i++)
-               ctx->ipad[i] = (__force __le32)cpu_to_be32(((u32 *)consts)[i]);
+               ctx->base.ipad.be[i] = cpu_to_be32(((u32 *)consts)[i]);
 
        if (len == AES_KEYSIZE_192) {
                ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC192;
@@ -2331,7 +2340,7 @@ static int safexcel_hmac_sm3_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Start from ipad precompute */
-       memcpy(req->state, ctx->ipad, SM3_DIGEST_SIZE);
+       memcpy(req->state, &ctx->base.ipad, SM3_DIGEST_SIZE);
        /* Already processed the key^ipad part now! */
        req->len        = SM3_BLOCK_SIZE;
        req->processed  = SM3_BLOCK_SIZE;
@@ -2424,11 +2433,11 @@ static int safexcel_sha3_fbcheck(struct ahash_request *req)
                                /* Set fallback cipher HMAC key */
                                u8 key[SHA3_224_BLOCK_SIZE];
 
-                               memcpy(key, ctx->ipad,
+                               memcpy(key, &ctx->base.ipad,
                                       crypto_ahash_blocksize(ctx->fback) / 2);
                                memcpy(key +
                                       crypto_ahash_blocksize(ctx->fback) / 2,
-                                      ctx->opad,
+                                      &ctx->base.opad,
                                       crypto_ahash_blocksize(ctx->fback) / 2);
                                ret = crypto_ahash_setkey(ctx->fback, key,
                                        crypto_ahash_blocksize(ctx->fback));
@@ -2801,7 +2810,7 @@ static int safexcel_hmac_sha3_setkey(struct crypto_ahash *tfm, const u8 *key,
                 * first using our fallback cipher
                 */
                ret = crypto_shash_digest(ctx->shdesc, key, keylen,
-                                         (u8 *)ctx->ipad);
+                                         ctx->base.ipad.byte);
                keylen = crypto_shash_digestsize(ctx->shpre);
 
                /*
@@ -2810,8 +2819,8 @@ static int safexcel_hmac_sha3_setkey(struct crypto_ahash *tfm, const u8 *key,
                 */
                if (keylen > crypto_ahash_blocksize(tfm) / 2)
                        /* Buffers overlap, need to use memmove iso memcpy! */
-                       memmove(ctx->opad,
-                               (u8 *)ctx->ipad +
+                       memmove(&ctx->base.opad,
+                               ctx->base.ipad.byte +
                                        crypto_ahash_blocksize(tfm) / 2,
                                keylen - crypto_ahash_blocksize(tfm) / 2);
        } else {
@@ -2821,11 +2830,11 @@ static int safexcel_hmac_sha3_setkey(struct crypto_ahash *tfm, const u8 *key,
                 * to match the existing HMAC driver infrastructure.
                 */
                if (keylen <= crypto_ahash_blocksize(tfm) / 2) {
-                       memcpy(ctx->ipad, key, keylen);
+                       memcpy(&ctx->base.ipad, key, keylen);
                } else {
-                       memcpy(ctx->ipad, key,
+                       memcpy(&ctx->base.ipad, key,
                               crypto_ahash_blocksize(tfm) / 2);
-                       memcpy(ctx->opad,
+                       memcpy(&ctx->base.opad,
                               key + crypto_ahash_blocksize(tfm) / 2,
                               keylen - crypto_ahash_blocksize(tfm) / 2);
                }
@@ -2833,11 +2842,11 @@ static int safexcel_hmac_sha3_setkey(struct crypto_ahash *tfm, const u8 *key,
 
        /* Pad key with zeroes */
        if (keylen <= crypto_ahash_blocksize(tfm) / 2) {
-               memset((u8 *)ctx->ipad + keylen, 0,
+               memset(ctx->base.ipad.byte + keylen, 0,
                       crypto_ahash_blocksize(tfm) / 2 - keylen);
-               memset(ctx->opad, 0, crypto_ahash_blocksize(tfm) / 2);
+               memset(&ctx->base.opad, 0, crypto_ahash_blocksize(tfm) / 2);
        } else {
-               memset((u8 *)ctx->opad + keylen -
+               memset(ctx->base.opad.byte + keylen -
                       crypto_ahash_blocksize(tfm) / 2, 0,
                       crypto_ahash_blocksize(tfm) - keylen);
        }
@@ -2856,7 +2865,7 @@ static int safexcel_hmac_sha3_224_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Copy (half of) the key */
-       memcpy(req->state, ctx->ipad, SHA3_224_BLOCK_SIZE / 2);
+       memcpy(req->state, &ctx->base.ipad, SHA3_224_BLOCK_SIZE / 2);
        /* Start of HMAC should have len == processed == blocksize */
        req->len        = SHA3_224_BLOCK_SIZE;
        req->processed  = SHA3_224_BLOCK_SIZE;
@@ -2927,7 +2936,7 @@ static int safexcel_hmac_sha3_256_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Copy (half of) the key */
-       memcpy(req->state, ctx->ipad, SHA3_256_BLOCK_SIZE / 2);
+       memcpy(req->state, &ctx->base.ipad, SHA3_256_BLOCK_SIZE / 2);
        /* Start of HMAC should have len == processed == blocksize */
        req->len        = SHA3_256_BLOCK_SIZE;
        req->processed  = SHA3_256_BLOCK_SIZE;
@@ -2998,7 +3007,7 @@ static int safexcel_hmac_sha3_384_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Copy (half of) the key */
-       memcpy(req->state, ctx->ipad, SHA3_384_BLOCK_SIZE / 2);
+       memcpy(req->state, &ctx->base.ipad, SHA3_384_BLOCK_SIZE / 2);
        /* Start of HMAC should have len == processed == blocksize */
        req->len        = SHA3_384_BLOCK_SIZE;
        req->processed  = SHA3_384_BLOCK_SIZE;
@@ -3069,7 +3078,7 @@ static int safexcel_hmac_sha3_512_init(struct ahash_request *areq)
        memset(req, 0, sizeof(*req));
 
        /* Copy (half of) the key */
-       memcpy(req->state, ctx->ipad, SHA3_512_BLOCK_SIZE / 2);
+       memcpy(req->state, &ctx->base.ipad, SHA3_512_BLOCK_SIZE / 2);
        /* Start of HMAC should have len == processed == blocksize */
        req->len        = SHA3_512_BLOCK_SIZE;
        req->processed  = SHA3_512_BLOCK_SIZE;
index e454c3d..90f1503 100644 (file)
@@ -236,8 +236,8 @@ struct safexcel_result_desc *safexcel_add_rdesc(struct safexcel_crypto_priv *pri
 
        rdesc->particle_size = len;
        rdesc->rsvd0 = 0;
-       rdesc->descriptor_overflow = 0;
-       rdesc->buffer_overflow = 0;
+       rdesc->descriptor_overflow = 1; /* assume error */
+       rdesc->buffer_overflow = 1;     /* assume error */
        rdesc->last_seg = last;
        rdesc->first_seg = first;
        rdesc->result_size = EIP197_RD64_RESULT_SIZE;
@@ -245,9 +245,10 @@ struct safexcel_result_desc *safexcel_add_rdesc(struct safexcel_crypto_priv *pri
        rdesc->data_lo = lower_32_bits(data);
        rdesc->data_hi = upper_32_bits(data);
 
-       /* Clear length & error code in result token */
+       /* Clear length in result token */
        rtoken->packet_length = 0;
-       rtoken->error_code = 0;
+       /* Assume errors - HW will clear if not the case */
+       rtoken->error_code = 0x7fff;
 
        return rdesc;
 }
index f478bb0..276012e 100644 (file)
@@ -528,7 +528,7 @@ static void release_ixp_crypto(struct device *dev)
 
        if (crypt_virt) {
                dma_free_coherent(dev,
-                       NPE_QLEN_TOTAL * sizeof( struct crypt_ctl),
+                       NPE_QLEN * sizeof(struct crypt_ctl),
                        crypt_virt, crypt_phys);
        }
 }
index d63bca9..0621185 100644 (file)
@@ -437,7 +437,6 @@ static int mv_cesa_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct mv_cesa_dev *cesa;
        struct mv_cesa_engine *engines;
-       struct resource *res;
        int irq, ret, i, cpu;
        u32 sram_size;
 
@@ -475,8 +474,7 @@ static int mv_cesa_probe(struct platform_device *pdev)
 
        spin_lock_init(&cesa->lock);
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
-       cesa->regs = devm_ioremap_resource(dev, res);
+       cesa->regs = devm_platform_ioremap_resource_byname(pdev, "regs");
        if (IS_ERR(cesa->regs))
                return PTR_ERR(cesa->regs);
 
index 0c9cbb6..fabfaac 100644 (file)
@@ -2,12 +2,10 @@
 #ifndef __MARVELL_CESA_H__
 #define __MARVELL_CESA_H__
 
-#include <crypto/algapi.h>
-#include <crypto/hash.h>
 #include <crypto/internal/hash.h>
 #include <crypto/internal/skcipher.h>
 
-#include <linux/crypto.h>
+#include <linux/dma-direction.h>
 #include <linux/dmapool.h>
 
 #define CESA_ENGINE_OFF(i)                     (((i) * 0x2000))
@@ -239,7 +237,7 @@ struct mv_cesa_sec_accel_desc {
  * Context associated to a cipher operation.
  */
 struct mv_cesa_skcipher_op_ctx {
-       u32 key[8];
+       __le32 key[8];
        u32 iv[4];
 };
 
@@ -252,7 +250,7 @@ struct mv_cesa_skcipher_op_ctx {
  */
 struct mv_cesa_hash_op_ctx {
        u32 iv[16];
-       u32 hash[8];
+       __le32 hash[8];
 };
 
 /**
@@ -300,8 +298,14 @@ struct mv_cesa_op_ctx {
  */
 struct mv_cesa_tdma_desc {
        __le32 byte_cnt;
-       __le32 src;
-       __le32 dst;
+       union {
+               __le32 src;
+               dma_addr_t src_dma;
+       };
+       union {
+               __le32 dst;
+               dma_addr_t dst_dma;
+       };
        __le32 next_dma;
 
        /* Software state */
@@ -506,7 +510,7 @@ struct mv_cesa_hash_ctx {
  */
 struct mv_cesa_hmac_ctx {
        struct mv_cesa_ctx base;
-       u32 iv[16];
+       __be32 iv[16];
 };
 
 /**
index 45b4d7a..b4a6ff9 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <crypto/aes.h>
 #include <crypto/internal/des.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
 
 #include "cesa.h"
 
@@ -262,8 +264,7 @@ static int mv_cesa_aes_setkey(struct crypto_skcipher *cipher, const u8 *key,
        remaining = (ctx->aes.key_length - 16) / 4;
        offset = ctx->aes.key_length + 24 - remaining;
        for (i = 0; i < remaining; i++)
-               ctx->aes.key_dec[4 + i] =
-                       cpu_to_le32(ctx->aes.key_enc[offset + i]);
+               ctx->aes.key_dec[4 + i] = ctx->aes.key_enc[offset + i];
 
        return 0;
 }
index f2a2fc1..add7ea0 100644 (file)
@@ -12,6 +12,8 @@
 #include <crypto/hmac.h>
 #include <crypto/md5.h>
 #include <crypto/sha.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
 
 #include "cesa.h"
 
@@ -222,9 +224,11 @@ static void mv_cesa_ahash_std_step(struct ahash_request *req)
                                              CESA_SA_DATA_SRAM_OFFSET + len,
                                              new_cache_ptr);
                        } else {
-                               len += mv_cesa_ahash_pad_req(creq,
-                                               engine->sram + len +
-                                               CESA_SA_DATA_SRAM_OFFSET);
+                               i = mv_cesa_ahash_pad_req(creq, creq->cache);
+                               len += i;
+                               memcpy_toio(engine->sram + len +
+                                           CESA_SA_DATA_SRAM_OFFSET,
+                                           creq->cache, i);
                        }
 
                        if (frag_mode == CESA_SA_DESC_CFG_LAST_FRAG)
@@ -342,7 +346,7 @@ static void mv_cesa_ahash_complete(struct crypto_async_request *req)
                 */
                data = creq->base.chain.last->op->ctx.hash.hash;
                for (i = 0; i < digsize / 4; i++)
-                       creq->state[i] = cpu_to_le32(data[i]);
+                       creq->state[i] = le32_to_cpu(data[i]);
 
                memcpy(ahashreq->result, data, digsize);
        } else {
@@ -1265,10 +1269,10 @@ static int mv_cesa_ahmac_md5_setkey(struct crypto_ahash *tfm, const u8 *key,
                return ret;
 
        for (i = 0; i < ARRAY_SIZE(istate.hash); i++)
-               ctx->iv[i] = be32_to_cpu(istate.hash[i]);
+               ctx->iv[i] = cpu_to_be32(istate.hash[i]);
 
        for (i = 0; i < ARRAY_SIZE(ostate.hash); i++)
-               ctx->iv[i + 8] = be32_to_cpu(ostate.hash[i]);
+               ctx->iv[i + 8] = cpu_to_be32(ostate.hash[i]);
 
        return 0;
 }
@@ -1336,10 +1340,10 @@ static int mv_cesa_ahmac_sha1_setkey(struct crypto_ahash *tfm, const u8 *key,
                return ret;
 
        for (i = 0; i < ARRAY_SIZE(istate.state); i++)
-               ctx->iv[i] = be32_to_cpu(istate.state[i]);
+               ctx->iv[i] = cpu_to_be32(istate.state[i]);
 
        for (i = 0; i < ARRAY_SIZE(ostate.state); i++)
-               ctx->iv[i + 8] = be32_to_cpu(ostate.state[i]);
+               ctx->iv[i + 8] = cpu_to_be32(ostate.state[i]);
 
        return 0;
 }
@@ -1394,10 +1398,10 @@ static int mv_cesa_ahmac_sha256_setkey(struct crypto_ahash *tfm, const u8 *key,
                return ret;
 
        for (i = 0; i < ARRAY_SIZE(istate.state); i++)
-               ctx->iv[i] = be32_to_cpu(istate.state[i]);
+               ctx->iv[i] = cpu_to_be32(istate.state[i]);
 
        for (i = 0; i < ARRAY_SIZE(ostate.state); i++)
-               ctx->iv[i + 8] = be32_to_cpu(ostate.state[i]);
+               ctx->iv[i + 8] = cpu_to_be32(ostate.state[i]);
 
        return 0;
 }
index b81ee27..5d9c48f 100644 (file)
@@ -83,10 +83,10 @@ void mv_cesa_dma_prepare(struct mv_cesa_req *dreq,
 
        for (tdma = dreq->chain.first; tdma; tdma = tdma->next) {
                if (tdma->flags & CESA_TDMA_DST_IN_SRAM)
-                       tdma->dst = cpu_to_le32(tdma->dst + engine->sram_dma);
+                       tdma->dst = cpu_to_le32(tdma->dst_dma + engine->sram_dma);
 
                if (tdma->flags & CESA_TDMA_SRC_IN_SRAM)
-                       tdma->src = cpu_to_le32(tdma->src + engine->sram_dma);
+                       tdma->src = cpu_to_le32(tdma->src_dma + engine->sram_dma);
 
                if ((tdma->flags & CESA_TDMA_TYPE_MSK) == CESA_TDMA_OP)
                        mv_cesa_adjust_op(engine, tdma->op);
@@ -114,7 +114,7 @@ void mv_cesa_tdma_chain(struct mv_cesa_engine *engine,
                 */
                if (!(last->flags & CESA_TDMA_BREAK_CHAIN) &&
                    !(dreq->chain.first->flags & CESA_TDMA_SET_STATE))
-                       last->next_dma = dreq->chain.first->cur_dma;
+                       last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma);
        }
 }
 
@@ -237,8 +237,8 @@ int mv_cesa_dma_add_result_op(struct mv_cesa_tdma_chain *chain, dma_addr_t src,
                return -EIO;
 
        tdma->byte_cnt = cpu_to_le32(size | BIT(31));
-       tdma->src = src;
-       tdma->dst = op_desc->src;
+       tdma->src_dma = src;
+       tdma->dst_dma = op_desc->src_dma;
        tdma->op = op_desc->op;
 
        flags &= (CESA_TDMA_DST_IN_SRAM | CESA_TDMA_SRC_IN_SRAM);
@@ -272,7 +272,7 @@ struct mv_cesa_op_ctx *mv_cesa_dma_add_op(struct mv_cesa_tdma_chain *chain,
        tdma->op = op;
        tdma->byte_cnt = cpu_to_le32(size | BIT(31));
        tdma->src = cpu_to_le32(dma_handle);
-       tdma->dst = CESA_SA_CFG_SRAM_OFFSET;
+       tdma->dst_dma = CESA_SA_CFG_SRAM_OFFSET;
        tdma->flags = CESA_TDMA_DST_IN_SRAM | CESA_TDMA_OP;
 
        return op;
@@ -289,8 +289,8 @@ int mv_cesa_dma_add_data_transfer(struct mv_cesa_tdma_chain *chain,
                return PTR_ERR(tdma);
 
        tdma->byte_cnt = cpu_to_le32(size | BIT(31));
-       tdma->src = src;
-       tdma->dst = dst;
+       tdma->src_dma = src;
+       tdma->dst_dma = dst;
 
        flags &= (CESA_TDMA_DST_IN_SRAM | CESA_TDMA_SRC_IN_SRAM);
        tdma->flags = flags | CESA_TDMA_DATA;
index cc103b1..40b4821 100644 (file)
@@ -824,18 +824,12 @@ static ssize_t eng_grp_info_show(struct device *dev,
 static int create_sysfs_eng_grps_info(struct device *dev,
                                      struct otx_cpt_eng_grp_info *eng_grp)
 {
-       int ret;
-
        eng_grp->info_attr.show = eng_grp_info_show;
        eng_grp->info_attr.store = NULL;
        eng_grp->info_attr.attr.name = eng_grp->sysfs_info_name;
        eng_grp->info_attr.attr.mode = 0440;
        sysfs_attr_init(&eng_grp->info_attr.attr);
-       ret = device_create_file(dev, &eng_grp->info_attr);
-       if (ret)
-               return ret;
-
-       return 0;
+       return device_create_file(dev, &eng_grp->info_attr);
 }
 
 static void ucode_unload(struct device *dev, struct otx_cpt_ucode *ucode)
index cbc3d78..c80baf1 100644 (file)
@@ -140,11 +140,11 @@ static inline int setup_sgio_components(struct pci_dev *pdev,
        case 3:
                sg_ptr->u.s.len2 = cpu_to_be16(list[i * 4 + 2].size);
                sg_ptr->ptr2 = cpu_to_be64(list[i * 4 + 2].dma_addr);
-               /* Fall through */
+               fallthrough;
        case 2:
                sg_ptr->u.s.len1 = cpu_to_be16(list[i * 4 + 1].size);
                sg_ptr->ptr1 = cpu_to_be64(list[i * 4 + 1].dma_addr);
-               /* Fall through */
+               fallthrough;
        case 1:
                sg_ptr->u.s.len0 = cpu_to_be16(list[i * 4 + 0].size);
                sg_ptr->ptr0 = cpu_to_be64(list[i * 4 + 0].dma_addr);
index 4ad3571..7323066 100644 (file)
@@ -126,7 +126,7 @@ struct mtk_aes_ctx {
 struct mtk_aes_ctr_ctx {
        struct mtk_aes_base_ctx base;
 
-       u32     iv[AES_BLOCK_SIZE / sizeof(u32)];
+       __be32  iv[AES_BLOCK_SIZE / sizeof(u32)];
        size_t offset;
        struct scatterlist src[2];
        struct scatterlist dst[2];
@@ -242,22 +242,6 @@ static inline void mtk_aes_restore_sg(const struct mtk_aes_dma *dma)
        sg->length += dma->remainder;
 }
 
-static inline void mtk_aes_write_state_le(__le32 *dst, const u32 *src, u32 size)
-{
-       int i;
-
-       for (i = 0; i < SIZE_IN_WORDS(size); i++)
-               dst[i] = cpu_to_le32(src[i]);
-}
-
-static inline void mtk_aes_write_state_be(__be32 *dst, const u32 *src, u32 size)
-{
-       int i;
-
-       for (i = 0; i < SIZE_IN_WORDS(size); i++)
-               dst[i] = cpu_to_be32(src[i]);
-}
-
 static inline int mtk_aes_complete(struct mtk_cryp *cryp,
                                   struct mtk_aes_rec *aes,
                                   int err)
@@ -321,7 +305,7 @@ static int mtk_aes_xmit(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
 
        /* Prepare enough space for authenticated tag */
        if (aes->flags & AES_FLAGS_GCM)
-               res->hdr += AES_BLOCK_SIZE;
+               le32_add_cpu(&res->hdr, AES_BLOCK_SIZE);
 
        /*
         * Make sure that all changes to the DMA ring are done before we
@@ -449,10 +433,10 @@ static void mtk_aes_info_init(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
                return;
        }
 
-       mtk_aes_write_state_le(info->state + ctx->keylen, (void *)req->iv,
-                              AES_BLOCK_SIZE);
+       memcpy(info->state + ctx->keylen, req->iv, AES_BLOCK_SIZE);
 ctr:
-       info->tfm[0] += AES_TFM_SIZE(SIZE_IN_WORDS(AES_BLOCK_SIZE));
+       le32_add_cpu(&info->tfm[0],
+                    le32_to_cpu(AES_TFM_SIZE(SIZE_IN_WORDS(AES_BLOCK_SIZE))));
        info->tfm[1] |= AES_TFM_FULL_IV;
        info->cmd[cnt++] = AES_CMD2;
 ecb:
@@ -601,8 +585,7 @@ static int mtk_aes_ctr_transfer(struct mtk_cryp *cryp, struct mtk_aes_rec *aes)
               scatterwalk_ffwd(cctx->dst, req->dst, cctx->offset));
 
        /* Write IVs into transform state buffer. */
-       mtk_aes_write_state_le(ctx->info.state + ctx->keylen, cctx->iv,
-                              AES_BLOCK_SIZE);
+       memcpy(ctx->info.state + ctx->keylen, cctx->iv, AES_BLOCK_SIZE);
 
        if (unlikely(fragmented)) {
        /*
@@ -654,7 +637,7 @@ static int mtk_aes_setkey(struct crypto_skcipher *tfm,
        }
 
        ctx->keylen = SIZE_IN_WORDS(keylen);
-       mtk_aes_write_state_le(ctx->key, (const u32 *)key, keylen);
+       memcpy(ctx->key, key, keylen);
 
        return 0;
 }
@@ -848,7 +831,7 @@ mtk_aes_gcm_ctx_cast(struct mtk_aes_base_ctx *ctx)
 static int mtk_aes_gcm_tag_verify(struct mtk_cryp *cryp,
                                  struct mtk_aes_rec *aes)
 {
-       u32 status = cryp->ring[aes->id]->res_prev->ct;
+       __le32 status = cryp->ring[aes->id]->res_prev->ct;
 
        return mtk_aes_complete(cryp, aes, (status & AES_AUTH_TAG_ERR) ?
                                -EBADMSG : 0);
@@ -866,7 +849,7 @@ static void mtk_aes_gcm_info_init(struct mtk_cryp *cryp,
        u32 ivsize = crypto_aead_ivsize(crypto_aead_reqtfm(req));
        u32 cnt = 0;
 
-       ctx->ct_hdr = AES_CT_CTRL_HDR | len;
+       ctx->ct_hdr = AES_CT_CTRL_HDR | cpu_to_le32(len);
 
        info->cmd[cnt++] = AES_GCM_CMD0 | cpu_to_le32(req->assoclen);
        info->cmd[cnt++] = AES_GCM_CMD1 | cpu_to_le32(req->assoclen);
@@ -889,8 +872,8 @@ static void mtk_aes_gcm_info_init(struct mtk_cryp *cryp,
        info->tfm[1] = AES_TFM_CTR_INIT | AES_TFM_IV_CTR_MODE | AES_TFM_3IV |
                       AES_TFM_ENC_HASH;
 
-       mtk_aes_write_state_le(info->state + ctx->keylen + SIZE_IN_WORDS(
-                              AES_BLOCK_SIZE), (const u32 *)req->iv, ivsize);
+       memcpy(info->state + ctx->keylen + SIZE_IN_WORDS(AES_BLOCK_SIZE),
+              req->iv, ivsize);
 }
 
 static int mtk_aes_gcm_dma(struct mtk_cryp *cryp, struct mtk_aes_rec *aes,
@@ -994,9 +977,13 @@ static int mtk_aes_gcm_setkey(struct crypto_aead *aead, const u8 *key,
                              u32 keylen)
 {
        struct mtk_aes_base_ctx *ctx = crypto_aead_ctx(aead);
-       u8 hash[AES_BLOCK_SIZE] __aligned(4) = {};
+       union {
+               u32 x32[SIZE_IN_WORDS(AES_BLOCK_SIZE)];
+               u8 x8[AES_BLOCK_SIZE];
+       } hash = {};
        struct crypto_aes_ctx aes_ctx;
        int err;
+       int i;
 
        switch (keylen) {
        case AES_KEYSIZE_128:
@@ -1019,12 +1006,16 @@ static int mtk_aes_gcm_setkey(struct crypto_aead *aead, const u8 *key,
        if (err)
                return err;
 
-       aes_encrypt(&aes_ctx, hash, hash);
+       aes_encrypt(&aes_ctx, hash.x8, hash.x8);
        memzero_explicit(&aes_ctx, sizeof(aes_ctx));
 
-       mtk_aes_write_state_le(ctx->key, (const u32 *)key, keylen);
-       mtk_aes_write_state_be(ctx->key + ctx->keylen, (const u32 *)hash,
-                              AES_BLOCK_SIZE);
+       memcpy(ctx->key, key, keylen);
+
+       /* Why do we need to do this? */
+       for (i = 0; i < SIZE_IN_WORDS(AES_BLOCK_SIZE); i++)
+               hash.x32[i] = swab32(hash.x32[i]);
+
+       memcpy(ctx->key + ctx->keylen, &hash, AES_BLOCK_SIZE);
 
        return 0;
 }
index 7e3ad08..9d87862 100644 (file)
@@ -185,8 +185,6 @@ static int mtk_dfe_dse_state_check(struct mtk_cryp *cryp)
 
 static int mtk_dfe_dse_reset(struct mtk_cryp *cryp)
 {
-       int err;
-
        /* Reset DSE/DFE and correct system priorities for all rings. */
        writel(MTK_DFSE_THR_CTRL_RESET, cryp->base + DFE_THR_CTRL);
        writel(0, cryp->base + DFE_PRIO_0);
@@ -200,11 +198,7 @@ static int mtk_dfe_dse_reset(struct mtk_cryp *cryp)
        writel(0, cryp->base + DSE_PRIO_2);
        writel(0, cryp->base + DSE_PRIO_3);
 
-       err = mtk_dfe_dse_state_check(cryp);
-       if (err)
-               return err;
-
-       return 0;
+       return mtk_dfe_dse_state_check(cryp);
 }
 
 static void mtk_cmd_desc_ring_setup(struct mtk_cryp *cryp,
@@ -442,7 +436,7 @@ static void mtk_desc_dma_free(struct mtk_cryp *cryp)
 static int mtk_desc_ring_alloc(struct mtk_cryp *cryp)
 {
        struct mtk_ring **ring = cryp->ring;
-       int i, err = ENOMEM;
+       int i;
 
        for (i = 0; i < MTK_RING_MAX; i++) {
                ring[i] = kzalloc(sizeof(**ring), GFP_KERNEL);
@@ -469,14 +463,14 @@ static int mtk_desc_ring_alloc(struct mtk_cryp *cryp)
        return 0;
 
 err_cleanup:
-       for (; i--; ) {
+       do {
                dma_free_coherent(cryp->dev, MTK_DESC_RING_SZ,
                                  ring[i]->res_base, ring[i]->res_dma);
                dma_free_coherent(cryp->dev, MTK_DESC_RING_SZ,
                                  ring[i]->cmd_base, ring[i]->cmd_dma);
                kfree(ring[i]);
-       }
-       return err;
+       } while (i--);
+       return -ENOMEM;
 }
 
 static int mtk_crypto_probe(struct platform_device *pdev)
index da3f0b8..3d5d7d6 100644 (file)
@@ -239,7 +239,7 @@ static int mtk_sha_append_sg(struct mtk_sha_reqctx *ctx)
 static void mtk_sha_fill_padding(struct mtk_sha_reqctx *ctx, u32 len)
 {
        u32 index, padlen;
-       u64 bits[2];
+       __be64 bits[2];
        u64 size = ctx->digcnt;
 
        size += ctx->bufcnt;
index d8aec51..3642bf8 100644 (file)
@@ -249,7 +249,7 @@ static inline bool n2_should_run_async(struct spu_queue *qp, int this_len)
 struct n2_ahash_alg {
        struct list_head        entry;
        const u8                *hash_zero;
-       const u32               *hash_init;
+       const u               *hash_init;
        u8                      hw_op_hashsz;
        u8                      digest_size;
        u8                      auth_type;
@@ -662,7 +662,6 @@ struct n2_skcipher_context {
                u8              aes[AES_MAX_KEY_SIZE];
                u8              des[DES_KEY_SIZE];
                u8              des3[3 * DES_KEY_SIZE];
-               u8              arc4[258]; /* S-box, X, Y */
        } key;
 };
 
@@ -789,36 +788,6 @@ static int n2_3des_setkey(struct crypto_skcipher *skcipher, const u8 *key,
        return 0;
 }
 
-static int n2_arc4_setkey(struct crypto_skcipher *skcipher, const u8 *key,
-                         unsigned int keylen)
-{
-       struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher);
-       struct n2_skcipher_context *ctx = crypto_tfm_ctx(tfm);
-       struct n2_skcipher_alg *n2alg = n2_skcipher_alg(skcipher);
-       u8 *s = ctx->key.arc4;
-       u8 *x = s + 256;
-       u8 *y = x + 1;
-       int i, j, k;
-
-       ctx->enc_type = n2alg->enc_type;
-
-       j = k = 0;
-       *x = 0;
-       *y = 0;
-       for (i = 0; i < 256; i++)
-               s[i] = i;
-       for (i = 0; i < 256; i++) {
-               u8 a = s[i];
-               j = (j + key[k] + a) & 0xff;
-               s[i] = s[j];
-               s[j] = a;
-               if (++k >= keylen)
-                       k = 0;
-       }
-
-       return 0;
-}
-
 static inline int skcipher_descriptor_len(int nbytes, unsigned int block_size)
 {
        int this_len = nbytes;
@@ -1122,21 +1091,6 @@ struct n2_skcipher_tmpl {
 };
 
 static const struct n2_skcipher_tmpl skcipher_tmpls[] = {
-       /* ARC4: only ECB is supported (chaining bits ignored) */
-       {       .name           = "ecb(arc4)",
-               .drv_name       = "ecb-arc4",
-               .block_size     = 1,
-               .enc_type       = (ENC_TYPE_ALG_RC4_STREAM |
-                                  ENC_TYPE_CHAINING_ECB),
-               .skcipher       = {
-                       .min_keysize    = 1,
-                       .max_keysize    = 256,
-                       .setkey         = n2_arc4_setkey,
-                       .encrypt        = n2_encrypt_ecb,
-                       .decrypt        = n2_decrypt_ecb,
-               },
-       },
-
        /* DES: ECB CBC and CFB are supported */
        {       .name           = "ecb(des)",
                .drv_name       = "ecb-des",
@@ -1271,7 +1225,7 @@ static LIST_HEAD(skcipher_algs);
 struct n2_hash_tmpl {
        const char      *name;
        const u8        *hash_zero;
-       const u32       *hash_init;
+       const u       *hash_init;
        u8              hw_op_hashsz;
        u8              digest_size;
        u8              block_size;
@@ -1279,7 +1233,7 @@ struct n2_hash_tmpl {
        u8              hmac_type;
 };
 
-static const u32 n2_md5_init[MD5_HASH_WORDS] = {
+static const __le32 n2_md5_init[MD5_HASH_WORDS] = {
        cpu_to_le32(MD5_H0),
        cpu_to_le32(MD5_H1),
        cpu_to_le32(MD5_H2),
@@ -1300,7 +1254,7 @@ static const u32 n2_sha224_init[SHA256_DIGEST_SIZE / 4] = {
 static const struct n2_hash_tmpl hash_tmpls[] = {
        { .name         = "md5",
          .hash_zero    = md5_zero_message_hash,
-         .hash_init    = n2_md5_init,
+         .hash_init    = (u8 *)n2_md5_init,
          .auth_type    = AUTH_TYPE_MD5,
          .hmac_type    = AUTH_TYPE_HMAC_MD5,
          .hw_op_hashsz = MD5_DIGEST_SIZE,
@@ -1308,7 +1262,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = {
          .block_size   = MD5_HMAC_BLOCK_SIZE },
        { .name         = "sha1",
          .hash_zero    = sha1_zero_message_hash,
-         .hash_init    = n2_sha1_init,
+         .hash_init    = (u8 *)n2_sha1_init,
          .auth_type    = AUTH_TYPE_SHA1,
          .hmac_type    = AUTH_TYPE_HMAC_SHA1,
          .hw_op_hashsz = SHA1_DIGEST_SIZE,
@@ -1316,7 +1270,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = {
          .block_size   = SHA1_BLOCK_SIZE },
        { .name         = "sha256",
          .hash_zero    = sha256_zero_message_hash,
-         .hash_init    = n2_sha256_init,
+         .hash_init    = (u8 *)n2_sha256_init,
          .auth_type    = AUTH_TYPE_SHA256,
          .hmac_type    = AUTH_TYPE_HMAC_SHA256,
          .hw_op_hashsz = SHA256_DIGEST_SIZE,
@@ -1324,7 +1278,7 @@ static const struct n2_hash_tmpl hash_tmpls[] = {
          .block_size   = SHA256_BLOCK_SIZE },
        { .name         = "sha224",
          .hash_zero    = sha224_zero_message_hash,
-         .hash_init    = n2_sha224_init,
+         .hash_init    = (u8 *)n2_sha224_init,
          .auth_type    = AUTH_TYPE_SHA256,
          .hmac_type    = AUTH_TYPE_RESERVED,
          .hw_op_hashsz = SHA256_DIGEST_SIZE,
index 954d703..a3b38d2 100644 (file)
@@ -39,6 +39,7 @@
 #include <crypto/hash.h>
 #include <crypto/hmac.h>
 #include <crypto/internal/hash.h>
+#include <crypto/engine.h>
 
 #define MD5_DIGEST_SIZE                        16
 
 #define DEFAULT_AUTOSUSPEND_DELAY      1000
 
 /* mostly device flags */
-#define FLAGS_BUSY             0
 #define FLAGS_FINAL            1
 #define FLAGS_DMA_ACTIVE       2
 #define FLAGS_OUTPUT_READY     3
@@ -144,7 +144,7 @@ struct omap_sham_dev;
 struct omap_sham_reqctx {
        struct omap_sham_dev    *dd;
        unsigned long           flags;
-       unsigned long           op;
+       u8                      op;
 
        u8                      digest[SHA512_DIGEST_SIZE] OMAP_ALIGNED;
        size_t                  digcnt;
@@ -168,6 +168,7 @@ struct omap_sham_hmac_ctx {
 };
 
 struct omap_sham_ctx {
+       struct crypto_engine_ctx        enginectx;
        unsigned long           flags;
 
        /* fallback stuff */
@@ -219,7 +220,6 @@ struct omap_sham_dev {
        struct device           *dev;
        void __iomem            *io_base;
        int                     irq;
-       spinlock_t              lock;
        int                     err;
        struct dma_chan         *dma_lch;
        struct tasklet_struct   done_task;
@@ -230,6 +230,7 @@ struct omap_sham_dev {
        int                     fallback_sz;
        struct crypto_queue     queue;
        struct ahash_request    *req;
+       struct crypto_engine    *engine;
 
        const struct omap_sham_pdata    *pdata;
 };
@@ -245,6 +246,9 @@ static struct omap_sham_drv sham = {
        .lock = __SPIN_LOCK_UNLOCKED(sham.lock),
 };
 
+static int omap_sham_enqueue(struct ahash_request *req, unsigned int op);
+static void omap_sham_finish_req(struct ahash_request *req, int err);
+
 static inline u32 omap_sham_read(struct omap_sham_dev *dd, u32 offset)
 {
        return __raw_readl(dd->io_base + offset);
@@ -456,6 +460,9 @@ static void omap_sham_write_ctrl_omap4(struct omap_sham_dev *dd, size_t length,
        struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
        u32 val, mask;
 
+       if (likely(ctx->digcnt))
+               omap_sham_write(dd, SHA_REG_DIGCNT(dd), ctx->digcnt);
+
        /*
         * Setting ALGO_CONST only for the first iteration and
         * CLOSE_HASH only for the last one. Note that flags mode bits
@@ -854,13 +861,16 @@ static int omap_sham_align_sgs(struct scatterlist *sg,
        return 0;
 }
 
-static int omap_sham_prepare_request(struct ahash_request *req, bool update)
+static int omap_sham_prepare_request(struct crypto_engine *engine, void *areq)
 {
+       struct ahash_request *req = container_of(areq, struct ahash_request,
+                                                base);
        struct omap_sham_reqctx *rctx = ahash_request_ctx(req);
        int bs;
        int ret;
        unsigned int nbytes;
        bool final = rctx->flags & BIT(FLAGS_FINUP);
+       bool update = rctx->op == OP_UPDATE;
        int hash_later;
 
        bs = get_block_size(rctx);
@@ -1021,7 +1031,7 @@ static int omap_sham_update_req(struct omap_sham_dev *dd)
        struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
        int err;
        bool final = (ctx->flags & BIT(FLAGS_FINUP)) &&
-                       !(dd->flags & BIT(FLAGS_HUGE));
+               !(dd->flags & BIT(FLAGS_HUGE));
 
        dev_dbg(dd->dev, "update_req: total: %u, digcnt: %zd, final: %d",
                ctx->total, ctx->digcnt, final);
@@ -1069,6 +1079,39 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
        return err;
 }
 
+static int omap_sham_hash_one_req(struct crypto_engine *engine, void *areq)
+{
+       struct ahash_request *req = container_of(areq, struct ahash_request,
+                                                base);
+       struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
+       struct omap_sham_dev *dd = ctx->dd;
+       int err;
+       bool final = (ctx->flags & BIT(FLAGS_FINUP)) &&
+                       !(dd->flags & BIT(FLAGS_HUGE));
+
+       dev_dbg(dd->dev, "hash-one: op: %u, total: %u, digcnt: %zd, final: %d",
+               ctx->op, ctx->total, ctx->digcnt, final);
+
+       dd->req = req;
+
+       err = omap_sham_hw_init(dd);
+       if (err)
+               return err;
+
+       if (ctx->digcnt)
+               dd->pdata->copy_hash(req, 0);
+
+       if (ctx->op == OP_UPDATE)
+               err = omap_sham_update_req(dd);
+       else if (ctx->op == OP_FINAL)
+               err = omap_sham_final_req(dd);
+
+       if (err != -EINPROGRESS)
+               omap_sham_finish_req(req, err);
+
+       return 0;
+}
+
 static int omap_sham_finish_hmac(struct ahash_request *req)
 {
        struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
@@ -1116,25 +1159,20 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)
 
        ctx->sg = NULL;
 
-       dd->flags &= ~(BIT(FLAGS_SGS_ALLOCED) | BIT(FLAGS_SGS_COPIED));
+       dd->flags &= ~(BIT(FLAGS_SGS_ALLOCED) | BIT(FLAGS_SGS_COPIED) |
+                      BIT(FLAGS_CPU) | BIT(FLAGS_DMA_READY) |
+                      BIT(FLAGS_OUTPUT_READY));
+
+       if (!err)
+               dd->pdata->copy_hash(req, 1);
 
        if (dd->flags & BIT(FLAGS_HUGE)) {
-               dd->flags &= ~(BIT(FLAGS_CPU) | BIT(FLAGS_DMA_READY) |
-                               BIT(FLAGS_OUTPUT_READY) | BIT(FLAGS_HUGE));
-               omap_sham_prepare_request(req, ctx->op == OP_UPDATE);
-               if (ctx->op == OP_UPDATE || (dd->flags & BIT(FLAGS_HUGE))) {
-                       err = omap_sham_update_req(dd);
-                       if (err != -EINPROGRESS &&
-                           (ctx->flags & BIT(FLAGS_FINUP)))
-                               err = omap_sham_final_req(dd);
-               } else if (ctx->op == OP_FINAL) {
-                       omap_sham_final_req(dd);
-               }
+               /* Re-enqueue the request */
+               omap_sham_enqueue(req, ctx->op);
                return;
        }
 
        if (!err) {
-               dd->pdata->copy_hash(req, 1);
                if (test_bit(FLAGS_FINAL, &dd->flags))
                        err = omap_sham_finish(req);
        } else {
@@ -1142,7 +1180,7 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)
        }
 
        /* atomic operation is not needed here */
-       dd->flags &= ~(BIT(FLAGS_BUSY) | BIT(FLAGS_FINAL) | BIT(FLAGS_CPU) |
+       dd->flags &= ~(BIT(FLAGS_FINAL) | BIT(FLAGS_CPU) |
                        BIT(FLAGS_DMA_READY) | BIT(FLAGS_OUTPUT_READY));
 
        pm_runtime_mark_last_busy(dd->dev);
@@ -1150,81 +1188,13 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)
 
        ctx->offset = 0;
 
-       if (req->base.complete)
-               req->base.complete(&req->base, err);
+       crypto_finalize_hash_request(dd->engine, req, err);
 }
 
 static int omap_sham_handle_queue(struct omap_sham_dev *dd,
                                  struct ahash_request *req)
 {
-       struct crypto_async_request *async_req, *backlog;
-       struct omap_sham_reqctx *ctx;
-       unsigned long flags;
-       int err = 0, ret = 0;
-
-retry:
-       spin_lock_irqsave(&dd->lock, flags);
-       if (req)
-               ret = ahash_enqueue_request(&dd->queue, req);
-       if (test_bit(FLAGS_BUSY, &dd->flags)) {
-               spin_unlock_irqrestore(&dd->lock, flags);
-               return ret;
-       }
-       backlog = crypto_get_backlog(&dd->queue);
-       async_req = crypto_dequeue_request(&dd->queue);
-       if (async_req)
-               set_bit(FLAGS_BUSY, &dd->flags);
-       spin_unlock_irqrestore(&dd->lock, flags);
-
-       if (!async_req)
-               return ret;
-
-       if (backlog)
-               backlog->complete(backlog, -EINPROGRESS);
-
-       req = ahash_request_cast(async_req);
-       dd->req = req;
-       ctx = ahash_request_ctx(req);
-
-       err = omap_sham_prepare_request(req, ctx->op == OP_UPDATE);
-       if (err || !ctx->total)
-               goto err1;
-
-       dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
-                                               ctx->op, req->nbytes);
-
-       err = omap_sham_hw_init(dd);
-       if (err)
-               goto err1;
-
-       if (ctx->digcnt)
-               /* request has changed - restore hash */
-               dd->pdata->copy_hash(req, 0);
-
-       if (ctx->op == OP_UPDATE || (dd->flags & BIT(FLAGS_HUGE))) {
-               err = omap_sham_update_req(dd);
-               if (err != -EINPROGRESS && (ctx->flags & BIT(FLAGS_FINUP)))
-                       /* no final() after finup() */
-                       err = omap_sham_final_req(dd);
-       } else if (ctx->op == OP_FINAL) {
-               err = omap_sham_final_req(dd);
-       }
-err1:
-       dev_dbg(dd->dev, "exit, err: %d\n", err);
-
-       if (err != -EINPROGRESS) {
-               /* done_task will not finish it, so do it here */
-               omap_sham_finish_req(req, err);
-               req = NULL;
-
-               /*
-                * Execute next request immediately if there is anything
-                * in queue.
-                */
-               goto retry;
-       }
-
-       return ret;
+       return crypto_transfer_hash_request_to_engine(dd->engine, req);
 }
 
 static int omap_sham_enqueue(struct ahash_request *req, unsigned int op)
@@ -1394,6 +1364,10 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
 
        }
 
+       tctx->enginectx.op.do_one_request = omap_sham_hash_one_req;
+       tctx->enginectx.op.prepare_request = omap_sham_prepare_request;
+       tctx->enginectx.op.unprepare_request = NULL;
+
        return 0;
 }
 
@@ -1757,11 +1731,6 @@ static void omap_sham_done_task(unsigned long data)
 
        dev_dbg(dd->dev, "%s: flags=%lx\n", __func__, dd->flags);
 
-       if (!test_bit(FLAGS_BUSY, &dd->flags)) {
-               omap_sham_handle_queue(dd, NULL);
-               return;
-       }
-
        if (test_bit(FLAGS_CPU, &dd->flags)) {
                if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags))
                        goto finish;
@@ -1786,20 +1755,12 @@ finish:
        dev_dbg(dd->dev, "update done: err: %d\n", err);
        /* finish curent request */
        omap_sham_finish_req(dd->req, err);
-
-       /* If we are not busy, process next req */
-       if (!test_bit(FLAGS_BUSY, &dd->flags))
-               omap_sham_handle_queue(dd, NULL);
 }
 
 static irqreturn_t omap_sham_irq_common(struct omap_sham_dev *dd)
 {
-       if (!test_bit(FLAGS_BUSY, &dd->flags)) {
-               dev_warn(dd->dev, "Interrupt when no active requests.\n");
-       } else {
-               set_bit(FLAGS_OUTPUT_READY, &dd->flags);
-               tasklet_schedule(&dd->done_task);
-       }
+       set_bit(FLAGS_OUTPUT_READY, &dd->flags);
+       tasklet_schedule(&dd->done_task);
 
        return IRQ_HANDLED;
 }
@@ -2072,7 +2033,6 @@ static ssize_t queue_len_store(struct device *dev,
        struct omap_sham_dev *dd = dev_get_drvdata(dev);
        ssize_t status;
        long value;
-       unsigned long flags;
 
        status = kstrtol(buf, 0, &value);
        if (status)
@@ -2086,9 +2046,7 @@ static ssize_t queue_len_store(struct device *dev,
         * than current size, it will just not accept new entries until
         * it has shrank enough.
         */
-       spin_lock_irqsave(&dd->lock, flags);
        dd->queue.max_qlen = value;
-       spin_unlock_irqrestore(&dd->lock, flags);
 
        return size;
 }
@@ -2125,7 +2083,6 @@ static int omap_sham_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, dd);
 
        INIT_LIST_HEAD(&dd->list);
-       spin_lock_init(&dd->lock);
        tasklet_init(&dd->done_task, omap_sham_done_task, (unsigned long)dd);
        crypto_init_queue(&dd->queue, OMAP_SHAM_QUEUE_LENGTH);
 
@@ -2190,6 +2147,16 @@ static int omap_sham_probe(struct platform_device *pdev)
        list_add_tail(&dd->list, &sham.dev_list);
        spin_unlock(&sham.lock);
 
+       dd->engine = crypto_engine_alloc_init(dev, 1);
+       if (!dd->engine) {
+               err = -ENOMEM;
+               goto err_engine;
+       }
+
+       err = crypto_engine_start(dd->engine);
+       if (err)
+               goto err_engine_start;
+
        for (i = 0; i < dd->pdata->algs_info_size; i++) {
                if (dd->pdata->algs_info[i].registered)
                        break;
@@ -2223,6 +2190,12 @@ err_algs:
                for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
                        crypto_unregister_ahash(
                                        &dd->pdata->algs_info[i].algs_list[j]);
+err_engine_start:
+       crypto_engine_exit(dd->engine);
+err_engine:
+       spin_lock(&sham.lock);
+       list_del(&dd->list);
+       spin_unlock(&sham.lock);
 err_pm:
        pm_runtime_disable(dev);
        if (!dd->polling_mode)
index 62c6fe8..1be549a 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/mm.h>
 #include <linux/percpu.h>
 #include <linux/smp.h>
 #include <linux/slab.h>
index dac6eb3..fb34bf9 100644 (file)
@@ -1685,11 +1685,6 @@ static int spacc_probe(struct platform_device *pdev)
                goto err_clk_put;
        }
 
-       ret = device_create_file(&pdev->dev, &dev_attr_stat_irq_thresh);
-       if (ret)
-               goto err_clk_disable;
-
-
        /*
         * Use an IRQ threshold of 50% as a default. This seems to be a
         * reasonable trade off of latency against throughput but can be
@@ -1697,6 +1692,10 @@ static int spacc_probe(struct platform_device *pdev)
         */
        engine->stat_irq_thresh = (engine->fifo_sz / 2);
 
+       ret = device_create_file(&pdev->dev, &dev_attr_stat_irq_thresh);
+       if (ret)
+               goto err_clk_disable;
+
        /*
         * Configure the interrupts. We only use the STAT_CNT interrupt as we
         * only submit a new packet for processing when we complete another in
index 020d099..ed0e8e3 100644 (file)
 #include <adf_cfg.h>
 #include "adf_c3xxx_hw_data.h"
 
-#define ADF_SYSTEM_DEVICE(device_id) \
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
-
 static const struct pci_device_id adf_pci_tbl[] = {
-       ADF_SYSTEM_DEVICE(ADF_C3XXX_PCI_DEVICE_ID),
-       {0,}
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QAT_C3XXX), },
+       { }
 };
 MODULE_DEVICE_TABLE(pci, adf_pci_tbl);
 
@@ -58,7 +55,7 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev)
 
        if (accel_dev->hw_device) {
                switch (accel_pci_dev->pci_dev->device) {
-               case ADF_C3XXX_PCI_DEVICE_ID:
+               case PCI_DEVICE_ID_INTEL_QAT_C3XXX:
                        adf_clean_hw_data_c3xxx(accel_dev->hw_device);
                        break;
                default:
@@ -83,7 +80,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        int ret;
 
        switch (ent->device) {
-       case ADF_C3XXX_PCI_DEVICE_ID:
+       case PCI_DEVICE_ID_INTEL_QAT_C3XXX:
                break;
        default:
                dev_err(&pdev->dev, "Invalid device 0x%x.\n", ent->device);
@@ -143,10 +140,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        /* Create dev top level debugfs entry */
-       snprintf(name, sizeof(name), "%s%s_%02x:%02d.%d",
-                ADF_DEVICE_NAME_PREFIX, hw_data->dev_class->name,
-                pdev->bus->number, PCI_SLOT(pdev->devfn),
-                PCI_FUNC(pdev->devfn));
+       snprintf(name, sizeof(name), "%s%s_%s", ADF_DEVICE_NAME_PREFIX,
+                hw_data->dev_class->name, pci_name(pdev));
 
        accel_dev->debugfs_dir = debugfs_create_dir(name, NULL);
 
@@ -203,7 +198,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        pci_set_master(pdev);
 
-       if (adf_enable_aer(accel_dev, &adf_driver)) {
+       if (adf_enable_aer(accel_dev)) {
                dev_err(&pdev->dev, "Failed to enable aer\n");
                ret = -EFAULT;
                goto out_err_free_reg;
index 11039fe..456979b 100644 (file)
 #include <adf_cfg.h>
 #include "adf_c3xxxvf_hw_data.h"
 
-#define ADF_SYSTEM_DEVICE(device_id) \
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
-
 static const struct pci_device_id adf_pci_tbl[] = {
-       ADF_SYSTEM_DEVICE(ADF_C3XXXIOV_PCI_DEVICE_ID),
-       {0,}
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QAT_C3XXX_VF), },
+       { }
 };
 MODULE_DEVICE_TABLE(pci, adf_pci_tbl);
 
@@ -58,7 +55,7 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev)
 
        if (accel_dev->hw_device) {
                switch (accel_pci_dev->pci_dev->device) {
-               case ADF_C3XXXIOV_PCI_DEVICE_ID:
+               case PCI_DEVICE_ID_INTEL_QAT_C3XXX_VF:
                        adf_clean_hw_data_c3xxxiov(accel_dev->hw_device);
                        break;
                default:
@@ -85,7 +82,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        int ret;
 
        switch (ent->device) {
-       case ADF_C3XXXIOV_PCI_DEVICE_ID:
+       case PCI_DEVICE_ID_INTEL_QAT_C3XXX_VF:
                break;
        default:
                dev_err(&pdev->dev, "Invalid device 0x%x.\n", ent->device);
@@ -127,10 +124,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        accel_pci_dev->sku = hw_data->get_sku(hw_data);
 
        /* Create dev top level debugfs entry */
-       snprintf(name, sizeof(name), "%s%s_%02x:%02d.%d",
-                ADF_DEVICE_NAME_PREFIX, hw_data->dev_class->name,
-                pdev->bus->number, PCI_SLOT(pdev->devfn),
-                PCI_FUNC(pdev->devfn));
+       snprintf(name, sizeof(name), "%s%s_%s", ADF_DEVICE_NAME_PREFIX,
+                hw_data->dev_class->name, pci_name(pdev));
 
        accel_dev->debugfs_dir = debugfs_create_dir(name, NULL);
 
index 4ba9c14..d8e7c9c 100644 (file)
 #include <adf_cfg.h>
 #include "adf_c62x_hw_data.h"
 
-#define ADF_SYSTEM_DEVICE(device_id) \
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
-
 static const struct pci_device_id adf_pci_tbl[] = {
-       ADF_SYSTEM_DEVICE(ADF_C62X_PCI_DEVICE_ID),
-       {0,}
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QAT_C62X), },
+       { }
 };
 MODULE_DEVICE_TABLE(pci, adf_pci_tbl);
 
@@ -58,7 +55,7 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev)
 
        if (accel_dev->hw_device) {
                switch (accel_pci_dev->pci_dev->device) {
-               case ADF_C62X_PCI_DEVICE_ID:
+               case PCI_DEVICE_ID_INTEL_QAT_C62X:
                        adf_clean_hw_data_c62x(accel_dev->hw_device);
                        break;
                default:
@@ -83,7 +80,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        int ret;
 
        switch (ent->device) {
-       case ADF_C62X_PCI_DEVICE_ID:
+       case PCI_DEVICE_ID_INTEL_QAT_C62X:
                break;
        default:
                dev_err(&pdev->dev, "Invalid device 0x%x.\n", ent->device);
@@ -143,10 +140,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        /* Create dev top level debugfs entry */
-       snprintf(name, sizeof(name), "%s%s_%02x:%02d.%d",
-                ADF_DEVICE_NAME_PREFIX, hw_data->dev_class->name,
-                pdev->bus->number, PCI_SLOT(pdev->devfn),
-                PCI_FUNC(pdev->devfn));
+       snprintf(name, sizeof(name), "%s%s_%s", ADF_DEVICE_NAME_PREFIX,
+                hw_data->dev_class->name, pci_name(pdev));
 
        accel_dev->debugfs_dir = debugfs_create_dir(name, NULL);
 
@@ -203,7 +198,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        pci_set_master(pdev);
 
-       if (adf_enable_aer(accel_dev, &adf_driver)) {
+       if (adf_enable_aer(accel_dev)) {
                dev_err(&pdev->dev, "Failed to enable aer\n");
                ret = -EFAULT;
                goto out_err_free_reg;
index b8b021d..b9810f7 100644 (file)
 #include <adf_cfg.h>
 #include "adf_c62xvf_hw_data.h"
 
-#define ADF_SYSTEM_DEVICE(device_id) \
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
-
 static const struct pci_device_id adf_pci_tbl[] = {
-       ADF_SYSTEM_DEVICE(ADF_C62XIOV_PCI_DEVICE_ID),
-       {0,}
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QAT_C62X_VF), },
+       { }
 };
 MODULE_DEVICE_TABLE(pci, adf_pci_tbl);
 
@@ -58,7 +55,7 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev)
 
        if (accel_dev->hw_device) {
                switch (accel_pci_dev->pci_dev->device) {
-               case ADF_C62XIOV_PCI_DEVICE_ID:
+               case PCI_DEVICE_ID_INTEL_QAT_C62X_VF:
                        adf_clean_hw_data_c62xiov(accel_dev->hw_device);
                        break;
                default:
@@ -85,7 +82,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        int ret;
 
        switch (ent->device) {
-       case ADF_C62XIOV_PCI_DEVICE_ID:
+       case PCI_DEVICE_ID_INTEL_QAT_C62X_VF:
                break;
        default:
                dev_err(&pdev->dev, "Invalid device 0x%x.\n", ent->device);
@@ -127,10 +124,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        accel_pci_dev->sku = hw_data->get_sku(hw_data);
 
        /* Create dev top level debugfs entry */
-       snprintf(name, sizeof(name), "%s%s_%02x:%02d.%d",
-                ADF_DEVICE_NAME_PREFIX, hw_data->dev_class->name,
-                pdev->bus->number, PCI_SLOT(pdev->devfn),
-                PCI_FUNC(pdev->devfn));
+       snprintf(name, sizeof(name), "%s%s_%s", ADF_DEVICE_NAME_PREFIX,
+                hw_data->dev_class->name, pci_name(pdev));
 
        accel_dev->debugfs_dir = debugfs_create_dir(name, NULL);
 
index c1db8c2..06952ec 100644 (file)
 #define ADF_C62XVF_DEVICE_NAME "c6xxvf"
 #define ADF_C3XXX_DEVICE_NAME "c3xxx"
 #define ADF_C3XXXVF_DEVICE_NAME "c3xxxvf"
-#define ADF_DH895XCC_PCI_DEVICE_ID 0x435
-#define ADF_DH895XCCIOV_PCI_DEVICE_ID 0x443
-#define ADF_C62X_PCI_DEVICE_ID 0x37c8
-#define ADF_C62XIOV_PCI_DEVICE_ID 0x37c9
-#define ADF_C3XXX_PCI_DEVICE_ID 0x19e2
-#define ADF_C3XXXIOV_PCI_DEVICE_ID 0x19e3
 #define ADF_ERRSOU3 (0x3A000 + 0x0C)
 #define ADF_ERRSOU5 (0x3A000 + 0xD8)
 #define ADF_DEVICE_FUSECTL_OFFSET 0x40
index 1c8ca15..ec9b390 100644 (file)
@@ -131,9 +131,10 @@ static int adf_put_admin_msg_sync(struct adf_accel_dev *accel_dev, u32 ae,
        memcpy(admin->virt_addr + offset, in, ADF_ADMINMSG_LEN);
        ADF_CSR_WR(mailbox, mb_offset, 1);
 
-       ret = readl_poll_timeout(mailbox + mb_offset, status,
-                                status == 0, ADF_ADMIN_POLL_DELAY_US,
-                                ADF_ADMIN_POLL_TIMEOUT_US);
+       ret = read_poll_timeout(ADF_CSR_RD, status, status == 0,
+                               ADF_ADMIN_POLL_DELAY_US,
+                               ADF_ADMIN_POLL_TIMEOUT_US, true,
+                               mailbox, mb_offset);
        if (ret < 0) {
                /* Response timeout */
                dev_err(&GET_DEV(accel_dev),
index 32102e2..d2ae293 100644 (file)
@@ -175,7 +175,6 @@ static const struct pci_error_handlers adf_err_handler = {
 /**
  * adf_enable_aer() - Enable Advance Error Reporting for acceleration device
  * @accel_dev:  Pointer to acceleration device.
- * @adf:        PCI device driver owning the given acceleration device.
  *
  * Function enables PCI Advance Error Reporting for the
  * QAT acceleration device accel_dev.
@@ -183,11 +182,12 @@ static const struct pci_error_handlers adf_err_handler = {
  *
  * Return: 0 on success, error code otherwise.
  */
-int adf_enable_aer(struct adf_accel_dev *accel_dev, struct pci_driver *adf)
+int adf_enable_aer(struct adf_accel_dev *accel_dev)
 {
        struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
+       struct pci_driver *pdrv = pdev->driver;
 
-       adf->err_handler = &adf_err_handler;
+       pdrv->err_handler = &adf_err_handler;
        pci_enable_pcie_error_reporting(pdev);
        return 0;
 }
index ac46279..22ae328 100644 (file)
@@ -52,24 +52,7 @@ static const struct seq_operations qat_dev_cfg_sops = {
        .show = qat_dev_cfg_show
 };
 
-static int qat_dev_cfg_open(struct inode *inode, struct file *file)
-{
-       int ret = seq_open(file, &qat_dev_cfg_sops);
-
-       if (!ret) {
-               struct seq_file *seq_f = file->private_data;
-
-               seq_f->private = inode->i_private;
-       }
-       return ret;
-}
-
-static const struct file_operations qat_dev_cfg_fops = {
-       .open = qat_dev_cfg_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = seq_release
-};
+DEFINE_SEQ_ATTRIBUTE(qat_dev_cfg);
 
 /**
  * adf_cfg_dev_add() - Create an acceleration device configuration table.
index ebfcb4e..f22342f 100644 (file)
@@ -95,7 +95,7 @@ void adf_ae_fw_release(struct adf_accel_dev *accel_dev);
 int adf_ae_start(struct adf_accel_dev *accel_dev);
 int adf_ae_stop(struct adf_accel_dev *accel_dev);
 
-int adf_enable_aer(struct adf_accel_dev *accel_dev, struct pci_driver *adf);
+int adf_enable_aer(struct adf_accel_dev *accel_dev);
 void adf_disable_aer(struct adf_accel_dev *accel_dev);
 void adf_reset_sbr(struct adf_accel_dev *accel_dev);
 void adf_reset_flr(struct adf_accel_dev *accel_dev);
index 71d0c44..eb9b3be 100644 (file)
@@ -416,8 +416,6 @@ static long adf_ctl_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
 
 static int __init adf_register_ctl_device_driver(void)
 {
-       mutex_init(&adf_ctl_lock);
-
        if (adf_chr_drv_create())
                goto err_chr_dev;
 
index 72753af..92ec035 100644 (file)
@@ -285,7 +285,7 @@ struct adf_accel_dev *adf_devmgr_get_first(void)
 
 /**
  * adf_devmgr_pci_to_accel_dev() - Get accel_dev associated with the pci_dev.
- * @accel_dev:  Pointer to pci device.
+ * @pci_dev:  Pointer to pci device.
  *
  * Function returns acceleration device associated with the given pci device.
  * To be used by QAT device specific drivers.
index 519fd5a..8b090b7 100644 (file)
@@ -340,7 +340,7 @@ static int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev)
                /* VF is newer than PF and decides whether it is compatible */
                if (accel_dev->vf.pf_version >= hw_data->min_iov_compat_ver)
                        break;
-               /* fall through */
+               fallthrough;
        case ADF_PF2VF_VF_INCOMPATIBLE:
                dev_err(&GET_DEV(accel_dev),
                        "PF (vers %d) and VF (vers %d) are not compatible\n",
index 8827aa1..963b2be 100644 (file)
@@ -173,10 +173,14 @@ EXPORT_SYMBOL_GPL(adf_disable_sriov);
 /**
  * adf_sriov_configure() - Enable SRIOV for the device
  * @pdev:  Pointer to pci device.
+ * @numvfs: Number of virtual functions (VFs) to enable.
+ *
+ * Note that the @numvfs parameter is ignored and all VFs supported by the
+ * device are enabled due to the design of the hardware.
  *
  * Function enables SRIOV for the pci device.
  *
- * Return: 0 on success, error code otherwise.
+ * Return: number of VFs enabled on success, error code otherwise.
  */
 int adf_sriov_configure(struct pci_dev *pdev, int numvfs)
 {
index 2a2eccb..dac25ba 100644 (file)
@@ -77,31 +77,14 @@ static void adf_ring_stop(struct seq_file *sfile, void *v)
        mutex_unlock(&ring_read_lock);
 }
 
-static const struct seq_operations adf_ring_sops = {
+static const struct seq_operations adf_ring_debug_sops = {
        .start = adf_ring_start,
        .next = adf_ring_next,
        .stop = adf_ring_stop,
        .show = adf_ring_show
 };
 
-static int adf_ring_open(struct inode *inode, struct file *file)
-{
-       int ret = seq_open(file, &adf_ring_sops);
-
-       if (!ret) {
-               struct seq_file *seq_f = file->private_data;
-
-               seq_f->private = inode->i_private;
-       }
-       return ret;
-}
-
-static const struct file_operations adf_ring_debug_fops = {
-       .open = adf_ring_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = seq_release
-};
+DEFINE_SEQ_ATTRIBUTE(adf_ring_debug);
 
 int adf_ring_debugfs_add(struct adf_etr_ring_data *ring, const char *name)
 {
@@ -188,31 +171,14 @@ static void adf_bank_stop(struct seq_file *sfile, void *v)
        mutex_unlock(&bank_read_lock);
 }
 
-static const struct seq_operations adf_bank_sops = {
+static const struct seq_operations adf_bank_debug_sops = {
        .start = adf_bank_start,
        .next = adf_bank_next,
        .stop = adf_bank_stop,
        .show = adf_bank_show
 };
 
-static int adf_bank_open(struct inode *inode, struct file *file)
-{
-       int ret = seq_open(file, &adf_bank_sops);
-
-       if (!ret) {
-               struct seq_file *seq_f = file->private_data;
-
-               seq_f->private = inode->i_private;
-       }
-       return ret;
-}
-
-static const struct file_operations adf_bank_debug_fops = {
-       .open = adf_bank_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = seq_release
-};
+DEFINE_SEQ_ATTRIBUTE(adf_bank_debug);
 
 int adf_bank_debugfs_add(struct adf_etr_bank_data *bank)
 {
index 72753b8..d552dbc 100644 (file)
@@ -828,6 +828,11 @@ static int qat_alg_aead_dec(struct aead_request *areq)
        struct icp_qat_fw_la_bulk_req *msg;
        int digst_size = crypto_aead_authsize(aead_tfm);
        int ret, ctr = 0;
+       u32 cipher_len;
+
+       cipher_len = areq->cryptlen - digst_size;
+       if (cipher_len % AES_BLOCK_SIZE != 0)
+               return -EINVAL;
 
        ret = qat_alg_sgl_to_bufl(ctx->inst, areq->src, areq->dst, qat_req);
        if (unlikely(ret))
@@ -842,7 +847,7 @@ static int qat_alg_aead_dec(struct aead_request *areq)
        qat_req->req.comn_mid.src_data_addr = qat_req->buf.blp;
        qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp;
        cipher_param = (void *)&qat_req->req.serv_specif_rqpars;
-       cipher_param->cipher_length = areq->cryptlen - digst_size;
+       cipher_param->cipher_length = cipher_len;
        cipher_param->cipher_offset = areq->assoclen;
        memcpy(cipher_param->u.cipher_IV_array, areq->iv, AES_BLOCK_SIZE);
        auth_param = (void *)((u8 *)cipher_param + sizeof(*cipher_param));
@@ -871,6 +876,9 @@ static int qat_alg_aead_enc(struct aead_request *areq)
        u8 *iv = areq->iv;
        int ret, ctr = 0;
 
+       if (areq->cryptlen % AES_BLOCK_SIZE != 0)
+               return -EINVAL;
+
        ret = qat_alg_sgl_to_bufl(ctx->inst, areq->src, areq->dst, qat_req);
        if (unlikely(ret))
                return ret;
index fa467e0..6b9d476 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright(c) 2014 - 2020 Intel Corporation */
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/pci_ids.h>
 
 #include "adf_accel_devices.h"
 #include "adf_common_drv.h"
@@ -412,7 +413,7 @@ static int qat_hal_init_esram(struct icp_qat_fw_loader_handle *handle)
        unsigned int csr_val;
        int times = 30;
 
-       if (handle->pci_dev->device != ADF_DH895XCC_PCI_DEVICE_ID)
+       if (handle->pci_dev->device != PCI_DEVICE_ID_INTEL_QAT_DH895XCC)
                return 0;
 
        csr_val = ADF_CSR_RD(csr_addr, 0);
@@ -672,13 +673,13 @@ int qat_hal_init(struct adf_accel_dev *accel_dev)
                (void __iomem *)((uintptr_t)handle->hal_cap_ae_xfer_csr_addr_v +
                                 LOCAL_TO_XFER_REG_OFFSET);
        handle->pci_dev = pci_info->pci_dev;
-       if (handle->pci_dev->device == ADF_DH895XCC_PCI_DEVICE_ID) {
+       if (handle->pci_dev->device == PCI_DEVICE_ID_INTEL_QAT_DH895XCC) {
                sram_bar =
                        &pci_info->pci_bars[hw_data->get_sram_bar_id(hw_data)];
                handle->hal_sram_addr_v = sram_bar->virt_addr;
        }
        handle->fw_auth = (handle->pci_dev->device ==
-                          ADF_DH895XCC_PCI_DEVICE_ID) ? false : true;
+                          PCI_DEVICE_ID_INTEL_QAT_DH895XCC) ? false : true;
        handle->hal_handle = kzalloc(sizeof(*handle->hal_handle), GFP_KERNEL);
        if (!handle->hal_handle)
                goto out_hal_handle;
index bff759e..5d1f28c 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/ctype.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/pci_ids.h>
 #include "adf_accel_devices.h"
 #include "adf_common_drv.h"
 #include "icp_qat_uclo.h"
@@ -711,11 +712,11 @@ static unsigned int
 qat_uclo_get_dev_type(struct icp_qat_fw_loader_handle *handle)
 {
        switch (handle->pci_dev->device) {
-       case ADF_DH895XCC_PCI_DEVICE_ID:
+       case PCI_DEVICE_ID_INTEL_QAT_DH895XCC:
                return ICP_QAT_AC_895XCC_DEV_TYPE;
-       case ADF_C62X_PCI_DEVICE_ID:
+       case PCI_DEVICE_ID_INTEL_QAT_C62X:
                return ICP_QAT_AC_C62X_DEV_TYPE;
-       case ADF_C3XXX_PCI_DEVICE_ID:
+       case PCI_DEVICE_ID_INTEL_QAT_C3XXX:
                return ICP_QAT_AC_C3XXX_DEV_TYPE;
        default:
                pr_err("QAT: unsupported device 0x%x\n",
@@ -752,7 +753,7 @@ static int qat_uclo_init_reg(struct icp_qat_fw_loader_handle *handle,
        case ICP_GPA_ABS:
        case ICP_GPB_ABS:
                ctx_mask = 0;
-               /* fall through */
+               fallthrough;
        case ICP_GPA_REL:
        case ICP_GPB_REL:
                return qat_hal_init_gpr(handle, ae, ctx_mask, reg_type,
@@ -762,7 +763,7 @@ static int qat_uclo_init_reg(struct icp_qat_fw_loader_handle *handle,
        case ICP_SR_RD_ABS:
        case ICP_DR_RD_ABS:
                ctx_mask = 0;
-               /* fall through */
+               fallthrough;
        case ICP_SR_REL:
        case ICP_DR_REL:
        case ICP_SR_RD_REL:
@@ -772,7 +773,7 @@ static int qat_uclo_init_reg(struct icp_qat_fw_loader_handle *handle,
        case ICP_SR_WR_ABS:
        case ICP_DR_WR_ABS:
                ctx_mask = 0;
-               /* fall through */
+               fallthrough;
        case ICP_SR_WR_REL:
        case ICP_DR_WR_REL:
                return qat_hal_init_wr_xfer(handle, ae, ctx_mask, reg_type,
@@ -1391,7 +1392,7 @@ int qat_uclo_wr_mimage(struct icp_qat_fw_loader_handle *handle,
                        status = qat_uclo_auth_fw(handle, desc);
                qat_uclo_ummap_auth_fw(handle, &desc);
        } else {
-               if (handle->pci_dev->device == ADF_C3XXX_PCI_DEVICE_ID) {
+               if (handle->pci_dev->device == PCI_DEVICE_ID_INTEL_QAT_C3XXX) {
                        pr_err("QAT: C3XXX doesn't support unsigned MMP\n");
                        return -EINVAL;
                }
index 4e877b7..ecb4f6f 100644 (file)
 #include <adf_cfg.h>
 #include "adf_dh895xcc_hw_data.h"
 
-#define ADF_SYSTEM_DEVICE(device_id) \
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
-
 static const struct pci_device_id adf_pci_tbl[] = {
-       ADF_SYSTEM_DEVICE(ADF_DH895XCC_PCI_DEVICE_ID),
-       {0,}
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QAT_DH895XCC), },
+       { }
 };
 MODULE_DEVICE_TABLE(pci, adf_pci_tbl);
 
@@ -58,7 +55,7 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev)
 
        if (accel_dev->hw_device) {
                switch (accel_pci_dev->pci_dev->device) {
-               case ADF_DH895XCC_PCI_DEVICE_ID:
+               case PCI_DEVICE_ID_INTEL_QAT_DH895XCC:
                        adf_clean_hw_data_dh895xcc(accel_dev->hw_device);
                        break;
                default:
@@ -83,7 +80,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        int ret;
 
        switch (ent->device) {
-       case ADF_DH895XCC_PCI_DEVICE_ID:
+       case PCI_DEVICE_ID_INTEL_QAT_DH895XCC:
                break;
        default:
                dev_err(&pdev->dev, "Invalid device 0x%x.\n", ent->device);
@@ -143,10 +140,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        /* Create dev top level debugfs entry */
-       snprintf(name, sizeof(name), "%s%s_%02x:%02d.%d",
-                ADF_DEVICE_NAME_PREFIX, hw_data->dev_class->name,
-                pdev->bus->number, PCI_SLOT(pdev->devfn),
-                PCI_FUNC(pdev->devfn));
+       snprintf(name, sizeof(name), "%s%s_%s", ADF_DEVICE_NAME_PREFIX,
+                hw_data->dev_class->name, pci_name(pdev));
 
        accel_dev->debugfs_dir = debugfs_create_dir(name, NULL);
 
@@ -205,7 +200,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        pci_set_master(pdev);
 
-       if (adf_enable_aer(accel_dev, &adf_driver)) {
+       if (adf_enable_aer(accel_dev)) {
                dev_err(&pdev->dev, "Failed to enable aer\n");
                ret = -EFAULT;
                goto out_err_free_reg;
index 7d6e1db..404cf9d 100644 (file)
 #include <adf_cfg.h>
 #include "adf_dh895xccvf_hw_data.h"
 
-#define ADF_SYSTEM_DEVICE(device_id) \
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
-
 static const struct pci_device_id adf_pci_tbl[] = {
-       ADF_SYSTEM_DEVICE(ADF_DH895XCCIOV_PCI_DEVICE_ID),
-       {0,}
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QAT_DH895XCC_VF), },
+       { }
 };
 MODULE_DEVICE_TABLE(pci, adf_pci_tbl);
 
@@ -58,7 +55,7 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev)
 
        if (accel_dev->hw_device) {
                switch (accel_pci_dev->pci_dev->device) {
-               case ADF_DH895XCCIOV_PCI_DEVICE_ID:
+               case PCI_DEVICE_ID_INTEL_QAT_DH895XCC_VF:
                        adf_clean_hw_data_dh895xcciov(accel_dev->hw_device);
                        break;
                default:
@@ -85,7 +82,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        int ret;
 
        switch (ent->device) {
-       case ADF_DH895XCCIOV_PCI_DEVICE_ID:
+       case PCI_DEVICE_ID_INTEL_QAT_DH895XCC_VF:
                break;
        default:
                dev_err(&pdev->dev, "Invalid device 0x%x.\n", ent->device);
@@ -127,10 +124,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        accel_pci_dev->sku = hw_data->get_sku(hw_data);
 
        /* Create dev top level debugfs entry */
-       snprintf(name, sizeof(name), "%s%s_%02x:%02d.%d",
-                ADF_DEVICE_NAME_PREFIX, hw_data->dev_class->name,
-                pdev->bus->number, PCI_SLOT(pdev->devfn),
-                PCI_FUNC(pdev->devfn));
+       snprintf(name, sizeof(name), "%s%s_%s", ADF_DEVICE_NAME_PREFIX,
+                hw_data->dev_class->name, pci_name(pdev));
 
        accel_dev->debugfs_dir = debugfs_create_dir(name, NULL);
 
index cb6d61e..ea616b7 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
index c230843..87be96a 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <crypto/internal/hash.h>
 
index 5630c5a..a2d3da0 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
index 4730f84..99ba8d5 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/acpi.h>
 #include <linux/clk.h>
 #include <linux/crypto.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
index f385587..35d7306 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include "rk3288_crypto.h"
+#include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
index 2b49c67..3db5955 100644 (file)
@@ -7,6 +7,7 @@
 #include <crypto/algapi.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/scatterlist.h>
 #include <crypto/internal/hash.h>
 #include <crypto/internal/skcipher.h>
 
index 6b7ecbe..81befe7 100644 (file)
@@ -8,6 +8,7 @@
  *
  * Some ideas are from marvell/cesa.c and s5p-sss.c driver.
  */
+#include <linux/device.h>
 #include "rk3288_crypto.h"
 
 /*
index 4a75c8e..1cece1a 100644 (file)
@@ -8,6 +8,7 @@
  *
  * Some ideas are from marvell-cesa.c and s5p-sss.c driver.
  */
+#include <linux/device.h>
 #include "rk3288_crypto.h"
 
 #define RK_CRYPTO_DEC                  BIT(0)
index 341433f..88a6c85 100644 (file)
@@ -260,6 +260,7 @@ struct s5p_aes_ctx {
  * struct s5p_aes_dev - Crypto device state container
  * @dev:       Associated device
  * @clk:       Clock for accessing hardware
+ * @pclk:      APB bus clock necessary to access the hardware
  * @ioaddr:    Mapped IO memory region
  * @aes_ioaddr:        Per-varian offset for AES block IO memory
  * @irq_fc:    Feed control interrupt line
@@ -342,13 +343,13 @@ struct s5p_aes_dev {
  * @engine:    Bits for selecting type of HASH in SSS block
  * @sg:                sg for DMA transfer
  * @sg_len:    Length of sg for DMA transfer
- * @sgl[]:     sg for joining buffer and req->src scatterlist
+ * @sgl:       sg for joining buffer and req->src scatterlist
  * @skip:      Skip offset in req->src for current op
  * @total:     Total number of bytes for current request
  * @finup:     Keep state for finup or final.
  * @error:     Keep track of error.
  * @bufcnt:    Number of bytes holded in buffer[]
- * @buffer[]:  For byte(s) from end of req->src in UPDATE op
+ * @buffer:    For byte(s) from end of req->src in UPDATE op
  */
 struct s5p_hash_reqctx {
        struct s5p_aes_dev      *dd;
@@ -1125,7 +1126,7 @@ static int s5p_hash_copy_sg_lists(struct s5p_hash_reqctx *ctx,
  * s5p_hash_prepare_sgs() - prepare sg for processing
  * @ctx:       request context
  * @sg:                source scatterlist request
- * @nbytes:    number of bytes to process from sg
+ * @new_len:   number of bytes to process from sg
  * @final:     final flag
  *
  * Check two conditions: (1) if buffers in sg have len aligned data, and (2)
@@ -2200,11 +2201,10 @@ static int s5p_aes_probe(struct platform_device *pdev)
        }
 
        pdata->clk = devm_clk_get(dev, variant->clk_names[0]);
-       if (IS_ERR(pdata->clk)) {
-               dev_err(dev, "failed to find secss clock %s\n",
-                       variant->clk_names[0]);
-               return -ENOENT;
-       }
+       if (IS_ERR(pdata->clk))
+               return dev_err_probe(dev, PTR_ERR(pdata->clk),
+                                    "failed to find secss clock %s\n",
+                                    variant->clk_names[0]);
 
        err = clk_prepare_enable(pdata->clk);
        if (err < 0) {
@@ -2216,9 +2216,9 @@ static int s5p_aes_probe(struct platform_device *pdev)
        if (variant->clk_names[1]) {
                pdata->pclk = devm_clk_get(dev, variant->clk_names[1]);
                if (IS_ERR(pdata->pclk)) {
-                       dev_err(dev, "failed to find clock %s\n",
-                               variant->clk_names[1]);
-                       err = -ENOENT;
+                       err = dev_err_probe(dev, PTR_ERR(pdata->pclk),
+                                           "failed to find clock %s\n",
+                                           variant->clk_names[1]);
                        goto err_clk;
                }
 
@@ -2307,8 +2307,7 @@ err_algs:
        tasklet_kill(&pdata->tasklet);
 
 err_irq:
-       if (pdata->pclk)
-               clk_disable_unprepare(pdata->pclk);
+       clk_disable_unprepare(pdata->pclk);
 
 err_clk:
        clk_disable_unprepare(pdata->clk);
@@ -2338,8 +2337,7 @@ static int s5p_aes_remove(struct platform_device *pdev)
                pdata->use_hash = false;
        }
 
-       if (pdata->pclk)
-               clk_disable_unprepare(pdata->pclk);
+       clk_disable_unprepare(pdata->pclk);
 
        clk_disable_unprepare(pdata->clk);
        s5p_dev = NULL;
index 5bc0990..eda93fa 100644 (file)
@@ -143,33 +143,38 @@ struct sa_alg_tmpl {
 };
 
 /**
+ * struct sa_mapped_sg: scatterlist information for tx and rx
+ * @mapped: Set to true if the @sgt is mapped
+ * @dir: mapping direction used for @sgt
+ * @split_sg: Set if the sg is split and needs to be freed up
+ * @static_sg: Static scatterlist entry for overriding data
+ * @sgt: scatterlist table for DMA API use
+ */
+struct sa_mapped_sg {
+       bool mapped;
+       enum dma_data_direction dir;
+       struct scatterlist static_sg;
+       struct scatterlist *split_sg;
+       struct sg_table sgt;
+};
+/**
  * struct sa_rx_data: RX Packet miscellaneous data place holder
  * @req: crypto request data pointer
  * @ddev: pointer to the DMA device
  * @tx_in: dma_async_tx_descriptor pointer for rx channel
- * @split_src_sg: Set if the src sg is split and needs to be freed up
- * @split_dst_sg: Set if the dst sg is split and needs to be freed up
+ * @mapped_sg: Information on tx (0) and rx (1) scatterlist DMA mapping
  * @enc: Flag indicating either encryption or decryption
  * @enc_iv_size: Initialisation vector size
  * @iv_idx: Initialisation vector index
- * @rx_sg: Static scatterlist entry for overriding RX data
- * @tx_sg: Static scatterlist entry for overriding TX data
- * @src: Source data pointer
- * @dst: Destination data pointer
  */
 struct sa_rx_data {
        void *req;
        struct device *ddev;
        struct dma_async_tx_descriptor *tx_in;
-       struct scatterlist *split_src_sg;
-       struct scatterlist *split_dst_sg;
+       struct sa_mapped_sg mapped_sg[2];
        u8 enc;
        u8 enc_iv_size;
        u8 iv_idx;
-       struct scatterlist rx_sg;
-       struct scatterlist tx_sg;
-       struct scatterlist *src;
-       struct scatterlist *dst;
 };
 
 /**
@@ -976,23 +981,46 @@ static int sa_3des_ecb_setkey(struct crypto_skcipher *tfm, const u8 *key,
        return sa_cipher_setkey(tfm, key, keylen, &ad);
 }
 
+static void sa_sync_from_device(struct sa_rx_data *rxd)
+{
+       struct sg_table *sgt;
+
+       if (rxd->mapped_sg[0].dir == DMA_BIDIRECTIONAL)
+               sgt = &rxd->mapped_sg[0].sgt;
+       else
+               sgt = &rxd->mapped_sg[1].sgt;
+
+       dma_sync_sgtable_for_cpu(rxd->ddev, sgt, DMA_FROM_DEVICE);
+}
+
+static void sa_free_sa_rx_data(struct sa_rx_data *rxd)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rxd->mapped_sg); i++) {
+               struct sa_mapped_sg *mapped_sg = &rxd->mapped_sg[i];
+
+               if (mapped_sg->mapped) {
+                       dma_unmap_sgtable(rxd->ddev, &mapped_sg->sgt,
+                                         mapped_sg->dir, 0);
+                       kfree(mapped_sg->split_sg);
+               }
+       }
+
+       kfree(rxd);
+}
+
 static void sa_aes_dma_in_callback(void *data)
 {
        struct sa_rx_data *rxd = (struct sa_rx_data *)data;
        struct skcipher_request *req;
-       int sglen;
        u32 *result;
        __be32 *mdptr;
        size_t ml, pl;
        int i;
-       enum dma_data_direction dir_src;
-       bool diff_dst;
 
+       sa_sync_from_device(rxd);
        req = container_of(rxd->req, struct skcipher_request, base);
-       sglen = sg_nents_for_len(req->src, req->cryptlen);
-
-       diff_dst = (req->src != req->dst) ? true : false;
-       dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
 
        if (req->iv) {
                mdptr = (__be32 *)dmaengine_desc_get_metadata_ptr(rxd->tx_in, &pl,
@@ -1003,18 +1031,7 @@ static void sa_aes_dma_in_callback(void *data)
                        result[i] = be32_to_cpu(mdptr[i + rxd->iv_idx]);
        }
 
-       dma_unmap_sg(rxd->ddev, req->src, sglen, dir_src);
-       kfree(rxd->split_src_sg);
-
-       if (diff_dst) {
-               sglen = sg_nents_for_len(req->dst, req->cryptlen);
-
-               dma_unmap_sg(rxd->ddev, req->dst, sglen,
-                            DMA_FROM_DEVICE);
-               kfree(rxd->split_dst_sg);
-       }
-
-       kfree(rxd);
+       sa_free_sa_rx_data(rxd);
 
        skcipher_request_complete(req, 0);
 }
@@ -1043,7 +1060,6 @@ static int sa_run(struct sa_req *req)
        struct device *ddev;
        struct dma_chan *dma_rx;
        int sg_nents, src_nents, dst_nents;
-       int mapped_src_nents, mapped_dst_nents;
        struct scatterlist *src, *dst;
        size_t pl, ml, split_size;
        struct sa_ctx_info *sa_ctx = req->enc ? &req->ctx->enc : &req->ctx->dec;
@@ -1052,6 +1068,7 @@ static int sa_run(struct sa_req *req)
        u32 *mdptr;
        bool diff_dst;
        enum dma_data_direction dir_src;
+       struct sa_mapped_sg *mapped_sg;
 
        gfp_flags = req->base->flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
                GFP_KERNEL : GFP_ATOMIC;
@@ -1082,6 +1099,7 @@ static int sa_run(struct sa_req *req)
                dma_rx = pdata->dma_rx1;
 
        ddev = dma_rx->device->dev;
+       rxd->ddev = ddev;
 
        memcpy(cmdl, sa_ctx->cmdl, sa_ctx->cmdl_size);
 
@@ -1109,60 +1127,90 @@ static int sa_run(struct sa_req *req)
 
        split_size = req->size;
 
+       mapped_sg = &rxd->mapped_sg[0];
        if (sg_nents == 1 && split_size <= req->src->length) {
-               src = &rxd->rx_sg;
+               src = &mapped_sg->static_sg;
+               src_nents = 1;
                sg_init_table(src, 1);
                sg_set_page(src, sg_page(req->src), split_size,
                            req->src->offset);
-               src_nents = 1;
-               dma_map_sg(ddev, src, sg_nents, dir_src);
+
+               mapped_sg->sgt.sgl = src;
+               mapped_sg->sgt.orig_nents = src_nents;
+               ret = dma_map_sgtable(ddev, &mapped_sg->sgt, dir_src, 0);
+               if (ret)
+                       return ret;
+
+               mapped_sg->dir = dir_src;
+               mapped_sg->mapped = true;
        } else {
-               mapped_src_nents = dma_map_sg(ddev, req->src, sg_nents,
-                                             dir_src);
-               ret = sg_split(req->src, mapped_src_nents, 0, 1, &split_size,
-                              &src, &src_nents, gfp_flags);
+               mapped_sg->sgt.sgl = req->src;
+               mapped_sg->sgt.orig_nents = sg_nents;
+               ret = dma_map_sgtable(ddev, &mapped_sg->sgt, dir_src, 0);
+               if (ret)
+                       return ret;
+
+               mapped_sg->dir = dir_src;
+               mapped_sg->mapped = true;
+
+               ret = sg_split(mapped_sg->sgt.sgl, mapped_sg->sgt.nents, 0, 1,
+                              &split_size, &src, &src_nents, gfp_flags);
                if (ret) {
-                       src_nents = sg_nents;
-                       src = req->src;
+                       src_nents = mapped_sg->sgt.nents;
+                       src = mapped_sg->sgt.sgl;
                } else {
-                       rxd->split_src_sg = src;
+                       mapped_sg->split_sg = src;
                }
        }
 
+       dma_sync_sgtable_for_device(ddev, &mapped_sg->sgt, DMA_TO_DEVICE);
+
        if (!diff_dst) {
                dst_nents = src_nents;
                dst = src;
        } else {
                dst_nents = sg_nents_for_len(req->dst, req->size);
+               mapped_sg = &rxd->mapped_sg[1];
 
                if (dst_nents == 1 && split_size <= req->dst->length) {
-                       dst = &rxd->tx_sg;
+                       dst = &mapped_sg->static_sg;
+                       dst_nents = 1;
                        sg_init_table(dst, 1);
                        sg_set_page(dst, sg_page(req->dst), split_size,
                                    req->dst->offset);
-                       dst_nents = 1;
-                       dma_map_sg(ddev, dst, dst_nents, DMA_FROM_DEVICE);
+
+                       mapped_sg->sgt.sgl = dst;
+                       mapped_sg->sgt.orig_nents = dst_nents;
+                       ret = dma_map_sgtable(ddev, &mapped_sg->sgt,
+                                             DMA_FROM_DEVICE, 0);
+                       if (ret)
+                               goto err_cleanup;
+
+                       mapped_sg->dir = DMA_FROM_DEVICE;
+                       mapped_sg->mapped = true;
                } else {
-                       mapped_dst_nents = dma_map_sg(ddev, req->dst, dst_nents,
-                                                     DMA_FROM_DEVICE);
-                       ret = sg_split(req->dst, mapped_dst_nents, 0, 1,
-                                      &split_size, &dst, &dst_nents,
+                       mapped_sg->sgt.sgl = req->dst;
+                       mapped_sg->sgt.orig_nents = dst_nents;
+                       ret = dma_map_sgtable(ddev, &mapped_sg->sgt,
+                                             DMA_FROM_DEVICE, 0);
+                       if (ret)
+                               goto err_cleanup;
+
+                       mapped_sg->dir = DMA_FROM_DEVICE;
+                       mapped_sg->mapped = true;
+
+                       ret = sg_split(mapped_sg->sgt.sgl, mapped_sg->sgt.nents,
+                                      0, 1, &split_size, &dst, &dst_nents,
                                       gfp_flags);
                        if (ret) {
-                               dst_nents = dst_nents;
-                               dst = req->dst;
+                               dst_nents = mapped_sg->sgt.nents;
+                               dst = mapped_sg->sgt.sgl;
                        } else {
-                               rxd->split_dst_sg = dst;
+                               mapped_sg->split_sg = dst;
                        }
                }
        }
 
-       if (unlikely(src_nents != sg_nents)) {
-               dev_warn_ratelimited(sa_k3_dev, "failed to map tx pkt\n");
-               ret = -EIO;
-               goto err_cleanup;
-       }
-
        rxd->tx_in = dmaengine_prep_slave_sg(dma_rx, dst, dst_nents,
                                             DMA_DEV_TO_MEM,
                                             DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -1174,9 +1222,6 @@ static int sa_run(struct sa_req *req)
 
        rxd->req = (void *)req->base;
        rxd->enc = req->enc;
-       rxd->ddev = ddev;
-       rxd->src = src;
-       rxd->dst = dst;
        rxd->iv_idx = req->ctx->iv_idx;
        rxd->enc_iv_size = sa_ctx->cmdl_upd_info.enc_iv.size;
        rxd->tx_in->callback = req->callback;
@@ -1214,16 +1259,7 @@ static int sa_run(struct sa_req *req)
        return -EINPROGRESS;
 
 err_cleanup:
-       dma_unmap_sg(ddev, req->src, sg_nents, DMA_TO_DEVICE);
-       kfree(rxd->split_src_sg);
-
-       if (req->src != req->dst) {
-               dst_nents = sg_nents_for_len(req->dst, req->size);
-               dma_unmap_sg(ddev, req->dst, dst_nents, DMA_FROM_DEVICE);
-               kfree(rxd->split_dst_sg);
-       }
-
-       kfree(rxd);
+       sa_free_sa_rx_data(rxd);
 
        return ret;
 }
@@ -1293,11 +1329,12 @@ static void sa_sha_dma_in_callback(void *data)
        struct ahash_request *req;
        struct crypto_ahash *tfm;
        unsigned int authsize;
-       int i, sg_nents;
+       int i;
        size_t ml, pl;
        u32 *result;
        __be32 *mdptr;
 
+       sa_sync_from_device(rxd);
        req = container_of(rxd->req, struct ahash_request, base);
        tfm = crypto_ahash_reqtfm(req);
        authsize = crypto_ahash_digestsize(tfm);
@@ -1308,12 +1345,7 @@ static void sa_sha_dma_in_callback(void *data)
        for (i = 0; i < (authsize / 4); i++)
                result[i] = be32_to_cpu(mdptr[i + 4]);
 
-       sg_nents = sg_nents_for_len(req->src, req->nbytes);
-       dma_unmap_sg(rxd->ddev, req->src, sg_nents, DMA_FROM_DEVICE);
-
-       kfree(rxd->split_src_sg);
-
-       kfree(rxd);
+       sa_free_sa_rx_data(rxd);
 
        ahash_request_complete(req, 0);
 }
@@ -1482,8 +1514,8 @@ static int sa_sha_init(struct ahash_request *req)
        struct sa_sha_req_ctx *rctx = ahash_request_ctx(req);
        struct sa_tfm_ctx *ctx = crypto_ahash_ctx(tfm);
 
-       dev_dbg(sa_k3_dev, "init: digest size: %d, rctx=%llx\n",
-               crypto_ahash_digestsize(tfm), (u64)rctx);
+       dev_dbg(sa_k3_dev, "init: digest size: %u, rctx=%p\n",
+               crypto_ahash_digestsize(tfm), rctx);
 
        ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback.ahash);
        rctx->fallback_req.base.flags =
@@ -1637,43 +1669,28 @@ static void sa_aead_dma_in_callback(void *data)
        unsigned int authsize;
        u8 auth_tag[SA_MAX_AUTH_TAG_SZ];
        size_t pl, ml;
-       int i, sglen;
+       int i;
        int err = 0;
        u16 auth_len;
        u32 *mdptr;
-       bool diff_dst;
-       enum dma_data_direction dir_src;
 
+       sa_sync_from_device(rxd);
        req = container_of(rxd->req, struct aead_request, base);
        tfm = crypto_aead_reqtfm(req);
        start = req->assoclen + req->cryptlen;
        authsize = crypto_aead_authsize(tfm);
 
-       diff_dst = (req->src != req->dst) ? true : false;
-       dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
-
        mdptr = (u32 *)dmaengine_desc_get_metadata_ptr(rxd->tx_in, &pl, &ml);
        for (i = 0; i < (authsize / 4); i++)
                mdptr[i + 4] = swab32(mdptr[i + 4]);
 
        auth_len = req->assoclen + req->cryptlen;
-       if (!rxd->enc)
-               auth_len -= authsize;
-
-       sglen =  sg_nents_for_len(rxd->src, auth_len);
-       dma_unmap_sg(rxd->ddev, rxd->src, sglen, dir_src);
-       kfree(rxd->split_src_sg);
-
-       if (diff_dst) {
-               sglen = sg_nents_for_len(rxd->dst, auth_len);
-               dma_unmap_sg(rxd->ddev, rxd->dst, sglen, DMA_FROM_DEVICE);
-               kfree(rxd->split_dst_sg);
-       }
 
        if (rxd->enc) {
                scatterwalk_map_and_copy(&mdptr[4], req->dst, start, authsize,
                                         1);
        } else {
+               auth_len -= authsize;
                start -= authsize;
                scatterwalk_map_and_copy(auth_tag, req->src, start, authsize,
                                         0);
@@ -1681,7 +1698,7 @@ static void sa_aead_dma_in_callback(void *data)
                err = memcmp(&mdptr[4], auth_tag, authsize) ? -EBADMSG : 0;
        }
 
-       kfree(rxd);
+       sa_free_sa_rx_data(rxd);
 
        aead_request_complete(req, err);
 }
@@ -2243,25 +2260,21 @@ static int sa_dma_init(struct sa_crypto_data *dd)
                return ret;
 
        dd->dma_rx1 = dma_request_chan(dd->dev, "rx1");
-       if (IS_ERR(dd->dma_rx1)) {
-               if (PTR_ERR(dd->dma_rx1) != -EPROBE_DEFER)
-                       dev_err(dd->dev, "Unable to request rx1 DMA channel\n");
-               return PTR_ERR(dd->dma_rx1);
-       }
+       if (IS_ERR(dd->dma_rx1))
+               return dev_err_probe(dd->dev, PTR_ERR(dd->dma_rx1),
+                                    "Unable to request rx1 DMA channel\n");
 
        dd->dma_rx2 = dma_request_chan(dd->dev, "rx2");
        if (IS_ERR(dd->dma_rx2)) {
                dma_release_channel(dd->dma_rx1);
-               if (PTR_ERR(dd->dma_rx2) != -EPROBE_DEFER)
-                       dev_err(dd->dev, "Unable to request rx2 DMA channel\n");
-               return PTR_ERR(dd->dma_rx2);
+               return dev_err_probe(dd->dev, PTR_ERR(dd->dma_rx2),
+                                    "Unable to request rx2 DMA channel\n");
        }
 
        dd->dma_tx = dma_request_chan(dd->dev, "tx");
        if (IS_ERR(dd->dma_tx)) {
-               if (PTR_ERR(dd->dma_tx) != -EPROBE_DEFER)
-                       dev_err(dd->dev, "Unable to request tx DMA channel\n");
-               ret = PTR_ERR(dd->dma_tx);
+               ret = dev_err_probe(dd->dev, PTR_ERR(dd->dma_tx),
+                                   "Unable to request tx DMA channel\n");
                goto err_dma_tx;
        }
 
@@ -2333,7 +2346,7 @@ static int sa_ul_probe(struct platform_device *pdev)
 
        pm_runtime_enable(dev);
        ret = pm_runtime_get_sync(dev);
-       if (ret) {
+       if (ret < 0) {
                dev_err(&pdev->dev, "%s: failed to get sync: %d\n", __func__,
                        ret);
                return ret;
index 0c8cb23..d60679c 100644 (file)
@@ -18,7 +18,7 @@
 #include <crypto/sha.h>
 
 #include <linux/clk.h>
-#include <linux/crypto.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
index 4ef3eb1..4a4c328 100644 (file)
@@ -3,6 +3,7 @@ config CRYPTO_DEV_STM32_CRC
        tristate "Support for STM32 crc accelerators"
        depends on ARCH_STM32
        select CRYPTO_HASH
+       select CRC32
        help
          This enables support for the CRC32 hw accelerator which can be found
          on STMicroelectronics STM32 SOC.
index 3ba4114..75867c0 100644 (file)
@@ -6,7 +6,10 @@
 
 #include <linux/bitrev.h>
 #include <linux/clk.h>
+#include <linux/crc32.h>
 #include <linux/crc32poly.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
@@ -147,7 +150,6 @@ static int burst_update(struct shash_desc *desc, const u8 *d8,
        struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc);
        struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm);
        struct stm32_crc *crc;
-       unsigned long flags;
 
        crc = stm32_crc_get_next_crc();
        if (!crc)
@@ -155,7 +157,15 @@ static int burst_update(struct shash_desc *desc, const u8 *d8,
 
        pm_runtime_get_sync(crc->dev);
 
-       spin_lock_irqsave(&crc->lock, flags);
+       if (!spin_trylock(&crc->lock)) {
+               /* Hardware is busy, calculate crc32 by software */
+               if (mctx->poly == CRC32_POLY_LE)
+                       ctx->partial = crc32_le(ctx->partial, d8, length);
+               else
+                       ctx->partial = __crc32c_le(ctx->partial, d8, length);
+
+               goto pm_out;
+       }
 
        /*
         * Restore previously calculated CRC for this context as init value
@@ -195,8 +205,9 @@ static int burst_update(struct shash_desc *desc, const u8 *d8,
        /* Store partial result */
        ctx->partial = readl_relaxed(crc->regs + CRC_DR);
 
-       spin_unlock_irqrestore(&crc->lock, flags);
+       spin_unlock(&crc->lock);
 
+pm_out:
        pm_runtime_mark_last_busy(crc->dev);
        pm_runtime_put_autosuspend(crc->dev);
 
@@ -216,9 +227,8 @@ static int stm32_crc_update(struct shash_desc *desc, const u8 *d8,
                return burst_update(desc, d8, length);
 
        /* Digest first bytes not 32bit aligned at first pass in the loop */
-       size = min(length,
-                  burst_sz + (unsigned int)d8 - ALIGN_DOWN((unsigned int)d8,
-                                                           sizeof(u32)));
+       size = min_t(size_t, length, burst_sz + (size_t)d8 -
+                                    ALIGN_DOWN((size_t)d8, sizeof(u32)));
        for (rem_sz = length, cur = d8; rem_sz;
             rem_sz -= size, cur += size, size = min(rem_sz, burst_sz)) {
                ret = burst_update(desc, cur, size);
index d347a1d..2670c30 100644 (file)
@@ -118,7 +118,7 @@ struct stm32_cryp_ctx {
        struct crypto_engine_ctx enginectx;
        struct stm32_cryp       *cryp;
        int                     keylen;
-       u32                     key[AES_KEYSIZE_256 / sizeof(u32)];
+       __be32                  key[AES_KEYSIZE_256 / sizeof(u32)];
        unsigned long           flags;
 };
 
@@ -380,24 +380,24 @@ static int stm32_cryp_copy_sgs(struct stm32_cryp *cryp)
        return 0;
 }
 
-static void stm32_cryp_hw_write_iv(struct stm32_cryp *cryp, u32 *iv)
+static void stm32_cryp_hw_write_iv(struct stm32_cryp *cryp, __be32 *iv)
 {
        if (!iv)
                return;
 
-       stm32_cryp_write(cryp, CRYP_IV0LR, cpu_to_be32(*iv++));
-       stm32_cryp_write(cryp, CRYP_IV0RR, cpu_to_be32(*iv++));
+       stm32_cryp_write(cryp, CRYP_IV0LR, be32_to_cpu(*iv++));
+       stm32_cryp_write(cryp, CRYP_IV0RR, be32_to_cpu(*iv++));
 
        if (is_aes(cryp)) {
-               stm32_cryp_write(cryp, CRYP_IV1LR, cpu_to_be32(*iv++));
-               stm32_cryp_write(cryp, CRYP_IV1RR, cpu_to_be32(*iv++));
+               stm32_cryp_write(cryp, CRYP_IV1LR, be32_to_cpu(*iv++));
+               stm32_cryp_write(cryp, CRYP_IV1RR, be32_to_cpu(*iv++));
        }
 }
 
 static void stm32_cryp_get_iv(struct stm32_cryp *cryp)
 {
        struct skcipher_request *req = cryp->req;
-       u32 *tmp = (void *)req->iv;
+       __be32 *tmp = (void *)req->iv;
 
        if (!tmp)
                return;
@@ -417,13 +417,13 @@ static void stm32_cryp_hw_write_key(struct stm32_cryp *c)
        int r_id;
 
        if (is_des(c)) {
-               stm32_cryp_write(c, CRYP_K1LR, cpu_to_be32(c->ctx->key[0]));
-               stm32_cryp_write(c, CRYP_K1RR, cpu_to_be32(c->ctx->key[1]));
+               stm32_cryp_write(c, CRYP_K1LR, be32_to_cpu(c->ctx->key[0]));
+               stm32_cryp_write(c, CRYP_K1RR, be32_to_cpu(c->ctx->key[1]));
        } else {
                r_id = CRYP_K3RR;
                for (i = c->ctx->keylen / sizeof(u32); i > 0; i--, r_id -= 4)
                        stm32_cryp_write(c, r_id,
-                                        cpu_to_be32(c->ctx->key[i - 1]));
+                                        be32_to_cpu(c->ctx->key[i - 1]));
        }
 }
 
@@ -469,7 +469,7 @@ static unsigned int stm32_cryp_get_input_text_len(struct stm32_cryp *cryp)
 static int stm32_cryp_gcm_init(struct stm32_cryp *cryp, u32 cfg)
 {
        int ret;
-       u32 iv[4];
+       __be32 iv[4];
 
        /* Phase 1 : init */
        memcpy(iv, cryp->areq->iv, 12);
@@ -491,6 +491,7 @@ static int stm32_cryp_ccm_init(struct stm32_cryp *cryp, u32 cfg)
 {
        int ret;
        u8 iv[AES_BLOCK_SIZE], b0[AES_BLOCK_SIZE];
+       __be32 *bd;
        u32 *d;
        unsigned int i, textlen;
 
@@ -498,7 +499,7 @@ static int stm32_cryp_ccm_init(struct stm32_cryp *cryp, u32 cfg)
        memcpy(iv, cryp->areq->iv, AES_BLOCK_SIZE);
        memset(iv + AES_BLOCK_SIZE - 1 - iv[0], 0, iv[0] + 1);
        iv[AES_BLOCK_SIZE - 1] = 1;
-       stm32_cryp_hw_write_iv(cryp, (u32 *)iv);
+       stm32_cryp_hw_write_iv(cryp, (__be32 *)iv);
 
        /* Build B0 */
        memcpy(b0, iv, AES_BLOCK_SIZE);
@@ -518,11 +519,14 @@ static int stm32_cryp_ccm_init(struct stm32_cryp *cryp, u32 cfg)
 
        /* Write B0 */
        d = (u32 *)b0;
+       bd = (__be32 *)b0;
 
        for (i = 0; i < AES_BLOCK_32; i++) {
+               u32 xd = d[i];
+
                if (!cryp->caps->padding_wa)
-                       *d = cpu_to_be32(*d);
-               stm32_cryp_write(cryp, CRYP_DIN, *d++);
+                       xd = be32_to_cpu(bd[i]);
+               stm32_cryp_write(cryp, CRYP_DIN, xd);
        }
 
        /* Wait for end of processing */
@@ -617,7 +621,7 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp)
        case CR_TDES_CBC:
        case CR_AES_CBC:
        case CR_AES_CTR:
-               stm32_cryp_hw_write_iv(cryp, (u32 *)cryp->req->iv);
+               stm32_cryp_hw_write_iv(cryp, (__be32 *)cryp->req->iv);
                break;
 
        default:
@@ -1120,7 +1124,7 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp)
                /* GCM: write aad and payload size (in bits) */
                size_bit = cryp->areq->assoclen * 8;
                if (cryp->caps->swap_final)
-                       size_bit = cpu_to_be32(size_bit);
+                       size_bit = (__force u32)cpu_to_be32(size_bit);
 
                stm32_cryp_write(cryp, CRYP_DIN, 0);
                stm32_cryp_write(cryp, CRYP_DIN, size_bit);
@@ -1129,7 +1133,7 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp)
                                cryp->areq->cryptlen - AES_BLOCK_SIZE;
                size_bit *= 8;
                if (cryp->caps->swap_final)
-                       size_bit = cpu_to_be32(size_bit);
+                       size_bit = (__force u32)cpu_to_be32(size_bit);
 
                stm32_cryp_write(cryp, CRYP_DIN, 0);
                stm32_cryp_write(cryp, CRYP_DIN, size_bit);
@@ -1137,14 +1141,19 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp)
                /* CCM: write CTR0 */
                u8 iv[AES_BLOCK_SIZE];
                u32 *iv32 = (u32 *)iv;
+               __be32 *biv;
+
+               biv = (void *)iv;
 
                memcpy(iv, cryp->areq->iv, AES_BLOCK_SIZE);
                memset(iv + AES_BLOCK_SIZE - 1 - iv[0], 0, iv[0] + 1);
 
                for (i = 0; i < AES_BLOCK_32; i++) {
+                       u32 xiv = iv32[i];
+
                        if (!cryp->caps->padding_wa)
-                               *iv32 = cpu_to_be32(*iv32);
-                       stm32_cryp_write(cryp, CRYP_DIN, *iv32++);
+                               xiv = be32_to_cpu(biv[i]);
+                       stm32_cryp_write(cryp, CRYP_DIN, xiv);
                }
        }
 
index 03c5e66..e3e2527 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/clk.h>
 #include <linux/crypto.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -748,7 +749,7 @@ static int stm32_hash_final_req(struct stm32_hash_dev *hdev)
 static void stm32_hash_copy_hash(struct ahash_request *req)
 {
        struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req);
-       u32 *hash = (u32 *)rctx->digest;
+       __be32 *hash = (void *)rctx->digest;
        unsigned int i, hashsize;
 
        switch (rctx->flags & HASH_FLAGS_ALGO_MASK) {
@@ -769,7 +770,7 @@ static void stm32_hash_copy_hash(struct ahash_request *req)
        }
 
        for (i = 0; i < hashsize / sizeof(u32); i++)
-               hash[i] = be32_to_cpu(stm32_hash_read(rctx->hdev,
+               hash[i] = cpu_to_be32(stm32_hash_read(rctx->hdev,
                                                      HASH_HREG(i)));
 }
 
@@ -1463,14 +1464,9 @@ static int stm32_hash_probe(struct platform_device *pdev)
        }
 
        hdev->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(hdev->clk)) {
-               if (PTR_ERR(hdev->clk) != -EPROBE_DEFER) {
-                       dev_err(dev, "failed to get clock for hash (%lu)\n",
-                               PTR_ERR(hdev->clk));
-               }
-
-               return PTR_ERR(hdev->clk);
-       }
+       if (IS_ERR(hdev->clk))
+               return dev_err_probe(dev, PTR_ERR(hdev->clk),
+                                    "failed to get clock for hash\n");
 
        ret = clk_prepare_enable(hdev->clk);
        if (ret) {
index 7c54735..6677389 100644 (file)
@@ -806,10 +806,10 @@ static int talitos_register_rng(struct device *dev)
        struct talitos_private *priv = dev_get_drvdata(dev);
        int err;
 
-       priv->rng.name          = dev_driver_string(dev),
-       priv->rng.init          = talitos_rng_init,
-       priv->rng.data_present  = talitos_rng_data_present,
-       priv->rng.data_read     = talitos_rng_data_read,
+       priv->rng.name          = dev_driver_string(dev);
+       priv->rng.init          = talitos_rng_init;
+       priv->rng.data_present  = talitos_rng_data_present;
+       priv->rng.data_read     = talitos_rng_data_read;
        priv->rng.priv          = (unsigned long)dev;
 
        err = hwrng_register(&priv->rng);
index f22f6fa..9866c2a 100644 (file)
@@ -314,17 +314,17 @@ void cryp_save_device_context(struct cryp_device_data *device_data,
        case CRYP_KEY_SIZE_256:
                ctx->key_4_l = readl_relaxed(&src_reg->key_4_l);
                ctx->key_4_r = readl_relaxed(&src_reg->key_4_r);
-               /* Fall through */
+               fallthrough;
 
        case CRYP_KEY_SIZE_192:
                ctx->key_3_l = readl_relaxed(&src_reg->key_3_l);
                ctx->key_3_r = readl_relaxed(&src_reg->key_3_r);
-               /* Fall through */
+               fallthrough;
 
        case CRYP_KEY_SIZE_128:
                ctx->key_2_l = readl_relaxed(&src_reg->key_2_l);
                ctx->key_2_r = readl_relaxed(&src_reg->key_2_r);
-               /* Fall through */
+               fallthrough;
 
        default:
                ctx->key_1_l = readl_relaxed(&src_reg->key_1_l);
@@ -364,17 +364,17 @@ void cryp_restore_device_context(struct cryp_device_data *device_data,
        case CRYP_KEY_SIZE_256:
                writel_relaxed(ctx->key_4_l, &reg->key_4_l);
                writel_relaxed(ctx->key_4_r, &reg->key_4_r);
-               /* Fall through */
+               fallthrough;
 
        case CRYP_KEY_SIZE_192:
                writel_relaxed(ctx->key_3_l, &reg->key_3_l);
                writel_relaxed(ctx->key_3_r, &reg->key_3_r);
-               /* Fall through */
+               fallthrough;
 
        case CRYP_KEY_SIZE_128:
                writel_relaxed(ctx->key_2_l, &reg->key_2_l);
                writel_relaxed(ctx->key_2_r, &reg->key_2_r);
-               /* Fall through */
+               fallthrough;
 
        default:
                writel_relaxed(ctx->key_1_l, &reg->key_1_l);
index 800dfc4..c3adeb2 100644 (file)
 
 #include <linux/clk.h>
 #include <linux/completion.h>
-#include <linux/crypto.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irqreturn.h>
+#include <linux/kernel.h>
 #include <linux/klist.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -27,7 +29,6 @@
 #include <linux/platform_data/dma-ste-dma40.h>
 
 #include <crypto/aes.h>
-#include <crypto/algapi.h>
 #include <crypto/ctr.h>
 #include <crypto/internal/des.h>
 #include <crypto/internal/skcipher.h>
@@ -92,17 +93,6 @@ struct cryp_ctx {
 static struct cryp_driver_data driver_data;
 
 /**
- * uint8p_to_uint32_be - 4*uint8 to uint32 big endian
- * @in: Data to convert.
- */
-static inline u32 uint8p_to_uint32_be(u8 *in)
-{
-       u32 *data = (u32 *)in;
-
-       return cpu_to_be32p(data);
-}
-
-/**
  * swap_bits_in_byte - mirror the bits in a byte
  * @b: the byte to be mirrored
  *
@@ -284,6 +274,7 @@ static int cfg_ivs(struct cryp_device_data *device_data, struct cryp_ctx *ctx)
        int i;
        int status = 0;
        int num_of_regs = ctx->blocksize / 8;
+       __be32 *civ = (__be32 *)ctx->iv;
        u32 iv[AES_BLOCK_SIZE / 4];
 
        dev_dbg(device_data->dev, "[%s]", __func__);
@@ -300,7 +291,7 @@ static int cfg_ivs(struct cryp_device_data *device_data, struct cryp_ctx *ctx)
        }
 
        for (i = 0; i < ctx->blocksize / 4; i++)
-               iv[i] = uint8p_to_uint32_be(ctx->iv + i*4);
+               iv[i] = be32_to_cpup(civ + i);
 
        for (i = 0; i < num_of_regs; i++) {
                status = cfg_iv(device_data, iv[i*2], iv[i*2+1],
@@ -339,23 +330,24 @@ static int cfg_keys(struct cryp_ctx *ctx)
        int i;
        int num_of_regs = ctx->keylen / 8;
        u32 swapped_key[CRYP_MAX_KEY_SIZE / 4];
+       __be32 *ckey = (__be32 *)ctx->key;
        int cryp_error = 0;
 
        dev_dbg(ctx->device->dev, "[%s]", __func__);
 
        if (mode_is_aes(ctx->config.algomode)) {
-               swap_words_in_key_and_bits_in_byte((u8 *)ctx->key,
+               swap_words_in_key_and_bits_in_byte((u8 *)ckey,
                                                   (u8 *)swapped_key,
                                                   ctx->keylen);
        } else {
                for (i = 0; i < ctx->keylen / 4; i++)
-                       swapped_key[i] = uint8p_to_uint32_be(ctx->key + i*4);
+                       swapped_key[i] = be32_to_cpup(ckey + i);
        }
 
        for (i = 0; i < num_of_regs; i++) {
                cryp_error = set_key(ctx->device,
-                                    *(((u32 *)swapped_key)+i*2),
-                                    *(((u32 *)swapped_key)+i*2+1),
+                                    swapped_key[i * 2],
+                                    swapped_key[i * 2 + 1],
                                     (enum cryp_key_reg_index) i);
 
                if (cryp_error != 0) {
index a5ee8c2..3d407ee 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/clk.h>
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -1071,27 +1072,32 @@ int hash_hw_update(struct ahash_request *req)
        struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
        struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
        struct crypto_hash_walk walk;
-       int msg_length = crypto_hash_walk_first(req, &walk);
-
-       /* Empty message ("") is correct indata */
-       if (msg_length == 0)
-               return ret;
+       int msg_length;
 
        index = req_ctx->state.index;
        buffer = (u8 *)req_ctx->state.buffer;
 
+       ret = hash_get_device_data(ctx, &device_data);
+       if (ret)
+               return ret;
+
+       msg_length = crypto_hash_walk_first(req, &walk);
+
+       /* Empty message ("") is correct indata */
+       if (msg_length == 0) {
+               ret = 0;
+               goto release_dev;
+       }
+
        /* Check if ctx->state.length + msg_length
           overflows */
        if (msg_length > (req_ctx->state.length.low_word + msg_length) &&
            HASH_HIGH_WORD_MAX_VAL == req_ctx->state.length.high_word) {
                pr_err("%s: HASH_MSG_LENGTH_OVERFLOW!\n", __func__);
-               return -EPERM;
+               ret = crypto_hash_walk_done(&walk, -EPERM);
+               goto release_dev;
        }
 
-       ret = hash_get_device_data(ctx, &device_data);
-       if (ret)
-               return ret;
-
        /* Main loop */
        while (0 != msg_length) {
                data_buffer = walk.data;
@@ -1101,7 +1107,8 @@ int hash_hw_update(struct ahash_request *req)
                if (ret) {
                        dev_err(device_data->dev, "%s: hash_internal_hw_update() failed!\n",
                                __func__);
-                       goto out;
+                       crypto_hash_walk_done(&walk, ret);
+                       goto release_dev;
                }
 
                msg_length = crypto_hash_walk_done(&walk, 0);
@@ -1111,7 +1118,7 @@ int hash_hw_update(struct ahash_request *req)
        dev_dbg(device_data->dev, "%s: indata length=%d, bin=%d\n",
                __func__, req_ctx->state.index, req_ctx->state.bit_index);
 
-out:
+release_dev:
        release_hash_device(device_data);
 
        return ret;
index fb29417..b894e3a 100644 (file)
@@ -5,7 +5,6 @@ config CRYPTO_DEV_VIRTIO
        select CRYPTO_AEAD
        select CRYPTO_SKCIPHER
        select CRYPTO_ENGINE
-       default m
        help
          This driver provides support for virtio crypto device. If you
          choose 'M' here, this module will be called virtio_crypto.
index 2707935..bf1f421 100644 (file)
@@ -10,6 +10,7 @@
 #include <crypto/internal/aead.h>
 #include <crypto/scatterwalk.h>
 
+#include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
index 4c0af2e..1e89513 100644 (file)
@@ -429,7 +429,7 @@ int dev_dax_probe(struct device *dev)
                return -EBUSY;
        }
 
-       dev_dax->pgmap.type = MEMORY_DEVICE_DEVDAX;
+       dev_dax->pgmap.type = MEMORY_DEVICE_GENERIC;
        addr = devm_memremap_pages(dev, &dev_dax->pgmap);
        if (IS_ERR(addr))
                return PTR_ERR(addr);
index c82cbcb..e84070b 100644 (file)
@@ -85,6 +85,12 @@ bool __generic_fsdax_supported(struct dax_device *dax_dev,
                return false;
        }
 
+       if (!dax_dev) {
+               pr_debug("%s: error: dax unsupported by block device\n",
+                               bdevname(bdev, buf));
+               return false;
+       }
+
        err = bdev_dax_pgoff(bdev, start, PAGE_SIZE, &pgoff);
        if (err) {
                pr_info("%s: error: unaligned partition for dax\n",
@@ -319,11 +325,15 @@ EXPORT_SYMBOL_GPL(dax_direct_access);
 bool dax_supported(struct dax_device *dax_dev, struct block_device *bdev,
                int blocksize, sector_t start, sector_t len)
 {
+       if (!dax_dev)
+               return false;
+
        if (!dax_alive(dax_dev))
                return false;
 
        return dax_dev->ops->dax_supported(dax_dev, bdev, blocksize, start, len);
 }
+EXPORT_SYMBOL_GPL(dax_supported);
 
 size_t dax_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,
                size_t bytes, struct iov_iter *i)
index 561d91b..071b59f 100644 (file)
@@ -1766,20 +1766,23 @@ static int devfreq_summary_show(struct seq_file *s, void *data)
        struct devfreq *p_devfreq = NULL;
        unsigned long cur_freq, min_freq, max_freq;
        unsigned int polling_ms;
+       unsigned int timer;
 
-       seq_printf(s, "%-30s %-30s %-15s %10s %12s %12s %12s\n",
+       seq_printf(s, "%-30s %-30s %-15s %-10s %10s %12s %12s %12s\n",
                        "dev",
                        "parent_dev",
                        "governor",
+                       "timer",
                        "polling_ms",
                        "cur_freq_Hz",
                        "min_freq_Hz",
                        "max_freq_Hz");
-       seq_printf(s, "%30s %30s %15s %10s %12s %12s %12s\n",
+       seq_printf(s, "%30s %30s %15s %10s %10s %12s %12s %12s\n",
                        "------------------------------",
                        "------------------------------",
                        "---------------",
                        "----------",
+                       "----------",
                        "------------",
                        "------------",
                        "------------");
@@ -1803,13 +1806,15 @@ static int devfreq_summary_show(struct seq_file *s, void *data)
                cur_freq = devfreq->previous_freq;
                get_freq_range(devfreq, &min_freq, &max_freq);
                polling_ms = devfreq->profile->polling_ms;
+               timer = devfreq->profile->timer;
                mutex_unlock(&devfreq->lock);
 
                seq_printf(s,
-                       "%-30s %-30s %-15s %10d %12ld %12ld %12ld\n",
+                       "%-30s %-30s %-15s %-10s %10d %12ld %12ld %12ld\n",
                        dev_name(&devfreq->dev),
                        p_devfreq ? dev_name(&p_devfreq->dev) : "null",
                        devfreq->governor_name,
+                       polling_ms ? timer_name[timer] : "null",
                        polling_ms,
                        cur_freq,
                        min_freq,
index e94a278..dedd39d 100644 (file)
@@ -836,7 +836,8 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
        rate = clk_round_rate(tegra->emc_clock, ULONG_MAX);
        if (rate < 0) {
                dev_err(&pdev->dev, "Failed to round clock rate: %ld\n", rate);
-               return rate;
+               err = rate;
+               goto disable_clk;
        }
 
        tegra->max_freq = rate / KHZ;
@@ -897,6 +898,7 @@ remove_opps:
        dev_pm_opp_remove_all_dynamic(&pdev->dev);
 
        reset_control_reset(tegra->reset);
+disable_clk:
        clk_disable_unprepare(tegra->clock);
 
        return err;
index 1699a8e..844967f 100644 (file)
@@ -59,6 +59,8 @@ static void dma_buf_release(struct dentry *dentry)
        struct dma_buf *dmabuf;
 
        dmabuf = dentry->d_fsdata;
+       if (unlikely(!dmabuf))
+               return;
 
        BUG_ON(dmabuf->vmapping_counter);
 
@@ -316,9 +318,9 @@ out:
  * name of the dma-buf if the same piece of memory is used for multiple
  * purpose between different devices.
  *
- * @dmabuf [in]     dmabuf buffer that will be renamed.
- * @buf:   [in]     A piece of userspace memory that contains the name of
- *                  the dma-buf.
+ * @dmabuf: [in]     dmabuf buffer that will be renamed.
+ * @buf:    [in]     A piece of userspace memory that contains the name of
+ *                   the dma-buf.
  *
  * Returns 0 on success. If the dma-buf buffer is already attached to
  * devices, return -EBUSY.
index 3d12350..7d129e6 100644 (file)
@@ -222,6 +222,7 @@ EXPORT_SYMBOL(dma_fence_chain_ops);
  * @chain: the chain node to initialize
  * @prev: the previous fence
  * @fence: the current fence
+ * @seqno: the sequence number to use for the fence chain
  *
  * Initialize a new chain node and either start a new chain or add the node to
  * the existing chain of the previous fence.
index 35f4804..235f139 100644 (file)
@@ -135,11 +135,13 @@ static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma)
                if (ret < 0) {
                        dev_warn(&adev->dev,
                                 "error in parsing resource group\n");
-                       return;
+                       break;
                }
 
                grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
        }
+
+       acpi_put_table((struct acpi_table_header *)csrt);
 }
 
 /**
index 9adc7a2..a24882b 100644 (file)
@@ -1767,7 +1767,7 @@ static u32 pl08x_memcpy_cctl(struct pl08x_driver_data *pl08x)
        default:
                dev_err(&pl08x->adev->dev,
                        "illegal burst size for memcpy, set to 1\n");
-               /* Fall through */
+               fallthrough;
        case PL08X_BURST_SZ_1:
                cctl |= PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT |
                        PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT;
@@ -1806,7 +1806,7 @@ static u32 pl08x_memcpy_cctl(struct pl08x_driver_data *pl08x)
        default:
                dev_err(&pl08x->adev->dev,
                        "illegal bus width for memcpy, set to 8 bits\n");
-               /* Fall through */
+               fallthrough;
        case PL08X_BUS_WIDTH_8_BITS:
                cctl |= PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT |
                        PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT;
@@ -1850,7 +1850,7 @@ static u32 pl08x_ftdmac020_memcpy_cctl(struct pl08x_driver_data *pl08x)
        default:
                dev_err(&pl08x->adev->dev,
                        "illegal bus width for memcpy, set to 8 bits\n");
-               /* Fall through */
+               fallthrough;
        case PL08X_BUS_WIDTH_8_BITS:
                cctl |= PL080_WIDTH_8BIT << FTDMAC020_LLI_SRC_WIDTH_SHIFT |
                        PL080_WIDTH_8BIT << FTDMAC020_LLI_DST_WIDTH_SHIFT;
@@ -2612,7 +2612,7 @@ static int pl08x_of_probe(struct amba_device *adev,
        switch (val) {
        default:
                dev_err(&adev->dev, "illegal burst size for memcpy, set to 1\n");
-               /* Fall through */
+               fallthrough;
        case 1:
                pd->memcpy_burst_size = PL08X_BURST_SZ_1;
                break;
@@ -2647,7 +2647,7 @@ static int pl08x_of_probe(struct amba_device *adev,
        switch (val) {
        default:
                dev_err(&adev->dev, "illegal bus width for memcpy, set to 8 bits\n");
-               /* Fall through */
+               fallthrough;
        case 8:
                pd->memcpy_bus_width = PL08X_BUS_WIDTH_8_BITS;
                break;
index 45bbcd6..a2cf25c 100644 (file)
@@ -1650,13 +1650,17 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
                return NULL;
 
        dmac_pdev = of_find_device_by_node(dma_spec->np);
+       if (!dmac_pdev)
+               return NULL;
 
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
        atslave = kmalloc(sizeof(*atslave), GFP_KERNEL);
-       if (!atslave)
+       if (!atslave) {
+               put_device(&dmac_pdev->dev);
                return NULL;
+       }
 
        atslave->cfg = ATC_DST_H2SEL_HW | ATC_SRC_H2SEL_HW;
        /*
@@ -1685,8 +1689,11 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
        atslave->dma_dev = &dmac_pdev->dev;
 
        chan = dma_request_channel(mask, at_dma_filter, atslave);
-       if (!chan)
+       if (!chan) {
+               put_device(&dmac_pdev->dev);
+               kfree(atslave);
                return NULL;
+       }
 
        atchan = to_at_dma_chan(chan);
        atchan->per_if = dma_spec->args[0] & 0xff;
index 448f663..8beed91 100644 (file)
@@ -879,24 +879,11 @@ static int jz4780_dma_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       ret = platform_get_irq(pdev, 0);
-       if (ret < 0)
-               return ret;
-
-       jzdma->irq = ret;
-
-       ret = request_irq(jzdma->irq, jz4780_dma_irq_handler, 0, dev_name(dev),
-                         jzdma);
-       if (ret) {
-               dev_err(dev, "failed to request IRQ %u!\n", jzdma->irq);
-               return ret;
-       }
-
        jzdma->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(jzdma->clk)) {
                dev_err(dev, "failed to get clock\n");
                ret = PTR_ERR(jzdma->clk);
-               goto err_free_irq;
+               return ret;
        }
 
        clk_prepare_enable(jzdma->clk);
@@ -949,10 +936,23 @@ static int jz4780_dma_probe(struct platform_device *pdev)
                jzchan->vchan.desc_free = jz4780_dma_desc_free;
        }
 
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0)
+               goto err_disable_clk;
+
+       jzdma->irq = ret;
+
+       ret = request_irq(jzdma->irq, jz4780_dma_irq_handler, 0, dev_name(dev),
+                         jzdma);
+       if (ret) {
+               dev_err(dev, "failed to request IRQ %u!\n", jzdma->irq);
+               goto err_disable_clk;
+       }
+
        ret = dmaenginem_async_device_register(dd);
        if (ret) {
                dev_err(dev, "failed to register device\n");
-               goto err_disable_clk;
+               goto err_free_irq;
        }
 
        /* Register with OF DMA helpers. */
@@ -960,17 +960,17 @@ static int jz4780_dma_probe(struct platform_device *pdev)
                                         jzdma);
        if (ret) {
                dev_err(dev, "failed to register OF DMA controller\n");
-               goto err_disable_clk;
+               goto err_free_irq;
        }
 
        dev_info(dev, "JZ4780 DMA controller initialised\n");
        return 0;
 
-err_disable_clk:
-       clk_disable_unprepare(jzdma->clk);
-
 err_free_irq:
        free_irq(jzdma->irq, jzdma);
+
+err_disable_clk:
+       clk_disable_unprepare(jzdma->clk);
        return ret;
 }
 
index 45d4d92..a819611 100644 (file)
@@ -129,6 +129,7 @@ struct dmatest_params {
  * @nr_channels:       number of channels under test
  * @lock:              access protection to the fields of this structure
  * @did_init:          module has been initialized completely
+ * @last_error:                test has faced configuration issues
  */
 static struct dmatest_info {
        /* Test parameters */
@@ -137,6 +138,7 @@ static struct dmatest_info {
        /* Internal state */
        struct list_head        channels;
        unsigned int            nr_channels;
+       int                     last_error;
        struct mutex            lock;
        bool                    did_init;
 } test_info = {
@@ -1184,10 +1186,22 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp)
                return ret;
        } else if (dmatest_run) {
                if (!is_threaded_test_pending(info)) {
-                       pr_info("No channels configured, continue with any\n");
-                       if (!is_threaded_test_run(info))
-                               stop_threaded_test(info);
-                       add_threaded_test(info);
+                       /*
+                        * We have nothing to run. This can be due to:
+                        */
+                       ret = info->last_error;
+                       if (ret) {
+                               /* 1) Misconfiguration */
+                               pr_err("Channel misconfigured, can't continue\n");
+                               mutex_unlock(&info->lock);
+                               return ret;
+                       } else {
+                               /* 2) We rely on defaults */
+                               pr_info("No channels configured, continue with any\n");
+                               if (!is_threaded_test_run(info))
+                                       stop_threaded_test(info);
+                               add_threaded_test(info);
+                       }
                }
                start_threaded_tests(info);
        } else {
@@ -1204,7 +1218,7 @@ static int dmatest_chan_set(const char *val, const struct kernel_param *kp)
        struct dmatest_info *info = &test_info;
        struct dmatest_chan *dtc;
        char chan_reset_val[20];
-       int ret = 0;
+       int ret;
 
        mutex_lock(&info->lock);
        ret = param_set_copystring(val, kp);
@@ -1259,12 +1273,14 @@ static int dmatest_chan_set(const char *val, const struct kernel_param *kp)
                goto add_chan_err;
        }
 
+       info->last_error = ret;
        mutex_unlock(&info->lock);
 
        return ret;
 
 add_chan_err:
        param_set_copystring(chan_reset_val, kp);
+       info->last_error = ret;
        mutex_unlock(&info->lock);
 
        return ret;
index ed430ad..b971505 100644 (file)
@@ -405,7 +405,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
                        if (xfer->cyclic) {
                                burst->dar = xfer->xfer.cyclic.paddr;
                        } else {
-                               burst->dar = sg_dma_address(sg);
+                               burst->dar = dst_addr;
                                /* Unlike the typical assumption by other
                                 * drivers/IPs the peripheral memory isn't
                                 * a FIFO memory, in this case, it's a
@@ -413,14 +413,13 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
                                 * and destination addresses are increased
                                 * by the same portion (data length)
                                 */
-                               src_addr += sg_dma_len(sg);
                        }
                } else {
                        burst->dar = dst_addr;
                        if (xfer->cyclic) {
                                burst->sar = xfer->xfer.cyclic.paddr;
                        } else {
-                               burst->sar = sg_dma_address(sg);
+                               burst->sar = src_addr;
                                /* Unlike the typical assumption by other
                                 * drivers/IPs the peripheral memory isn't
                                 * a FIFO memory, in this case, it's a
@@ -428,12 +427,14 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
                                 * and destination addresses are increased
                                 * by the same portion (data length)
                                 */
-                               dst_addr += sg_dma_len(sg);
                        }
                }
 
-               if (!xfer->cyclic)
+               if (!xfer->cyclic) {
+                       src_addr += sg_dma_len(sg);
+                       dst_addr += sg_dma_len(sg);
                        sg = sg_next(sg);
+               }
        }
 
        return vchan_tx_prep(&chan->vc, &desc->vd, xfer->flags);
index ad72b3f..e342cf5 100644 (file)
@@ -1163,7 +1163,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
        switch (chan->feature & FSL_DMA_IP_MASK) {
        case FSL_DMA_IP_85XX:
                chan->toggle_ext_pause = fsl_chan_toggle_ext_pause;
-               /* Fall through */
+               fallthrough;
        case FSL_DMA_IP_83XX:
                chan->toggle_ext_start = fsl_chan_toggle_ext_start;
                chan->set_src_loop_size = fsl_chan_set_src_loop_size;
index 56f18ae..308bed0 100644 (file)
@@ -205,10 +205,10 @@ struct fsldma_chan {
 #else
 static u64 fsl_ioread64(const u64 __iomem *addr)
 {
-       u32 fsl_addr = lower_32_bits(addr);
-       u64 fsl_addr_hi = (u64)in_le32((u32 *)(fsl_addr + 1)) << 32;
+       u32 val_lo = in_le32((u32 __iomem *)addr);
+       u32 val_hi = in_le32((u32 __iomem *)addr + 1);
 
-       return fsl_addr_hi | in_le32((u32 *)fsl_addr);
+       return ((u64)val_hi << 32) + val_lo;
 }
 
 static void fsl_iowrite64(u64 val, u64 __iomem *addr)
@@ -219,10 +219,10 @@ static void fsl_iowrite64(u64 val, u64 __iomem *addr)
 
 static u64 fsl_ioread64be(const u64 __iomem *addr)
 {
-       u32 fsl_addr = lower_32_bits(addr);
-       u64 fsl_addr_hi = (u64)in_be32((u32 *)fsl_addr) << 32;
+       u32 val_hi = in_be32((u32 __iomem *)addr);
+       u32 val_lo = in_be32((u32 __iomem *)addr + 1);
 
-       return fsl_addr_hi | in_be32((u32 *)(fsl_addr + 1));
+       return ((u64)val_hi << 32) + val_lo;
 }
 
 static void fsl_iowrite64be(u64 val, u64 __iomem *addr)
index 14b4585..b75d699 100644 (file)
@@ -410,10 +410,27 @@ int idxd_device_enable(struct idxd_device *idxd)
        return 0;
 }
 
+void idxd_device_wqs_clear_state(struct idxd_device *idxd)
+{
+       int i;
+
+       lockdep_assert_held(&idxd->dev_lock);
+
+       for (i = 0; i < idxd->max_wqs; i++) {
+               struct idxd_wq *wq = &idxd->wqs[i];
+
+               if (wq->state == IDXD_WQ_ENABLED) {
+                       idxd_wq_disable_cleanup(wq);
+                       wq->state = IDXD_WQ_DISABLED;
+               }
+       }
+}
+
 int idxd_device_disable(struct idxd_device *idxd)
 {
        struct device *dev = &idxd->pdev->dev;
        u32 status;
+       unsigned long flags;
 
        if (!idxd_is_enabled(idxd)) {
                dev_dbg(dev, "Device is not enabled\n");
@@ -429,13 +446,22 @@ int idxd_device_disable(struct idxd_device *idxd)
                return -ENXIO;
        }
 
+       spin_lock_irqsave(&idxd->dev_lock, flags);
+       idxd_device_wqs_clear_state(idxd);
        idxd->state = IDXD_DEV_CONF_READY;
+       spin_unlock_irqrestore(&idxd->dev_lock, flags);
        return 0;
 }
 
 void idxd_device_reset(struct idxd_device *idxd)
 {
+       unsigned long flags;
+
        idxd_cmd_exec(idxd, IDXD_CMD_RESET_DEVICE, 0, NULL);
+       spin_lock_irqsave(&idxd->dev_lock, flags);
+       idxd_device_wqs_clear_state(idxd);
+       idxd->state = IDXD_DEV_CONF_READY;
+       spin_unlock_irqrestore(&idxd->dev_lock, flags);
 }
 
 /* Device configuration bits */
index b514255..1e9e699 100644 (file)
 #include "idxd.h"
 #include "registers.h"
 
-void idxd_device_wqs_clear_state(struct idxd_device *idxd)
-{
-       int i;
-
-       lockdep_assert_held(&idxd->dev_lock);
-       for (i = 0; i < idxd->max_wqs; i++) {
-               struct idxd_wq *wq = &idxd->wqs[i];
-
-               wq->state = IDXD_WQ_DISABLED;
-       }
-}
-
 static void idxd_device_reinit(struct work_struct *work)
 {
        struct idxd_device *idxd = container_of(work, struct idxd_device, work);
index 5c0fb31..8871750 100644 (file)
@@ -556,7 +556,7 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
                 * We fall-through here intentionally, since a 2D transfer is
                 * similar to MEMCPY just adding the 2D slot configuration.
                 */
-               /* Fall through */
+               fallthrough;
        case IMXDMA_DESC_MEMCPY:
                imx_dmav1_writel(imxdma, d->src, DMA_SAR(imxdmac->channel));
                imx_dmav1_writel(imxdma, d->dest, DMA_DAR(imxdmac->channel));
index c499c95..d44eabb 100644 (file)
@@ -496,7 +496,7 @@ iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt,
                }
                hw_desc->src_edc[AAU_EDCR2_IDX].e_desc_ctrl = edcr;
                src_cnt = 24;
-               /* fall through */
+               fallthrough;
        case 17 ... 24:
                if (!u_desc_ctrl.field.blk_ctrl) {
                        hw_desc->src_edc[AAU_EDCR2_IDX].e_desc_ctrl = 0;
@@ -510,7 +510,7 @@ iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt,
                }
                hw_desc->src_edc[AAU_EDCR1_IDX].e_desc_ctrl = edcr;
                src_cnt = 16;
-               /* fall through */
+               fallthrough;
        case 9 ... 16:
                if (!u_desc_ctrl.field.blk_ctrl)
                        u_desc_ctrl.field.blk_ctrl = 0x2; /* use EDCR0 */
@@ -522,7 +522,7 @@ iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt,
                }
                hw_desc->src_edc[AAU_EDCR0_IDX].e_desc_ctrl = edcr;
                src_cnt = 8;
-               /* fall through */
+               fallthrough;
        case 2 ... 8:
                shift = 1;
                for (i = 0; i < src_cnt; i++) {
@@ -602,19 +602,19 @@ iop_desc_init_null_xor(struct iop_adma_desc_slot *desc, int src_cnt,
        case 25 ... 32:
                u_desc_ctrl.field.blk_ctrl = 0x3; /* use EDCR[2:0] */
                hw_desc->src_edc[AAU_EDCR2_IDX].e_desc_ctrl = 0;
-               /* fall through */
+               fallthrough;
        case 17 ... 24:
                if (!u_desc_ctrl.field.blk_ctrl) {
                        hw_desc->src_edc[AAU_EDCR2_IDX].e_desc_ctrl = 0;
                        u_desc_ctrl.field.blk_ctrl = 0x3; /* use EDCR[2:0] */
                }
                hw_desc->src_edc[AAU_EDCR1_IDX].e_desc_ctrl = 0;
-               /* fall through */
+               fallthrough;
        case 9 ... 16:
                if (!u_desc_ctrl.field.blk_ctrl)
                        u_desc_ctrl.field.blk_ctrl = 0x2; /* use EDCR0 */
                hw_desc->src_edc[AAU_EDCR0_IDX].e_desc_ctrl = 0;
-               /* fall through */
+               fallthrough;
        case 1 ... 8:
                if (!u_desc_ctrl.field.blk_ctrl && src_cnt > 4)
                        u_desc_ctrl.field.blk_ctrl = 0x1; /* use mini-desc */
index 74df621..ca4e093 100644 (file)
@@ -483,7 +483,7 @@ static size_t nbpf_xfer_size(struct nbpf_device *nbpf,
 
        default:
                pr_warn("%s(): invalid bus width %u\n", __func__, width);
-               /* fall through */
+               fallthrough;
        case DMA_SLAVE_BUSWIDTH_1_BYTE:
                size = burst;
        }
index 863f2aa..8a4f608 100644 (file)
@@ -71,12 +71,12 @@ static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
                return NULL;
 
        chan = ofdma_target->of_dma_xlate(&dma_spec_target, ofdma_target);
-       if (chan) {
-               chan->router = ofdma->dma_router;
-               chan->route_data = route_data;
-       } else {
+       if (IS_ERR_OR_NULL(chan)) {
                ofdma->dma_router->route_free(ofdma->dma_router->dev,
                                              route_data);
+       } else {
+               chan->router = ofdma->dma_router;
+               chan->route_data = route_data;
        }
 
        /*
index 2c508ee..5274a07 100644 (file)
@@ -1061,16 +1061,16 @@ static bool _start(struct pl330_thread *thrd)
 
                if (_state(thrd) == PL330_STATE_KILLING)
                        UNTIL(thrd, PL330_STATE_STOPPED)
-               /* fall through */
+               fallthrough;
 
        case PL330_STATE_FAULTING:
                _stop(thrd);
-               /* fall through */
+               fallthrough;
 
        case PL330_STATE_KILLING:
        case PL330_STATE_COMPLETING:
                UNTIL(thrd, PL330_STATE_STOPPED)
-               /* fall through */
+               fallthrough;
 
        case PL330_STATE_STOPPED:
                return _trigger(thrd);
@@ -1121,7 +1121,6 @@ static u32 _emit_load(unsigned int dry_run, u8 buf[],
 
        switch (direction) {
        case DMA_MEM_TO_MEM:
-               /* fall through */
        case DMA_MEM_TO_DEV:
                off += _emit_LD(dry_run, &buf[off], cond);
                break;
@@ -1155,7 +1154,6 @@ static inline u32 _emit_store(unsigned int dry_run, u8 buf[],
 
        switch (direction) {
        case DMA_MEM_TO_MEM:
-               /* fall through */
        case DMA_DEV_TO_MEM:
                off += _emit_ST(dry_run, &buf[off], cond);
                break;
@@ -1216,7 +1214,6 @@ static int _bursts(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[],
 
        switch (pxs->desc->rqtype) {
        case DMA_MEM_TO_DEV:
-               /* fall through */
        case DMA_DEV_TO_MEM:
                off += _ldst_peripheral(pl330, dry_run, &buf[off], pxs, cyc,
                        cond);
@@ -1266,7 +1263,6 @@ static int _dregs(struct pl330_dmac *pl330, unsigned int dry_run, u8 buf[],
 
        switch (pxs->desc->rqtype) {
        case DMA_MEM_TO_DEV:
-               /* fall through */
        case DMA_DEV_TO_MEM:
                off += _emit_MOV(dry_run, &buf[off], CCR, dregs_ccr);
                off += _ldst_peripheral(pl330, dry_run, &buf[off], pxs, 1,
@@ -2801,6 +2797,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
        while (burst != (1 << desc->rqcfg.brst_size))
                desc->rqcfg.brst_size++;
 
+       desc->rqcfg.brst_len = get_burst_len(desc, len);
        /*
         * If burst size is smaller than bus width then make sure we only
         * transfer one at a time to avoid a burst stradling an MFIFO entry.
@@ -2808,7 +2805,6 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
        if (desc->rqcfg.brst_size * 8 < pl330->pcfg.data_bus_width)
                desc->rqcfg.brst_len = 1;
 
-       desc->rqcfg.brst_len = get_burst_len(desc, len);
        desc->bytes_requested = len;
 
        desc->txd.flags = flags;
index 2deeaab..788d696 100644 (file)
@@ -383,7 +383,7 @@ static dma_async_tx_callback __ld_cleanup(struct shdma_chan *schan, bool all)
                        switch (desc->mark) {
                        case DESC_COMPLETED:
                                desc->mark = DESC_WAITING;
-                               /* Fall through */
+                               fallthrough;
                        case DESC_WAITING:
                                if (head_acked)
                                        async_tx_ack(&desc->async_tx);
index c14e6cb..d86dba0 100644 (file)
@@ -2059,9 +2059,9 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl,
                        return NULL;
                }
 
-               cppi5_tr_init(&tr_req[i].flags, CPPI5_TR_TYPE1, false, false,
-                             CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
-               cppi5_tr_csf_set(&tr_req[i].flags, CPPI5_TR_CSF_SUPR_EVT);
+               cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false,
+                             false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+               cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT);
 
                tr_req[tr_idx].addr = sg_addr;
                tr_req[tr_idx].icnt0 = tr0_cnt0;
@@ -3101,14 +3101,14 @@ static struct udma_match_data am654_main_data = {
        .psil_base = 0x1000,
        .enable_memcpy_support = true,
        .statictr_z_mask = GENMASK(11, 0),
-       .rchan_oes_offset = 0x2000,
+       .rchan_oes_offset = 0x200,
 };
 
 static struct udma_match_data am654_mcu_data = {
        .psil_base = 0x6000,
        .enable_memcpy_support = false,
        .statictr_z_mask = GENMASK(11, 0),
-       .rchan_oes_offset = 0x2000,
+       .rchan_oes_offset = 0x200,
 };
 
 static struct udma_match_data j721e_main_data = {
index 7b6ec30..7a47680 100644 (file)
@@ -100,6 +100,13 @@ config EDAC_AMD64_ERROR_INJECTION
          In addition, there are two control files, inject_read and inject_write,
          which trigger the DRAM ECC Read and Write respectively.
 
+config EDAC_AL_MC
+       tristate "Amazon's Annapurna Lab Memory Controller"
+       depends on (ARCH_ALPINE || COMPILE_TEST)
+       help
+         Support for error detection and correction for Amazon's Annapurna
+         Labs Alpine chips which allow 1 bit correction and 2 bits detection.
+
 config EDAC_AMD76X
        tristate "AMD 76x (760, 762, 768)"
        depends on PCI && X86_32
index 269e151..3a84916 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_EDAC_GHES)                       += ghes_edac.o
 edac_mce_amd-y                         := mce_amd.o
 obj-$(CONFIG_EDAC_DECODE_MCE)          += edac_mce_amd.o
 
+obj-$(CONFIG_EDAC_AL_MC)               += al_mc_edac.o
 obj-$(CONFIG_EDAC_AMD76X)              += amd76x_edac.o
 obj-$(CONFIG_EDAC_CPC925)              += cpc925_edac.o
 obj-$(CONFIG_EDAC_I5000)               += i5000_edac.o
diff --git a/drivers/edac/al_mc_edac.c b/drivers/edac/al_mc_edac.c
new file mode 100644 (file)
index 0000000..7d4f396
--- /dev/null
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ */
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/edac.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include "edac_module.h"
+
+/* Registers Offset */
+#define AL_MC_ECC_CFG          0x70
+#define AL_MC_ECC_CLEAR                0x7c
+#define AL_MC_ECC_ERR_COUNT    0x80
+#define AL_MC_ECC_CE_ADDR0     0x84
+#define AL_MC_ECC_CE_ADDR1     0x88
+#define AL_MC_ECC_UE_ADDR0     0xa4
+#define AL_MC_ECC_UE_ADDR1     0xa8
+#define AL_MC_ECC_CE_SYND0     0x8c
+#define AL_MC_ECC_CE_SYND1     0x90
+#define AL_MC_ECC_CE_SYND2     0x94
+#define AL_MC_ECC_UE_SYND0     0xac
+#define AL_MC_ECC_UE_SYND1     0xb0
+#define AL_MC_ECC_UE_SYND2     0xb4
+
+/* Registers Fields */
+#define AL_MC_ECC_CFG_SCRUB_DISABLED   BIT(4)
+
+#define AL_MC_ECC_CLEAR_UE_COUNT       BIT(3)
+#define AL_MC_ECC_CLEAR_CE_COUNT       BIT(2)
+#define AL_MC_ECC_CLEAR_UE_ERR         BIT(1)
+#define AL_MC_ECC_CLEAR_CE_ERR         BIT(0)
+
+#define AL_MC_ECC_ERR_COUNT_UE         GENMASK(31, 16)
+#define AL_MC_ECC_ERR_COUNT_CE         GENMASK(15, 0)
+
+#define AL_MC_ECC_CE_ADDR0_RANK                GENMASK(25, 24)
+#define AL_MC_ECC_CE_ADDR0_ROW         GENMASK(17, 0)
+
+#define AL_MC_ECC_CE_ADDR1_BG          GENMASK(25, 24)
+#define AL_MC_ECC_CE_ADDR1_BANK                GENMASK(18, 16)
+#define AL_MC_ECC_CE_ADDR1_COLUMN      GENMASK(11, 0)
+
+#define AL_MC_ECC_UE_ADDR0_RANK                GENMASK(25, 24)
+#define AL_MC_ECC_UE_ADDR0_ROW         GENMASK(17, 0)
+
+#define AL_MC_ECC_UE_ADDR1_BG          GENMASK(25, 24)
+#define AL_MC_ECC_UE_ADDR1_BANK                GENMASK(18, 16)
+#define AL_MC_ECC_UE_ADDR1_COLUMN      GENMASK(11, 0)
+
+#define DRV_NAME "al_mc_edac"
+#define AL_MC_EDAC_MSG_MAX 256
+
+struct al_mc_edac {
+       void __iomem *mmio_base;
+       spinlock_t lock;
+       int irq_ce;
+       int irq_ue;
+};
+
+static void prepare_msg(char *message, size_t buffer_size,
+                       enum hw_event_mc_err_type type,
+                       u8 rank, u32 row, u8 bg, u8 bank, u16 column,
+                       u32 syn0, u32 syn1, u32 syn2)
+{
+       snprintf(message, buffer_size,
+                "%s rank=0x%x row=0x%x bg=0x%x bank=0x%x col=0x%x syn0: 0x%x syn1: 0x%x syn2: 0x%x",
+                type == HW_EVENT_ERR_UNCORRECTED ? "UE" : "CE",
+                rank, row, bg, bank, column, syn0, syn1, syn2);
+}
+
+static int handle_ce(struct mem_ctl_info *mci)
+{
+       u32 eccerrcnt, ecccaddr0, ecccaddr1, ecccsyn0, ecccsyn1, ecccsyn2, row;
+       struct al_mc_edac *al_mc = mci->pvt_info;
+       char msg[AL_MC_EDAC_MSG_MAX];
+       u16 ce_count, column;
+       unsigned long flags;
+       u8 rank, bg, bank;
+
+       eccerrcnt = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_ERR_COUNT);
+       ce_count = FIELD_GET(AL_MC_ECC_ERR_COUNT_CE, eccerrcnt);
+       if (!ce_count)
+               return 0;
+
+       ecccaddr0 = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_CE_ADDR0);
+       ecccaddr1 = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_CE_ADDR1);
+       ecccsyn0 = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_CE_SYND0);
+       ecccsyn1 = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_CE_SYND1);
+       ecccsyn2 = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_CE_SYND2);
+
+       writel_relaxed(AL_MC_ECC_CLEAR_CE_COUNT | AL_MC_ECC_CLEAR_CE_ERR,
+                      al_mc->mmio_base + AL_MC_ECC_CLEAR);
+
+       dev_dbg(mci->pdev, "eccuaddr0=0x%08x eccuaddr1=0x%08x\n",
+               ecccaddr0, ecccaddr1);
+
+       rank = FIELD_GET(AL_MC_ECC_CE_ADDR0_RANK, ecccaddr0);
+       row = FIELD_GET(AL_MC_ECC_CE_ADDR0_ROW, ecccaddr0);
+
+       bg = FIELD_GET(AL_MC_ECC_CE_ADDR1_BG, ecccaddr1);
+       bank = FIELD_GET(AL_MC_ECC_CE_ADDR1_BANK, ecccaddr1);
+       column = FIELD_GET(AL_MC_ECC_CE_ADDR1_COLUMN, ecccaddr1);
+
+       prepare_msg(msg, sizeof(msg), HW_EVENT_ERR_CORRECTED,
+                   rank, row, bg, bank, column,
+                   ecccsyn0, ecccsyn1, ecccsyn2);
+
+       spin_lock_irqsave(&al_mc->lock, flags);
+       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+                            ce_count, 0, 0, 0, 0, 0, -1, mci->ctl_name, msg);
+       spin_unlock_irqrestore(&al_mc->lock, flags);
+
+       return ce_count;
+}
+
+static int handle_ue(struct mem_ctl_info *mci)
+{
+       u32 eccerrcnt, eccuaddr0, eccuaddr1, eccusyn0, eccusyn1, eccusyn2, row;
+       struct al_mc_edac *al_mc = mci->pvt_info;
+       char msg[AL_MC_EDAC_MSG_MAX];
+       u16 ue_count, column;
+       unsigned long flags;
+       u8 rank, bg, bank;
+
+       eccerrcnt = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_ERR_COUNT);
+       ue_count = FIELD_GET(AL_MC_ECC_ERR_COUNT_UE, eccerrcnt);
+       if (!ue_count)
+               return 0;
+
+       eccuaddr0 = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_UE_ADDR0);
+       eccuaddr1 = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_UE_ADDR1);
+       eccusyn0 = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_UE_SYND0);
+       eccusyn1 = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_UE_SYND1);
+       eccusyn2 = readl_relaxed(al_mc->mmio_base + AL_MC_ECC_UE_SYND2);
+
+       writel_relaxed(AL_MC_ECC_CLEAR_UE_COUNT | AL_MC_ECC_CLEAR_UE_ERR,
+                      al_mc->mmio_base + AL_MC_ECC_CLEAR);
+
+       dev_dbg(mci->pdev, "eccuaddr0=0x%08x eccuaddr1=0x%08x\n",
+               eccuaddr0, eccuaddr1);
+
+       rank = FIELD_GET(AL_MC_ECC_UE_ADDR0_RANK, eccuaddr0);
+       row = FIELD_GET(AL_MC_ECC_UE_ADDR0_ROW, eccuaddr0);
+
+       bg = FIELD_GET(AL_MC_ECC_UE_ADDR1_BG, eccuaddr1);
+       bank = FIELD_GET(AL_MC_ECC_UE_ADDR1_BANK, eccuaddr1);
+       column = FIELD_GET(AL_MC_ECC_UE_ADDR1_COLUMN, eccuaddr1);
+
+       prepare_msg(msg, sizeof(msg), HW_EVENT_ERR_UNCORRECTED,
+                   rank, row, bg, bank, column,
+                   eccusyn0, eccusyn1, eccusyn2);
+
+       spin_lock_irqsave(&al_mc->lock, flags);
+       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+                            ue_count, 0, 0, 0, 0, 0, -1, mci->ctl_name, msg);
+       spin_unlock_irqrestore(&al_mc->lock, flags);
+
+       return ue_count;
+}
+
+static void al_mc_edac_check(struct mem_ctl_info *mci)
+{
+       struct al_mc_edac *al_mc = mci->pvt_info;
+
+       if (al_mc->irq_ue <= 0)
+               handle_ue(mci);
+
+       if (al_mc->irq_ce <= 0)
+               handle_ce(mci);
+}
+
+static irqreturn_t al_mc_edac_irq_handler_ue(int irq, void *info)
+{
+       struct platform_device *pdev = info;
+       struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+       if (handle_ue(mci))
+               return IRQ_HANDLED;
+       return IRQ_NONE;
+}
+
+static irqreturn_t al_mc_edac_irq_handler_ce(int irq, void *info)
+{
+       struct platform_device *pdev = info;
+       struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+       if (handle_ce(mci))
+               return IRQ_HANDLED;
+       return IRQ_NONE;
+}
+
+static enum scrub_type get_scrub_mode(void __iomem *mmio_base)
+{
+       u32 ecccfg0;
+
+       ecccfg0 = readl(mmio_base + AL_MC_ECC_CFG);
+
+       if (FIELD_GET(AL_MC_ECC_CFG_SCRUB_DISABLED, ecccfg0))
+               return SCRUB_NONE;
+       else
+               return SCRUB_HW_SRC;
+}
+
+static void devm_al_mc_edac_free(void *data)
+{
+       edac_mc_free(data);
+}
+
+static void devm_al_mc_edac_del(void *data)
+{
+       edac_mc_del_mc(data);
+}
+
+static int al_mc_edac_probe(struct platform_device *pdev)
+{
+       struct edac_mc_layer layers[1];
+       struct mem_ctl_info *mci;
+       struct al_mc_edac *al_mc;
+       void __iomem *mmio_base;
+       struct dimm_info *dimm;
+       int ret;
+
+       mmio_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(mmio_base)) {
+               dev_err(&pdev->dev, "failed to ioremap memory (%ld)\n",
+                       PTR_ERR(mmio_base));
+               return PTR_ERR(mmio_base);
+       }
+
+       layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+       layers[0].size = 1;
+       layers[0].is_virt_csrow = false;
+       mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
+                           sizeof(struct al_mc_edac));
+       if (!mci)
+               return -ENOMEM;
+
+       ret = devm_add_action(&pdev->dev, devm_al_mc_edac_free, mci);
+       if (ret) {
+               edac_mc_free(mci);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, mci);
+       al_mc = mci->pvt_info;
+
+       al_mc->mmio_base = mmio_base;
+
+       al_mc->irq_ue = of_irq_get_byname(pdev->dev.of_node, "ue");
+       if (al_mc->irq_ue <= 0)
+               dev_dbg(&pdev->dev,
+                       "no IRQ defined for UE - falling back to polling\n");
+
+       al_mc->irq_ce = of_irq_get_byname(pdev->dev.of_node, "ce");
+       if (al_mc->irq_ce <= 0)
+               dev_dbg(&pdev->dev,
+                       "no IRQ defined for CE - falling back to polling\n");
+
+       /*
+        * In case both interrupts (ue/ce) are to be found, use interrupt mode.
+        * In case none of the interrupt are foud, use polling mode.
+        * In case only one interrupt is found, use interrupt mode for it but
+        * keep polling mode enable for the other.
+        */
+       if (al_mc->irq_ue <= 0 || al_mc->irq_ce <= 0) {
+               edac_op_state = EDAC_OPSTATE_POLL;
+               mci->edac_check = al_mc_edac_check;
+       } else {
+               edac_op_state = EDAC_OPSTATE_INT;
+       }
+
+       spin_lock_init(&al_mc->lock);
+
+       mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR4;
+       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+       mci->edac_cap = EDAC_FLAG_SECDED;
+       mci->mod_name = DRV_NAME;
+       mci->ctl_name = "al_mc";
+       mci->pdev = &pdev->dev;
+       mci->scrub_mode = get_scrub_mode(mmio_base);
+
+       dimm = *mci->dimms;
+       dimm->grain = 1;
+
+       ret = edac_mc_add_mc(mci);
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "fail to add memory controller device (%d)\n",
+                       ret);
+               return ret;
+       }
+
+       ret = devm_add_action(&pdev->dev, devm_al_mc_edac_del, &pdev->dev);
+       if (ret) {
+               edac_mc_del_mc(&pdev->dev);
+               return ret;
+       }
+
+       if (al_mc->irq_ue > 0) {
+               ret = devm_request_irq(&pdev->dev,
+                                      al_mc->irq_ue,
+                                      al_mc_edac_irq_handler_ue,
+                                      IRQF_SHARED,
+                                      pdev->name,
+                                      pdev);
+               if (ret != 0) {
+                       dev_err(&pdev->dev,
+                               "failed to request UE IRQ %d (%d)\n",
+                               al_mc->irq_ue, ret);
+                       return ret;
+               }
+       }
+
+       if (al_mc->irq_ce > 0) {
+               ret = devm_request_irq(&pdev->dev,
+                                      al_mc->irq_ce,
+                                      al_mc_edac_irq_handler_ce,
+                                      IRQF_SHARED,
+                                      pdev->name,
+                                      pdev);
+               if (ret != 0) {
+                       dev_err(&pdev->dev,
+                               "failed to request CE IRQ %d (%d)\n",
+                               al_mc->irq_ce, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static const struct of_device_id al_mc_edac_of_match[] = {
+       { .compatible = "amazon,al-mc-edac", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, al_mc_edac_of_match);
+
+static struct platform_driver al_mc_edac_driver = {
+       .probe = al_mc_edac_probe,
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = al_mc_edac_of_match,
+       },
+};
+
+module_platform_driver(al_mc_edac_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Talel Shenhar");
+MODULE_DESCRIPTION("Amazon's Annapurna Lab's Memory Controller EDAC Driver");
index 6262f63..1362274 100644 (file)
@@ -3375,7 +3375,7 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
                        pvt->ops = &family_types[F17_M70H_CPUS].ops;
                        break;
                }
-               /* fall through */
+               fallthrough;
        case 0x18:
                fam_type        = &family_types[F17_CPUS];
                pvt->ops        = &family_types[F17_CPUS].ops;
@@ -3385,6 +3385,12 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
                break;
 
        case 0x19:
+               if (pvt->model >= 0x20 && pvt->model <= 0x2f) {
+                       fam_type = &family_types[F17_M70H_CPUS];
+                       pvt->ops = &family_types[F17_M70H_CPUS].ops;
+                       fam_type->ctl_name = "F19h_M20h";
+                       break;
+               }
                fam_type        = &family_types[F19_CPUS];
                pvt->ops        = &family_types[F19_CPUS].ops;
                family_types[F19_CPUS].ctl_name = "F19h";
index b194658..fde809e 100644 (file)
@@ -209,8 +209,8 @@ static int config_irq(void *ctx, struct platform_device *pdev)
        /* register interrupt handler */
        irq = platform_get_irq(pdev, 0);
        dev_dbg(&pdev->dev, "got irq %d\n", irq);
-       if (!irq)
-               return -ENODEV;
+       if (irq < 0)
+               return irq;
 
        rc = devm_request_irq(&pdev->dev, irq, mcr_isr, IRQF_TRIGGER_HIGH,
                              DRV_NAME, ctx);
@@ -388,23 +388,7 @@ static struct platform_driver aspeed_driver = {
        .probe          = aspeed_probe,
        .remove         = aspeed_remove
 };
-
-
-static int __init aspeed_init(void)
-{
-       return platform_driver_register(&aspeed_driver);
-}
-
-
-static void __exit aspeed_exit(void)
-{
-       platform_driver_unregister(&aspeed_driver);
-}
-
-
-module_init(aspeed_init);
-module_exit(aspeed_exit);
-
+module_platform_driver(aspeed_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Stefan Schaeckeler <sschaeck@cisco.com>");
index de732dc..313d080 100644 (file)
@@ -7,7 +7,7 @@
  * Implement support for the e7520, E7525, e7320 and i3100 memory controllers.
  *
  * Datasheets:
- *     http://www.intel.in/content/www/in/en/chipsets/e7525-memory-controller-hub-datasheet.html
+ *     https://www.intel.in/content/www/in/en/chipsets/e7525-memory-controller-hub-datasheet.html
  *     ftp://download.intel.com/design/intarch/datashts/31345803.pdf
  *
  * Written by Tom Zimmerman
index 4e6aca5..2f9f1e7 100644 (file)
@@ -474,8 +474,12 @@ static ssize_t dimmdev_location_show(struct device *dev,
                                     struct device_attribute *mattr, char *data)
 {
        struct dimm_info *dimm = to_dimm(dev);
+       ssize_t count;
 
-       return edac_dimm_info_location(dimm, data, PAGE_SIZE);
+       count = edac_dimm_info_location(dimm, data, PAGE_SIZE);
+       count += scnprintf(data + count, PAGE_SIZE - count, "\n");
+
+       return count;
 }
 
 static ssize_t dimmdev_label_show(struct device *dev,
@@ -813,15 +817,23 @@ static ssize_t mci_max_location_show(struct device *dev,
                                     char *data)
 {
        struct mem_ctl_info *mci = to_mci(dev);
-       int i;
+       int len = PAGE_SIZE;
        char *p = data;
+       int i, n;
 
        for (i = 0; i < mci->n_layers; i++) {
-               p += sprintf(p, "%s %d ",
-                            edac_layer_name[mci->layers[i].type],
-                            mci->layers[i].size - 1);
+               n = scnprintf(p, len, "%s %d ",
+                             edac_layer_name[mci->layers[i].type],
+                             mci->layers[i].size - 1);
+               len -= n;
+               if (len <= 0)
+                       goto out;
+
+               p += n;
        }
 
+       p += scnprintf(p, len, "\n");
+out:
        return p - data;
 }
 
index da60c29..a918ca9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2013 by Mauro Carvalho Chehab
  *
- * Red Hat Inc. http://www.redhat.com
+ * Red Hat Inc. https://www.redhat.com
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -55,6 +55,8 @@ static DEFINE_SPINLOCK(ghes_lock);
 static bool __read_mostly force_load;
 module_param(force_load, bool, 0);
 
+static bool system_scanned;
+
 /* Memory Device - Type 17 of SMBIOS spec */
 struct memdev_dmi_entry {
        u8 type;
@@ -225,14 +227,12 @@ static void enumerate_dimms(const struct dmi_header *dh, void *arg)
 
 static void ghes_scan_system(void)
 {
-       static bool scanned;
-
-       if (scanned)
+       if (system_scanned)
                return;
 
        dmi_walk(enumerate_dimms, &ghes_hw);
 
-       scanned = true;
+       system_scanned = true;
 }
 
 void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
@@ -372,8 +372,18 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
                p += sprintf(p, "rank:%d ", mem_err->rank);
        if (mem_err->validation_bits & CPER_MEM_VALID_BANK)
                p += sprintf(p, "bank:%d ", mem_err->bank);
-       if (mem_err->validation_bits & CPER_MEM_VALID_ROW)
-               p += sprintf(p, "row:%d ", mem_err->row);
+       if (mem_err->validation_bits & CPER_MEM_VALID_BANK_GROUP)
+               p += sprintf(p, "bank_group:%d ",
+                            mem_err->bank >> CPER_MEM_BANK_GROUP_SHIFT);
+       if (mem_err->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
+               p += sprintf(p, "bank_address:%d ",
+                            mem_err->bank & CPER_MEM_BANK_ADDRESS_MASK);
+       if (mem_err->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
+               u32 row = mem_err->row;
+
+               row |= cper_get_mem_extension(mem_err->validation_bits, mem_err->extended);
+               p += sprintf(p, "row:%d ", row);
+       }
        if (mem_err->validation_bits & CPER_MEM_VALID_COLUMN)
                p += sprintf(p, "col:%d ", mem_err->column);
        if (mem_err->validation_bits & CPER_MEM_VALID_BIT_POSITION)
@@ -395,6 +405,9 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
                        strcpy(e->label, dimm->label);
                }
        }
+       if (mem_err->validation_bits & CPER_MEM_VALID_CHIP_ID)
+               p += sprintf(p, "chipID: %d ",
+                            mem_err->extended >> CPER_MEM_CHIP_ID_SHIFT);
        if (p > e->location)
                *(p - 1) = '\0';
 
@@ -508,6 +521,7 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev)
                if (!force_load && idx < 0)
                        return -ENODEV;
        } else {
+               force_load = true;
                idx = 0;
        }
 
@@ -629,8 +643,14 @@ void ghes_edac_unregister(struct ghes *ghes)
        struct mem_ctl_info *mci;
        unsigned long flags;
 
+       if (!force_load)
+               return;
+
        mutex_lock(&ghes_reg_mutex);
 
+       system_scanned = false;
+       memset(&ghes_hw, 0, sizeof(struct ghes_hw_desc));
+
        if (!refcount_dec_and_test(&ghes_refcount))
                goto unlock;
 
index 191aa7c..324a46b 100644 (file)
@@ -1061,16 +1061,15 @@ static int i5100_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                                    PCI_DEVICE_ID_INTEL_5100_19, 0);
        if (!einj) {
                ret = -ENODEV;
-               goto bail_einj;
+               goto bail_mc_free;
        }
 
        rc = pci_enable_device(einj);
        if (rc < 0) {
                ret = rc;
-               goto bail_disable_einj;
+               goto bail_einj;
        }
 
-
        mci->pdev = &pdev->dev;
 
        priv = mci->pvt_info;
@@ -1136,14 +1135,14 @@ static int i5100_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 bail_scrub:
        priv->scrub_enable = 0;
        cancel_delayed_work_sync(&(priv->i5100_scrubbing));
-       edac_mc_free(mci);
-
-bail_disable_einj:
        pci_disable_device(einj);
 
 bail_einj:
        pci_dev_put(einj);
 
+bail_mc_free:
+       edac_mc_free(mci);
+
 bail_disable_ch1:
        pci_disable_device(ch1mm);
 
index f131c05..92d63eb 100644 (file)
@@ -8,7 +8,7 @@
  *      Ben Woodard <woodard@redhat.com>
  *      Mauro Carvalho Chehab
  *
- * Red Hat Inc. http://www.redhat.com
+ * Red Hat Inc. https://www.redhat.com
  *
  * Forked and adapted from the i5000_edac driver which was
  * written by Douglas Thompson Linux Networx <norsk5@xmission.com>
@@ -1460,7 +1460,7 @@ module_exit(i5400_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ben Woodard <woodard@redhat.com>");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
-MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_AUTHOR("Red Hat Inc. (https://www.redhat.com)");
 MODULE_DESCRIPTION("MC Driver for Intel I5400 memory controllers - "
                   I5400_REVISION);
 
index 2e9bbe5..4f28b8c 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2010 by:
  *      Mauro Carvalho Chehab
  *
- * Red Hat Inc. http://www.redhat.com
+ * Red Hat Inc. https://www.redhat.com
  *
  * Intel 7300 Chipset Memory Controller Hub (MCH) - Datasheet
  *     http://www.intel.com/Assets/PDF/datasheet/318082.pdf
@@ -1206,7 +1206,7 @@ module_exit(i7300_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
-MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_AUTHOR("Red Hat Inc. (https://www.redhat.com)");
 MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - "
                   I7300_REVISION);
 
index 2acd9f9..23d2572 100644 (file)
@@ -9,7 +9,7 @@
  * Copyright (c) 2009-2010 by:
  *      Mauro Carvalho Chehab
  *
- * Red Hat Inc. http://www.redhat.com
+ * Red Hat Inc. https://www.redhat.com
  *
  * Forked and adapted from the i5400_edac driver
  *
@@ -2391,7 +2391,7 @@ module_exit(i7core_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
-MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_AUTHOR("Red Hat Inc. (https://www.redhat.com)");
 MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - "
                   I7CORE_REVISION);
 
index ebe5099..c479632 100644 (file)
@@ -9,7 +9,7 @@
  * Since the DRAM controller is on the cpu chip, we can use its PCI device
  * id to identify these processors.
  *
- * PCI DRAM controller device ids (Taken from The PCI ID Repository - http://pci-ids.ucw.cz/)
+ * PCI DRAM controller device ids (Taken from The PCI ID Repository - https://pci-ids.ucw.cz/)
  *
  * 0108: Xeon E3-1200 Processor Family DRAM Controller
  * 010c: Xeon E3-1200/2nd Generation Core Processor Family DRAM Controller
@@ -23,9 +23,9 @@
  * 3e..: 8th/9th Gen Core Processor Host Bridge/DRAM Registers
  *
  * Based on Intel specification:
- * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf
+ * https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf
  * http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200-family-vol-2-datasheet.html
- * http://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-h-processor-lines-datasheet-vol-2.html
+ * https://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-h-processor-lines-datasheet-vol-2.html
  * https://www.intel.com/content/www/us/en/products/docs/processors/core/8th-gen-core-family-datasheet-vol-2.html
  *
  * According to the above datasheet (p.16):
index 325aedf..7f28edb 100644 (file)
@@ -210,6 +210,11 @@ static const char * const smca_if_mce_desc[] = {
        "L2 BTB Multi-Match Error",
        "L2 Cache Response Poison Error",
        "System Read Data Error",
+       "Hardware Assertion Error",
+       "L1-TLB Multi-Hit",
+       "L2-TLB Multi-Hit",
+       "BSR Parity Error",
+       "CT MCE",
 };
 
 static const char * const smca_l2_mce_desc[] = {
@@ -228,7 +233,8 @@ static const char * const smca_de_mce_desc[] = {
        "Fetch address FIFO parity error",
        "Patch RAM data parity error",
        "Patch RAM sequencer parity error",
-       "Micro-op buffer parity error"
+       "Micro-op buffer parity error",
+       "Hardware Assertion MCA Error",
 };
 
 static const char * const smca_ex_mce_desc[] = {
@@ -244,6 +250,8 @@ static const char * const smca_ex_mce_desc[] = {
        "Scheduling queue parity error",
        "Branch buffer queue parity error",
        "Hardware Assertion error",
+       "Spec Map parity error",
+       "Retire Map parity error",
 };
 
 static const char * const smca_fp_mce_desc[] = {
@@ -360,6 +368,7 @@ static const char * const smca_smu2_mce_desc[] = {
        "Instruction Tag Cache Bank A ECC or parity error",
        "Instruction Tag Cache Bank B ECC or parity error",
        "System Hub Read Buffer ECC or parity error",
+       "PHY RAM ECC error",
 };
 
 static const char * const smca_mp5_mce_desc[] = {
@@ -990,10 +999,8 @@ static void decode_smca_error(struct mce *m)
        pr_emerg(HW_ERR "%s Ext. Error Code: %d", ip_name, xec);
 
        /* Only print the decode of valid error codes */
-       if (xec < smca_mce_descs[bank_type].num_descs &&
-                       (hwid->xec_bitmap & BIT_ULL(xec))) {
+       if (xec < smca_mce_descs[bank_type].num_descs)
                pr_cont(", %s.\n", smca_mce_descs[bank_type].descs[xec]);
-       }
 
        if (bank_type == SMCA_UMC && xec == 0 && decode_dram_ecc)
                decode_dram_ecc(cpu_to_node(m->extcpu), m);
index b8fc4b8..928f63a 100644 (file)
@@ -198,7 +198,7 @@ static int apl_rd_reg(int port, int off, int op, void *data, size_t sz, char *na
        switch (sz) {
        case 8:
                ret = _apl_rd_reg(port, off + 4, op, (u32 *)(data + 4));
-               /* fall through */
+               fallthrough;
        case 4:
                ret |= _apl_rd_reg(port, off, op, (u32 *)data);
                pnd2_printk(KERN_DEBUG, "%s=%x%08x ret=%d\n", name,
index c5ab634..93daa42 100644 (file)
@@ -939,12 +939,9 @@ static enum dev_type sbridge_get_width(struct sbridge_pvt *pvt, u32 mtr)
 
 static enum dev_type __ibridge_get_width(u32 mtr)
 {
-       enum dev_type type;
+       enum dev_type type = DEV_UNKNOWN;
 
        switch (mtr) {
-       case 3:
-               type = DEV_UNKNOWN;
-               break;
        case 2:
                type = DEV_X16;
                break;
@@ -3552,6 +3549,6 @@ MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
-MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_AUTHOR("Red Hat Inc. (https://www.redhat.com)");
 MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge and Ivy Bridge memory controllers - "
                   SBRIDGE_REVISION);
index 4af9744..0eb5eb9 100644 (file)
@@ -454,7 +454,7 @@ DEBUGFS_STRUCT(inject_int, 0200, thunderx_lmc_inject_int_write, NULL);
 DEBUGFS_STRUCT(inject_ecc, 0200, thunderx_lmc_inject_ecc_write, NULL);
 DEBUGFS_STRUCT(int_w1c, 0400, NULL, thunderx_lmc_int_read);
 
-struct debugfs_entry *lmc_dfs_ents[] = {
+static struct debugfs_entry *lmc_dfs_ents[] = {
        &debugfs_mask0,
        &debugfs_mask2,
        &debugfs_parity_test,
index 8be3e89..e7eae20 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
  *
  * Texas Instruments DDR3 ECC error correction and detection driver
  *
@@ -278,7 +278,8 @@ static int ti_edac_probe(struct platform_device *pdev)
 
        /* add EMIF ECC error handler */
        error_irq = platform_get_irq(pdev, 0);
-       if (!error_irq) {
+       if (error_irq < 0) {
+               ret = error_irq;
                edac_printk(KERN_ERR, EDAC_MOD_NAME,
                            "EMIF irq number not defined.\n");
                goto err;
index b785e93..80db43a 100644 (file)
@@ -957,7 +957,7 @@ static void set_broadcast_channel(struct fw_device *device, int generation)
                                device->bc_implemented = BC_IMPLEMENTED;
                                break;
                        }
-                       /* else, fall through - to case address error */
+                       fallthrough;    /* to case address error */
                case RCODE_ADDRESS_ERROR:
                        device->bc_implemented = BC_UNIMPLEMENTED;
                }
index 185b0b7..af70e74 100644 (file)
@@ -277,7 +277,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation,
                        if ((data[0] & bit) == (data[1] & bit))
                                continue;
 
-                       /* fall through - It's a 1394-1995 IRM, retry. */
+                       fallthrough;    /* It's a 1394-1995 IRM, retry */
                default:
                        if (retry) {
                                retry--;
index 94a13fc..ec68ed2 100644 (file)
@@ -54,7 +54,7 @@ static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count)
                switch (port_type) {
                case SELFID_PORT_CHILD:
                        (*child_port_count)++;
-                       /* fall through */
+                       fallthrough;
                case SELFID_PORT_PARENT:
                case SELFID_PORT_NCONN:
                        (*total_port_count)++;
index 439d918..ac487c9 100644 (file)
@@ -1097,14 +1097,14 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
                        rcode = RCODE_ADDRESS_ERROR;
                        break;
                }
-               /* else fall through */
+               fallthrough;
 
        case CSR_NODE_IDS:
                /*
                 * per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.8
                 * and 9.6, but interoperable with IEEE 1394.1-2004 bridges
                 */
-               /* fall through */
+               fallthrough;
 
        case CSR_STATE_CLEAR:
        case CSR_STATE_SET:
index 7dde21b..020cb15 100644 (file)
@@ -1495,7 +1495,7 @@ static int handle_at_packet(struct context *context,
                        packet->ack = RCODE_GENERATION;
                        break;
                }
-               /* fall through */
+               fallthrough;
 
        default:
                packet->ack = RCODE_SEND_ERROR;
@@ -3054,7 +3054,7 @@ static int ohci_start_iso(struct fw_iso_context *base,
 
        case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
                control |= IR_CONTEXT_BUFFER_FILL|IR_CONTEXT_MULTI_CHANNEL_MODE;
-               /* fall through */
+               fallthrough;
        case FW_ISO_CONTEXT_RECEIVE:
                index = ctx - ohci->ir_context_list;
                match = (tags << 28) | (sync << 8) | ctx->base.channel;
index b4b9ce9..840754d 100644 (file)
@@ -78,11 +78,26 @@ struct sdei_crosscall_args {
        int first_error;
 };
 
-#define CROSSCALL_INIT(arg, event)     (arg.event = event, \
-                                        arg.first_error = 0, \
-                                        atomic_set(&arg.errors, 0))
+#define CROSSCALL_INIT(arg, event)             \
+       do {                                    \
+               arg.event = event;              \
+               arg.first_error = 0;            \
+               atomic_set(&arg.errors, 0);     \
+       } while (0)
+
+static inline int sdei_do_local_call(smp_call_func_t fn,
+                                    struct sdei_event *event)
+{
+       struct sdei_crosscall_args arg;
+
+       CROSSCALL_INIT(arg, event);
+       fn(&arg);
 
-static inline int sdei_do_cross_call(void *fn, struct sdei_event * event)
+       return arg.first_error;
+}
+
+static inline int sdei_do_cross_call(smp_call_func_t fn,
+                                    struct sdei_event *event)
 {
        struct sdei_crosscall_args arg;
 
@@ -114,26 +129,7 @@ static int sdei_to_linux_errno(unsigned long sdei_err)
                return -ENOMEM;
        }
 
-       /* Not an error value ... */
-       return sdei_err;
-}
-
-/*
- * If x0 is any of these values, then the call failed, use sdei_to_linux_errno()
- * to translate.
- */
-static int sdei_is_err(struct arm_smccc_res *res)
-{
-       switch (res->a0) {
-       case SDEI_NOT_SUPPORTED:
-       case SDEI_INVALID_PARAMETERS:
-       case SDEI_DENIED:
-       case SDEI_PENDING:
-       case SDEI_OUT_OF_RESOURCE:
-               return true;
-       }
-
-       return false;
+       return 0;
 }
 
 static int invoke_sdei_fn(unsigned long function_id, unsigned long arg0,
@@ -141,14 +137,13 @@ static int invoke_sdei_fn(unsigned long function_id, unsigned long arg0,
                          unsigned long arg3, unsigned long arg4,
                          u64 *result)
 {
-       int err = 0;
+       int err;
        struct arm_smccc_res res;
 
        if (sdei_firmware_call) {
                sdei_firmware_call(function_id, arg0, arg1, arg2, arg3, arg4,
                                   &res);
-               if (sdei_is_err(&res))
-                       err = sdei_to_linux_errno(res.a0);
+               err = sdei_to_linux_errno(res.a0);
        } else {
                /*
                 * !sdei_firmware_call means we failed to probe or called
@@ -210,36 +205,34 @@ static struct sdei_event *sdei_event_create(u32 event_num,
        lockdep_assert_held(&sdei_events_lock);
 
        event = kzalloc(sizeof(*event), GFP_KERNEL);
-       if (!event)
-               return ERR_PTR(-ENOMEM);
+       if (!event) {
+               err = -ENOMEM;
+               goto fail;
+       }
 
        INIT_LIST_HEAD(&event->list);
        event->event_num = event_num;
 
        err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
                                      &result);
-       if (err) {
-               kfree(event);
-               return ERR_PTR(err);
-       }
+       if (err)
+               goto fail;
        event->priority = result;
 
        err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_TYPE,
                                      &result);
-       if (err) {
-               kfree(event);
-               return ERR_PTR(err);
-       }
+       if (err)
+               goto fail;
        event->type = result;
 
        if (event->type == SDEI_EVENT_TYPE_SHARED) {
                reg = kzalloc(sizeof(*reg), GFP_KERNEL);
                if (!reg) {
-                       kfree(event);
-                       return ERR_PTR(-ENOMEM);
+                       err = -ENOMEM;
+                       goto fail;
                }
 
-               reg->event_num = event_num;
+               reg->event_num = event->event_num;
                reg->priority = event->priority;
 
                reg->callback = cb;
@@ -251,8 +244,8 @@ static struct sdei_event *sdei_event_create(u32 event_num,
 
                regs = alloc_percpu(struct sdei_registered_event);
                if (!regs) {
-                       kfree(event);
-                       return ERR_PTR(-ENOMEM);
+                       err = -ENOMEM;
+                       goto fail;
                }
 
                for_each_possible_cpu(cpu) {
@@ -272,6 +265,10 @@ static struct sdei_event *sdei_event_create(u32 event_num,
        spin_unlock(&sdei_list_lock);
 
        return event;
+
+fail:
+       kfree(event);
+       return ERR_PTR(err);
 }
 
 static void sdei_event_destroy_llocked(struct sdei_event *event)
@@ -490,16 +487,6 @@ static void _local_event_unregister(void *data)
        sdei_cross_call_return(arg, err);
 }
 
-static int _sdei_event_unregister(struct sdei_event *event)
-{
-       lockdep_assert_held(&sdei_events_lock);
-
-       if (event->type == SDEI_EVENT_TYPE_SHARED)
-               return sdei_api_event_unregister(event->event_num);
-
-       return sdei_do_cross_call(_local_event_unregister, event);
-}
-
 int sdei_event_unregister(u32 event_num)
 {
        int err;
@@ -509,24 +496,27 @@ int sdei_event_unregister(u32 event_num)
 
        mutex_lock(&sdei_events_lock);
        event = sdei_event_find(event_num);
-       do {
-               if (!event) {
-                       pr_warn("Event %u not registered\n", event_num);
-                       err = -ENOENT;
-                       break;
-               }
+       if (!event) {
+               pr_warn("Event %u not registered\n", event_num);
+               err = -ENOENT;
+               goto unlock;
+       }
 
-               spin_lock(&sdei_list_lock);
-               event->reregister = false;
-               event->reenable = false;
-               spin_unlock(&sdei_list_lock);
+       spin_lock(&sdei_list_lock);
+       event->reregister = false;
+       event->reenable = false;
+       spin_unlock(&sdei_list_lock);
 
-               err = _sdei_event_unregister(event);
-               if (err)
-                       break;
+       if (event->type == SDEI_EVENT_TYPE_SHARED)
+               err = sdei_api_event_unregister(event->event_num);
+       else
+               err = sdei_do_cross_call(_local_event_unregister, event);
 
-               sdei_event_destroy(event);
-       } while (0);
+       if (err)
+               goto unlock;
+
+       sdei_event_destroy(event);
+unlock:
        mutex_unlock(&sdei_events_lock);
 
        return err;
@@ -547,7 +537,7 @@ static int sdei_unregister_shared(void)
                if (event->type != SDEI_EVENT_TYPE_SHARED)
                        continue;
 
-               err = _sdei_event_unregister(event);
+               err = sdei_api_event_unregister(event->event_num);
                if (err)
                        break;
        }
@@ -581,25 +571,6 @@ static void _local_event_register(void *data)
        sdei_cross_call_return(arg, err);
 }
 
-static int _sdei_event_register(struct sdei_event *event)
-{
-       int err;
-
-       lockdep_assert_held(&sdei_events_lock);
-
-       if (event->type == SDEI_EVENT_TYPE_SHARED)
-               return sdei_api_event_register(event->event_num,
-                                              sdei_entry_point,
-                                              event->registered,
-                                              SDEI_EVENT_REGISTER_RM_ANY, 0);
-
-       err = sdei_do_cross_call(_local_event_register, event);
-       if (err)
-               sdei_do_cross_call(_local_event_unregister, event);
-
-       return err;
-}
-
 int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
 {
        int err;
@@ -608,63 +579,44 @@ int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
        WARN_ON(in_nmi());
 
        mutex_lock(&sdei_events_lock);
-       do {
-               if (sdei_event_find(event_num)) {
-                       pr_warn("Event %u already registered\n", event_num);
-                       err = -EBUSY;
-                       break;
-               }
-
-               event = sdei_event_create(event_num, cb, arg);
-               if (IS_ERR(event)) {
-                       err = PTR_ERR(event);
-                       pr_warn("Failed to create event %u: %d\n", event_num,
-                               err);
-                       break;
-               }
-
-               cpus_read_lock();
-               err = _sdei_event_register(event);
-               if (err) {
-                       sdei_event_destroy(event);
-                       pr_warn("Failed to register event %u: %d\n", event_num,
-                               err);
-               } else {
-                       spin_lock(&sdei_list_lock);
-                       event->reregister = true;
-                       spin_unlock(&sdei_list_lock);
-               }
-               cpus_read_unlock();
-       } while (0);
-       mutex_unlock(&sdei_events_lock);
-
-       return err;
-}
-
-static int sdei_reregister_event_llocked(struct sdei_event *event)
-{
-       int err;
-
-       lockdep_assert_held(&sdei_events_lock);
-       lockdep_assert_held(&sdei_list_lock);
+       if (sdei_event_find(event_num)) {
+               pr_warn("Event %u already registered\n", event_num);
+               err = -EBUSY;
+               goto unlock;
+       }
 
-       err = _sdei_event_register(event);
-       if (err) {
-               pr_err("Failed to re-register event %u\n", event->event_num);
-               sdei_event_destroy_llocked(event);
-               return err;
+       event = sdei_event_create(event_num, cb, arg);
+       if (IS_ERR(event)) {
+               err = PTR_ERR(event);
+               pr_warn("Failed to create event %u: %d\n", event_num, err);
+               goto unlock;
        }
 
-       if (event->reenable) {
-               if (event->type == SDEI_EVENT_TYPE_SHARED)
-                       err = sdei_api_event_enable(event->event_num);
-               else
-                       err = sdei_do_cross_call(_local_event_enable, event);
+       cpus_read_lock();
+       if (event->type == SDEI_EVENT_TYPE_SHARED) {
+               err = sdei_api_event_register(event->event_num,
+                                             sdei_entry_point,
+                                             event->registered,
+                                             SDEI_EVENT_REGISTER_RM_ANY, 0);
+       } else {
+               err = sdei_do_cross_call(_local_event_register, event);
+               if (err)
+                       sdei_do_cross_call(_local_event_unregister, event);
        }
 
-       if (err)
-               pr_err("Failed to re-enable event %u\n", event->event_num);
+       if (err) {
+               sdei_event_destroy(event);
+               pr_warn("Failed to register event %u: %d\n", event_num, err);
+               goto cpu_unlock;
+       }
 
+       spin_lock(&sdei_list_lock);
+       event->reregister = true;
+       spin_unlock(&sdei_list_lock);
+cpu_unlock:
+       cpus_read_unlock();
+unlock:
+       mutex_unlock(&sdei_events_lock);
        return err;
 }
 
@@ -680,9 +632,24 @@ static int sdei_reregister_shared(void)
                        continue;
 
                if (event->reregister) {
-                       err = sdei_reregister_event_llocked(event);
-                       if (err)
+                       err = sdei_api_event_register(event->event_num,
+                                       sdei_entry_point, event->registered,
+                                       SDEI_EVENT_REGISTER_RM_ANY, 0);
+                       if (err) {
+                               pr_err("Failed to re-register event %u\n",
+                                      event->event_num);
+                               sdei_event_destroy_llocked(event);
                                break;
+                       }
+               }
+
+               if (event->reenable) {
+                       err = sdei_api_event_enable(event->event_num);
+                       if (err) {
+                               pr_err("Failed to re-enable event %u\n",
+                                      event->event_num);
+                               break;
+                       }
                }
        }
        spin_unlock(&sdei_list_lock);
@@ -694,7 +661,7 @@ static int sdei_reregister_shared(void)
 static int sdei_cpuhp_down(unsigned int cpu)
 {
        struct sdei_event *event;
-       struct sdei_crosscall_args arg;
+       int err;
 
        /* un-register private events */
        spin_lock(&sdei_list_lock);
@@ -702,12 +669,11 @@ static int sdei_cpuhp_down(unsigned int cpu)
                if (event->type == SDEI_EVENT_TYPE_SHARED)
                        continue;
 
-               CROSSCALL_INIT(arg, event);
-               /* call the cross-call function locally... */
-               _local_event_unregister(&arg);
-               if (arg.first_error)
+               err = sdei_do_local_call(_local_event_unregister, event);
+               if (err) {
                        pr_err("Failed to unregister event %u: %d\n",
-                              event->event_num, arg.first_error);
+                              event->event_num, err);
+               }
        }
        spin_unlock(&sdei_list_lock);
 
@@ -717,7 +683,7 @@ static int sdei_cpuhp_down(unsigned int cpu)
 static int sdei_cpuhp_up(unsigned int cpu)
 {
        struct sdei_event *event;
-       struct sdei_crosscall_args arg;
+       int err;
 
        /* re-register/enable private events */
        spin_lock(&sdei_list_lock);
@@ -726,20 +692,19 @@ static int sdei_cpuhp_up(unsigned int cpu)
                        continue;
 
                if (event->reregister) {
-                       CROSSCALL_INIT(arg, event);
-                       /* call the cross-call function locally... */
-                       _local_event_register(&arg);
-                       if (arg.first_error)
+                       err = sdei_do_local_call(_local_event_register, event);
+                       if (err) {
                                pr_err("Failed to re-register event %u: %d\n",
-                                      event->event_num, arg.first_error);
+                                      event->event_num, err);
+                       }
                }
 
                if (event->reenable) {
-                       CROSSCALL_INIT(arg, event);
-                       _local_event_enable(&arg);
-                       if (arg.first_error)
+                       err = sdei_do_local_call(_local_event_enable, event);
+                       if (err) {
                                pr_err("Failed to re-enable event %u: %d\n",
-                                      event->event_num, arg.first_error);
+                                      event->event_num, err);
+                       }
                }
        }
        spin_unlock(&sdei_list_lock);
@@ -976,7 +941,7 @@ static int sdei_get_conduit(struct platform_device *pdev)
                }
 
                pr_warn("invalid \"method\" property: %s\n", method);
-       } else if (IS_ENABLED(CONFIG_ACPI) && !acpi_disabled) {
+       } else if (!acpi_disabled) {
                if (acpi_psci_use_hvc()) {
                        sdei_firmware_call = &sdei_smccc_hvc;
                        return SMCCC_CONDUIT_HVC;
@@ -1000,8 +965,6 @@ static int sdei_probe(struct platform_device *pdev)
                return 0;
 
        err = sdei_api_get_version(&ver);
-       if (err == -EOPNOTSUPP)
-               pr_err("advertised but not implemented in platform firmware\n");
        if (err) {
                pr_err("Failed to get SDEI version: %d\n", err);
                sdei_mark_interface_broken();
@@ -1099,16 +1062,20 @@ static bool __init sdei_present_acpi(void)
 
 static int __init sdei_init(void)
 {
-       int ret = platform_driver_register(&sdei_driver);
-
-       if (!ret && sdei_present_acpi()) {
-               struct platform_device *pdev;
-
-               pdev = platform_device_register_simple(sdei_driver.driver.name,
-                                                      0, NULL, 0);
-               if (IS_ERR(pdev))
-                       pr_info("Failed to register ACPI:SDEI platform device %ld\n",
-                               PTR_ERR(pdev));
+       struct platform_device *pdev;
+       int ret;
+
+       ret = platform_driver_register(&sdei_driver);
+       if (ret || !sdei_present_acpi())
+               return ret;
+
+       pdev = platform_device_register_simple(sdei_driver.driver.name,
+                                              0, NULL, 0);
+       if (IS_ERR(pdev)) {
+               ret = PTR_ERR(pdev);
+               platform_driver_unregister(&sdei_driver);
+               pr_info("Failed to register ACPI:SDEI platform device %d\n",
+                       ret);
        }
 
        return ret;
index 3939699..da1887f 100644 (file)
@@ -4,20 +4,15 @@ menu "EFI (Extensible Firmware Interface) Support"
 
 config EFI_VARS
        tristate "EFI Variable Support via sysfs"
-       depends on EFI
+       depends on EFI && (X86 || IA64)
        default n
        help
          If you say Y here, you are able to get EFI (Extensible Firmware
          Interface) variable information via sysfs.  You may read,
          write, create, and destroy EFI variables through this interface.
-
-         Note that using this driver in concert with efibootmgr requires
-         at least test release version 0.5.0-test3 or later, which is
-         available from:
-         <http://linux.dell.com/efibootmgr/testing/efibootmgr-0.5.0-test3.tar.gz>
-
-         Subsequent efibootmgr releases may be found at:
-         <http://github.com/vathpela/efibootmgr>
+         Note that this driver is only retained for compatibility with
+         legacy users: new users should use the efivarfs filesystem
+         instead.
 
 config EFI_ESRT
        bool
@@ -26,7 +21,7 @@ config EFI_ESRT
 
 config EFI_VARS_PSTORE
        tristate "Register efivars backend for pstore"
-       depends on EFI_VARS && PSTORE
+       depends on PSTORE
        default y
        help
          Say Y here to enable use efivars as a backend to pstore. This
@@ -137,7 +132,6 @@ config EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER
 
 config EFI_BOOTLOADER_CONTROL
        tristate "EFI Bootloader Control"
-       depends on EFI_VARS
        default n
        help
          This module installs a reboot hook, such that if reboot() is
@@ -281,7 +275,7 @@ config EFI_EARLYCON
 
 config EFI_CUSTOM_SSDT_OVERLAYS
        bool "Load custom ACPI SSDT overlay from an EFI variable"
-       depends on EFI_VARS && ACPI
+       depends on EFI && ACPI
        default ACPI_TABLE_UPGRADE
        help
          Allow loading of an ACPI SSDT overlay from an EFI variable specified
index 7a21698..e8da782 100644 (file)
@@ -28,11 +28,12 @@ obj-$(CONFIG_EFI_DEV_PATH_PARSER)   += dev-path-parser.o
 obj-$(CONFIG_APPLE_PROPERTIES)         += apple-properties.o
 obj-$(CONFIG_EFI_RCI2_TABLE)           += rci2-table.o
 obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE)    += embedded-firmware.o
+obj-$(CONFIG_LOAD_UEFI_KEYS)           += mokvar-table.o
 
 fake_map-y                             += fake_mem.o
 fake_map-$(CONFIG_X86)                 += x86_fake_mem.o
 
-arm-obj-$(CONFIG_EFI)                  := arm-init.o arm-runtime.o
+arm-obj-$(CONFIG_EFI)                  := efi-init.o arm-runtime.o
 obj-$(CONFIG_ARM)                      += $(arm-obj-y)
 obj-$(CONFIG_ARM64)                    += $(arm-obj-y)
 obj-$(CONFIG_EFI_CAPSULE_LOADER)       += capsule-loader.o
index f564e15..e15d484 100644 (file)
@@ -232,10 +232,20 @@ static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
                n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
        if (mem->validation_bits & CPER_MEM_VALID_BANK)
                n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
+       if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
+               n += scnprintf(msg + n, len - n, "bank_group: %d ",
+                              mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
+       if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
+               n += scnprintf(msg + n, len - n, "bank_address: %d ",
+                              mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
        if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
                n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
-       if (mem->validation_bits & CPER_MEM_VALID_ROW)
-               n += scnprintf(msg + n, len - n, "row: %d ", mem->row);
+       if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
+               u32 row = mem->row;
+
+               row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
+               n += scnprintf(msg + n, len - n, "row: %d ", row);
+       }
        if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
                n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
        if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
@@ -250,6 +260,9 @@ static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
        if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
                scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
                          mem->target_id);
+       if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
+               scnprintf(msg + n, len - n, "chip_id: %d ",
+                         mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
 
        msg[n] = '\0';
        return n;
@@ -292,6 +305,7 @@ void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
        cmem->requestor_id = mem->requestor_id;
        cmem->responder_id = mem->responder_id;
        cmem->target_id = mem->target_id;
+       cmem->extended = mem->extended;
        cmem->rank = mem->rank;
        cmem->mem_array_handle = mem->mem_array_handle;
        cmem->mem_dev_handle = mem->mem_dev_handle;
similarity index 99%
rename from drivers/firmware/efi/arm-init.c
rename to drivers/firmware/efi/efi-init.c
index 71c445d..f55a92f 100644 (file)
@@ -236,6 +236,7 @@ void __init efi_init(void)
 
        reserve_regions();
        efi_esrt_init();
+       efi_mokvar_table_init();
 
        memblock_reserve(data.phys_map & PAGE_MASK,
                         PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK)));
index feb7fe6..0ef086e 100644 (file)
@@ -8,6 +8,8 @@
 
 #define DUMP_NAME_LEN 66
 
+#define EFIVARS_DATA_SIZE_MAX 1024
+
 static bool efivars_pstore_disable =
        IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
 
@@ -18,6 +20,9 @@ module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
         EFI_VARIABLE_BOOTSERVICE_ACCESS | \
         EFI_VARIABLE_RUNTIME_ACCESS)
 
+static LIST_HEAD(efi_pstore_list);
+static DECLARE_WORK(efivar_work, NULL);
+
 static int efi_pstore_open(struct pstore_info *psi)
 {
        psi->data = NULL;
@@ -126,7 +131,7 @@ static inline int __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry,
        if (entry->deleting) {
                list_del(&entry->list);
                efivar_entry_iter_end();
-               efivar_unregister(entry);
+               kfree(entry);
                if (efivar_entry_iter_begin())
                        return -EINTR;
        } else if (turn_off_scanning)
@@ -169,7 +174,7 @@ static int efi_pstore_sysfs_entry_iter(struct pstore_record *record)
 {
        struct efivar_entry **pos = (struct efivar_entry **)&record->psi->data;
        struct efivar_entry *entry, *n;
-       struct list_head *head = &efivar_sysfs_list;
+       struct list_head *head = &efi_pstore_list;
        int size = 0;
        int ret;
 
@@ -263,8 +268,9 @@ static int efi_pstore_write(struct pstore_record *record)
        ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES,
                              preemptible(), record->size, record->psi->buf);
 
-       if (record->reason == KMSG_DUMP_OOPS)
-               efivar_run_worker();
+       if (record->reason == KMSG_DUMP_OOPS && try_module_get(THIS_MODULE))
+               if (!schedule_work(&efivar_work))
+                       module_put(THIS_MODULE);
 
        return ret;
 };
@@ -314,12 +320,12 @@ static int efi_pstore_erase_name(const char *name)
        if (efivar_entry_iter_begin())
                return -EINTR;
 
-       found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list,
+       found = __efivar_entry_iter(efi_pstore_erase_func, &efi_pstore_list,
                                    efi_name, &entry);
        efivar_entry_iter_end();
 
        if (found && !entry->scanning)
-               efivar_unregister(entry);
+               kfree(entry);
 
        return found ? 0 : -ENOENT;
 }
@@ -354,14 +360,77 @@ static struct pstore_info efi_pstore_info = {
        .erase          = efi_pstore_erase,
 };
 
+static int efi_pstore_callback(efi_char16_t *name, efi_guid_t vendor,
+                              unsigned long name_size, void *data)
+{
+       struct efivar_entry *entry;
+       int ret;
+
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       memcpy(entry->var.VariableName, name, name_size);
+       entry->var.VendorGuid = vendor;
+
+       ret = efivar_entry_add(entry, &efi_pstore_list);
+       if (ret)
+               kfree(entry);
+
+       return ret;
+}
+
+static int efi_pstore_update_entry(efi_char16_t *name, efi_guid_t vendor,
+                                  unsigned long name_size, void *data)
+{
+       struct efivar_entry *entry = data;
+
+       if (efivar_entry_find(name, vendor, &efi_pstore_list, false))
+               return 0;
+
+       memcpy(entry->var.VariableName, name, name_size);
+       memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
+
+       return 1;
+}
+
+static void efi_pstore_update_entries(struct work_struct *work)
+{
+       struct efivar_entry *entry;
+       int err;
+
+       /* Add new sysfs entries */
+       while (1) {
+               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+               if (!entry)
+                       return;
+
+               err = efivar_init(efi_pstore_update_entry, entry,
+                                 false, &efi_pstore_list);
+               if (!err)
+                       break;
+
+               efivar_entry_add(entry, &efi_pstore_list);
+       }
+
+       kfree(entry);
+       module_put(THIS_MODULE);
+}
+
 static __init int efivars_pstore_init(void)
 {
+       int ret;
+
        if (!efivars_kobject() || !efivar_supports_writes())
                return 0;
 
        if (efivars_pstore_disable)
                return 0;
 
+       ret = efivar_init(efi_pstore_callback, NULL, true, &efi_pstore_list);
+       if (ret)
+               return ret;
+
        efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
        if (!efi_pstore_info.buf)
                return -ENOMEM;
@@ -374,6 +443,8 @@ static __init int efivars_pstore_init(void)
                efi_pstore_info.bufsize = 0;
        }
 
+       INIT_WORK(&efivar_work, efi_pstore_update_entries);
+
        return 0;
 }
 
index 3aa07c3..5e5480a 100644 (file)
@@ -43,6 +43,9 @@ struct efi __read_mostly efi = {
        .esrt                   = EFI_INVALID_TABLE_ADDR,
        .tpm_log                = EFI_INVALID_TABLE_ADDR,
        .tpm_final_log          = EFI_INVALID_TABLE_ADDR,
+#ifdef CONFIG_LOAD_UEFI_KEYS
+       .mokvar_table           = EFI_INVALID_TABLE_ADDR,
+#endif
 };
 EXPORT_SYMBOL(efi);
 
@@ -519,6 +522,9 @@ static const efi_config_table_type_t common_tables[] __initconst = {
 #ifdef CONFIG_EFI_RCI2_TABLE
        {DELLEMC_EFI_RCI2_TABLE_GUID,           &rci2_table_phys                        },
 #endif
+#ifdef CONFIG_LOAD_UEFI_KEYS
+       {LINUX_EFI_MOK_VARIABLE_TABLE_GUID,     &efi.mokvar_table,      "MOKvar"        },
+#endif
        {},
 };
 
@@ -714,7 +720,7 @@ void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
                vendor);
 }
 
-static __initdata char memory_type_name[][20] = {
+static __initdata char memory_type_name[][13] = {
        "Reserved",
        "Loader Code",
        "Loader Data",
@@ -722,14 +728,14 @@ static __initdata char memory_type_name[][20] = {
        "Boot Data",
        "Runtime Code",
        "Runtime Data",
-       "Conventional Memory",
-       "Unusable Memory",
-       "ACPI Reclaim Memory",
-       "ACPI Memory NVS",
-       "Memory Mapped I/O",
-       "MMIO Port Space",
+       "Conventional",
+       "Unusable",
+       "ACPI Reclaim",
+       "ACPI Mem NVS",
+       "MMIO",
+       "MMIO Port",
        "PAL Code",
-       "Persistent Memory",
+       "Persistent",
 };
 
 char * __init efi_md_typeattr_format(char *buf, size_t size,
@@ -756,26 +762,27 @@ char * __init efi_md_typeattr_format(char *buf, size_t size,
        if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
                     EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
                     EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
-                    EFI_MEMORY_NV | EFI_MEMORY_SP |
+                    EFI_MEMORY_NV | EFI_MEMORY_SP | EFI_MEMORY_CPU_CRYPTO |
                     EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
                snprintf(pos, size, "|attr=0x%016llx]",
                         (unsigned long long)attr);
        else
                snprintf(pos, size,
-                        "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
-                        attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
-                        attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
-                        attr & EFI_MEMORY_SP      ? "SP"  : "",
-                        attr & EFI_MEMORY_NV      ? "NV"  : "",
-                        attr & EFI_MEMORY_XP      ? "XP"  : "",
-                        attr & EFI_MEMORY_RP      ? "RP"  : "",
-                        attr & EFI_MEMORY_WP      ? "WP"  : "",
-                        attr & EFI_MEMORY_RO      ? "RO"  : "",
-                        attr & EFI_MEMORY_UCE     ? "UCE" : "",
-                        attr & EFI_MEMORY_WB      ? "WB"  : "",
-                        attr & EFI_MEMORY_WT      ? "WT"  : "",
-                        attr & EFI_MEMORY_WC      ? "WC"  : "",
-                        attr & EFI_MEMORY_UC      ? "UC"  : "");
+                        "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
+                        attr & EFI_MEMORY_RUNTIME              ? "RUN" : "",
+                        attr & EFI_MEMORY_MORE_RELIABLE        ? "MR"  : "",
+                        attr & EFI_MEMORY_CPU_CRYPTO           ? "CC"  : "",
+                        attr & EFI_MEMORY_SP                   ? "SP"  : "",
+                        attr & EFI_MEMORY_NV                   ? "NV"  : "",
+                        attr & EFI_MEMORY_XP                   ? "XP"  : "",
+                        attr & EFI_MEMORY_RP                   ? "RP"  : "",
+                        attr & EFI_MEMORY_WP                   ? "WP"  : "",
+                        attr & EFI_MEMORY_RO                   ? "RO"  : "",
+                        attr & EFI_MEMORY_UCE                  ? "UCE" : "",
+                        attr & EFI_MEMORY_WB                   ? "WB"  : "",
+                        attr & EFI_MEMORY_WT                   ? "WT"  : "",
+                        attr & EFI_MEMORY_WC                   ? "WC"  : "",
+                        attr & EFI_MEMORY_UC                   ? "UC"  : "");
        return buf;
 }
 
index 35dccc8..15a4753 100644 (file)
@@ -84,7 +84,7 @@ static int __init efibc_init(void)
 {
        int ret;
 
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efivars_kobject() || !efivar_supports_writes())
                return -ENODEV;
 
        ret = register_reboot_notifier(&efibc_reboot_notifier);
index dcea137..e6b16b3 100644 (file)
@@ -22,10 +22,8 @@ MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
 MODULE_DESCRIPTION("sysfs interface to EFI Variables");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(EFIVARS_VERSION);
-MODULE_ALIAS("platform:efivars");
 
-LIST_HEAD(efivar_sysfs_list);
-EXPORT_SYMBOL_GPL(efivar_sysfs_list);
+static LIST_HEAD(efivar_sysfs_list);
 
 static struct kset *efivars_kset;
 
@@ -591,42 +589,6 @@ out_free:
        return error;
 }
 
-static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor,
-                                    unsigned long name_size, void *data)
-{
-       struct efivar_entry *entry = data;
-
-       if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false))
-               return 0;
-
-       memcpy(entry->var.VariableName, name, name_size);
-       memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
-
-       return 1;
-}
-
-static void efivar_update_sysfs_entries(struct work_struct *work)
-{
-       struct efivar_entry *entry;
-       int err;
-
-       /* Add new sysfs entries */
-       while (1) {
-               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-               if (!entry)
-                       return;
-
-               err = efivar_init(efivar_update_sysfs_entry, entry,
-                                 false, &efivar_sysfs_list);
-               if (!err)
-                       break;
-
-               efivar_create_sysfs_entry(entry);
-       }
-
-       kfree(entry);
-}
-
 static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor,
                                  unsigned long name_size, void *data)
 {
@@ -675,7 +637,7 @@ static void efivars_sysfs_exit(void)
        kset_unregister(efivars_kset);
 }
 
-int efivars_sysfs_init(void)
+static int efivars_sysfs_init(void)
 {
        struct kobject *parent_kobj = efivars_kobject();
        int error = 0;
@@ -701,11 +663,8 @@ int efivars_sysfs_init(void)
                return error;
        }
 
-       INIT_WORK(&efivar_work, efivar_update_sysfs_entries);
-
        return 0;
 }
-EXPORT_SYMBOL_GPL(efivars_sysfs_init);
 
 module_init(efivars_sysfs_init);
 module_exit(efivars_sysfs_exit);
index e97a9c9..21ae0c4 100644 (file)
@@ -16,9 +16,9 @@
 
 /* Exported for use by lib/test_firmware.c only */
 LIST_HEAD(efi_embedded_fw_list);
-EXPORT_SYMBOL_GPL(efi_embedded_fw_list);
-
-static bool checked_for_fw;
+EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_list, TEST_FIRMWARE);
+bool efi_embedded_fw_checked;
+EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_checked, TEST_FIRMWARE);
 
 static const struct dmi_system_id * const embedded_fw_table[] = {
 #ifdef CONFIG_TOUCHSCREEN_DMI
@@ -116,14 +116,14 @@ void __init efi_check_for_embedded_firmwares(void)
                }
        }
 
-       checked_for_fw = true;
+       efi_embedded_fw_checked = true;
 }
 
 int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size)
 {
        struct efi_embedded_fw *iter, *fw = NULL;
 
-       if (!checked_for_fw) {
+       if (!efi_embedded_fw_checked) {
                pr_warn("Warning %s called while we did not check for embedded fw\n",
                        __func__);
                return -ENOENT;
index 296b18f..039a9ac 100644 (file)
@@ -18,7 +18,8 @@ cflags-$(CONFIG_X86)          += -m$(BITS) -D__KERNEL__ \
 # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly
 # disable the stackleak plugin
 cflags-$(CONFIG_ARM64)         := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
-                                  -fpie $(DISABLE_STACKLEAK_PLUGIN)
+                                  -fpie $(DISABLE_STACKLEAK_PLUGIN) \
+                                  $(call cc-option,-mbranch-protection=none)
 cflags-$(CONFIG_ARM)           := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
                                   -fno-builtin -fpic \
                                   $(call cc-option,-mno-single-pic-base)
@@ -26,7 +27,7 @@ cflags-$(CONFIG_ARM)          := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
 cflags-$(CONFIG_EFI_GENERIC_STUB) += -I$(srctree)/scripts/dtc/libfdt
 
 KBUILD_CFLAGS                  := $(cflags-y) -Os -DDISABLE_BRANCH_PROFILING \
-                                  -include $(srctree)/drivers/firmware/efi/libstub/hidden.h \
+                                  -include $(srctree)/include/linux/hidden.h \
                                   -D__NO_FORTIFY \
                                   -ffreestanding \
                                   -fno-stack-protector \
@@ -64,7 +65,12 @@ lib-$(CONFIG_ARM)            += arm32-stub.o
 lib-$(CONFIG_ARM64)            += arm64-stub.o
 lib-$(CONFIG_X86)              += x86-stub.o
 CFLAGS_arm32-stub.o            := -DTEXT_OFFSET=$(TEXT_OFFSET)
-CFLAGS_arm64-stub.o            := -DTEXT_OFFSET=$(TEXT_OFFSET)
+
+# Even when -mbranch-protection=none is set, Clang will generate a
+# .note.gnu.property for code-less object files (like lib/ctype.c),
+# so work around this by explicitly removing the unwanted section.
+# https://bugs.llvm.org/show_bug.cgi?id=46480
+STUBCOPY_FLAGS-y               += --remove-section=.note.gnu.property
 
 #
 # For x86, bootloaders like systemd-boot or grub-efi do not zero-initialize the
index d08e5d5..4b5b240 100644 (file)
@@ -113,162 +113,58 @@ void free_screen_info(struct screen_info *si)
        efi_bs_call(free_pool, si);
 }
 
-static efi_status_t reserve_kernel_base(unsigned long dram_base,
-                                       unsigned long *reserve_addr,
-                                       unsigned long *reserve_size)
-{
-       efi_physical_addr_t alloc_addr;
-       efi_memory_desc_t *memory_map;
-       unsigned long nr_pages, map_size, desc_size, buff_size;
-       efi_status_t status;
-       unsigned long l;
-
-       struct efi_boot_memmap map = {
-               .map            = &memory_map,
-               .map_size       = &map_size,
-               .desc_size      = &desc_size,
-               .desc_ver       = NULL,
-               .key_ptr        = NULL,
-               .buff_size      = &buff_size,
-       };
-
-       /*
-        * Reserve memory for the uncompressed kernel image. This is
-        * all that prevents any future allocations from conflicting
-        * with the kernel. Since we can't tell from the compressed
-        * image how much DRAM the kernel actually uses (due to BSS
-        * size uncertainty) we allocate the maximum possible size.
-        * Do this very early, as prints can cause memory allocations
-        * that may conflict with this.
-        */
-       alloc_addr = dram_base + MAX_UNCOMP_KERNEL_SIZE;
-       nr_pages = MAX_UNCOMP_KERNEL_SIZE / EFI_PAGE_SIZE;
-       status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
-                            EFI_BOOT_SERVICES_DATA, nr_pages, &alloc_addr);
-       if (status == EFI_SUCCESS) {
-               if (alloc_addr == dram_base) {
-                       *reserve_addr = alloc_addr;
-                       *reserve_size = MAX_UNCOMP_KERNEL_SIZE;
-                       return EFI_SUCCESS;
-               }
-               /*
-                * If we end up here, the allocation succeeded but starts below
-                * dram_base. This can only occur if the real base of DRAM is
-                * not a multiple of 128 MB, in which case dram_base will have
-                * been rounded up. Since this implies that a part of the region
-                * was already occupied, we need to fall through to the code
-                * below to ensure that the existing allocations don't conflict.
-                * For this reason, we use EFI_BOOT_SERVICES_DATA above and not
-                * EFI_LOADER_DATA, which we wouldn't able to distinguish from
-                * allocations that we want to disallow.
-                */
-       }
-
-       /*
-        * If the allocation above failed, we may still be able to proceed:
-        * if the only allocations in the region are of types that will be
-        * released to the OS after ExitBootServices(), the decompressor can
-        * safely overwrite them.
-        */
-       status = efi_get_memory_map(&map);
-       if (status != EFI_SUCCESS) {
-               efi_err("reserve_kernel_base(): Unable to retrieve memory map.\n");
-               return status;
-       }
-
-       for (l = 0; l < map_size; l += desc_size) {
-               efi_memory_desc_t *desc;
-               u64 start, end;
-
-               desc = (void *)memory_map + l;
-               start = desc->phys_addr;
-               end = start + desc->num_pages * EFI_PAGE_SIZE;
-
-               /* Skip if entry does not intersect with region */
-               if (start >= dram_base + MAX_UNCOMP_KERNEL_SIZE ||
-                   end <= dram_base)
-                       continue;
-
-               switch (desc->type) {
-               case EFI_BOOT_SERVICES_CODE:
-               case EFI_BOOT_SERVICES_DATA:
-                       /* Ignore types that are released to the OS anyway */
-                       continue;
-
-               case EFI_CONVENTIONAL_MEMORY:
-                       /* Skip soft reserved conventional memory */
-                       if (efi_soft_reserve_enabled() &&
-                           (desc->attribute & EFI_MEMORY_SP))
-                               continue;
-
-                       /*
-                        * Reserve the intersection between this entry and the
-                        * region.
-                        */
-                       start = max(start, (u64)dram_base);
-                       end = min(end, (u64)dram_base + MAX_UNCOMP_KERNEL_SIZE);
-
-                       status = efi_bs_call(allocate_pages,
-                                            EFI_ALLOCATE_ADDRESS,
-                                            EFI_LOADER_DATA,
-                                            (end - start) / EFI_PAGE_SIZE,
-                                            &start);
-                       if (status != EFI_SUCCESS) {
-                               efi_err("reserve_kernel_base(): alloc failed.\n");
-                               goto out;
-                       }
-                       break;
-
-               case EFI_LOADER_CODE:
-               case EFI_LOADER_DATA:
-                       /*
-                        * These regions may be released and reallocated for
-                        * another purpose (including EFI_RUNTIME_SERVICE_DATA)
-                        * at any time during the execution of the OS loader,
-                        * so we cannot consider them as safe.
-                        */
-               default:
-                       /*
-                        * Treat any other allocation in the region as unsafe */
-                       status = EFI_OUT_OF_RESOURCES;
-                       goto out;
-               }
-       }
-
-       status = EFI_SUCCESS;
-out:
-       efi_bs_call(free_pool, memory_map);
-       return status;
-}
-
 efi_status_t handle_kernel_image(unsigned long *image_addr,
                                 unsigned long *image_size,
                                 unsigned long *reserve_addr,
                                 unsigned long *reserve_size,
-                                unsigned long dram_base,
                                 efi_loaded_image_t *image)
 {
-       unsigned long kernel_base;
+       const int slack = TEXT_OFFSET - 5 * PAGE_SIZE;
+       int alloc_size = MAX_UNCOMP_KERNEL_SIZE + EFI_PHYS_ALIGN;
+       unsigned long alloc_base, kernel_base;
        efi_status_t status;
 
-       /* use a 16 MiB aligned base for the decompressed kernel */
-       kernel_base = round_up(dram_base, SZ_16M) + TEXT_OFFSET;
-
        /*
-        * Note that some platforms (notably, the Raspberry Pi 2) put
-        * spin-tables and other pieces of firmware at the base of RAM,
-        * abusing the fact that the window of TEXT_OFFSET bytes at the
-        * base of the kernel image is only partially used at the moment.
-        * (Up to 5 pages are used for the swapper page tables)
+        * Allocate space for the decompressed kernel as low as possible.
+        * The region should be 16 MiB aligned, but the first 'slack' bytes
+        * are not used by Linux, so we allow those to be occupied by the
+        * firmware.
         */
-       status = reserve_kernel_base(kernel_base - 5 * PAGE_SIZE, reserve_addr,
-                                    reserve_size);
+       status = efi_low_alloc_above(alloc_size, EFI_PAGE_SIZE, &alloc_base, 0x0);
        if (status != EFI_SUCCESS) {
                efi_err("Unable to allocate memory for uncompressed kernel.\n");
                return status;
        }
 
-       *image_addr = kernel_base;
+       if ((alloc_base % EFI_PHYS_ALIGN) > slack) {
+               /*
+                * More than 'slack' bytes are already occupied at the base of
+                * the allocation, so we need to advance to the next 16 MiB block.
+                */
+               kernel_base = round_up(alloc_base, EFI_PHYS_ALIGN);
+               efi_info("Free memory starts at 0x%lx, setting kernel_base to 0x%lx\n",
+                        alloc_base, kernel_base);
+       } else {
+               kernel_base = round_down(alloc_base, EFI_PHYS_ALIGN);
+       }
+
+       *reserve_addr = kernel_base + slack;
+       *reserve_size = MAX_UNCOMP_KERNEL_SIZE;
+
+       /* now free the parts that we will not use */
+       if (*reserve_addr > alloc_base) {
+               efi_bs_call(free_pages, alloc_base,
+                           (*reserve_addr - alloc_base) / EFI_PAGE_SIZE);
+               alloc_size -= *reserve_addr - alloc_base;
+       }
+       efi_bs_call(free_pages, *reserve_addr + MAX_UNCOMP_KERNEL_SIZE,
+                   (alloc_size - MAX_UNCOMP_KERNEL_SIZE) / EFI_PAGE_SIZE);
+
+       *image_addr = kernel_base + TEXT_OFFSET;
        *image_size = 0;
+
+       efi_debug("image addr == 0x%lx, reserve_addr == 0x%lx\n",
+                 *image_addr, *reserve_addr);
+
        return EFI_SUCCESS;
 }
index e5bfac7..22ece1a 100644 (file)
@@ -50,7 +50,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                                 unsigned long *image_size,
                                 unsigned long *reserve_addr,
                                 unsigned long *reserve_size,
-                                unsigned long dram_base,
                                 efi_loaded_image_t *image)
 {
        efi_status_t status;
@@ -62,10 +61,12 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                        status = efi_get_random_bytes(sizeof(phys_seed),
                                                      (u8 *)&phys_seed);
                        if (status == EFI_NOT_FOUND) {
-                               efi_info("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
+                               efi_info("EFI_RNG_PROTOCOL unavailable, KASLR will be disabled\n");
+                               efi_nokaslr = true;
                        } else if (status != EFI_SUCCESS) {
-                               efi_err("efi_get_random_bytes() failed\n");
-                               return status;
+                               efi_err("efi_get_random_bytes() failed (0x%lx), KASLR will be disabled\n",
+                                       status);
+                               efi_nokaslr = true;
                        }
                } else {
                        efi_info("KASLR disabled on kernel command line\n");
@@ -77,7 +78,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 
        kernel_size = _edata - _text;
        kernel_memsize = kernel_size + (_end - _edata);
-       *reserve_size = kernel_memsize + TEXT_OFFSET % min_kimg_align();
+       *reserve_size = kernel_memsize;
 
        if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
                /*
@@ -91,7 +92,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
        }
 
        if (status != EFI_SUCCESS) {
-               if (IS_ALIGNED((u64)_text - TEXT_OFFSET, min_kimg_align())) {
+               if (IS_ALIGNED((u64)_text, min_kimg_align())) {
                        /*
                         * Just execute from wherever we were loaded by the
                         * UEFI PE/COFF loader if the alignment is suitable.
@@ -111,7 +112,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                }
        }
 
-       *image_addr = *reserve_addr + TEXT_OFFSET % min_kimg_align();
+       *image_addr = *reserve_addr;
        memcpy((void *)*image_addr, _text, kernel_size);
 
        return EFI_SUCCESS;
index f735db5..aa8da0a 100644 (file)
@@ -239,6 +239,102 @@ efi_status_t efi_parse_options(char const *cmdline)
 }
 
 /*
+ * The EFI_LOAD_OPTION descriptor has the following layout:
+ *     u32 Attributes;
+ *     u16 FilePathListLength;
+ *     u16 Description[];
+ *     efi_device_path_protocol_t FilePathList[];
+ *     u8 OptionalData[];
+ *
+ * This function validates and unpacks the variable-size data fields.
+ */
+static
+bool efi_load_option_unpack(efi_load_option_unpacked_t *dest,
+                           const efi_load_option_t *src, size_t size)
+{
+       const void *pos;
+       u16 c;
+       efi_device_path_protocol_t header;
+       const efi_char16_t *description;
+       const efi_device_path_protocol_t *file_path_list;
+
+       if (size < offsetof(efi_load_option_t, variable_data))
+               return false;
+       pos = src->variable_data;
+       size -= offsetof(efi_load_option_t, variable_data);
+
+       if ((src->attributes & ~EFI_LOAD_OPTION_MASK) != 0)
+               return false;
+
+       /* Scan description. */
+       description = pos;
+       do {
+               if (size < sizeof(c))
+                       return false;
+               c = *(const u16 *)pos;
+               pos += sizeof(c);
+               size -= sizeof(c);
+       } while (c != L'\0');
+
+       /* Scan file_path_list. */
+       file_path_list = pos;
+       do {
+               if (size < sizeof(header))
+                       return false;
+               header = *(const efi_device_path_protocol_t *)pos;
+               if (header.length < sizeof(header))
+                       return false;
+               if (size < header.length)
+                       return false;
+               pos += header.length;
+               size -= header.length;
+       } while ((header.type != EFI_DEV_END_PATH && header.type != EFI_DEV_END_PATH2) ||
+                (header.sub_type != EFI_DEV_END_ENTIRE));
+       if (pos != (const void *)file_path_list + src->file_path_list_length)
+               return false;
+
+       dest->attributes = src->attributes;
+       dest->file_path_list_length = src->file_path_list_length;
+       dest->description = description;
+       dest->file_path_list = file_path_list;
+       dest->optional_data_size = size;
+       dest->optional_data = size ? pos : NULL;
+
+       return true;
+}
+
+/*
+ * At least some versions of Dell firmware pass the entire contents of the
+ * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the
+ * OptionalData field.
+ *
+ * Detect this case and extract OptionalData.
+ */
+void efi_apply_loadoptions_quirk(const void **load_options, int *load_options_size)
+{
+       const efi_load_option_t *load_option = *load_options;
+       efi_load_option_unpacked_t load_option_unpacked;
+
+       if (!IS_ENABLED(CONFIG_X86))
+               return;
+       if (!load_option)
+               return;
+       if (*load_options_size < sizeof(*load_option))
+               return;
+       if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0)
+               return;
+
+       if (!efi_load_option_unpack(&load_option_unpacked, load_option, *load_options_size))
+               return;
+
+       efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n");
+       efi_warn_once(FW_BUG "Using OptionalData as a workaround\n");
+
+       *load_options = load_option_unpacked.optional_data;
+       *load_options_size = load_option_unpacked.optional_data_size;
+}
+
+/*
  * Convert the unicode UEFI command line to ASCII to pass to kernel.
  * Size of memory allocated return in *cmd_line_len.
  * Returns NULL on error.
@@ -247,12 +343,15 @@ char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len)
 {
        const u16 *s2;
        unsigned long cmdline_addr = 0;
-       int options_chars = efi_table_attr(image, load_options_size) / 2;
+       int options_chars = efi_table_attr(image, load_options_size);
        const u16 *options = efi_table_attr(image, load_options);
        int options_bytes = 0, safe_options_bytes = 0;  /* UTF-8 bytes */
        bool in_quote = false;
        efi_status_t status;
 
+       efi_apply_loadoptions_quirk((const void **)&options, &options_chars);
+       options_chars /= sizeof(*options);
+
        if (options) {
                s2 = options;
                while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
index a5a405d..311a168 100644 (file)
@@ -87,40 +87,6 @@ static void install_memreserve_table(void)
                efi_err("Failed to install memreserve config table!\n");
 }
 
-static unsigned long get_dram_base(void)
-{
-       efi_status_t status;
-       unsigned long map_size, buff_size;
-       unsigned long membase  = EFI_ERROR;
-       struct efi_memory_map map;
-       efi_memory_desc_t *md;
-       struct efi_boot_memmap boot_map;
-
-       boot_map.map            = (efi_memory_desc_t **)&map.map;
-       boot_map.map_size       = &map_size;
-       boot_map.desc_size      = &map.desc_size;
-       boot_map.desc_ver       = NULL;
-       boot_map.key_ptr        = NULL;
-       boot_map.buff_size      = &buff_size;
-
-       status = efi_get_memory_map(&boot_map);
-       if (status != EFI_SUCCESS)
-               return membase;
-
-       map.map_end = map.map + map_size;
-
-       for_each_efi_memory_desc_in_map(&map, md) {
-               if (md->attribute & EFI_MEMORY_WB) {
-                       if (membase > md->phys_addr)
-                               membase = md->phys_addr;
-               }
-       }
-
-       efi_bs_call(free_pool, map.map);
-
-       return membase;
-}
-
 /*
  * EFI entry point for the arm/arm64 EFI stubs.  This is the entrypoint
  * that is described in the PE/COFF header.  Most of the code is the same
@@ -134,7 +100,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
        efi_status_t status;
        unsigned long image_addr;
        unsigned long image_size = 0;
-       unsigned long dram_base;
        /* addr/point and size pairs for memory management*/
        unsigned long initrd_addr = 0;
        unsigned long initrd_size = 0;
@@ -174,13 +139,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
                goto fail;
        }
 
-       dram_base = get_dram_base();
-       if (dram_base == EFI_ERROR) {
-               efi_err("Failed to find DRAM base\n");
-               status = EFI_LOAD_ERROR;
-               goto fail;
-       }
-
        /*
         * Get the command line from EFI, using the LOADED_IMAGE
         * protocol. We are going to copy the command line into the
@@ -218,7 +176,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
        status = handle_kernel_image(&image_addr, &image_size,
                                     &reserve_addr,
                                     &reserve_size,
-                                    dram_base, image);
+                                    image);
        if (status != EFI_SUCCESS) {
                efi_err("Failed to relocate kernel\n");
                goto fail_free_screeninfo;
@@ -262,7 +220,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
                efi_info("Generating empty DTB\n");
 
        if (!efi_noinitrd) {
-               max_addr = efi_get_max_initrd_addr(dram_base, image_addr);
+               max_addr = efi_get_max_initrd_addr(image_addr);
                status = efi_load_initrd(image, &initrd_addr, &initrd_size,
                                         ULONG_MAX, max_addr);
                if (status != EFI_SUCCESS)
@@ -306,7 +264,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
        install_memreserve_table();
 
        status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr,
-                                               efi_get_max_fdt_addr(dram_base),
+                                               efi_get_max_fdt_addr(image_addr),
                                                initrd_addr, initrd_size,
                                                cmdline_ptr, fdt_addr, fdt_size);
        if (status != EFI_SUCCESS)
index 85050f5..2d7abcd 100644 (file)
@@ -10,9 +10,6 @@
 #include <linux/types.h>
 #include <asm/efi.h>
 
-/* error code which can't be mistaken for valid address */
-#define EFI_ERROR      (~0UL)
-
 /*
  * __init annotations should not be used in the EFI stub, since the code is
  * either included in the decompressor (x86, ARM) where they have no effect,
@@ -55,11 +52,34 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
 
 #define efi_info(fmt, ...) \
        efi_printk(KERN_INFO fmt, ##__VA_ARGS__)
+#define efi_warn(fmt, ...) \
+       efi_printk(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
 #define efi_err(fmt, ...) \
        efi_printk(KERN_ERR "ERROR: " fmt, ##__VA_ARGS__)
 #define efi_debug(fmt, ...) \
        efi_printk(KERN_DEBUG "DEBUG: " fmt, ##__VA_ARGS__)
 
+#define efi_printk_once(fmt, ...)              \
+({                                             \
+       static bool __print_once;               \
+       bool __ret_print_once = !__print_once;  \
+                                               \
+       if (!__print_once) {                    \
+               __print_once = true;            \
+               efi_printk(fmt, ##__VA_ARGS__); \
+       }                                       \
+       __ret_print_once;                       \
+})
+
+#define efi_info_once(fmt, ...) \
+       efi_printk_once(KERN_INFO fmt, ##__VA_ARGS__)
+#define efi_warn_once(fmt, ...) \
+       efi_printk_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
+#define efi_err_once(fmt, ...) \
+       efi_printk_once(KERN_ERR "ERROR: " fmt, ##__VA_ARGS__)
+#define efi_debug_once(fmt, ...) \
+       efi_printk_once(KERN_DEBUG "DEBUG: " fmt, ##__VA_ARGS__)
+
 /* Helper macros for the usual case of using simple C variables: */
 #ifndef fdt_setprop_inplace_var
 #define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
@@ -688,6 +708,35 @@ union efi_load_file_protocol {
        } mixed_mode;
 };
 
+typedef struct {
+       u32 attributes;
+       u16 file_path_list_length;
+       u8 variable_data[];
+       // efi_char16_t description[];
+       // efi_device_path_protocol_t file_path_list[];
+       // u8 optional_data[];
+} __packed efi_load_option_t;
+
+#define EFI_LOAD_OPTION_ACTIVE         0x0001U
+#define EFI_LOAD_OPTION_FORCE_RECONNECT        0x0002U
+#define EFI_LOAD_OPTION_HIDDEN         0x0008U
+#define EFI_LOAD_OPTION_CATEGORY       0x1f00U
+#define   EFI_LOAD_OPTION_CATEGORY_BOOT        0x0000U
+#define   EFI_LOAD_OPTION_CATEGORY_APP 0x0100U
+
+#define EFI_LOAD_OPTION_BOOT_MASK \
+       (EFI_LOAD_OPTION_ACTIVE|EFI_LOAD_OPTION_HIDDEN|EFI_LOAD_OPTION_CATEGORY)
+#define EFI_LOAD_OPTION_MASK (EFI_LOAD_OPTION_FORCE_RECONNECT|EFI_LOAD_OPTION_BOOT_MASK)
+
+typedef struct {
+       u32 attributes;
+       u16 file_path_list_length;
+       const efi_char16_t *description;
+       const efi_device_path_protocol_t *file_path_list;
+       size_t optional_data_size;
+       const void *optional_data;
+} efi_load_option_unpacked_t;
+
 void efi_pci_disable_bridge_busmaster(void);
 
 typedef efi_status_t (*efi_exit_boot_map_processing)(
@@ -730,6 +779,8 @@ __printf(1, 2) int efi_printk(char const *fmt, ...);
 
 void efi_free(unsigned long size, unsigned long addr);
 
+void efi_apply_loadoptions_quirk(const void **load_options, int *load_options_size);
+
 char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len);
 
 efi_status_t efi_get_memory_map(struct efi_boot_memmap *map);
@@ -740,6 +791,9 @@ efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
 efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
                                        unsigned long max, unsigned long align);
 
+efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
+                                unsigned long *addr, unsigned long min);
+
 efi_status_t efi_relocate_kernel(unsigned long *image_addr,
                                 unsigned long image_size,
                                 unsigned long alloc_size,
@@ -786,7 +840,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                                 unsigned long *image_size,
                                 unsigned long *reserve_addr,
                                 unsigned long *reserve_size,
-                                unsigned long dram_base,
                                 efi_loaded_image_t *image);
 
 asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
index 11ecf3c..368cd60 100644 (file)
@@ -136,7 +136,7 @@ static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
        if (status)
                goto fdt_set_fail;
 
-       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
+       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && !efi_nokaslr) {
                efi_status_t efi_status;
 
                efi_status = efi_get_random_bytes(sizeof(fdt_val64),
@@ -145,8 +145,6 @@ static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
                        status = fdt_setprop_var(fdt, node, "kaslr-seed", fdt_val64);
                        if (status)
                                goto fdt_set_fail;
-               } else if (efi_status != EFI_NOT_FOUND) {
-                       return efi_status;
                }
        }
 
index 630caa6..4e81c60 100644 (file)
@@ -136,7 +136,7 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
                                  unsigned long *load_size)
 {
        const efi_char16_t *cmdline = image->load_options;
-       int cmdline_len = image->load_options_size / 2;
+       int cmdline_len = image->load_options_size;
        unsigned long efi_chunk_size = ULONG_MAX;
        efi_file_protocol_t *volume = NULL;
        efi_file_protocol_t *file;
@@ -148,6 +148,9 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
        if (!load_addr || !load_size)
                return EFI_INVALID_PARAMETER;
 
+       efi_apply_loadoptions_quirk((const void **)&cmdline, &cmdline_len);
+       cmdline_len /= sizeof(*cmdline);
+
        if (IS_ENABLED(CONFIG_X86) && !efi_nochunk)
                efi_chunk_size = EFI_READ_CHUNK_SIZE;
 
diff --git a/drivers/firmware/efi/libstub/hidden.h b/drivers/firmware/efi/libstub/hidden.h
deleted file mode 100644 (file)
index 3493b04..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * To prevent the compiler from emitting GOT-indirected (and thus absolute)
- * references to any global symbols, override their visibility as 'hidden'
- */
-#pragma GCC visibility push(hidden)
index 9b1aaf8..8ee9eb2 100644 (file)
@@ -20,8 +20,8 @@
  *
  * Return:     status code
  */
-static efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
-                                       unsigned long *addr, unsigned long min)
+efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
+                                unsigned long *addr, unsigned long min)
 {
        unsigned long map_size, desc_size, buff_size;
        efi_memory_desc_t *map;
index 1ac2f87..5d13e43 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/ctype.h>
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/string.h>
 
index e65ef49..1088e28 100644 (file)
@@ -135,7 +135,7 @@ char *number(char *end, unsigned long long num, int base, char locase)
                break;
        default:
                unreachable();
-       };
+       }
 
        return end;
 }
diff --git a/drivers/firmware/efi/mokvar-table.c b/drivers/firmware/efi/mokvar-table.c
new file mode 100644 (file)
index 0000000..d8bc013
--- /dev/null
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mokvar-table.c
+ *
+ * Copyright (c) 2020 Red Hat
+ * Author: Lenny Szubowicz <lszubowi@redhat.com>
+ *
+ * This module contains the kernel support for the Linux EFI Machine
+ * Owner Key (MOK) variable configuration table, which is identified by
+ * the LINUX_EFI_MOK_VARIABLE_TABLE_GUID.
+ *
+ * This EFI configuration table provides a more robust alternative to
+ * EFI volatile variables by which an EFI boot loader can pass the
+ * contents of the Machine Owner Key (MOK) certificate stores to the
+ * kernel during boot. If both the EFI MOK config table and corresponding
+ * EFI MOK variables are present, the table should be considered as
+ * more authoritative.
+ *
+ * This module includes code that validates and maps the EFI MOK table,
+ * if it's presence was detected very early in boot.
+ *
+ * Kernel interface routines are provided to walk through all the
+ * entries in the MOK config table or to search for a specific named
+ * entry.
+ *
+ * The contents of the individual named MOK config table entries are
+ * made available to user space via read-only sysfs binary files under:
+ *
+ * /sys/firmware/efi/mok-variables/
+ *
+ */
+#define pr_fmt(fmt) "mokvar: " fmt
+
+#include <linux/capability.h>
+#include <linux/efi.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include <asm/early_ioremap.h>
+
+/*
+ * The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table is a packed
+ * sequence of struct efi_mokvar_table_entry, one for each named
+ * MOK variable. The sequence is terminated by an entry with a
+ * completely NULL name and 0 data size.
+ *
+ * efi_mokvar_table_size is set to the computed size of the
+ * MOK config table by efi_mokvar_table_init(). This will be
+ * non-zero if and only if the table if present and has been
+ * validated by efi_mokvar_table_init().
+ */
+static size_t efi_mokvar_table_size;
+
+/*
+ * efi_mokvar_table_va is the kernel virtual address at which the
+ * EFI MOK config table has been mapped by efi_mokvar_sysfs_init().
+ */
+static struct efi_mokvar_table_entry *efi_mokvar_table_va;
+
+/*
+ * Each /sys/firmware/efi/mok-variables/ sysfs file is represented by
+ * an instance of struct efi_mokvar_sysfs_attr on efi_mokvar_sysfs_list.
+ * bin_attr.private points to the associated EFI MOK config table entry.
+ *
+ * This list is created during boot and then remains unchanged.
+ * So no synchronization is currently required to walk the list.
+ */
+struct efi_mokvar_sysfs_attr {
+       struct bin_attribute bin_attr;
+       struct list_head node;
+};
+
+static LIST_HEAD(efi_mokvar_sysfs_list);
+static struct kobject *mokvar_kobj;
+
+/*
+ * efi_mokvar_table_init() - Early boot validation of EFI MOK config table
+ *
+ * If present, validate and compute the size of the EFI MOK variable
+ * configuration table. This table may be provided by an EFI boot loader
+ * as an alternative to ordinary EFI variables, due to platform-dependent
+ * limitations. The memory occupied by this table is marked as reserved.
+ *
+ * This routine must be called before efi_free_boot_services() in order
+ * to guarantee that it can mark the table as reserved.
+ *
+ * Implicit inputs:
+ * efi.mokvar_table:   Physical address of EFI MOK variable config table
+ *                     or special value that indicates no such table.
+ *
+ * Implicit outputs:
+ * efi_mokvar_table_size: Computed size of EFI MOK variable config table.
+ *                     The table is considered present and valid if this
+ *                     is non-zero.
+ */
+void __init efi_mokvar_table_init(void)
+{
+       efi_memory_desc_t md;
+       void *va = NULL;
+       unsigned long cur_offset = 0;
+       unsigned long offset_limit;
+       unsigned long map_size = 0;
+       unsigned long map_size_needed = 0;
+       unsigned long size;
+       struct efi_mokvar_table_entry *mokvar_entry;
+       int err;
+
+       if (!efi_enabled(EFI_MEMMAP))
+               return;
+
+       if (efi.mokvar_table == EFI_INVALID_TABLE_ADDR)
+               return;
+       /*
+        * The EFI MOK config table must fit within a single EFI memory
+        * descriptor range.
+        */
+       err = efi_mem_desc_lookup(efi.mokvar_table, &md);
+       if (err) {
+               pr_warn("EFI MOKvar config table is not within the EFI memory map\n");
+               return;
+       }
+
+       offset_limit = efi_mem_desc_end(&md) - efi.mokvar_table;
+
+       /*
+        * Validate the MOK config table. Since there is no table header
+        * from which we could get the total size of the MOK config table,
+        * we compute the total size as we validate each variably sized
+        * entry, remapping as necessary.
+        */
+       err = -EINVAL;
+       while (cur_offset + sizeof(*mokvar_entry) <= offset_limit) {
+               mokvar_entry = va + cur_offset;
+               map_size_needed = cur_offset + sizeof(*mokvar_entry);
+               if (map_size_needed > map_size) {
+                       if (va)
+                               early_memunmap(va, map_size);
+                       /*
+                        * Map a little more than the fixed size entry
+                        * header, anticipating some data. It's safe to
+                        * do so as long as we stay within current memory
+                        * descriptor.
+                        */
+                       map_size = min(map_size_needed + 2*EFI_PAGE_SIZE,
+                                      offset_limit);
+                       va = early_memremap(efi.mokvar_table, map_size);
+                       if (!va) {
+                               pr_err("Failed to map EFI MOKvar config table pa=0x%lx, size=%lu.\n",
+                                      efi.mokvar_table, map_size);
+                               return;
+                       }
+                       mokvar_entry = va + cur_offset;
+               }
+
+               /* Check for last sentinel entry */
+               if (mokvar_entry->name[0] == '\0') {
+                       if (mokvar_entry->data_size != 0)
+                               break;
+                       err = 0;
+                       break;
+               }
+
+               /* Sanity check that the name is null terminated */
+               size = strnlen(mokvar_entry->name,
+                              sizeof(mokvar_entry->name));
+               if (size >= sizeof(mokvar_entry->name))
+                       break;
+
+               /* Advance to the next entry */
+               cur_offset = map_size_needed + mokvar_entry->data_size;
+       }
+
+       if (va)
+               early_memunmap(va, map_size);
+       if (err) {
+               pr_err("EFI MOKvar config table is not valid\n");
+               return;
+       }
+       efi_mem_reserve(efi.mokvar_table, map_size_needed);
+       efi_mokvar_table_size = map_size_needed;
+}
+
+/*
+ * efi_mokvar_entry_next() - Get next entry in the EFI MOK config table
+ *
+ * mokvar_entry:       Pointer to current EFI MOK config table entry
+ *                     or null. Null indicates get first entry.
+ *                     Passed by reference. This is updated to the
+ *                     same value as the return value.
+ *
+ * Returns:            Pointer to next EFI MOK config table entry
+ *                     or null, if there are no more entries.
+ *                     Same value is returned in the mokvar_entry
+ *                     parameter.
+ *
+ * This routine depends on the EFI MOK config table being entirely
+ * mapped with it's starting virtual address in efi_mokvar_table_va.
+ */
+struct efi_mokvar_table_entry *efi_mokvar_entry_next(
+                       struct efi_mokvar_table_entry **mokvar_entry)
+{
+       struct efi_mokvar_table_entry *mokvar_cur;
+       struct efi_mokvar_table_entry *mokvar_next;
+       size_t size_cur;
+
+       mokvar_cur = *mokvar_entry;
+       *mokvar_entry = NULL;
+
+       if (efi_mokvar_table_va == NULL)
+               return NULL;
+
+       if (mokvar_cur == NULL) {
+               mokvar_next = efi_mokvar_table_va;
+       } else {
+               if (mokvar_cur->name[0] == '\0')
+                       return NULL;
+               size_cur = sizeof(*mokvar_cur) + mokvar_cur->data_size;
+               mokvar_next = (void *)mokvar_cur + size_cur;
+       }
+
+       if (mokvar_next->name[0] == '\0')
+               return NULL;
+
+       *mokvar_entry = mokvar_next;
+       return mokvar_next;
+}
+
+/*
+ * efi_mokvar_entry_find() - Find EFI MOK config entry by name
+ *
+ * name:       Name of the entry to look for.
+ *
+ * Returns:    Pointer to EFI MOK config table entry if found;
+ *             null otherwise.
+ *
+ * This routine depends on the EFI MOK config table being entirely
+ * mapped with it's starting virtual address in efi_mokvar_table_va.
+ */
+struct efi_mokvar_table_entry *efi_mokvar_entry_find(const char *name)
+{
+       struct efi_mokvar_table_entry *mokvar_entry = NULL;
+
+       while (efi_mokvar_entry_next(&mokvar_entry)) {
+               if (!strncmp(name, mokvar_entry->name,
+                            sizeof(mokvar_entry->name)))
+                       return mokvar_entry;
+       }
+       return NULL;
+}
+
+/*
+ * efi_mokvar_sysfs_read() - sysfs binary file read routine
+ *
+ * Returns:    Count of bytes read.
+ *
+ * Copy EFI MOK config table entry data for this mokvar sysfs binary file
+ * to the supplied buffer, starting at the specified offset into mokvar table
+ * entry data, for the specified count bytes. The copy is limited by the
+ * amount of data in this mokvar config table entry.
+ */
+static ssize_t efi_mokvar_sysfs_read(struct file *file, struct kobject *kobj,
+                                struct bin_attribute *bin_attr, char *buf,
+                                loff_t off, size_t count)
+{
+       struct efi_mokvar_table_entry *mokvar_entry = bin_attr->private;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return 0;
+
+       if (off >= mokvar_entry->data_size)
+               return 0;
+       if (count >  mokvar_entry->data_size - off)
+               count = mokvar_entry->data_size - off;
+
+       memcpy(buf, mokvar_entry->data + off, count);
+       return count;
+}
+
+/*
+ * efi_mokvar_sysfs_init() - Map EFI MOK config table and create sysfs
+ *
+ * Map the EFI MOK variable config table for run-time use by the kernel
+ * and create the sysfs entries in /sys/firmware/efi/mok-variables/
+ *
+ * This routine just returns if a valid EFI MOK variable config table
+ * was not found earlier during boot.
+ *
+ * This routine must be called during a "middle" initcall phase, i.e.
+ * after efi_mokvar_table_init() but before UEFI certs are loaded
+ * during late init.
+ *
+ * Implicit inputs:
+ * efi.mokvar_table:   Physical address of EFI MOK variable config table
+ *                     or special value that indicates no such table.
+ *
+ * efi_mokvar_table_size: Computed size of EFI MOK variable config table.
+ *                     The table is considered present and valid if this
+ *                     is non-zero.
+ *
+ * Implicit outputs:
+ * efi_mokvar_table_va:        Start virtual address of the EFI MOK config table.
+ */
+static int __init efi_mokvar_sysfs_init(void)
+{
+       void *config_va;
+       struct efi_mokvar_table_entry *mokvar_entry = NULL;
+       struct efi_mokvar_sysfs_attr *mokvar_sysfs = NULL;
+       int err = 0;
+
+       if (efi_mokvar_table_size == 0)
+               return -ENOENT;
+
+       config_va = memremap(efi.mokvar_table, efi_mokvar_table_size,
+                            MEMREMAP_WB);
+       if (!config_va) {
+               pr_err("Failed to map EFI MOKvar config table\n");
+               return -ENOMEM;
+       }
+       efi_mokvar_table_va = config_va;
+
+       mokvar_kobj = kobject_create_and_add("mok-variables", efi_kobj);
+       if (!mokvar_kobj) {
+               pr_err("Failed to create EFI mok-variables sysfs entry\n");
+               return -ENOMEM;
+       }
+
+       while (efi_mokvar_entry_next(&mokvar_entry)) {
+               mokvar_sysfs = kzalloc(sizeof(*mokvar_sysfs), GFP_KERNEL);
+               if (!mokvar_sysfs) {
+                       err = -ENOMEM;
+                       break;
+               }
+
+               sysfs_bin_attr_init(&mokvar_sysfs->bin_attr);
+               mokvar_sysfs->bin_attr.private = mokvar_entry;
+               mokvar_sysfs->bin_attr.attr.name = mokvar_entry->name;
+               mokvar_sysfs->bin_attr.attr.mode = 0400;
+               mokvar_sysfs->bin_attr.size = mokvar_entry->data_size;
+               mokvar_sysfs->bin_attr.read = efi_mokvar_sysfs_read;
+
+               err = sysfs_create_bin_file(mokvar_kobj,
+                                          &mokvar_sysfs->bin_attr);
+               if (err)
+                       break;
+
+               list_add_tail(&mokvar_sysfs->node, &efi_mokvar_sysfs_list);
+       }
+
+       if (err) {
+               pr_err("Failed to create some EFI mok-variables sysfs entries\n");
+               kfree(mokvar_sysfs);
+       }
+       return err;
+}
+device_initcall(efi_mokvar_sysfs_init);
index 973eef2..41c1d00 100644 (file)
@@ -32,10 +32,6 @@ static struct efivars *__efivars;
  */
 static DEFINE_SEMAPHORE(efivars_lock);
 
-static bool efivar_wq_enabled = true;
-DECLARE_WORK(efivar_work, NULL);
-EXPORT_SYMBOL_GPL(efivar_work);
-
 static bool
 validate_device_path(efi_char16_t *var_name, int match, u8 *buffer,
                     unsigned long len)
@@ -391,13 +387,6 @@ static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
        size_t i, len8 = len16 / sizeof(efi_char16_t);
        char *str8;
 
-       /*
-        * Disable the workqueue since the algorithm it uses for
-        * detecting new variables won't work with this buggy
-        * implementation of GetNextVariableName().
-        */
-       efivar_wq_enabled = false;
-
        str8 = kzalloc(len8, GFP_KERNEL);
        if (!str8)
                return;
@@ -414,7 +403,6 @@ static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
  * efivar_init - build the initial list of EFI variables
  * @func: callback function to invoke for every variable
  * @data: function-specific data to pass to @func
- * @atomic: do we need to execute the @func-loop atomically?
  * @duplicates: error if we encounter duplicates on @head?
  * @head: initialised head of variable list
  *
@@ -1158,16 +1146,6 @@ struct kobject *efivars_kobject(void)
 EXPORT_SYMBOL_GPL(efivars_kobject);
 
 /**
- * efivar_run_worker - schedule the efivar worker thread
- */
-void efivar_run_worker(void)
-{
-       if (efivar_wq_enabled)
-               schedule_work(&efivar_work);
-}
-EXPORT_SYMBOL_GPL(efivar_run_worker);
-
-/**
  * efivars_register - register an efivars
  * @efivars: efivars to register
  * @ops: efivars operations
index a3a6ca6..97968ae 100644 (file)
@@ -15,7 +15,7 @@ config GOOGLE_SMI
        help
          Say Y here if you want to enable SMI callbacks for Google
          platforms.  This provides an interface for writing to and
-         clearing the event log.  If EFI_VARS is also enabled this
+         clearing the event log.  If CONFIG_EFI is also enabled this
          driver provides an interface for reading and writing NVRAM
          variables.
 
index 5b2011e..7d9367b 100644 (file)
@@ -302,7 +302,7 @@ static int gsmi_exec(u8 func, u8 sub)
        return rc;
 }
 
-#ifdef CONFIG_EFI_VARS
+#ifdef CONFIG_EFI
 
 static struct efivars efivars;
 
@@ -483,7 +483,7 @@ static const struct efivar_operations efivar_ops = {
        .get_next_variable = gsmi_get_next_variable,
 };
 
-#endif /* CONFIG_EFI_VARS */
+#endif /* CONFIG_EFI */
 
 static ssize_t eventlog_write(struct file *filp, struct kobject *kobj,
                               struct bin_attribute *bin_attr,
@@ -1007,7 +1007,7 @@ static __init int gsmi_init(void)
                goto out_remove_bin_file;
        }
 
-#ifdef CONFIG_EFI_VARS
+#ifdef CONFIG_EFI
        ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj);
        if (ret) {
                printk(KERN_INFO "gsmi: Failed to register efivars\n");
@@ -1047,7 +1047,7 @@ static void __exit gsmi_exit(void)
        unregister_die_notifier(&gsmi_die_notifier);
        atomic_notifier_chain_unregister(&panic_notifier_list,
                                         &gsmi_panic_notifier);
-#ifdef CONFIG_EFI_VARS
+#ifdef CONFIG_EFI
        efivars_unregister(&efivars);
 #endif
 
index 53cee17..722af9e 100644 (file)
@@ -65,36 +65,18 @@ struct ti_sci_xfers_info {
 };
 
 /**
- * struct ti_sci_rm_type_map - Structure representing TISCI Resource
- *                             management representation of dev_ids.
- * @dev_id:    TISCI device ID
- * @type:      Corresponding id as identified by TISCI RM.
- *
- * Note: This is used only as a work around for using RM range apis
- *     for AM654 SoC. For future SoCs dev_id will be used as type
- *     for RM range APIs. In order to maintain ABI backward compatibility
- *     type is not being changed for AM654 SoC.
- */
-struct ti_sci_rm_type_map {
-       u32 dev_id;
-       u16 type;
-};
-
-/**
  * struct ti_sci_desc - Description of SoC integration
  * @default_host_id:   Host identifier representing the compute entity
  * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
  * @max_msgs: Maximum number of messages that can be pending
  *               simultaneously in the system
  * @max_msg_size: Maximum size of data per message that can be handled.
- * @rm_type_map: RM resource type mapping structure.
  */
 struct ti_sci_desc {
        u8 default_host_id;
        int max_rx_timeout_ms;
        int max_msgs;
        int max_msg_size;
-       struct ti_sci_rm_type_map *rm_type_map;
 };
 
 /**
@@ -1710,33 +1692,6 @@ fail:
        return ret;
 }
 
-static int ti_sci_get_resource_type(struct ti_sci_info *info, u16 dev_id,
-                                   u16 *type)
-{
-       struct ti_sci_rm_type_map *rm_type_map = info->desc->rm_type_map;
-       bool found = false;
-       int i;
-
-       /* If map is not provided then assume dev_id is used as type */
-       if (!rm_type_map) {
-               *type = dev_id;
-               return 0;
-       }
-
-       for (i = 0; rm_type_map[i].dev_id; i++) {
-               if (rm_type_map[i].dev_id == dev_id) {
-                       *type = rm_type_map[i].type;
-                       found = true;
-                       break;
-               }
-       }
-
-       if (!found)
-               return -EINVAL;
-
-       return 0;
-}
-
 /**
  * ti_sci_get_resource_range - Helper to get a range of resources assigned
  *                            to a host. Resource is uniquely identified by
@@ -1760,7 +1715,6 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
        struct ti_sci_xfer *xfer;
        struct ti_sci_info *info;
        struct device *dev;
-       u16 type;
        int ret = 0;
 
        if (IS_ERR(handle))
@@ -1780,15 +1734,9 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
                return ret;
        }
 
-       ret = ti_sci_get_resource_type(info, dev_id, &type);
-       if (ret) {
-               dev_err(dev, "rm type lookup failed for %u\n", dev_id);
-               goto fail;
-       }
-
        req = (struct ti_sci_msg_req_get_resource_range *)xfer->xfer_buf;
        req->secondary_host = s_host;
-       req->type = type & MSG_RM_RESOURCE_TYPE_MASK;
+       req->type = dev_id & MSG_RM_RESOURCE_TYPE_MASK;
        req->subtype = subtype & MSG_RM_RESOURCE_SUBTYPE_MASK;
 
        ret = ti_sci_do_xfer(info, xfer);
@@ -3260,61 +3208,50 @@ u32 ti_sci_get_num_resources(struct ti_sci_resource *res)
 EXPORT_SYMBOL_GPL(ti_sci_get_num_resources);
 
 /**
- * devm_ti_sci_get_of_resource() - Get a TISCI resource assigned to a device
+ * devm_ti_sci_get_resource_sets() - Get a TISCI resources assigned to a device
  * @handle:    TISCI handle
  * @dev:       Device pointer to which the resource is assigned
  * @dev_id:    TISCI device id to which the resource is assigned
- * @of_prop:   property name by which the resource are represented
+ * @sub_types: Array of sub_types assigned corresponding to device
+ * @sets:      Number of sub_types
  *
  * Return: Pointer to ti_sci_resource if all went well else appropriate
  *        error pointer.
  */
-struct ti_sci_resource *
-devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
-                           struct device *dev, u32 dev_id, char *of_prop)
+static struct ti_sci_resource *
+devm_ti_sci_get_resource_sets(const struct ti_sci_handle *handle,
+                             struct device *dev, u32 dev_id, u32 *sub_types,
+                             u32 sets)
 {
        struct ti_sci_resource *res;
        bool valid_set = false;
-       u32 resource_subtype;
        int i, ret;
 
        res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
        if (!res)
                return ERR_PTR(-ENOMEM);
 
-       ret = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
-                                             sizeof(u32));
-       if (ret < 0) {
-               dev_err(dev, "%s resource type ids not available\n", of_prop);
-               return ERR_PTR(ret);
-       }
-       res->sets = ret;
-
+       res->sets = sets;
        res->desc = devm_kcalloc(dev, res->sets, sizeof(*res->desc),
                                 GFP_KERNEL);
        if (!res->desc)
                return ERR_PTR(-ENOMEM);
 
        for (i = 0; i < res->sets; i++) {
-               ret = of_property_read_u32_index(dev_of_node(dev), of_prop, i,
-                                                &resource_subtype);
-               if (ret)
-                       return ERR_PTR(-EINVAL);
-
                ret = handle->ops.rm_core_ops.get_range(handle, dev_id,
-                                                       resource_subtype,
+                                                       sub_types[i],
                                                        &res->desc[i].start,
                                                        &res->desc[i].num);
                if (ret) {
                        dev_dbg(dev, "dev = %d subtype %d not allocated for this host\n",
-                               dev_id, resource_subtype);
+                               dev_id, sub_types[i]);
                        res->desc[i].start = 0;
                        res->desc[i].num = 0;
                        continue;
                }
 
                dev_dbg(dev, "dev = %d, subtype = %d, start = %d, num = %d\n",
-                       dev_id, resource_subtype, res->desc[i].start,
+                       dev_id, sub_types[i], res->desc[i].start,
                        res->desc[i].num);
 
                valid_set = true;
@@ -3332,6 +3269,62 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
        return ERR_PTR(-EINVAL);
 }
 
+/**
+ * devm_ti_sci_get_of_resource() - Get a TISCI resource assigned to a device
+ * @handle:    TISCI handle
+ * @dev:       Device pointer to which the resource is assigned
+ * @dev_id:    TISCI device id to which the resource is assigned
+ * @of_prop:   property name by which the resource are represented
+ *
+ * Return: Pointer to ti_sci_resource if all went well else appropriate
+ *        error pointer.
+ */
+struct ti_sci_resource *
+devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
+                           struct device *dev, u32 dev_id, char *of_prop)
+{
+       struct ti_sci_resource *res;
+       u32 *sub_types;
+       int sets;
+
+       sets = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
+                                              sizeof(u32));
+       if (sets < 0) {
+               dev_err(dev, "%s resource type ids not available\n", of_prop);
+               return ERR_PTR(sets);
+       }
+
+       sub_types = kcalloc(sets, sizeof(*sub_types), GFP_KERNEL);
+       if (!sub_types)
+               return ERR_PTR(-ENOMEM);
+
+       of_property_read_u32_array(dev_of_node(dev), of_prop, sub_types, sets);
+       res = devm_ti_sci_get_resource_sets(handle, dev, dev_id, sub_types,
+                                           sets);
+
+       kfree(sub_types);
+       return res;
+}
+EXPORT_SYMBOL_GPL(devm_ti_sci_get_of_resource);
+
+/**
+ * devm_ti_sci_get_resource() - Get a resource range assigned to the device
+ * @handle:    TISCI handle
+ * @dev:       Device pointer to which the resource is assigned
+ * @dev_id:    TISCI device id to which the resource is assigned
+ * @suub_type: TISCI resource subytpe representing the resource.
+ *
+ * Return: Pointer to ti_sci_resource if all went well else appropriate
+ *        error pointer.
+ */
+struct ti_sci_resource *
+devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev,
+                        u32 dev_id, u32 sub_type)
+{
+       return devm_ti_sci_get_resource_sets(handle, dev, dev_id, &sub_type, 1);
+}
+EXPORT_SYMBOL_GPL(devm_ti_sci_get_resource);
+
 static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
                                void *cmd)
 {
@@ -3352,17 +3345,6 @@ static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
        /* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */
        .max_msgs = 20,
        .max_msg_size = 64,
-       .rm_type_map = NULL,
-};
-
-static struct ti_sci_rm_type_map ti_sci_am654_rm_type_map[] = {
-       {.dev_id = 56, .type = 0x00b}, /* GIC_IRQ */
-       {.dev_id = 179, .type = 0x000}, /* MAIN_NAV_UDMASS_IA0 */
-       {.dev_id = 187, .type = 0x009}, /* MAIN_NAV_RA */
-       {.dev_id = 188, .type = 0x006}, /* MAIN_NAV_UDMAP */
-       {.dev_id = 194, .type = 0x007}, /* MCU_NAV_UDMAP */
-       {.dev_id = 195, .type = 0x00a}, /* MCU_NAV_RA */
-       {.dev_id = 0, .type = 0x000}, /* end of table */
 };
 
 /* Description for AM654 */
@@ -3373,7 +3355,6 @@ static const struct ti_sci_desc ti_sci_pmmc_am654_desc = {
        /* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */
        .max_msgs = 20,
        .max_msg_size = 60,
-       .rm_type_map = ti_sci_am654_rm_type_map,
 };
 
 static const struct of_device_id ti_sci_of_match[] = {
index 4e44ba4..2a21354 100644 (file)
@@ -92,7 +92,7 @@ static int amd_fch_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
        ret = (readl_relaxed(ptr) & AMD_FCH_GPIO_FLAG_DIRECTION);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       return ret ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
+       return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
 }
 
 static void amd_fch_gpio_set(struct gpio_chip *gc,
index d16645c..64e54f8 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/string.h>
 
-#define MAX_NR_SGPIO                   80
+/*
+ * MAX_NR_HW_GPIO represents the number of actual hardware-supported GPIOs (ie,
+ * slots within the clocked serial GPIO data). Since each HW GPIO is both an
+ * input and an output, we provide MAX_NR_HW_GPIO * 2 lines on our gpiochip
+ * device.
+ *
+ * We use SGPIO_OUTPUT_OFFSET to define the split between the inputs and
+ * outputs; the inputs start at line 0, the outputs start at OUTPUT_OFFSET.
+ */
+#define MAX_NR_HW_SGPIO                        80
+#define SGPIO_OUTPUT_OFFSET            MAX_NR_HW_SGPIO
 
 #define ASPEED_SGPIO_CTRL              0x54
 
@@ -30,8 +40,8 @@ struct aspeed_sgpio {
        struct clk *pclk;
        spinlock_t lock;
        void __iomem *base;
-       uint32_t dir_in[3];
        int irq;
+       int n_sgpio;
 };
 
 struct aspeed_sgpio_bank {
@@ -111,31 +121,69 @@ static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
        }
 }
 
-#define GPIO_BANK(x)    ((x) >> 5)
-#define GPIO_OFFSET(x)  ((x) & 0x1f)
+#define GPIO_BANK(x)    ((x % SGPIO_OUTPUT_OFFSET) >> 5)
+#define GPIO_OFFSET(x)  ((x % SGPIO_OUTPUT_OFFSET) & 0x1f)
 #define GPIO_BIT(x)     BIT(GPIO_OFFSET(x))
 
 static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
 {
-       unsigned int bank = GPIO_BANK(offset);
+       unsigned int bank;
+
+       bank = GPIO_BANK(offset);
 
        WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
        return &aspeed_sgpio_banks[bank];
 }
 
+static int aspeed_sgpio_init_valid_mask(struct gpio_chip *gc,
+               unsigned long *valid_mask, unsigned int ngpios)
+{
+       struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
+       int n = sgpio->n_sgpio;
+       int c = SGPIO_OUTPUT_OFFSET - n;
+
+       WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
+
+       /* input GPIOs in the lower range */
+       bitmap_set(valid_mask, 0, n);
+       bitmap_clear(valid_mask, n, c);
+
+       /* output GPIOS above SGPIO_OUTPUT_OFFSET */
+       bitmap_set(valid_mask, SGPIO_OUTPUT_OFFSET, n);
+       bitmap_clear(valid_mask, SGPIO_OUTPUT_OFFSET + n, c);
+
+       return 0;
+}
+
+static void aspeed_sgpio_irq_init_valid_mask(struct gpio_chip *gc,
+               unsigned long *valid_mask, unsigned int ngpios)
+{
+       struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
+       int n = sgpio->n_sgpio;
+
+       WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
+
+       /* input GPIOs in the lower range */
+       bitmap_set(valid_mask, 0, n);
+       bitmap_clear(valid_mask, n, ngpios - n);
+}
+
+static bool aspeed_sgpio_is_input(unsigned int offset)
+{
+       return offset < SGPIO_OUTPUT_OFFSET;
+}
+
 static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
 {
        struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
        const struct aspeed_sgpio_bank *bank = to_bank(offset);
        unsigned long flags;
        enum aspeed_sgpio_reg reg;
-       bool is_input;
        int rc = 0;
 
        spin_lock_irqsave(&gpio->lock, flags);
 
-       is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
-       reg = is_input ? reg_val : reg_rdata;
+       reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata;
        rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
 
        spin_unlock_irqrestore(&gpio->lock, flags);
@@ -143,22 +191,31 @@ static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
        return rc;
 }
 
-static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
+static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
 {
        struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
        const struct aspeed_sgpio_bank *bank = to_bank(offset);
-       void __iomem *addr;
+       void __iomem *addr_r, *addr_w;
        u32 reg = 0;
 
-       addr = bank_reg(gpio, bank, reg_val);
-       reg = ioread32(addr);
+       if (aspeed_sgpio_is_input(offset))
+               return -EINVAL;
+
+       /* Since this is an output, read the cached value from rdata, then
+        * update val. */
+       addr_r = bank_reg(gpio, bank, reg_rdata);
+       addr_w = bank_reg(gpio, bank, reg_val);
+
+       reg = ioread32(addr_r);
 
        if (val)
                reg |= GPIO_BIT(offset);
        else
                reg &= ~GPIO_BIT(offset);
 
-       iowrite32(reg, addr);
+       iowrite32(reg, addr_w);
+
+       return 0;
 }
 
 static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
@@ -175,43 +232,28 @@ static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
 
 static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
 {
-       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&gpio->lock, flags);
-       gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
-       spin_unlock_irqrestore(&gpio->lock, flags);
-
-       return 0;
+       return aspeed_sgpio_is_input(offset) ? 0 : -EINVAL;
 }
 
 static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
 {
        struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
        unsigned long flags;
+       int rc;
 
-       spin_lock_irqsave(&gpio->lock, flags);
-
-       gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
-       sgpio_set_value(gc, offset, val);
+       /* No special action is required for setting the direction; we'll
+        * error-out in sgpio_set_value if this isn't an output GPIO */
 
+       spin_lock_irqsave(&gpio->lock, flags);
+       rc = sgpio_set_value(gc, offset, val);
        spin_unlock_irqrestore(&gpio->lock, flags);
 
-       return 0;
+       return rc;
 }
 
 static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
 {
-       int dir_status;
-       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&gpio->lock, flags);
-       dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
-       spin_unlock_irqrestore(&gpio->lock, flags);
-
-       return dir_status;
-
+       return !!aspeed_sgpio_is_input(offset);
 }
 
 static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
@@ -303,16 +345,16 @@ static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
        switch (type & IRQ_TYPE_SENSE_MASK) {
        case IRQ_TYPE_EDGE_BOTH:
                type2 |= bit;
-               /* fall through */
+               fallthrough;
        case IRQ_TYPE_EDGE_RISING:
                type0 |= bit;
-               /* fall through */
+               fallthrough;
        case IRQ_TYPE_EDGE_FALLING:
                handler = handle_edge_irq;
                break;
        case IRQ_TYPE_LEVEL_HIGH:
                type0 |= bit;
-               /* fall through */
+               fallthrough;
        case IRQ_TYPE_LEVEL_LOW:
                type1 |= bit;
                handler = handle_level_irq;
@@ -402,6 +444,7 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
 
        irq = &gpio->chip.irq;
        irq->chip = &aspeed_sgpio_irqchip;
+       irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask;
        irq->handler = handle_bad_irq;
        irq->default_type = IRQ_TYPE_NONE;
        irq->parent_handler = aspeed_sgpio_irq_handler;
@@ -409,17 +452,15 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
        irq->parents = &gpio->irq;
        irq->num_parents = 1;
 
-       /* set IRQ settings and Enable Interrupt */
+       /* Apply default IRQ settings */
        for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
                bank = &aspeed_sgpio_banks[i];
                /* set falling or level-low irq */
                iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
                /* trigger type is edge */
                iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
-               /* dual edge trigger mode. */
-               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
-               /* enable irq */
-               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
+               /* single edge trigger */
+               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
        }
 
        return 0;
@@ -452,11 +493,12 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
        if (rc < 0) {
                dev_err(&pdev->dev, "Could not read ngpios property\n");
                return -EINVAL;
-       } else if (nr_gpios > MAX_NR_SGPIO) {
+       } else if (nr_gpios > MAX_NR_HW_SGPIO) {
                dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
-                       MAX_NR_SGPIO, nr_gpios);
+                       MAX_NR_HW_SGPIO, nr_gpios);
                return -EINVAL;
        }
+       gpio->n_sgpio = nr_gpios;
 
        rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
        if (rc < 0) {
@@ -497,7 +539,8 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
        spin_lock_init(&gpio->lock);
 
        gpio->chip.parent = &pdev->dev;
-       gpio->chip.ngpio = nr_gpios;
+       gpio->chip.ngpio = MAX_NR_HW_SGPIO * 2;
+       gpio->chip.init_valid_mask = aspeed_sgpio_init_valid_mask;
        gpio->chip.direction_input = aspeed_sgpio_dir_in;
        gpio->chip.direction_output = aspeed_sgpio_dir_out;
        gpio->chip.get_direction = aspeed_sgpio_get_direction;
@@ -509,9 +552,6 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
        gpio->chip.label = dev_name(&pdev->dev);
        gpio->chip.base = -1;
 
-       /* set all SGPIO pins as input (1). */
-       memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
-
        aspeed_sgpio_setup_irqs(gpio, pdev);
 
        rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
index 879db23..e44d5de 100644 (file)
@@ -611,16 +611,16 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type)
        switch (type & IRQ_TYPE_SENSE_MASK) {
        case IRQ_TYPE_EDGE_BOTH:
                type2 |= bit;
-               /* fall through */
+               fallthrough;
        case IRQ_TYPE_EDGE_RISING:
                type0 |= bit;
-               /* fall through */
+               fallthrough;
        case IRQ_TYPE_EDGE_FALLING:
                handler = handle_edge_irq;
                break;
        case IRQ_TYPE_LEVEL_HIGH:
                type0 |= bit;
-               /* fall through */
+               fallthrough;
        case IRQ_TYPE_LEVEL_LOW:
                type1 |= bit;
                handler = handle_level_irq;
@@ -1114,8 +1114,8 @@ static const struct aspeed_gpio_config ast2500_config =
 
 static const struct aspeed_bank_props ast2600_bank_props[] = {
        /*     input      output   */
-       {5, 0xffffffff,  0x0000ffff}, /* U/V/W/X */
-       {6, 0xffff0000,  0x0fff0000}, /* Y/Z */
+       {5, 0xffffffff,  0xffffff00}, /* U/V/W/X */
+       {6, 0x0000ffff,  0x0000ffff}, /* Y/Z */
        { },
 };
 
index 53fae02..d535934 100644 (file)
@@ -129,7 +129,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
 
        case IRQ_TYPE_LEVEL_HIGH:
                polarity |= mask;
-               /* fall through */
+               fallthrough;
        case IRQ_TYPE_LEVEL_LOW:
                type |= mask;
                break;
index 8c97577..ad61daf 100644 (file)
@@ -617,14 +617,12 @@ static int sprd_eic_probe(struct platform_device *pdev)
                sprd_eic->chip.free = sprd_eic_free;
                sprd_eic->chip.set_config = sprd_eic_set_config;
                sprd_eic->chip.set = sprd_eic_set;
-               /* fall-through */
+               fallthrough;
        case SPRD_EIC_ASYNC:
-               /* fall-through */
        case SPRD_EIC_SYNC:
                sprd_eic->chip.get = sprd_eic_get;
                break;
        case SPRD_EIC_LATCH:
-               /* fall-through */
        default:
                break;
        }
index bc34518..1652897 100644 (file)
@@ -552,6 +552,7 @@ static int __init gpio_mockup_init(void)
        err = platform_driver_register(&gpio_mockup_driver);
        if (err) {
                gpio_mockup_err("error registering platform driver\n");
+               debugfs_remove_recursive(gpio_mockup_dbg_dir);
                return err;
        }
 
@@ -582,6 +583,7 @@ static int __init gpio_mockup_init(void)
                        gpio_mockup_err("error registering device");
                        platform_driver_unregister(&gpio_mockup_driver);
                        gpio_mockup_unregister_pdevs();
+                       debugfs_remove_recursive(gpio_mockup_dbg_dir);
                        return PTR_ERR(pdev);
                }
 
index 7fbe0c9..0ea640f 100644 (file)
@@ -1516,7 +1516,7 @@ static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
        return 0;
 }
 
-static int omap_gpio_suspend(struct device *dev)
+static int __maybe_unused omap_gpio_suspend(struct device *dev)
 {
        struct gpio_bank *bank = dev_get_drvdata(dev);
 
@@ -1528,7 +1528,7 @@ static int omap_gpio_suspend(struct device *dev)
        return omap_gpio_runtime_suspend(dev);
 }
 
-static int omap_gpio_resume(struct device *dev)
+static int __maybe_unused omap_gpio_resume(struct device *dev)
 {
        struct gpio_bank *bank = dev_get_drvdata(dev);
 
index bd2e96c..c2d6121 100644 (file)
@@ -818,12 +818,27 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
        int level;
        bool ret;
 
+       bitmap_zero(pending, MAX_LINE);
+
        mutex_lock(&chip->i2c_lock);
        ret = pca953x_irq_pending(chip, pending);
        mutex_unlock(&chip->i2c_lock);
 
-       for_each_set_bit(level, pending, gc->ngpio)
-               handle_nested_irq(irq_find_mapping(gc->irq.domain, level));
+       if (ret) {
+               ret = 0;
+
+               for_each_set_bit(level, pending, gc->ngpio) {
+                       int nested_irq = irq_find_mapping(gc->irq.domain, level);
+
+                       if (unlikely(nested_irq <= 0)) {
+                               dev_warn_ratelimited(gc->parent, "unmapped interrupt %d\n", level);
+                               continue;
+                       }
+
+                       handle_nested_irq(nested_irq);
+                       ret = 1;
+               }
+       }
 
        return IRQ_RETVAL(ret);
 }
@@ -940,6 +955,7 @@ out:
 static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
 {
        DECLARE_BITMAP(val, MAX_LINE);
+       unsigned int i;
        int ret;
 
        ret = device_pca95xx_init(chip, invert);
@@ -947,7 +963,9 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
                goto out;
 
        /* To enable register 6, 7 to control pull up and pull down */
-       memset(val, 0x02, NBANK(chip));
+       for (i = 0; i < NBANK(chip); i++)
+               bitmap_set_value8(val, 0x02, i * BANK_SZ);
+
        ret = pca953x_write_regs(chip, PCA957X_BKEN, val);
        if (ret)
                goto out;
index 26e1fe0..f8c5e9f 100644 (file)
@@ -245,6 +245,7 @@ static int gpio_siox_probe(struct siox_device *sdevice)
        girq->chip = &ddata->ichip;
        girq->default_type = IRQ_TYPE_NONE;
        girq->handler = handle_level_irq;
+       girq->threaded = true;
 
        ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL);
        if (ret)
index d7314d3..36ea8a3 100644 (file)
@@ -149,17 +149,20 @@ static int sprd_gpio_irq_set_type(struct irq_data *data,
                sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
                sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
                sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 1);
+               sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
                irq_set_handler_locked(data, handle_edge_irq);
                break;
        case IRQ_TYPE_EDGE_FALLING:
                sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
                sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
                sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 0);
+               sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
                irq_set_handler_locked(data, handle_edge_irq);
                break;
        case IRQ_TYPE_EDGE_BOTH:
                sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
                sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 1);
+               sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
                irq_set_handler_locked(data, handle_edge_irq);
                break;
        case IRQ_TYPE_LEVEL_HIGH:
index 6c48809..b0155d6 100644 (file)
@@ -308,7 +308,7 @@ static void stmpe_dbg_show_one(struct seq_file *s,
                        if (ret < 0)
                                return;
                        edge_det = !!(ret & mask);
-                       /* fall through */
+                       fallthrough;
                case STMPE1801:
                        rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB + bank];
                        fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB + bank];
@@ -321,7 +321,7 @@ static void stmpe_dbg_show_one(struct seq_file *s,
                        if (ret < 0)
                                return;
                        fall = !!(ret & mask);
-                       /* fall through */
+                       fallthrough;
                case STMPE801:
                case STMPE1600:
                        irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB + bank];
index 58b0da9..ea3f68a 100644 (file)
@@ -212,7 +212,7 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
                                continue;
 
                        tc3589x_gpio->oldregs[i][j] = new;
-                       tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new);
+                       tc3589x_reg_write(tc3589x, regmap[i] + j, new);
                }
        }
 
index 178e912..9500074 100644 (file)
@@ -430,7 +430,18 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int type)
        else
                irq_set_handler_locked(data, handle_edge_irq);
 
-       return irq_chip_set_type_parent(data, type);
+       if (data->parent_data)
+               return irq_chip_set_type_parent(data, type);
+
+       return 0;
+}
+
+static int tegra186_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+       if (data->parent_data)
+               return irq_chip_set_wake_parent(data, on);
+
+       return 0;
 }
 
 static void tegra186_gpio_irq(struct irq_desc *desc)
@@ -678,7 +689,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
        gpio->intc.irq_mask = tegra186_irq_mask;
        gpio->intc.irq_unmask = tegra186_irq_unmask;
        gpio->intc.irq_set_type = tegra186_irq_set_type;
-       gpio->intc.irq_set_wake = irq_chip_set_wake_parent;
+       gpio->intc.irq_set_wake = tegra186_irq_set_wake;
 
        irq = &gpio->gpio.irq;
        irq->chip = &gpio->intc;
index 9276051..54ca3c1 100644 (file)
@@ -1264,7 +1264,7 @@ static int acpi_gpio_package_count(const union acpi_object *obj)
                switch (element->type) {
                case ACPI_TYPE_LOCAL_REFERENCE:
                        element += 3;
-                       /* Fallthrough */
+                       fallthrough;
                case ACPI_TYPE_INTEGER:
                        element++;
                        count++;
index e6c9b78..fed5a3b 100644 (file)
@@ -423,6 +423,21 @@ static __poll_t lineevent_poll(struct file *file,
        return events;
 }
 
+static ssize_t lineevent_get_size(void)
+{
+#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
+       /* i386 has no padding after 'id' */
+       if (in_ia32_syscall()) {
+               struct compat_gpioeevent_data {
+                       compat_u64      timestamp;
+                       u32             id;
+               };
+
+               return sizeof(struct compat_gpioeevent_data);
+       }
+#endif
+       return sizeof(struct gpioevent_data);
+}
 
 static ssize_t lineevent_read(struct file *file,
                              char __user *buf,
@@ -432,9 +447,20 @@ static ssize_t lineevent_read(struct file *file,
        struct lineevent_state *le = file->private_data;
        struct gpioevent_data ge;
        ssize_t bytes_read = 0;
+       ssize_t ge_size;
        int ret;
 
-       if (count < sizeof(ge))
+       /*
+        * When compatible system call is being used the struct gpioevent_data,
+        * in case of at least ia32, has different size due to the alignment
+        * differences. Because we have first member 64 bits followed by one of
+        * 32 bits there is no gap between them. The only difference is the
+        * padding at the end of the data structure. Hence, we calculate the
+        * actual sizeof() and pass this as an argument to copy_to_user() to
+        * drop unneeded bytes from the output.
+        */
+       ge_size = lineevent_get_size();
+       if (count < ge_size)
                return -EINVAL;
 
        do {
@@ -470,10 +496,10 @@ static ssize_t lineevent_read(struct file *file,
                        break;
                }
 
-               if (copy_to_user(buf + bytes_read, &ge, sizeof(ge)))
+               if (copy_to_user(buf + bytes_read, &ge, ge_size))
                        return -EFAULT;
-               bytes_read += sizeof(ge);
-       } while (count >= bytes_read + sizeof(ge));
+               bytes_read += ge_size;
+       } while (count >= bytes_read + ge_size);
 
        return bytes_read;
 }
index ffe149a..dfef5a7 100644 (file)
@@ -207,11 +207,11 @@ uint8_t amdgpu_amdkfd_get_xgmi_hops_count(struct kgd_dev *dst, struct kgd_dev *s
        })
 
 /* GPUVM API */
-int amdgpu_amdkfd_gpuvm_create_process_vm(struct kgd_dev *kgd, unsigned int pasid,
+int amdgpu_amdkfd_gpuvm_create_process_vm(struct kgd_dev *kgd, u32 pasid,
                                        void **vm, void **process_info,
                                        struct dma_fence **ef);
 int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct kgd_dev *kgd,
-                                       struct file *filp, unsigned int pasid,
+                                       struct file *filp, u32 pasid,
                                        void **vm, void **process_info,
                                        struct dma_fence **ef);
 void amdgpu_amdkfd_gpuvm_destroy_cb(struct amdgpu_device *adev,
index bf927f4..ee531c3 100644 (file)
@@ -105,7 +105,7 @@ static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
        unlock_srbm(kgd);
 }
 
-static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
+static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, u32 pasid,
                                        unsigned int vmid)
 {
        struct amdgpu_device *adev = get_amdgpu_device(kgd);
index 7e59e47..cdea133 100644 (file)
@@ -152,7 +152,7 @@ static uint32_t get_sdma_rlc_reg_offset(struct amdgpu_device *adev,
                dev_warn(adev->dev,
                         "Invalid sdma engine id (%d), using engine id 0\n",
                         engine_id);
-               /* fall through */
+               fallthrough;
        case 0:
                sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA0, 0,
                                mmSDMA0_RLC0_RB_CNTL) - mmSDMA0_RLC0_RB_CNTL;
index 744366c..4d41317 100644 (file)
@@ -139,7 +139,7 @@ static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
        unlock_srbm(kgd);
 }
 
-static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
+static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, u32 pasid,
                                        unsigned int vmid)
 {
        struct amdgpu_device *adev = get_amdgpu_device(kgd);
index feab4cc..35917d4 100644 (file)
@@ -96,7 +96,7 @@ static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
        unlock_srbm(kgd);
 }
 
-static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
+static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, u32 pasid,
                                        unsigned int vmid)
 {
        struct amdgpu_device *adev = get_amdgpu_device(kgd);
index 1102de7..1abfe63 100644 (file)
@@ -110,7 +110,7 @@ void kgd_gfx_v9_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
        unlock_srbm(kgd);
 }
 
-int kgd_gfx_v9_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
+int kgd_gfx_v9_set_pasid_vmid_mapping(struct kgd_dev *kgd, u32 pasid,
                                        unsigned int vmid)
 {
        struct amdgpu_device *adev = get_amdgpu_device(kgd);
index aedf67d..ff2bc72 100644 (file)
@@ -26,7 +26,7 @@ void kgd_gfx_v9_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
                uint32_t sh_mem_config,
                uint32_t sh_mem_ape1_base, uint32_t sh_mem_ape1_limit,
                uint32_t sh_mem_bases);
-int kgd_gfx_v9_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
+int kgd_gfx_v9_set_pasid_vmid_mapping(struct kgd_dev *kgd, u32 pasid,
                unsigned int vmid);
 int kgd_gfx_v9_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id);
 int kgd_gfx_v9_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
index a58af51..d02c5c1 100644 (file)
@@ -992,7 +992,7 @@ create_evict_fence_fail:
        return ret;
 }
 
-int amdgpu_amdkfd_gpuvm_create_process_vm(struct kgd_dev *kgd, unsigned int pasid,
+int amdgpu_amdkfd_gpuvm_create_process_vm(struct kgd_dev *kgd, u32 pasid,
                                          void **vm, void **process_info,
                                          struct dma_fence **ef)
 {
@@ -1028,7 +1028,7 @@ amdgpu_vm_init_fail:
 }
 
 int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct kgd_dev *kgd,
-                                          struct file *filp, unsigned int pasid,
+                                          struct file *filp, u32 pasid,
                                           void **vm, void **process_info,
                                           struct dma_fence **ef)
 {
index eb7cfe8..d0b8d0d 100644 (file)
@@ -80,8 +80,6 @@ MODULE_FIRMWARE("amdgpu/renoir_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/navi10_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/navi14_gpu_info.bin");
 MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin");
-MODULE_FIRMWARE("amdgpu/sienna_cichlid_gpu_info.bin");
-MODULE_FIRMWARE("amdgpu/navy_flounder_gpu_info.bin");
 
 #define AMDGPU_RESUME_MS               2000
 
@@ -1600,6 +1598,8 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev)
        case CHIP_CARRIZO:
        case CHIP_STONEY:
        case CHIP_VEGA20:
+       case CHIP_SIENNA_CICHLID:
+       case CHIP_NAVY_FLOUNDER:
        default:
                return 0;
        case CHIP_VEGA10:
@@ -1631,12 +1631,6 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev)
        case CHIP_NAVI12:
                chip_name = "navi12";
                break;
-       case CHIP_SIENNA_CICHLID:
-               chip_name = "sienna_cichlid";
-               break;
-       case CHIP_NAVY_FLOUNDER:
-               chip_name = "navy_flounder";
-               break;
        }
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_gpu_info.bin", chip_name);
index d761729..44c1f6e 100644 (file)
@@ -297,7 +297,7 @@ int amdgpu_display_crtc_set_config(struct drm_mode_set *set,
           take the current one */
        if (active && !adev->have_disp_power_ref) {
                adev->have_disp_power_ref = true;
-               goto out;
+               return ret;
        }
        /* if we have no active crtcs, then drop the power ref
           we got before */
index 26127c7..321032d 100644 (file)
@@ -1044,8 +1044,16 @@ static const struct pci_device_id pciidlist[] = {
        {0x1002, 0x1636, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RENOIR|AMD_IS_APU},
 
        /* Navi12 */
-       {0x1002, 0x7360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI12|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x7362, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI12|AMD_EXP_HW_SUPPORT},
+       {0x1002, 0x7360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI12},
+       {0x1002, 0x7362, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI12},
+
+       /* Sienna_Cichlid */
+       {0x1002, 0x73A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SIENNA_CICHLID},
+       {0x1002, 0x73A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SIENNA_CICHLID},
+       {0x1002, 0x73A3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SIENNA_CICHLID},
+       {0x1002, 0x73AB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SIENNA_CICHLID},
+       {0x1002, 0x73AE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SIENNA_CICHLID},
+       {0x1002, 0x73BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SIENNA_CICHLID},
 
        {0, 0, 0}
 };
index 7521f4a..6e9a9e5 100644 (file)
@@ -43,7 +43,7 @@ static DEFINE_IDA(amdgpu_pasid_ida);
 /* Helper to free pasid from a fence callback */
 struct amdgpu_pasid_cb {
        struct dma_fence_cb cb;
-       unsigned int pasid;
+       u32 pasid;
 };
 
 /**
@@ -79,7 +79,7 @@ int amdgpu_pasid_alloc(unsigned int bits)
  * amdgpu_pasid_free - Free a PASID
  * @pasid: PASID to free
  */
-void amdgpu_pasid_free(unsigned int pasid)
+void amdgpu_pasid_free(u32 pasid)
 {
        trace_amdgpu_pasid_freed(pasid);
        ida_simple_remove(&amdgpu_pasid_ida, pasid);
@@ -105,7 +105,7 @@ static void amdgpu_pasid_free_cb(struct dma_fence *fence,
  * Free the pasid only after all the fences in resv are signaled.
  */
 void amdgpu_pasid_free_delayed(struct dma_resv *resv,
-                              unsigned int pasid)
+                              u32 pasid)
 {
        struct dma_fence *fence, **fences;
        struct amdgpu_pasid_cb *cb;
index 8e58325..0c3b4fa 100644 (file)
@@ -71,9 +71,9 @@ struct amdgpu_vmid_mgr {
 };
 
 int amdgpu_pasid_alloc(unsigned int bits);
-void amdgpu_pasid_free(unsigned int pasid);
+void amdgpu_pasid_free(u32 pasid);
 void amdgpu_pasid_free_delayed(struct dma_resv *resv,
-                              unsigned int pasid);
+                              u32 pasid);
 
 bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
                               struct amdgpu_vmid *id);
index 0047da0..b403b2a 100644 (file)
@@ -179,6 +179,7 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags)
                case CHIP_VEGA20:
                case CHIP_ARCTURUS:
                case CHIP_SIENNA_CICHLID:
+               case CHIP_NAVY_FLOUNDER:
                        /* enable runpm if runpm=1 */
                        if (amdgpu_runtime_pm > 0)
                                adev->runpm = true;
@@ -678,8 +679,12 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                 * in the bitfields */
                if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK)
                        se_num = 0xffffffff;
+               else if (se_num >= AMDGPU_GFX_MAX_SE)
+                       return -EINVAL;
                if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK)
                        sh_num = 0xffffffff;
+               else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE)
+                       return -EINVAL;
 
                if (info->read_mmr_reg.count > 128)
                        return -EINVAL;
@@ -1079,7 +1084,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
        struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
        struct amdgpu_bo_list *list;
        struct amdgpu_bo *pd;
-       unsigned int pasid;
+       u32 pasid;
        int handle;
 
        if (!fpriv)
index 7fe5642..0675768 100644 (file)
@@ -178,7 +178,7 @@ static int psp_sw_init(void *handle)
                return ret;
        }
 
-       if (adev->asic_type == CHIP_NAVI10) {
+       if (adev->asic_type == CHIP_NAVI10 || adev->asic_type == CHIP_SIENNA_CICHLID) {
                ret= psp_sysfs_init(adev);
                if (ret) {
                        return ret;
@@ -522,8 +522,7 @@ static int psp_asd_load(struct psp_context *psp)
         * add workaround to bypass it for sriov now.
         * TODO: add version check to make it common
         */
-       if (amdgpu_sriov_vf(psp->adev) ||
-           (psp->adev->asic_type == CHIP_NAVY_FLOUNDER))
+       if (amdgpu_sriov_vf(psp->adev) || !psp->asd_fw)
                return 0;
 
        cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
index e11c5d6..978bae7 100644 (file)
@@ -1076,6 +1076,7 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)
 
 release_sg:
        kfree(ttm->sg);
+       ttm->sg = NULL;
        return r;
 }
 
index 71e005c..cb1d7cd 100644 (file)
@@ -2785,7 +2785,7 @@ long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout)
  * 0 for success, error for failure.
  */
 int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
-                  int vm_context, unsigned int pasid)
+                  int vm_context, u32 pasid)
 {
        struct amdgpu_bo_param bp;
        struct amdgpu_bo *root;
@@ -2956,7 +2956,7 @@ static int amdgpu_vm_check_clean_reserved(struct amdgpu_device *adev,
  * 0 for success, -errno for errors.
  */
 int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm,
-                          unsigned int pasid)
+                          u32 pasid)
 {
        bool pte_support_ats = (adev->asic_type == CHIP_RAVEN);
        int r;
@@ -3254,7 +3254,7 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
  * @pasid: PASID identifier for VM
  * @task_info: task_info to fill.
  */
-void amdgpu_vm_get_task_info(struct amdgpu_device *adev, unsigned int pasid,
+void amdgpu_vm_get_task_info(struct amdgpu_device *adev, u32 pasid,
                         struct amdgpu_task_info *task_info)
 {
        struct amdgpu_vm *vm;
@@ -3298,7 +3298,7 @@ void amdgpu_vm_set_task_info(struct amdgpu_vm *vm)
  * Try to gracefully handle a VM fault. Return true if the fault was handled and
  * shouldn't be reported any more.
  */
-bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, unsigned int pasid,
+bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
                            uint64_t addr)
 {
        struct amdgpu_bo *root;
index 770025a..ffbc0cc 100644 (file)
@@ -372,8 +372,8 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev);
 
 long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout);
 int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
-                  int vm_context, unsigned int pasid);
-int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm, unsigned int pasid);
+                  int vm_context, u32 pasid);
+int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm, u32 pasid);
 void amdgpu_vm_release_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm);
 void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
 void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
@@ -430,9 +430,9 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring,
                                  struct amdgpu_job *job);
 void amdgpu_vm_check_compute_bug(struct amdgpu_device *adev);
 
-void amdgpu_vm_get_task_info(struct amdgpu_device *adev, unsigned int pasid,
+void amdgpu_vm_get_task_info(struct amdgpu_device *adev, u32 pasid,
                             struct amdgpu_task_info *task_info);
-bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, unsigned int pasid,
+bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
                            uint64_t addr);
 
 void amdgpu_vm_set_task_info(struct amdgpu_vm *vm);
index 65997ff..f73ce97 100644 (file)
@@ -3595,6 +3595,9 @@ static void gfx_v10_0_check_gfxoff_flag(struct amdgpu_device *adev)
                if (!gfx_v10_0_navi10_gfxoff_should_enable(adev))
                        adev->pm.pp_feature &= ~PP_GFXOFF_MASK;
                break;
+       case CHIP_NAVY_FLOUNDER:
+               adev->pm.pp_feature &= ~PP_GFXOFF_MASK;
+               break;
        default:
                break;
        }
@@ -7263,10 +7266,8 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade
                def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
                data &= ~(RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE_MASK |
                          RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGCG_OVERRIDE_MASK |
-                         RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK);
-
-               /* only for Vega10 & Raven1 */
-               data |= RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE_MASK;
+                         RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK |
+                         RLC_CGTT_MGCG_OVERRIDE__ENABLE_CGTS_LEGACY_MASK);
 
                if (def != data)
                        WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data);
index 33f1c4a..88f63d7 100644 (file)
@@ -3250,7 +3250,7 @@ static void gfx_v8_0_tiling_mode_table_init(struct amdgpu_device *adev)
                dev_warn(adev->dev,
                         "Unknown chip type (%d) in function gfx_v8_0_tiling_mode_table_init() falling through to CHIP_CARRIZO\n",
                         adev->asic_type);
-               /* fall through */
+               fallthrough;
 
        case CHIP_CARRIZO:
                modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
index 6e4f3ff..b67ba38 100644 (file)
@@ -1297,7 +1297,7 @@ static void gmc_v9_0_init_golden_registers(struct amdgpu_device *adev)
        case CHIP_VEGA10:
                if (amdgpu_sriov_vf(adev))
                        break;
-               /* fall through */
+               fallthrough;
        case CHIP_VEGA20:
                soc15_program_register_sequence(adev,
                                                golden_settings_mmhub_1_0_0,
index da8024c..ca11253 100644 (file)
@@ -364,6 +364,7 @@ nv_asic_reset_method(struct amdgpu_device *adev)
 
        switch (adev->asic_type) {
        case CHIP_SIENNA_CICHLID:
+       case CHIP_NAVY_FLOUNDER:
                return AMD_RESET_METHOD_MODE1;
        default:
                if (smu_baco_is_support(smu))
index e16874f..6c5d961 100644 (file)
@@ -58,7 +58,7 @@ MODULE_FIRMWARE("amdgpu/arcturus_ta.bin");
 MODULE_FIRMWARE("amdgpu/sienna_cichlid_sos.bin");
 MODULE_FIRMWARE("amdgpu/sienna_cichlid_ta.bin");
 MODULE_FIRMWARE("amdgpu/navy_flounder_sos.bin");
-MODULE_FIRMWARE("amdgpu/navy_flounder_asd.bin");
+MODULE_FIRMWARE("amdgpu/navy_flounder_ta.bin");
 
 /* address block */
 #define smnMP1_FIRMWARE_FLAGS          0x3010024
index ea914b2..b5986d1 100644 (file)
@@ -6196,7 +6196,7 @@ static void si_request_link_speed_change_before_state_change(struct amdgpu_devic
                        si_pi->force_pcie_gen = AMDGPU_PCIE_GEN2;
                        if (current_link_speed == AMDGPU_PCIE_GEN2)
                                break;
-                       /* fall through */
+                       fallthrough;
                case AMDGPU_PCIE_GEN2:
                        if (amdgpu_acpi_pcie_performance_request(adev, PCIE_PERF_REQ_PECI_GEN2, false) == 0)
                                break;
index 84d811b..c28ebf4 100644 (file)
@@ -694,12 +694,12 @@ static void soc15_reg_base_init(struct amdgpu_device *adev)
                 * it doesn't support SRIOV. */
                if (amdgpu_discovery) {
                        r = amdgpu_discovery_reg_base_init(adev);
-                       if (r) {
-                               DRM_WARN("failed to init reg base from ip discovery table, "
-                                        "fallback to legacy init method\n");
-                               vega10_reg_base_init(adev);
-                       }
+                       if (r == 0)
+                               break;
+                       DRM_WARN("failed to init reg base from ip discovery table, "
+                                "fallback to legacy init method\n");
                }
+               vega10_reg_base_init(adev);
                break;
        case CHIP_VEGA20:
                vega20_reg_base_init(adev);
index 63e5547..3a805ea 100644 (file)
@@ -746,18 +746,18 @@ static void vcn_v3_0_disable_clock_gating(struct amdgpu_device *adev, int inst)
                | UVD_SUVD_CGC_GATE__IME_HEVC_MASK
                | UVD_SUVD_CGC_GATE__EFC_MASK
                | UVD_SUVD_CGC_GATE__SAOE_MASK
-               | 0x08000000
+               | UVD_SUVD_CGC_GATE__SRE_AV1_MASK
                | UVD_SUVD_CGC_GATE__FBC_PCLK_MASK
                | UVD_SUVD_CGC_GATE__FBC_CCLK_MASK
-               | 0x40000000
+               | UVD_SUVD_CGC_GATE__SCM_AV1_MASK
                | UVD_SUVD_CGC_GATE__SMPA_MASK);
        WREG32_SOC15(VCN, inst, mmUVD_SUVD_CGC_GATE, data);
 
        data = RREG32_SOC15(VCN, inst, mmUVD_SUVD_CGC_GATE2);
        data |= (UVD_SUVD_CGC_GATE2__MPBE0_MASK
                | UVD_SUVD_CGC_GATE2__MPBE1_MASK
-               | 0x00000004
-               | 0x00000008
+               | UVD_SUVD_CGC_GATE2__SIT_AV1_MASK
+               | UVD_SUVD_CGC_GATE2__SDB_AV1_MASK
                | UVD_SUVD_CGC_GATE2__MPC1_MASK);
        WREG32_SOC15(VCN, inst, mmUVD_SUVD_CGC_GATE2, data);
 
@@ -776,8 +776,8 @@ static void vcn_v3_0_disable_clock_gating(struct amdgpu_device *adev, int inst)
                | UVD_SUVD_CGC_CTRL__SMPA_MODE_MASK
                | UVD_SUVD_CGC_CTRL__MPBE0_MODE_MASK
                | UVD_SUVD_CGC_CTRL__MPBE1_MODE_MASK
-               | 0x00008000
-               | 0x00010000
+               | UVD_SUVD_CGC_CTRL__SIT_AV1_MODE_MASK
+               | UVD_SUVD_CGC_CTRL__SDB_AV1_MODE_MASK
                | UVD_SUVD_CGC_CTRL__MPC1_MODE_MASK
                | UVD_SUVD_CGC_CTRL__FBC_PCLK_MASK
                | UVD_SUVD_CGC_CTRL__FBC_CCLK_MASK);
@@ -892,8 +892,8 @@ static void vcn_v3_0_enable_clock_gating(struct amdgpu_device *adev, int inst)
                | UVD_SUVD_CGC_CTRL__SMPA_MODE_MASK
                | UVD_SUVD_CGC_CTRL__MPBE0_MODE_MASK
                | UVD_SUVD_CGC_CTRL__MPBE1_MODE_MASK
-               | 0x00008000
-               | 0x00010000
+               | UVD_SUVD_CGC_CTRL__SIT_AV1_MODE_MASK
+               | UVD_SUVD_CGC_CTRL__SDB_AV1_MODE_MASK
                | UVD_SUVD_CGC_CTRL__MPC1_MODE_MASK
                | UVD_SUVD_CGC_CTRL__FBC_PCLK_MASK
                | UVD_SUVD_CGC_CTRL__FBC_CCLK_MASK);
index 24b4717..dcb1d89 100644 (file)
@@ -91,7 +91,7 @@ static void cik_event_interrupt_wq(struct kfd_dev *dev,
                        (const struct cik_ih_ring_entry *)ih_ring_entry;
        uint32_t context_id = ihre->data & 0xfffffff;
        unsigned int vmid  = (ihre->ring_id & 0x0000ff00) >> 8;
-       unsigned int pasid = (ihre->ring_id & 0xffff0000) >> 16;
+       u32 pasid = (ihre->ring_id & 0xffff0000) >> 16;
 
        if (pasid == 0)
                return;
index 27bcc5b..b258a3d 100644 (file)
@@ -45,7 +45,7 @@ static void dbgdev_address_watch_disable_nodiq(struct kfd_dev *dev)
 }
 
 static int dbgdev_diq_submit_ib(struct kfd_dbgdev *dbgdev,
-                               unsigned int pasid, uint64_t vmid0_address,
+                               u32 pasid, uint64_t vmid0_address,
                                uint32_t *packet_buff, size_t size_in_bytes)
 {
        struct pm4__release_mem *rm_packet;
index a04a1fe..f9c6df1 100644 (file)
@@ -275,7 +275,7 @@ struct kfd_dbgdev {
 };
 
 struct kfd_dbgmgr {
-       unsigned int pasid;
+       u32 pasid;
        struct kfd_dev *dev;
        struct kfd_dbgdev *dbgdev;
 };
index e0e60b0..a8d3167 100644 (file)
@@ -40,7 +40,7 @@
 #define CIK_HPD_EOP_BYTES (1U << CIK_HPD_EOP_BYTES_LOG2)
 
 static int set_pasid_vmid_mapping(struct device_queue_manager *dqm,
-                                       unsigned int pasid, unsigned int vmid);
+                                 u32 pasid, unsigned int vmid);
 
 static int execute_queues_cpsch(struct device_queue_manager *dqm,
                                enum kfd_unmap_queues_filter filter,
@@ -948,7 +948,7 @@ out:
 }
 
 static int
-set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid,
+set_pasid_vmid_mapping(struct device_queue_manager *dqm, u32 pasid,
                        unsigned int vmid)
 {
        return dqm->dev->kfd2kgd->set_pasid_vmid_mapping(
@@ -1216,6 +1216,8 @@ static int stop_cpsch(struct device_queue_manager *dqm)
        dqm->sched_running = false;
        dqm_unlock(dqm);
 
+       pm_release_ib(&dqm->packets);
+
        kfd_gtt_sa_free(dqm->dev, dqm->fence_mem);
        pm_uninit(&dqm->packets, hanging);
 
@@ -1326,7 +1328,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
        if (q->properties.is_active) {
                increment_queue_count(dqm, q->properties.type);
 
-               retval = execute_queues_cpsch(dqm,
+               execute_queues_cpsch(dqm,
                                KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0);
        }
 
@@ -1979,8 +1981,7 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm)
        kfree(dqm);
 }
 
-int kfd_process_vm_fault(struct device_queue_manager *dqm,
-                        unsigned int pasid)
+int kfd_process_vm_fault(struct device_queue_manager *dqm, u32 pasid)
 {
        struct kfd_process_device *pdd;
        struct kfd_process *p = kfd_lookup_process_by_pasid(pasid);
index a9583b9..ba2c2ce 100644 (file)
@@ -460,7 +460,7 @@ static void set_event_from_interrupt(struct kfd_process *p,
        }
 }
 
-void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id,
+void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id,
                                uint32_t valid_id_bits)
 {
        struct kfd_event *ev = NULL;
@@ -872,7 +872,7 @@ static void lookup_events_by_type_and_signal(struct kfd_process *p,
 }
 
 #ifdef KFD_SUPPORT_IOMMU_V2
-void kfd_signal_iommu_event(struct kfd_dev *dev, unsigned int pasid,
+void kfd_signal_iommu_event(struct kfd_dev *dev, u32 pasid,
                unsigned long address, bool is_write_requested,
                bool is_execute_requested)
 {
@@ -950,7 +950,7 @@ void kfd_signal_iommu_event(struct kfd_dev *dev, unsigned int pasid,
 }
 #endif /* KFD_SUPPORT_IOMMU_V2 */
 
-void kfd_signal_hw_exception_event(unsigned int pasid)
+void kfd_signal_hw_exception_event(u32 pasid)
 {
        /*
         * Because we are called from arbitrary context (workqueue) as opposed
@@ -971,7 +971,7 @@ void kfd_signal_hw_exception_event(unsigned int pasid)
        kfd_unref_process(p);
 }
 
-void kfd_signal_vm_fault_event(struct kfd_dev *dev, unsigned int pasid,
+void kfd_signal_vm_fault_event(struct kfd_dev *dev, u32 pasid,
                                struct kfd_vm_fault_info *info)
 {
        struct kfd_event *ev;
index c7ac6c7..c8fe5db 100644 (file)
@@ -79,7 +79,7 @@ struct kfd_event {
 #define KFD_EVENT_TYPE_DEBUG 5
 #define KFD_EVENT_TYPE_MEMORY 8
 
-extern void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id,
-                                       uint32_t valid_id_bits);
+extern void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id,
+                                      uint32_t valid_id_bits);
 
 #endif
index 7c8786b..e8ef388 100644 (file)
@@ -139,7 +139,7 @@ void kfd_iommu_unbind_process(struct kfd_process *p)
 }
 
 /* Callback for process shutdown invoked by the IOMMU driver */
-static void iommu_pasid_shutdown_callback(struct pci_dev *pdev, int pasid)
+static void iommu_pasid_shutdown_callback(struct pci_dev *pdev, u32 pasid)
 {
        struct kfd_dev *dev = kfd_device_by_pci_dev(pdev);
        struct kfd_process *p;
@@ -185,8 +185,8 @@ static void iommu_pasid_shutdown_callback(struct pci_dev *pdev, int pasid)
 }
 
 /* This function called by IOMMU driver on PPR failure */
-static int iommu_invalid_ppr_cb(struct pci_dev *pdev, int pasid,
-               unsigned long address, u16 flags)
+static int iommu_invalid_ppr_cb(struct pci_dev *pdev, u32 pasid,
+                               unsigned long address, u16 flags)
 {
        struct kfd_dev *dev;
 
index 2a07c4f..af5816f 100644 (file)
@@ -51,7 +51,7 @@ unsigned int kfd_get_pasid_limit(void)
        return 1U << pasid_bits;
 }
 
-unsigned int kfd_pasid_alloc(void)
+u32 kfd_pasid_alloc(void)
 {
        int r = amdgpu_pasid_alloc(pasid_bits);
 
@@ -63,7 +63,7 @@ unsigned int kfd_pasid_alloc(void)
        return 0;
 }
 
-void kfd_pasid_free(unsigned int pasid)
+void kfd_pasid_free(u32 pasid)
 {
        amdgpu_pasid_free(pasid);
 }
index 6727e9d..922ae13 100644 (file)
@@ -723,7 +723,7 @@ struct kfd_process {
        /* We want to receive a notification when the mm_struct is destroyed */
        struct mmu_notifier mmu_notifier;
 
-       uint16_t pasid;
+       u32 pasid;
        unsigned int doorbell_index;
 
        /*
@@ -800,7 +800,7 @@ int kfd_process_create_wq(void);
 void kfd_process_destroy_wq(void);
 struct kfd_process *kfd_create_process(struct file *filep);
 struct kfd_process *kfd_get_process(const struct task_struct *);
-struct kfd_process *kfd_lookup_process_by_pasid(unsigned int pasid);
+struct kfd_process *kfd_lookup_process_by_pasid(u32 pasid);
 struct kfd_process *kfd_lookup_process_by_mm(const struct mm_struct *mm);
 void kfd_unref_process(struct kfd_process *p);
 int kfd_process_evict_queues(struct kfd_process *p);
@@ -841,8 +841,8 @@ int kfd_pasid_init(void);
 void kfd_pasid_exit(void);
 bool kfd_set_pasid_limit(unsigned int new_limit);
 unsigned int kfd_get_pasid_limit(void);
-unsigned int kfd_pasid_alloc(void);
-void kfd_pasid_free(unsigned int pasid);
+u32 kfd_pasid_alloc(void);
+void kfd_pasid_free(u32 pasid);
 
 /* Doorbells */
 size_t kfd_doorbell_process_slice(struct kfd_dev *kfd);
@@ -927,7 +927,7 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm);
 struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
                                        enum kfd_queue_type type);
 void kernel_queue_uninit(struct kernel_queue *kq, bool hanging);
-int kfd_process_vm_fault(struct device_queue_manager *dqm, unsigned int pasid);
+int kfd_process_vm_fault(struct device_queue_manager *dqm, u32 pasid);
 
 /* Process Queue Manager */
 struct process_queue_node {
@@ -1049,12 +1049,12 @@ int kfd_wait_on_events(struct kfd_process *p,
                       uint32_t num_events, void __user *data,
                       bool all, uint32_t user_timeout_ms,
                       uint32_t *wait_result);
-void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id,
+void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id,
                                uint32_t valid_id_bits);
 void kfd_signal_iommu_event(struct kfd_dev *dev,
-               unsigned int pasid, unsigned long address,
-               bool is_write_requested, bool is_execute_requested);
-void kfd_signal_hw_exception_event(unsigned int pasid);
+                           u32 pasid, unsigned long address,
+                           bool is_write_requested, bool is_execute_requested);
+void kfd_signal_hw_exception_event(u32 pasid);
 int kfd_set_event(struct kfd_process *p, uint32_t event_id);
 int kfd_reset_event(struct kfd_process *p, uint32_t event_id);
 int kfd_event_page_set(struct kfd_process *p, void *kernel_address,
@@ -1065,7 +1065,7 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p,
                     uint64_t *event_page_offset, uint32_t *event_slot_index);
 int kfd_event_destroy(struct kfd_process *p, uint32_t event_id);
 
-void kfd_signal_vm_fault_event(struct kfd_dev *dev, unsigned int pasid,
+void kfd_signal_vm_fault_event(struct kfd_dev *dev, u32 pasid,
                                struct kfd_vm_fault_info *info);
 
 void kfd_signal_reset_event(struct kfd_dev *dev);
index 40695d5..6277930 100644 (file)
@@ -1306,7 +1306,7 @@ void kfd_process_device_remove_obj_handle(struct kfd_process_device *pdd,
 }
 
 /* This increments the process->ref counter. */
-struct kfd_process *kfd_lookup_process_by_pasid(unsigned int pasid)
+struct kfd_process *kfd_lookup_process_by_pasid(u32 pasid)
 {
        struct kfd_process *p, *ret_p = NULL;
        unsigned int temp;
index df93382..a717a49 100644 (file)
@@ -1409,7 +1409,7 @@ static int dm_late_init(void *handle)
        if (dmcu)
                ret = dmcu_load_iram(dmcu, params);
        else if (adev->dm.dc->ctx->dmub_srv)
-               ret = dmub_init_abm_config(adev->dm.dc->res_pool->abm, params);
+               ret = dmub_init_abm_config(adev->dm.dc->res_pool, params);
 
        if (!ret)
                return -EINVAL;
@@ -2834,12 +2834,18 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
                                    &dm_atomic_state_funcs);
 
        r = amdgpu_display_modeset_create_props(adev);
-       if (r)
+       if (r) {
+               dc_release_state(state->context);
+               kfree(state);
                return r;
+       }
 
        r = amdgpu_dm_audio_init(adev);
-       if (r)
+       if (r) {
+               dc_release_state(state->context);
+               kfree(state);
                return r;
+       }
 
        return 0;
 }
@@ -2856,6 +2862,8 @@ static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm)
 #if defined(CONFIG_ACPI)
        struct amdgpu_dm_backlight_caps caps;
 
+       memset(&caps, 0, sizeof(caps));
+
        if (dm->backlight_caps.caps_valid)
                return;
 
@@ -2894,51 +2902,50 @@ static int set_backlight_via_aux(struct dc_link *link, uint32_t brightness)
        return rc ? 0 : 1;
 }
 
-static u32 convert_brightness(const struct amdgpu_dm_backlight_caps *caps,
-                             const uint32_t user_brightness)
+static int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps,
+                               unsigned *min, unsigned *max)
 {
-       u32 min, max, conversion_pace;
-       u32 brightness = user_brightness;
-
        if (!caps)
-               goto out;
+               return 0;
 
-       if (!caps->aux_support) {
-               max = caps->max_input_signal;
-               min = caps->min_input_signal;
-               /*
-                * The brightness input is in the range 0-255
-                * It needs to be rescaled to be between the
-                * requested min and max input signal
-                * It also needs to be scaled up by 0x101 to
-                * match the DC interface which has a range of
-                * 0 to 0xffff
-                */
-               conversion_pace = 0x101;
-               brightness =
-                       user_brightness
-                       * conversion_pace
-                       * (max - min)
-                       / AMDGPU_MAX_BL_LEVEL
-                       + min * conversion_pace;
+       if (caps->aux_support) {
+               // Firmware limits are in nits, DC API wants millinits.
+               *max = 1000 * caps->aux_max_input_signal;
+               *min = 1000 * caps->aux_min_input_signal;
        } else {
-               /* TODO
-                * We are doing a linear interpolation here, which is OK but
-                * does not provide the optimal result. We probably want
-                * something close to the Perceptual Quantizer (PQ) curve.
-                */
-               max = caps->aux_max_input_signal;
-               min = caps->aux_min_input_signal;
-
-               brightness = (AMDGPU_MAX_BL_LEVEL - user_brightness) * min
-                              + user_brightness * max;
-               // Multiple the value by 1000 since we use millinits
-               brightness *= 1000;
-               brightness = DIV_ROUND_CLOSEST(brightness, AMDGPU_MAX_BL_LEVEL);
+               // Firmware limits are 8-bit, PWM control is 16-bit.
+               *max = 0x101 * caps->max_input_signal;
+               *min = 0x101 * caps->min_input_signal;
        }
+       return 1;
+}
+
+static u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps,
+                                       uint32_t brightness)
+{
+       unsigned min, max;
+
+       if (!get_brightness_range(caps, &min, &max))
+               return brightness;
+
+       // Rescale 0..255 to min..max
+       return min + DIV_ROUND_CLOSEST((max - min) * brightness,
+                                      AMDGPU_MAX_BL_LEVEL);
+}
+
+static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *caps,
+                                     uint32_t brightness)
+{
+       unsigned min, max;
+
+       if (!get_brightness_range(caps, &min, &max))
+               return brightness;
 
-out:
-       return brightness;
+       if (brightness < min)
+               return 0;
+       // Rescale min..max to 0..255
+       return DIV_ROUND_CLOSEST(AMDGPU_MAX_BL_LEVEL * (brightness - min),
+                                max - min);
 }
 
 static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
@@ -2954,7 +2961,7 @@ static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
 
        link = (struct dc_link *)dm->backlight_link;
 
-       brightness = convert_brightness(&caps, bd->props.brightness);
+       brightness = convert_brightness_from_user(&caps, bd->props.brightness);
        // Change brightness based on AUX property
        if (caps.aux_support)
                return set_backlight_via_aux(link, brightness);
@@ -2971,7 +2978,7 @@ static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd)
 
        if (ret == DC_ERROR_UNEXPECTED)
                return bd->props.brightness;
-       return ret;
+       return convert_brightness_to_user(&dm->backlight_caps, ret);
 }
 
 static const struct backlight_ops amdgpu_dm_backlight_ops = {
@@ -5271,19 +5278,6 @@ static void dm_crtc_helper_disable(struct drm_crtc *crtc)
 {
 }
 
-static bool does_crtc_have_active_cursor(struct drm_crtc_state *new_crtc_state)
-{
-       struct drm_device *dev = new_crtc_state->crtc->dev;
-       struct drm_plane *plane;
-
-       drm_for_each_plane_mask(plane, dev, new_crtc_state->plane_mask) {
-               if (plane->type == DRM_PLANE_TYPE_CURSOR)
-                       return true;
-       }
-
-       return false;
-}
-
 static int count_crtc_active_planes(struct drm_crtc_state *new_crtc_state)
 {
        struct drm_atomic_state *state = new_crtc_state->state;
@@ -5347,19 +5341,20 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
                return ret;
        }
 
-       /* In some use cases, like reset, no stream is attached */
-       if (!dm_crtc_state->stream)
-               return 0;
-
        /*
-        * We want at least one hardware plane enabled to use
-        * the stream with a cursor enabled.
+        * We require the primary plane to be enabled whenever the CRTC is, otherwise
+        * drm_mode_cursor_universal may end up trying to enable the cursor plane while all other
+        * planes are disabled, which is not supported by the hardware. And there is legacy
+        * userspace which stops using the HW cursor altogether in response to the resulting EINVAL.
         */
-       if (state->enable && state->active &&
-           does_crtc_have_active_cursor(state) &&
-           dm_crtc_state->active_planes == 0)
+       if (state->enable &&
+           !(state->plane_mask & drm_plane_mask(crtc->primary)))
                return -EINVAL;
 
+       /* In some use cases, like reset, no stream is attached */
+       if (!dm_crtc_state->stream)
+               return 0;
+
        if (dc_validate_stream(dc, dm_crtc_state->stream) == DC_OK)
                return 0;
 
index 694c5bc..c2cd184 100644 (file)
@@ -604,7 +604,7 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
        int i = 0;
 
        hdcp_work = kcalloc(max_caps, sizeof(*hdcp_work), GFP_KERNEL);
-       if (hdcp_work == NULL)
+       if (ZERO_OR_NULL_PTR(hdcp_work))
                return NULL;
 
        hdcp_work->srm = kcalloc(PSP_HDCP_SRM_FIRST_GEN_MAX_SIZE, sizeof(*hdcp_work->srm), GFP_KERNEL);
index e85b58f..336aaa0 100644 (file)
@@ -67,7 +67,7 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
        result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload,
                                      &operation_result);
 
-       if (payload.write)
+       if (payload.write && result >= 0)
                result = msg->size;
 
        if (result < 0)
index c664404..21a3073 100644 (file)
@@ -94,6 +94,15 @@ int rn_get_active_display_cnt_wa(
        return display_count;
 }
 
+void rn_set_low_power_state(struct clk_mgr *clk_mgr_base)
+{
+       struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+
+       rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER);
+       /* update power state */
+       clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
+}
+
 void rn_update_clocks(struct clk_mgr *clk_mgr_base,
                        struct dc_state *context,
                        bool safe_to_lower)
@@ -516,6 +525,7 @@ static struct clk_mgr_funcs dcn21_funcs = {
        .init_clocks = rn_init_clocks,
        .enable_pme_wa = rn_enable_pme_wa,
        .are_clock_states_equal = rn_are_clock_states_equal,
+       .set_low_power_state = rn_set_low_power_state,
        .notify_wm_ranges = rn_notify_wm_ranges,
        .notify_link_rate_change = rn_notify_link_rate_change,
 };
@@ -773,7 +783,6 @@ void rn_clk_mgr_construct(
        } else {
                struct clk_log_info log_info = {0};
 
-               clk_mgr->smu_ver = rn_vbios_smu_get_smu_version(clk_mgr);
                clk_mgr->periodic_retraining_disabled = rn_vbios_smu_is_periodic_retraining_disabled(clk_mgr);
 
                /* SMU Version 55.51.0 and up no longer have an issue
index 117d8aa..437d1a7 100644 (file)
@@ -763,6 +763,7 @@ static bool detect_dp(struct dc_link *link,
                sink_caps->signal = dp_passive_dongle_detection(link->ddc,
                                                                sink_caps,
                                                                audio_support);
+               link->dpcd_caps.dongle_type = sink_caps->dongle_type;
        }
 
        return true;
@@ -3286,10 +3287,10 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
                core_link_set_avmute(pipe_ctx, true);
        }
 
-       dc->hwss.blank_stream(pipe_ctx);
 #if defined(CONFIG_DRM_AMD_DC_HDCP)
        update_psp_stream_config(pipe_ctx, true);
 #endif
+       dc->hwss.blank_stream(pipe_ctx);
 
        if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
                deallocate_mst_payload(pipe_ctx);
index 9bc03f2..b2be6ad 100644 (file)
@@ -4409,9 +4409,9 @@ bool dc_link_get_backlight_level_nits(struct dc_link *link,
                        link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
                return false;
 
-       if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK,
+       if (core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK,
                        dpcd_backlight_get.raw,
-                       sizeof(union dpcd_source_backlight_get)))
+                       sizeof(union dpcd_source_backlight_get)) != DC_OK)
                return false;
 
        *backlight_millinits_avg =
@@ -4450,9 +4450,9 @@ bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_milli
                link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
                return false;
 
-       if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
+       if (core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
                (uint8_t *) backlight_millinits,
-               sizeof(uint32_t)))
+               sizeof(uint32_t)) != DC_OK)
                return false;
 
        return true;
index 633442b..d9888f3 100644 (file)
@@ -233,7 +233,7 @@ struct dc_stream_state {
        union stream_update_flags update_flags;
 };
 
-#define ABM_LEVEL_IMMEDIATE_DISABLE 0xFFFFFFFF
+#define ABM_LEVEL_IMMEDIATE_DISABLE 255
 
 struct dc_stream_update {
        struct dc_stream_state *stream;
index a643927..fa643ec 100644 (file)
@@ -1450,33 +1450,42 @@ void dcn10_init_hw(struct dc *dc)
 void dcn10_power_down_on_boot(struct dc *dc)
 {
        int i = 0;
+       struct dc_link *edp_link;
 
-       if (dc->config.power_down_display_on_boot) {
-               struct dc_link *edp_link = get_edp_link(dc);
-
-               if (edp_link &&
-                               edp_link->link_enc->funcs->is_dig_enabled &&
-                               edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
-                               dc->hwseq->funcs.edp_backlight_control &&
-                               dc->hwss.power_down &&
-                               dc->hwss.edp_power_control) {
-                       dc->hwseq->funcs.edp_backlight_control(edp_link, false);
-                       dc->hwss.power_down(dc);
-                       dc->hwss.edp_power_control(edp_link, false);
-               } else {
-                       for (i = 0; i < dc->link_count; i++) {
-                               struct dc_link *link = dc->links[i];
-
-                               if (link->link_enc->funcs->is_dig_enabled &&
-                                               link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
-                                               dc->hwss.power_down) {
-                                       dc->hwss.power_down(dc);
-                                       break;
-                               }
+       if (!dc->config.power_down_display_on_boot)
+               return;
+
+       edp_link = get_edp_link(dc);
+       if (edp_link &&
+                       edp_link->link_enc->funcs->is_dig_enabled &&
+                       edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
+                       dc->hwseq->funcs.edp_backlight_control &&
+                       dc->hwss.power_down &&
+                       dc->hwss.edp_power_control) {
+               dc->hwseq->funcs.edp_backlight_control(edp_link, false);
+               dc->hwss.power_down(dc);
+               dc->hwss.edp_power_control(edp_link, false);
+       } else {
+               for (i = 0; i < dc->link_count; i++) {
+                       struct dc_link *link = dc->links[i];
 
+                       if (link->link_enc->funcs->is_dig_enabled &&
+                                       link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
+                                       dc->hwss.power_down) {
+                               dc->hwss.power_down(dc);
+                               break;
                        }
+
                }
        }
+
+       /*
+        * Call update_clocks with empty context
+        * to send DISPLAY_OFF
+        * Otherwise DISPLAY_OFF may not be asserted
+        */
+       if (dc->clk_mgr->funcs->set_low_power_state)
+               dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr);
 }
 
 void dcn10_reset_hw_ctx_wrap(
index 17d5cb4..8939541 100644 (file)
@@ -1213,6 +1213,7 @@ static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *cont
        bool video_large = false;
        bool desktop_large = false;
        bool dcc_disabled = false;
+       bool mpo_enabled = false;
 
        for (i = 0; i < context->stream_count; i++) {
                if (context->stream_status[i].plane_count == 0)
@@ -1221,6 +1222,9 @@ static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *cont
                if (context->stream_status[i].plane_count > 2)
                        return DC_FAIL_UNSUPPORTED_1;
 
+               if (context->stream_status[i].plane_count > 1)
+                       mpo_enabled = true;
+
                for (j = 0; j < context->stream_status[i].plane_count; j++) {
                        struct dc_plane_state *plane =
                                context->stream_status[i].plane_states[j];
@@ -1244,6 +1248,10 @@ static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *cont
                }
        }
 
+       /* Disable MPO in multi-display configurations. */
+       if (context->stream_count > 1 && mpo_enabled)
+               return DC_FAIL_UNSUPPORTED_1;
+
        /*
         * Workaround: On DCN10 there is UMC issue that causes underflow when
         * playing 4k video on 4k desktop with video downscaled and single channel
index 9140b3f..f31f48d 100644 (file)
@@ -409,8 +409,8 @@ static struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv14_soc = {
                        },
                },
        .num_states = 5,
-       .sr_exit_time_us = 8.6,
-       .sr_enter_plus_exit_time_us = 10.9,
+       .sr_exit_time_us = 11.6,
+       .sr_enter_plus_exit_time_us = 13.9,
        .urgent_latency_us = 4.0,
        .urgent_latency_pixel_data_only_us = 4.0,
        .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
index 025637a..bd2a068 100644 (file)
@@ -31,9 +31,21 @@ DCN30 = dcn30_init.o dcn30_hubbub.o dcn30_hubp.o dcn30_dpp.o dcn30_optc.o \
        dcn30_dio_link_encoder.o dcn30_resource.o
 
 
-CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -mhard-float -msse -mpreferred-stack-boundary=4
-
+ifdef CONFIG_X86
 CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o := -mhard-float -msse
+CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -mhard-float -msse
+endif
+
+ifdef CONFIG_PPC64
+CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o := -mhard-float -maltivec
+CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -mhard-float -maltivec
+endif
+
+ifdef CONFIG_ARM64
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o := -mgeneral-regs-only
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -mgeneral-regs-only
+endif
+
 ifdef CONFIG_CC_IS_GCC
 ifeq ($(call cc-ifversion, -lt, 0701, y), y)
 IS_OLD_GCC = 1
@@ -45,8 +57,10 @@ ifdef IS_OLD_GCC
 # GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
 # (8B stack alignment).
 CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o += -mpreferred-stack-boundary=4
+CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o += -mpreferred-stack-boundary=4
 else
 CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o += -msse2
+CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o += -msse2
 endif
 
 AMD_DAL_DCN30 = $(addprefix $(AMDDALPATH)/dc/dcn30/,$(DCN30))
index 5994d2a..947d610 100644 (file)
@@ -230,6 +230,8 @@ struct clk_mgr_funcs {
 
        int (*get_dp_ref_clk_frequency)(struct clk_mgr *clk_mgr);
 
+       void (*set_low_power_state)(struct clk_mgr *clk_mgr);
+
        void (*init_clocks)(struct clk_mgr *clk_mgr);
 
        void (*enable_pme_wa) (struct clk_mgr *clk_mgr);
index d3192b9..47f8ee2 100644 (file)
@@ -27,7 +27,7 @@
 #define MOD_HDCP_LOG_H_
 
 #ifdef CONFIG_DRM_AMD_DC_HDCP
-#define HDCP_LOG_ERR(hdcp, ...) DRM_WARN(__VA_ARGS__)
+#define HDCP_LOG_ERR(hdcp, ...) DRM_DEBUG_KMS(__VA_ARGS__)
 #define HDCP_LOG_VER(hdcp, ...) DRM_DEBUG_KMS(__VA_ARGS__)
 #define HDCP_LOG_FSM(hdcp, ...) DRM_DEBUG_KMS(__VA_ARGS__)
 #define HDCP_LOG_TOP(hdcp, ...) pr_debug("[HDCP_TOP]:"__VA_ARGS__)
index fb1161d..3a367a5 100644 (file)
@@ -88,7 +88,7 @@ enum mod_hdcp_status mod_hdcp_add_display_to_topology(struct mod_hdcp *hdcp,
        enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
 
        if (!psp->dtm_context.dtm_initialized) {
-               DRM_ERROR("Failed to add display topology, DTM TA is not initialized.");
+               DRM_INFO("Failed to add display topology, DTM TA is not initialized.");
                display->state = MOD_HDCP_DISPLAY_INACTIVE;
                return MOD_HDCP_STATUS_FAILURE;
        }
index 8597247..6149795 100644 (file)
@@ -657,7 +657,7 @@ void fill_iram_v_2_3(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parame
                        params, ram_table, big_endian);
 }
 
-bool dmub_init_abm_config(struct abm *abm,
+bool dmub_init_abm_config(struct resource_pool *res_pool,
        struct dmcu_iram_parameters params)
 {
        struct iram_table_v_2_2 ram_table;
@@ -665,8 +665,13 @@ bool dmub_init_abm_config(struct abm *abm,
        bool result = false;
        uint32_t i, j = 0;
 
-       if (abm == NULL)
+#if defined(CONFIG_DRM_AMD_DC_DCN3_0)
+       if (res_pool->abm == NULL && res_pool->multiple_abms[0] == NULL)
                return false;
+#else
+       if (res_pool->abm == NULL)
+               return false;
+#endif
 
        memset(&ram_table, 0, sizeof(ram_table));
        memset(&config, 0, sizeof(config));
@@ -707,8 +712,14 @@ bool dmub_init_abm_config(struct abm *abm,
 
        config.min_abm_backlight = ram_table.min_abm_backlight;
 
-       result = abm->funcs->init_abm_config(
-               abm, (char *)(&config), sizeof(struct abm_config_table));
+#if defined(CONFIG_DRM_AMD_DC_DCN3_0)
+       if (res_pool->multiple_abms[0]) {
+               result = res_pool->multiple_abms[0]->funcs->init_abm_config(
+                       res_pool->multiple_abms[0], (char *)(&config), sizeof(struct abm_config_table));
+       } else
+#endif
+               result = res_pool->abm->funcs->init_abm_config(
+                       res_pool->abm, (char *)(&config), sizeof(struct abm_config_table));
 
        return result;
 }
index 46fbca2..fa4728d 100644 (file)
@@ -28,6 +28,8 @@
 #include "dc/inc/hw/dmcu.h"
 #include "dc/inc/hw/abm.h"
 
+struct resource_pool;
+
 
 enum abm_defines {
        abm_defines_max_level = 4,
@@ -45,7 +47,7 @@ struct dmcu_iram_parameters {
 
 bool dmcu_load_iram(struct dmcu *dmcu,
                struct dmcu_iram_parameters params);
-bool dmub_init_abm_config(struct abm *abm,
+bool dmub_init_abm_config(struct resource_pool *res_pool,
                struct dmcu_iram_parameters params);
 
 #endif /* MODULES_POWER_POWER_HELPERS_H_ */
index 1116779..e245e91 100644 (file)
 #define mmDB_STENCIL_WRITE_BASE_DEFAULT                                          0x00000000
 #define mmDB_RESERVED_REG_1_DEFAULT                                              0x00000000
 #define mmDB_RESERVED_REG_3_DEFAULT                                              0x00000000
+#define mmDB_VRS_OVERRIDE_CNTL_DEFAULT                                           0x00000000
 #define mmDB_Z_READ_BASE_HI_DEFAULT                                              0x00000000
 #define mmDB_STENCIL_READ_BASE_HI_DEFAULT                                        0x00000000
 #define mmDB_Z_WRITE_BASE_HI_DEFAULT                                             0x00000000
 #define mmPA_SU_OVER_RASTERIZATION_CNTL_DEFAULT                                  0x00000000
 #define mmPA_STEREO_CNTL_DEFAULT                                                 0x00000000
 #define mmPA_STATE_STEREO_X_DEFAULT                                              0x00000000
+#define mmPA_CL_VRS_CNTL_DEFAULT                                                 0x00000000
 #define mmPA_SU_POINT_SIZE_DEFAULT                                               0x00000000
 #define mmPA_SU_POINT_MINMAX_DEFAULT                                             0x00000000
 #define mmPA_SU_LINE_CNTL_DEFAULT                                                0x00000000
index 05d1b0a..644a9fa 100644 (file)
 #define mmDB_RESERVED_REG_1_BASE_IDX                                                                   1
 #define mmDB_RESERVED_REG_3                                                                            0x0017
 #define mmDB_RESERVED_REG_3_BASE_IDX                                                                   1
+#define mmDB_VRS_OVERRIDE_CNTL                                                                         0x0019
+#define mmDB_VRS_OVERRIDE_CNTL_BASE_IDX                                                                1
 #define mmDB_Z_READ_BASE_HI                                                                            0x001a
 #define mmDB_Z_READ_BASE_HI_BASE_IDX                                                                   1
 #define mmDB_STENCIL_READ_BASE_HI                                                                      0x001b
 #define mmPA_STEREO_CNTL_BASE_IDX                                                                      1
 #define mmPA_STATE_STEREO_X                                                                            0x0211
 #define mmPA_STATE_STEREO_X_BASE_IDX                                                                   1
+#define mmPA_CL_VRS_CNTL                                                                               0x0212
+#define mmPA_CL_VRS_CNTL_BASE_IDX                                                                      1
 #define mmPA_SU_POINT_SIZE                                                                             0x0280
 #define mmPA_SU_POINT_SIZE_BASE_IDX                                                                    1
 #define mmPA_SU_POINT_MINMAX                                                                           0x0281
index aac57f7..2e449fc 100644 (file)
 #define DB_EXCEPTION_CONTROL__AUTO_FLUSH_HTILE__SHIFT                                                         0x3
 #define DB_EXCEPTION_CONTROL__AUTO_FLUSH_QUAD__SHIFT                                                          0x4
 #define DB_EXCEPTION_CONTROL__FORCE_SUMMARIZE__SHIFT                                                          0x8
+#define DB_EXCEPTION_CONTROL__FORCE_VRS_RATE_FINE__SHIFT                                                      0x10
 #define DB_EXCEPTION_CONTROL__DTAG_WATERMARK__SHIFT                                                           0x18
 #define DB_EXCEPTION_CONTROL__EARLY_Z_PANIC_DISABLE_MASK                                                      0x00000001L
 #define DB_EXCEPTION_CONTROL__LATE_Z_PANIC_DISABLE_MASK                                                       0x00000002L
 #define DB_EXCEPTION_CONTROL__AUTO_FLUSH_HTILE_MASK                                                           0x00000008L
 #define DB_EXCEPTION_CONTROL__AUTO_FLUSH_QUAD_MASK                                                            0x00000010L
 #define DB_EXCEPTION_CONTROL__FORCE_SUMMARIZE_MASK                                                            0x00000F00L
+#define DB_EXCEPTION_CONTROL__FORCE_VRS_RATE_FINE_MASK                                                        0x00FF0000L
 #define DB_EXCEPTION_CONTROL__DTAG_WATERMARK_MASK                                                             0x7F000000L
 //DB_DFSM_CONFIG
 #define DB_DFSM_CONFIG__BYPASS_DFSM__SHIFT                                                                    0x0
 #define CB_HW_CONTROL_3__DISABLE_NACK_PROCESSING_CM__SHIFT                                                    0x18
 #define CB_HW_CONTROL_3__DISABLE_NACK_COLOR_RD_WR_OPT__SHIFT                                                  0x19
 #define CB_HW_CONTROL_3__DISABLE_BLENDER_CLOCK_GATING__SHIFT                                                  0x1a
+#define CB_HW_CONTROL_3__DISABLE_DCC_VRS_OPT__SHIFT                                                           0x1c
 #define CB_HW_CONTROL_3__DISABLE_FMASK_NOFETCH_OPT__SHIFT                                                     0x1e
 #define CB_HW_CONTROL_3__DISABLE_FMASK_NOFETCH_OPT_BC__SHIFT                                                  0x1f
 #define CB_HW_CONTROL_3__DISABLE_SLOW_MODE_EMPTY_HALF_QUAD_KILL_MASK                                          0x00000001L
 #define CB_HW_CONTROL_3__DISABLE_NACK_PROCESSING_CM_MASK                                                      0x01000000L
 #define CB_HW_CONTROL_3__DISABLE_NACK_COLOR_RD_WR_OPT_MASK                                                    0x02000000L
 #define CB_HW_CONTROL_3__DISABLE_BLENDER_CLOCK_GATING_MASK                                                    0x04000000L
+#define CB_HW_CONTROL_3__DISABLE_DCC_VRS_OPT_MASK                                                             0x10000000L
 #define CB_HW_CONTROL_3__DISABLE_FMASK_NOFETCH_OPT_MASK                                                       0x40000000L
 #define CB_HW_CONTROL_3__DISABLE_FMASK_NOFETCH_OPT_BC_MASK                                                    0x80000000L
 //CB_HW_CONTROL
 #define CB_HW_CONTROL__ALLOW_MRT_WITH_DUAL_SOURCE__SHIFT                                                      0x0
+#define CB_HW_CONTROL__DISABLE_VRS_FILLRATE_OPTIMIZATION__SHIFT                                               0x1
 #define CB_HW_CONTROL__DISABLE_FILLRATE_OPT_FIX_WITH_CFC__SHIFT                                               0x3
 #define CB_HW_CONTROL__DISABLE_POST_DCC_WITH_CFC_FIX__SHIFT                                                   0x4
+#define CB_HW_CONTROL__DISABLE_COMPRESS_1FRAG_WHEN_VRS_RATE_HINT_EN__SHIFT                                    0x5
 #define CB_HW_CONTROL__RMI_CREDITS__SHIFT                                                                     0x6
 #define CB_HW_CONTROL__CHICKEN_BITS__SHIFT                                                                    0xc
 #define CB_HW_CONTROL__DISABLE_FMASK_MULTI_MGCG_DOMAINS__SHIFT                                                0xf
 #define CB_HW_CONTROL__DISABLE_CC_IB_SERIALIZER_STATE_OPT__SHIFT                                              0x1e
 #define CB_HW_CONTROL__DISABLE_PIXEL_IN_QUAD_FIX_FOR_LINEAR_SURFACE__SHIFT                                    0x1f
 #define CB_HW_CONTROL__ALLOW_MRT_WITH_DUAL_SOURCE_MASK                                                        0x00000001L
+#define CB_HW_CONTROL__DISABLE_VRS_FILLRATE_OPTIMIZATION_MASK                                                 0x00000002L
 #define CB_HW_CONTROL__DISABLE_FILLRATE_OPT_FIX_WITH_CFC_MASK                                                 0x00000008L
 #define CB_HW_CONTROL__DISABLE_POST_DCC_WITH_CFC_FIX_MASK                                                     0x00000010L
+#define CB_HW_CONTROL__DISABLE_COMPRESS_1FRAG_WHEN_VRS_RATE_HINT_EN_MASK                                      0x00000020L
 #define CB_HW_CONTROL__RMI_CREDITS_MASK                                                                       0x00000FC0L
 #define CB_HW_CONTROL__CHICKEN_BITS_MASK                                                                      0x00007000L
 #define CB_HW_CONTROL__DISABLE_FMASK_MULTI_MGCG_DOMAINS_MASK                                                  0x00008000L
 #define DB_RENDER_OVERRIDE2__PRESERVE_SRESULTS__SHIFT                                                         0x16
 #define DB_RENDER_OVERRIDE2__DISABLE_FAST_PASS__SHIFT                                                         0x17
 #define DB_RENDER_OVERRIDE2__ALLOW_PARTIAL_RES_HIER_KILL__SHIFT                                               0x19
+#define DB_RENDER_OVERRIDE2__FORCE_VRS_RATE_FINE__SHIFT                                                       0x1a
 #define DB_RENDER_OVERRIDE2__CENTROID_COMPUTATION_MODE__SHIFT                                                 0x1b
 #define DB_RENDER_OVERRIDE2__PARTIAL_SQUAD_LAUNCH_CONTROL_MASK                                                0x00000003L
 #define DB_RENDER_OVERRIDE2__PARTIAL_SQUAD_LAUNCH_COUNTDOWN_MASK                                              0x0000001CL
 #define DB_RENDER_OVERRIDE2__PRESERVE_SRESULTS_MASK                                                           0x00400000L
 #define DB_RENDER_OVERRIDE2__DISABLE_FAST_PASS_MASK                                                           0x00800000L
 #define DB_RENDER_OVERRIDE2__ALLOW_PARTIAL_RES_HIER_KILL_MASK                                                 0x02000000L
+#define DB_RENDER_OVERRIDE2__FORCE_VRS_RATE_FINE_MASK                                                         0x04000000L
 #define DB_RENDER_OVERRIDE2__CENTROID_COMPUTATION_MODE_MASK                                                   0x18000000L
 //DB_HTILE_DATA_BASE
 #define DB_HTILE_DATA_BASE__BASE_256B__SHIFT                                                                  0x0
 //DB_RESERVED_REG_3
 #define DB_RESERVED_REG_3__FIELD_1__SHIFT                                                                     0x0
 #define DB_RESERVED_REG_3__FIELD_1_MASK                                                                       0x003FFFFFL
+//DB_VRS_OVERRIDE_CNTL
+#define DB_VRS_OVERRIDE_CNTL__VRS_OVERRIDE_RATE_COMBINER_MODE__SHIFT                                          0x0
+#define DB_VRS_OVERRIDE_CNTL__VRS_OVERRIDE_RATE_X__SHIFT                                                      0x4
+#define DB_VRS_OVERRIDE_CNTL__VRS_OVERRIDE_RATE_Y__SHIFT                                                      0x6
+#define DB_VRS_OVERRIDE_CNTL__VRS_OVERRIDE_RATE_COMBINER_MODE_MASK                                            0x00000007L
+#define DB_VRS_OVERRIDE_CNTL__VRS_OVERRIDE_RATE_X_MASK                                                        0x00000030L
+#define DB_VRS_OVERRIDE_CNTL__VRS_OVERRIDE_RATE_Y_MASK                                                        0x000000C0L
 //DB_Z_READ_BASE_HI
 #define DB_Z_READ_BASE_HI__BASE_HI__SHIFT                                                                     0x0
 #define DB_Z_READ_BASE_HI__BASE_HI_MASK                                                                       0x000000FFL
 #define PA_CL_VS_OUT_CNTL__VS_OUT_MISC_SIDE_BUS_ENA__SHIFT                                                    0x18
 #define PA_CL_VS_OUT_CNTL__USE_VTX_GS_CUT_FLAG__SHIFT                                                         0x19
 #define PA_CL_VS_OUT_CNTL__USE_VTX_LINE_WIDTH__SHIFT                                                          0x1b
+#define PA_CL_VS_OUT_CNTL__USE_VTX_VRS_RATE__SHIFT                                                            0x1c
 #define PA_CL_VS_OUT_CNTL__BYPASS_VTX_RATE_COMBINER__SHIFT                                                    0x1d
 #define PA_CL_VS_OUT_CNTL__BYPASS_PRIM_RATE_COMBINER__SHIFT                                                   0x1e
 #define PA_CL_VS_OUT_CNTL__CLIP_DIST_ENA_0_MASK                                                               0x00000001L
 #define PA_CL_VS_OUT_CNTL__VS_OUT_MISC_SIDE_BUS_ENA_MASK                                                      0x01000000L
 #define PA_CL_VS_OUT_CNTL__USE_VTX_GS_CUT_FLAG_MASK                                                           0x02000000L
 #define PA_CL_VS_OUT_CNTL__USE_VTX_LINE_WIDTH_MASK                                                            0x08000000L
+#define PA_CL_VS_OUT_CNTL__USE_VTX_VRS_RATE_MASK                                                              0x10000000L
 #define PA_CL_VS_OUT_CNTL__BYPASS_VTX_RATE_COMBINER_MASK                                                      0x20000000L
 #define PA_CL_VS_OUT_CNTL__BYPASS_PRIM_RATE_COMBINER_MASK                                                     0x40000000L
 //PA_CL_NANINF_CNTL
 //PA_STATE_STEREO_X
 #define PA_STATE_STEREO_X__STEREO_X_OFFSET__SHIFT                                                             0x0
 #define PA_STATE_STEREO_X__STEREO_X_OFFSET_MASK                                                               0xFFFFFFFFL
+//PA_CL_VRS_CNTL
+#define PA_CL_VRS_CNTL__VERTEX_RATE_COMBINER_MODE__SHIFT                                                      0x0
+#define PA_CL_VRS_CNTL__PRIMITIVE_RATE_COMBINER_MODE__SHIFT                                                   0x3
+#define PA_CL_VRS_CNTL__HTILE_RATE_COMBINER_MODE__SHIFT                                                       0x6
+#define PA_CL_VRS_CNTL__SAMPLE_ITER_COMBINER_MODE__SHIFT                                                      0x9
+#define PA_CL_VRS_CNTL__EXPOSE_VRS_PIXELS_MASK__SHIFT                                                         0xd
+#define PA_CL_VRS_CNTL__CMASK_RATE_HINT_FORCE_ZERO__SHIFT                                                     0xe
+#define PA_CL_VRS_CNTL__VERTEX_RATE_COMBINER_MODE_MASK                                                        0x00000007L
+#define PA_CL_VRS_CNTL__PRIMITIVE_RATE_COMBINER_MODE_MASK                                                     0x00000038L
+#define PA_CL_VRS_CNTL__HTILE_RATE_COMBINER_MODE_MASK                                                         0x000001C0L
+#define PA_CL_VRS_CNTL__SAMPLE_ITER_COMBINER_MODE_MASK                                                        0x00000E00L
+#define PA_CL_VRS_CNTL__EXPOSE_VRS_PIXELS_MASK_MASK                                                           0x00002000L
+#define PA_CL_VRS_CNTL__CMASK_RATE_HINT_FORCE_ZERO_MASK                                                       0x00004000L
 //PA_SU_POINT_SIZE
 #define PA_SU_POINT_SIZE__HEIGHT__SHIFT                                                                       0x0
 #define PA_SU_POINT_SIZE__WIDTH__SHIFT                                                                        0x10
 #define DB_HTILE_SURFACE__DST_OUTSIDE_ZERO_TO_ONE__SHIFT                                                      0x10
 #define DB_HTILE_SURFACE__RESERVED_FIELD_6__SHIFT                                                             0x11
 #define DB_HTILE_SURFACE__PIPE_ALIGNED__SHIFT                                                                 0x12
+#define DB_HTILE_SURFACE__VRS_HTILE_ENCODING__SHIFT                                                           0x13
 #define DB_HTILE_SURFACE__RESERVED_FIELD_1_MASK                                                               0x00000001L
 #define DB_HTILE_SURFACE__FULL_CACHE_MASK                                                                     0x00000002L
 #define DB_HTILE_SURFACE__RESERVED_FIELD_2_MASK                                                               0x00000004L
 #define DB_HTILE_SURFACE__DST_OUTSIDE_ZERO_TO_ONE_MASK                                                        0x00010000L
 #define DB_HTILE_SURFACE__RESERVED_FIELD_6_MASK                                                               0x00020000L
 #define DB_HTILE_SURFACE__PIPE_ALIGNED_MASK                                                                   0x00040000L
+#define DB_HTILE_SURFACE__VRS_HTILE_ENCODING_MASK                                                             0x00180000L
 //DB_SRESULTS_COMPARE_STATE0
 #define DB_SRESULTS_COMPARE_STATE0__COMPAREFUNC0__SHIFT                                                       0x0
 #define DB_SRESULTS_COMPARE_STATE0__COMPAREVALUE0__SHIFT                                                      0x4
 #define CB_COLOR0_ATTRIB3__CMASK_PIPE_ALIGNED__SHIFT                                                          0x1a
 #define CB_COLOR0_ATTRIB3__RESOURCE_LEVEL__SHIFT                                                              0x1b
 #define CB_COLOR0_ATTRIB3__DCC_PIPE_ALIGNED__SHIFT                                                            0x1e
+#define CB_COLOR0_ATTRIB3__VRS_RATE_HINT_ENABLE__SHIFT                                                        0x1f
 #define CB_COLOR0_ATTRIB3__MIP0_DEPTH_MASK                                                                    0x00001FFFL
 #define CB_COLOR0_ATTRIB3__META_LINEAR_MASK                                                                   0x00002000L
 #define CB_COLOR0_ATTRIB3__COLOR_SW_MODE_MASK                                                                 0x0007C000L
 #define CB_COLOR0_ATTRIB3__CMASK_PIPE_ALIGNED_MASK                                                            0x04000000L
 #define CB_COLOR0_ATTRIB3__RESOURCE_LEVEL_MASK                                                                0x38000000L
 #define CB_COLOR0_ATTRIB3__DCC_PIPE_ALIGNED_MASK                                                              0x40000000L
+#define CB_COLOR0_ATTRIB3__VRS_RATE_HINT_ENABLE_MASK                                                          0x80000000L
 //CB_COLOR1_ATTRIB3
 #define CB_COLOR1_ATTRIB3__MIP0_DEPTH__SHIFT                                                                  0x0
 #define CB_COLOR1_ATTRIB3__META_LINEAR__SHIFT                                                                 0xd
 #define CB_COLOR1_ATTRIB3__CMASK_PIPE_ALIGNED__SHIFT                                                          0x1a
 #define CB_COLOR1_ATTRIB3__RESOURCE_LEVEL__SHIFT                                                              0x1b
 #define CB_COLOR1_ATTRIB3__DCC_PIPE_ALIGNED__SHIFT                                                            0x1e
+#define CB_COLOR1_ATTRIB3__VRS_RATE_HINT_ENABLE__SHIFT                                                        0x1f
 #define CB_COLOR1_ATTRIB3__MIP0_DEPTH_MASK                                                                    0x00001FFFL
 #define CB_COLOR1_ATTRIB3__META_LINEAR_MASK                                                                   0x00002000L
 #define CB_COLOR1_ATTRIB3__COLOR_SW_MODE_MASK                                                                 0x0007C000L
 #define CB_COLOR1_ATTRIB3__CMASK_PIPE_ALIGNED_MASK                                                            0x04000000L
 #define CB_COLOR1_ATTRIB3__RESOURCE_LEVEL_MASK                                                                0x38000000L
 #define CB_COLOR1_ATTRIB3__DCC_PIPE_ALIGNED_MASK                                                              0x40000000L
+#define CB_COLOR1_ATTRIB3__VRS_RATE_HINT_ENABLE_MASK                                                          0x80000000L
 //CB_COLOR2_ATTRIB3
 #define CB_COLOR2_ATTRIB3__MIP0_DEPTH__SHIFT                                                                  0x0
 #define CB_COLOR2_ATTRIB3__META_LINEAR__SHIFT                                                                 0xd
 #define CB_COLOR2_ATTRIB3__CMASK_PIPE_ALIGNED__SHIFT                                                          0x1a
 #define CB_COLOR2_ATTRIB3__RESOURCE_LEVEL__SHIFT                                                              0x1b
 #define CB_COLOR2_ATTRIB3__DCC_PIPE_ALIGNED__SHIFT                                                            0x1e
+#define CB_COLOR2_ATTRIB3__VRS_RATE_HINT_ENABLE__SHIFT                                                        0x1f
 #define CB_COLOR2_ATTRIB3__MIP0_DEPTH_MASK                                                                    0x00001FFFL
 #define CB_COLOR2_ATTRIB3__META_LINEAR_MASK                                                                   0x00002000L
 #define CB_COLOR2_ATTRIB3__COLOR_SW_MODE_MASK                                                                 0x0007C000L
 #define CB_COLOR2_ATTRIB3__CMASK_PIPE_ALIGNED_MASK                                                            0x04000000L
 #define CB_COLOR2_ATTRIB3__RESOURCE_LEVEL_MASK                                                                0x38000000L
 #define CB_COLOR2_ATTRIB3__DCC_PIPE_ALIGNED_MASK                                                              0x40000000L
+#define CB_COLOR2_ATTRIB3__VRS_RATE_HINT_ENABLE_MASK                                                          0x80000000L
 //CB_COLOR3_ATTRIB3
 #define CB_COLOR3_ATTRIB3__MIP0_DEPTH__SHIFT                                                                  0x0
 #define CB_COLOR3_ATTRIB3__META_LINEAR__SHIFT                                                                 0xd
 #define CB_COLOR3_ATTRIB3__CMASK_PIPE_ALIGNED__SHIFT                                                          0x1a
 #define CB_COLOR3_ATTRIB3__RESOURCE_LEVEL__SHIFT                                                              0x1b
 #define CB_COLOR3_ATTRIB3__DCC_PIPE_ALIGNED__SHIFT                                                            0x1e
+#define CB_COLOR3_ATTRIB3__VRS_RATE_HINT_ENABLE__SHIFT                                                        0x1f
 #define CB_COLOR3_ATTRIB3__MIP0_DEPTH_MASK                                                                    0x00001FFFL
 #define CB_COLOR3_ATTRIB3__META_LINEAR_MASK                                                                   0x00002000L
 #define CB_COLOR3_ATTRIB3__COLOR_SW_MODE_MASK                                                                 0x0007C000L
 #define CB_COLOR3_ATTRIB3__CMASK_PIPE_ALIGNED_MASK                                                            0x04000000L
 #define CB_COLOR3_ATTRIB3__RESOURCE_LEVEL_MASK                                                                0x38000000L
 #define CB_COLOR3_ATTRIB3__DCC_PIPE_ALIGNED_MASK                                                              0x40000000L
+#define CB_COLOR3_ATTRIB3__VRS_RATE_HINT_ENABLE_MASK                                                          0x80000000L
 //CB_COLOR4_ATTRIB3
 #define CB_COLOR4_ATTRIB3__MIP0_DEPTH__SHIFT                                                                  0x0
 #define CB_COLOR4_ATTRIB3__META_LINEAR__SHIFT                                                                 0xd
 #define CB_COLOR4_ATTRIB3__CMASK_PIPE_ALIGNED__SHIFT                                                          0x1a
 #define CB_COLOR4_ATTRIB3__RESOURCE_LEVEL__SHIFT                                                              0x1b
 #define CB_COLOR4_ATTRIB3__DCC_PIPE_ALIGNED__SHIFT                                                            0x1e
+#define CB_COLOR4_ATTRIB3__VRS_RATE_HINT_ENABLE__SHIFT                                                        0x1f
 #define CB_COLOR4_ATTRIB3__MIP0_DEPTH_MASK                                                                    0x00001FFFL
 #define CB_COLOR4_ATTRIB3__META_LINEAR_MASK                                                                   0x00002000L
 #define CB_COLOR4_ATTRIB3__COLOR_SW_MODE_MASK                                                                 0x0007C000L
 #define CB_COLOR4_ATTRIB3__CMASK_PIPE_ALIGNED_MASK                                                            0x04000000L
 #define CB_COLOR4_ATTRIB3__RESOURCE_LEVEL_MASK                                                                0x38000000L
 #define CB_COLOR4_ATTRIB3__DCC_PIPE_ALIGNED_MASK                                                              0x40000000L
+#define CB_COLOR4_ATTRIB3__VRS_RATE_HINT_ENABLE_MASK                                                          0x80000000L
 //CB_COLOR5_ATTRIB3
 #define CB_COLOR5_ATTRIB3__MIP0_DEPTH__SHIFT                                                                  0x0
 #define CB_COLOR5_ATTRIB3__META_LINEAR__SHIFT                                                                 0xd
 #define CB_COLOR5_ATTRIB3__CMASK_PIPE_ALIGNED__SHIFT                                                          0x1a
 #define CB_COLOR5_ATTRIB3__RESOURCE_LEVEL__SHIFT                                                              0x1b
 #define CB_COLOR5_ATTRIB3__DCC_PIPE_ALIGNED__SHIFT                                                            0x1e
+#define CB_COLOR5_ATTRIB3__VRS_RATE_HINT_ENABLE__SHIFT                                                        0x1f
 #define CB_COLOR5_ATTRIB3__MIP0_DEPTH_MASK                                                                    0x00001FFFL
 #define CB_COLOR5_ATTRIB3__META_LINEAR_MASK                                                                   0x00002000L
 #define CB_COLOR5_ATTRIB3__COLOR_SW_MODE_MASK                                                                 0x0007C000L
 #define CB_COLOR5_ATTRIB3__CMASK_PIPE_ALIGNED_MASK                                                            0x04000000L
 #define CB_COLOR5_ATTRIB3__RESOURCE_LEVEL_MASK                                                                0x38000000L
 #define CB_COLOR5_ATTRIB3__DCC_PIPE_ALIGNED_MASK                                                              0x40000000L
+#define CB_COLOR5_ATTRIB3__VRS_RATE_HINT_ENABLE_MASK                                                          0x80000000L
 //CB_COLOR6_ATTRIB3
 #define CB_COLOR6_ATTRIB3__MIP0_DEPTH__SHIFT                                                                  0x0
 #define CB_COLOR6_ATTRIB3__META_LINEAR__SHIFT                                                                 0xd
 #define CB_COLOR6_ATTRIB3__CMASK_PIPE_ALIGNED__SHIFT                                                          0x1a
 #define CB_COLOR6_ATTRIB3__RESOURCE_LEVEL__SHIFT                                                              0x1b
 #define CB_COLOR6_ATTRIB3__DCC_PIPE_ALIGNED__SHIFT                                                            0x1e
+#define CB_COLOR6_ATTRIB3__VRS_RATE_HINT_ENABLE__SHIFT                                                        0x1f
 #define CB_COLOR6_ATTRIB3__MIP0_DEPTH_MASK                                                                    0x00001FFFL
 #define CB_COLOR6_ATTRIB3__META_LINEAR_MASK                                                                   0x00002000L
 #define CB_COLOR6_ATTRIB3__COLOR_SW_MODE_MASK                                                                 0x0007C000L
 #define CB_COLOR6_ATTRIB3__CMASK_PIPE_ALIGNED_MASK                                                            0x04000000L
 #define CB_COLOR6_ATTRIB3__RESOURCE_LEVEL_MASK                                                                0x38000000L
 #define CB_COLOR6_ATTRIB3__DCC_PIPE_ALIGNED_MASK                                                              0x40000000L
+#define CB_COLOR6_ATTRIB3__VRS_RATE_HINT_ENABLE_MASK                                                          0x80000000L
 //CB_COLOR7_ATTRIB3
 #define CB_COLOR7_ATTRIB3__MIP0_DEPTH__SHIFT                                                                  0x0
 #define CB_COLOR7_ATTRIB3__META_LINEAR__SHIFT                                                                 0xd
 #define CB_COLOR7_ATTRIB3__CMASK_PIPE_ALIGNED__SHIFT                                                          0x1a
 #define CB_COLOR7_ATTRIB3__RESOURCE_LEVEL__SHIFT                                                              0x1b
 #define CB_COLOR7_ATTRIB3__DCC_PIPE_ALIGNED__SHIFT                                                            0x1e
+#define CB_COLOR7_ATTRIB3__VRS_RATE_HINT_ENABLE__SHIFT                                                        0x1f
 #define CB_COLOR7_ATTRIB3__MIP0_DEPTH_MASK                                                                    0x00001FFFL
 #define CB_COLOR7_ATTRIB3__META_LINEAR_MASK                                                                   0x00002000L
 #define CB_COLOR7_ATTRIB3__COLOR_SW_MODE_MASK                                                                 0x0007C000L
 #define CB_COLOR7_ATTRIB3__CMASK_PIPE_ALIGNED_MASK                                                            0x04000000L
 #define CB_COLOR7_ATTRIB3__RESOURCE_LEVEL_MASK                                                                0x38000000L
 #define CB_COLOR7_ATTRIB3__DCC_PIPE_ALIGNED_MASK                                                              0x40000000L
+#define CB_COLOR7_ATTRIB3__VRS_RATE_HINT_ENABLE_MASK                                                          0x80000000L
 
 
 // addressBlock: gc_gfxudec
index c0efd90..58cf7ad 100644 (file)
 #define VCN_FEATURES__HAS_MJPEG2_IDCT_DEC__SHIFT                                                              0x7
 #define VCN_FEATURES__HAS_SCLR_DEC__SHIFT                                                                     0x8
 #define VCN_FEATURES__HAS_VP9_DEC__SHIFT                                                                      0x9
+#define VCN_FEATURES__HAS_AV1_DEC__SHIFT                                                                      0xa
 #define VCN_FEATURES__HAS_EFC_ENC__SHIFT                                                                      0xb
 #define VCN_FEATURES__HAS_EFC_HDR2SDR_ENC__SHIFT                                                              0xc
 #define VCN_FEATURES__HAS_DUAL_MJPEG_DEC__SHIFT                                                               0xd
 #define VCN_FEATURES__HAS_MJPEG2_IDCT_DEC_MASK                                                                0x00000080L
 #define VCN_FEATURES__HAS_SCLR_DEC_MASK                                                                       0x00000100L
 #define VCN_FEATURES__HAS_VP9_DEC_MASK                                                                        0x00000200L
+#define VCN_FEATURES__HAS_AV1_DEC_MASK                                                                        0x00000400L
 #define VCN_FEATURES__HAS_EFC_ENC_MASK                                                                        0x00000800L
 #define VCN_FEATURES__HAS_EFC_HDR2SDR_ENC_MASK                                                                0x00001000L
 #define VCN_FEATURES__HAS_DUAL_MJPEG_DEC_MASK                                                                 0x00002000L
 #define UVD_SUVD_CGC_GATE__IME_HEVC__SHIFT                                                                    0x18
 #define UVD_SUVD_CGC_GATE__EFC__SHIFT                                                                         0x19
 #define UVD_SUVD_CGC_GATE__SAOE__SHIFT                                                                        0x1a
+#define UVD_SUVD_CGC_GATE__SRE_AV1__SHIFT                                                                     0x1b
 #define UVD_SUVD_CGC_GATE__FBC_PCLK__SHIFT                                                                    0x1c
 #define UVD_SUVD_CGC_GATE__FBC_CCLK__SHIFT                                                                    0x1d
+#define UVD_SUVD_CGC_GATE__SCM_AV1__SHIFT                                                                     0x1e
 #define UVD_SUVD_CGC_GATE__SMPA__SHIFT                                                                        0x1f
 #define UVD_SUVD_CGC_GATE__SRE_MASK                                                                           0x00000001L
 #define UVD_SUVD_CGC_GATE__SIT_MASK                                                                           0x00000002L
 #define UVD_SUVD_CGC_GATE__IME_HEVC_MASK                                                                      0x01000000L
 #define UVD_SUVD_CGC_GATE__EFC_MASK                                                                           0x02000000L
 #define UVD_SUVD_CGC_GATE__SAOE_MASK                                                                          0x04000000L
+#define UVD_SUVD_CGC_GATE__SRE_AV1_MASK                                                                       0x08000000L
 #define UVD_SUVD_CGC_GATE__FBC_PCLK_MASK                                                                      0x10000000L
 #define UVD_SUVD_CGC_GATE__FBC_CCLK_MASK                                                                      0x20000000L
+#define UVD_SUVD_CGC_GATE__SCM_AV1_MASK                                                                       0x40000000L
 #define UVD_SUVD_CGC_GATE__SMPA_MASK                                                                          0x80000000L
 //UVD_SUVD_CGC_STATUS
 #define UVD_SUVD_CGC_STATUS__SRE_VCLK__SHIFT                                                                  0x0
 #define UVD_SUVD_CGC_STATUS__IME_HEVC_DCLK__SHIFT                                                             0x1b
 #define UVD_SUVD_CGC_STATUS__EFC_DCLK__SHIFT                                                                  0x1c
 #define UVD_SUVD_CGC_STATUS__SAOE_DCLK__SHIFT                                                                 0x1d
+#define UVD_SUVD_CGC_STATUS__SRE_AV1_VCLK__SHIFT                                                              0x1e
+#define UVD_SUVD_CGC_STATUS__SCM_AV1_DCLK__SHIFT                                                              0x1f
 #define UVD_SUVD_CGC_STATUS__SRE_VCLK_MASK                                                                    0x00000001L
 #define UVD_SUVD_CGC_STATUS__SRE_DCLK_MASK                                                                    0x00000002L
 #define UVD_SUVD_CGC_STATUS__SIT_DCLK_MASK                                                                    0x00000004L
 #define UVD_SUVD_CGC_STATUS__IME_HEVC_DCLK_MASK                                                               0x08000000L
 #define UVD_SUVD_CGC_STATUS__EFC_DCLK_MASK                                                                    0x10000000L
 #define UVD_SUVD_CGC_STATUS__SAOE_DCLK_MASK                                                                   0x20000000L
+#define UVD_SUVD_CGC_STATUS__SRE_AV1_VCLK_MASK                                                                0x40000000L
+#define UVD_SUVD_CGC_STATUS__SCM_AV1_DCLK_MASK                                                                0x80000000L
 //UVD_SUVD_CGC_CTRL
 #define UVD_SUVD_CGC_CTRL__SRE_MODE__SHIFT                                                                    0x0
 #define UVD_SUVD_CGC_CTRL__SIT_MODE__SHIFT                                                                    0x1
 #define UVD_SUVD_CGC_CTRL__SMPA_MODE__SHIFT                                                                   0xc
 #define UVD_SUVD_CGC_CTRL__MPBE0_MODE__SHIFT                                                                  0xd
 #define UVD_SUVD_CGC_CTRL__MPBE1_MODE__SHIFT                                                                  0xe
+#define UVD_SUVD_CGC_CTRL__SIT_AV1_MODE__SHIFT                                                                0xf
+#define UVD_SUVD_CGC_CTRL__SDB_AV1_MODE__SHIFT                                                                0x10
 #define UVD_SUVD_CGC_CTRL__MPC1_MODE__SHIFT                                                                   0x11
 #define UVD_SUVD_CGC_CTRL__FBC_PCLK__SHIFT                                                                    0x1c
 #define UVD_SUVD_CGC_CTRL__FBC_CCLK__SHIFT                                                                    0x1d
 #define UVD_SUVD_CGC_CTRL__SMPA_MODE_MASK                                                                     0x00001000L
 #define UVD_SUVD_CGC_CTRL__MPBE0_MODE_MASK                                                                    0x00002000L
 #define UVD_SUVD_CGC_CTRL__MPBE1_MODE_MASK                                                                    0x00004000L
+#define UVD_SUVD_CGC_CTRL__SIT_AV1_MODE_MASK                                                                  0x00008000L
+#define UVD_SUVD_CGC_CTRL__SDB_AV1_MODE_MASK                                                                  0x00010000L
 #define UVD_SUVD_CGC_CTRL__MPC1_MODE_MASK                                                                     0x00020000L
 #define UVD_SUVD_CGC_CTRL__FBC_PCLK_MASK                                                                      0x10000000L
 #define UVD_SUVD_CGC_CTRL__FBC_CCLK_MASK                                                                      0x20000000L
 #define UVD_SUVD_CGC_STATUS2__SMPA_VCLK__SHIFT                                                                0x0
 #define UVD_SUVD_CGC_STATUS2__SMPA_DCLK__SHIFT                                                                0x1
 #define UVD_SUVD_CGC_STATUS2__MPBE1_DCLK__SHIFT                                                               0x3
+#define UVD_SUVD_CGC_STATUS2__SIT_AV1_DCLK__SHIFT                                                             0x4
+#define UVD_SUVD_CGC_STATUS2__SDB_AV1_DCLK__SHIFT                                                             0x5
 #define UVD_SUVD_CGC_STATUS2__MPC1_DCLK__SHIFT                                                                0x6
 #define UVD_SUVD_CGC_STATUS2__MPC1_SCLK__SHIFT                                                                0x7
 #define UVD_SUVD_CGC_STATUS2__MPC1_VCLK__SHIFT                                                                0x8
 #define UVD_SUVD_CGC_STATUS2__SMPA_VCLK_MASK                                                                  0x00000001L
 #define UVD_SUVD_CGC_STATUS2__SMPA_DCLK_MASK                                                                  0x00000002L
 #define UVD_SUVD_CGC_STATUS2__MPBE1_DCLK_MASK                                                                 0x00000008L
+#define UVD_SUVD_CGC_STATUS2__SIT_AV1_DCLK_MASK                                                               0x00000010L
+#define UVD_SUVD_CGC_STATUS2__SDB_AV1_DCLK_MASK                                                               0x00000020L
 #define UVD_SUVD_CGC_STATUS2__MPC1_DCLK_MASK                                                                  0x00000040L
 #define UVD_SUVD_CGC_STATUS2__MPC1_SCLK_MASK                                                                  0x00000080L
 #define UVD_SUVD_CGC_STATUS2__MPC1_VCLK_MASK                                                                  0x00000100L
 //UVD_SUVD_CGC_GATE2
 #define UVD_SUVD_CGC_GATE2__MPBE0__SHIFT                                                                      0x0
 #define UVD_SUVD_CGC_GATE2__MPBE1__SHIFT                                                                      0x1
+#define UVD_SUVD_CGC_GATE2__SIT_AV1__SHIFT                                                                    0x2
+#define UVD_SUVD_CGC_GATE2__SDB_AV1__SHIFT                                                                    0x3
 #define UVD_SUVD_CGC_GATE2__MPC1__SHIFT                                                                       0x4
 #define UVD_SUVD_CGC_GATE2__MPBE0_MASK                                                                        0x00000001L
 #define UVD_SUVD_CGC_GATE2__MPBE1_MASK                                                                        0x00000002L
+#define UVD_SUVD_CGC_GATE2__SIT_AV1_MASK                                                                      0x00000004L
+#define UVD_SUVD_CGC_GATE2__SDB_AV1_MASK                                                                      0x00000008L
 #define UVD_SUVD_CGC_GATE2__MPC1_MASK                                                                         0x00000010L
 //UVD_SUVD_INT_STATUS2
 #define UVD_SUVD_INT_STATUS2__SMPA_FUNC_INT__SHIFT                                                            0x0
 #define UVD_SUVD_INT_STATUS2__SMPA_ERR_INT__SHIFT                                                             0x5
+#define UVD_SUVD_INT_STATUS2__SDB_AV1_FUNC_INT__SHIFT                                                         0x6
+#define UVD_SUVD_INT_STATUS2__SDB_AV1_ERR_INT__SHIFT                                                          0xb
 #define UVD_SUVD_INT_STATUS2__SMPA_FUNC_INT_MASK                                                              0x0000001FL
 #define UVD_SUVD_INT_STATUS2__SMPA_ERR_INT_MASK                                                               0x00000020L
+#define UVD_SUVD_INT_STATUS2__SDB_AV1_FUNC_INT_MASK                                                           0x000007C0L
+#define UVD_SUVD_INT_STATUS2__SDB_AV1_ERR_INT_MASK                                                            0x00000800L
 //UVD_SUVD_INT_EN2
 #define UVD_SUVD_INT_EN2__SMPA_FUNC_INT_EN__SHIFT                                                             0x0
 #define UVD_SUVD_INT_EN2__SMPA_ERR_INT_EN__SHIFT                                                              0x5
+#define UVD_SUVD_INT_EN2__SDB_AV1_FUNC_INT_EN__SHIFT                                                          0x6
+#define UVD_SUVD_INT_EN2__SDB_AV1_ERR_INT_EN__SHIFT                                                           0xb
 #define UVD_SUVD_INT_EN2__SMPA_FUNC_INT_EN_MASK                                                               0x0000001FL
 #define UVD_SUVD_INT_EN2__SMPA_ERR_INT_EN_MASK                                                                0x00000020L
+#define UVD_SUVD_INT_EN2__SDB_AV1_FUNC_INT_EN_MASK                                                            0x000007C0L
+#define UVD_SUVD_INT_EN2__SDB_AV1_ERR_INT_EN_MASK                                                             0x00000800L
 //UVD_SUVD_INT_ACK2
 #define UVD_SUVD_INT_ACK2__SMPA_FUNC_INT_ACK__SHIFT                                                           0x0
 #define UVD_SUVD_INT_ACK2__SMPA_ERR_INT_ACK__SHIFT                                                            0x5
+#define UVD_SUVD_INT_ACK2__SDB_AV1_FUNC_INT_ACK__SHIFT                                                        0x6
+#define UVD_SUVD_INT_ACK2__SDB_AV1_ERR_INT_ACK__SHIFT                                                         0xb
 #define UVD_SUVD_INT_ACK2__SMPA_FUNC_INT_ACK_MASK                                                             0x0000001FL
 #define UVD_SUVD_INT_ACK2__SMPA_ERR_INT_ACK_MASK                                                              0x00000020L
+#define UVD_SUVD_INT_ACK2__SDB_AV1_FUNC_INT_ACK_MASK                                                          0x000007C0L
+#define UVD_SUVD_INT_ACK2__SDB_AV1_ERR_INT_ACK_MASK                                                           0x00000800L
 
 
 // addressBlock: uvd0_ecpudec
index a3c238c..301de49 100644 (file)
@@ -226,7 +226,7 @@ struct kfd2kgd_calls {
                        uint32_t sh_mem_config, uint32_t sh_mem_ape1_base,
                        uint32_t sh_mem_ape1_limit, uint32_t sh_mem_bases);
 
-       int (*set_pasid_vmid_mapping)(struct kgd_dev *kgd, unsigned int pasid,
+       int (*set_pasid_vmid_mapping)(struct kgd_dev *kgd, u32 pasid,
                                        unsigned int vmid);
 
        int (*init_interrupts)(struct kgd_dev *kgd, uint32_t pipe_id);
index 0826625..8dc5abb 100644 (file)
@@ -479,17 +479,6 @@ static int smu_late_init(void *handle)
                return ret;
        }
 
-       /*
-        * Set initialized values (get from vbios) to dpm tables context such as
-        * gfxclk, memclk, dcefclk, and etc. And enable the DPM feature for each
-        * type of clks.
-        */
-       ret = smu_set_default_dpm_table(smu);
-       if (ret) {
-               dev_err(adev->dev, "Failed to setup default dpm clock tables!\n");
-               return ret;
-       }
-
        ret = smu_populate_umd_state_clk(smu);
        if (ret) {
                dev_err(adev->dev, "Failed to populate UMD state clocks!\n");
@@ -984,6 +973,17 @@ static int smu_smc_hw_setup(struct smu_context *smu)
                return ret;
        }
 
+       /*
+        * Set initialized values (get from vbios) to dpm tables context such as
+        * gfxclk, memclk, dcefclk, and etc. And enable the DPM feature for each
+        * type of clks.
+        */
+       ret = smu_set_default_dpm_table(smu);
+       if (ret) {
+               dev_err(adev->dev, "Failed to setup default dpm clock tables!\n");
+               return ret;
+       }
+
        ret = smu_notify_display_change(smu);
        if (ret)
                return ret;
@@ -1126,7 +1126,7 @@ static int smu_disable_dpms(struct smu_context *smu)
         */
        if (smu->uploading_custom_pp_table &&
            (adev->asic_type >= CHIP_NAVI10) &&
-           (adev->asic_type <= CHIP_NAVI12))
+           (adev->asic_type <= CHIP_NAVY_FLOUNDER))
                return 0;
 
        /*
@@ -1211,7 +1211,9 @@ static int smu_hw_fini(void *handle)
 int smu_reset(struct smu_context *smu)
 {
        struct amdgpu_device *adev = smu->adev;
-       int ret = 0;
+       int ret;
+
+       amdgpu_gfx_off_ctrl(smu->adev, false);
 
        ret = smu_hw_fini(adev);
        if (ret)
@@ -1222,8 +1224,12 @@ int smu_reset(struct smu_context *smu)
                return ret;
 
        ret = smu_late_init(adev);
+       if (ret)
+               return ret;
 
-       return ret;
+       amdgpu_gfx_off_ctrl(smu->adev, true);
+
+       return 0;
 }
 
 static int smu_suspend(void *handle)
index fb962b9..9582b38 100644 (file)
@@ -1840,10 +1840,14 @@ static bool arcturus_is_dpm_running(struct smu_context *smu)
 {
        int ret = 0;
        uint32_t feature_mask[2];
-       unsigned long feature_enabled;
+       uint64_t feature_enabled;
+
        ret = smu_cmn_get_enabled_mask(smu, feature_mask, 2);
-       feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
-                          ((uint64_t)feature_mask[1] << 32));
+       if (ret)
+               return false;
+
+       feature_enabled = (uint64_t)feature_mask[1] << 32 | feature_mask[0];
+
        return !!(feature_enabled & SMC_DPM_FEATURE);
 }
 
index c9cfe90..43f7adf 100644 (file)
@@ -204,8 +204,7 @@ static int smu10_set_min_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clo
 {
        struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
 
-       if (smu10_data->need_min_deep_sleep_dcefclk &&
-               smu10_data->deep_sleep_dcefclk != clock) {
+       if (clock && smu10_data->deep_sleep_dcefclk != clock) {
                smu10_data->deep_sleep_dcefclk = clock;
                smum_send_msg_to_smc_with_parameter(hwmgr,
                                        PPSMC_MSG_SetMinDeepSleepDcefclk,
@@ -219,8 +218,7 @@ static int smu10_set_hard_min_dcefclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t c
 {
        struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
 
-       if (smu10_data->dcf_actual_hard_min_freq &&
-               smu10_data->dcf_actual_hard_min_freq != clock) {
+       if (clock && smu10_data->dcf_actual_hard_min_freq != clock) {
                smu10_data->dcf_actual_hard_min_freq = clock;
                smum_send_msg_to_smc_with_parameter(hwmgr,
                                        PPSMC_MSG_SetHardMinDcefclkByFreq,
@@ -234,8 +232,7 @@ static int smu10_set_hard_min_fclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t cloc
 {
        struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
 
-       if (smu10_data->f_actual_hard_min_freq &&
-               smu10_data->f_actual_hard_min_freq != clock) {
+       if (clock && smu10_data->f_actual_hard_min_freq != clock) {
                smu10_data->f_actual_hard_min_freq = clock;
                smum_send_msg_to_smc_with_parameter(hwmgr,
                                        PPSMC_MSG_SetHardMinFclkByFreq,
@@ -566,6 +563,8 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
        struct smu10_hwmgr *data = hwmgr->backend;
        uint32_t min_sclk = hwmgr->display_config->min_core_set_clock;
        uint32_t min_mclk = hwmgr->display_config->min_mem_set_clock/100;
+       uint32_t index_fclk = data->clock_vol_info.vdd_dep_on_fclk->count - 1;
+       uint32_t index_socclk = data->clock_vol_info.vdd_dep_on_socclk->count - 1;
 
        if (hwmgr->smu_version < 0x1E3700) {
                pr_info("smu firmware version too old, can not set dpm level\n");
@@ -679,13 +678,13 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
                smum_send_msg_to_smc_with_parameter(hwmgr,
                                                PPSMC_MSG_SetHardMinFclkByFreq,
                                                hwmgr->display_config->num_display > 3 ?
-                                               SMU10_UMD_PSTATE_PEAK_FCLK :
+                                               data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk :
                                                min_mclk,
                                                NULL);
 
                smum_send_msg_to_smc_with_parameter(hwmgr,
                                                PPSMC_MSG_SetHardMinSocclkByFreq,
-                                               SMU10_UMD_PSTATE_MIN_SOCCLK,
+                                               data->clock_vol_info.vdd_dep_on_socclk->entries[0].clk,
                                                NULL);
                smum_send_msg_to_smc_with_parameter(hwmgr,
                                                PPSMC_MSG_SetHardMinVcn,
@@ -698,11 +697,11 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
                                                NULL);
                smum_send_msg_to_smc_with_parameter(hwmgr,
                                                PPSMC_MSG_SetSoftMaxFclkByFreq,
-                                               SMU10_UMD_PSTATE_PEAK_FCLK,
+                                               data->clock_vol_info.vdd_dep_on_fclk->entries[index_fclk].clk,
                                                NULL);
                smum_send_msg_to_smc_with_parameter(hwmgr,
                                                PPSMC_MSG_SetSoftMaxSocclkByFreq,
-                                               SMU10_UMD_PSTATE_PEAK_SOCCLK,
+                                               data->clock_vol_info.vdd_dep_on_socclk->entries[index_socclk].clk,
                                                NULL);
                smum_send_msg_to_smc_with_parameter(hwmgr,
                                                PPSMC_MSG_SetSoftMaxVcn,
index ffe05b7..4a3b64a 100644 (file)
@@ -3581,7 +3581,8 @@ static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx,
        case AMDGPU_PP_SENSOR_GPU_POWER:
                return smu7_get_gpu_power(hwmgr, (uint32_t *)value);
        case AMDGPU_PP_SENSOR_VDDGFX:
-               if ((data->vr_config & 0xff) == 0x2)
+               if ((data->vr_config & VRCONF_VDDGFX_MASK) ==
+                   (VR_SVI2_PLANE_2 << VRCONF_VDDGFX_SHIFT))
                        val_vid = PHM_READ_INDIRECT_FIELD(hwmgr->device,
                                        CGS_IND_REG__SMC, PWR_SVI2_STATUS, PLANE2_VID);
                else
index 468bdd6..952cd3d 100644 (file)
@@ -363,17 +363,29 @@ int vega10_thermal_get_temperature(struct pp_hwmgr *hwmgr)
 static int vega10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
                struct PP_TemperatureRange *range)
 {
+       struct phm_ppt_v2_information *pp_table_info =
+               (struct phm_ppt_v2_information *)(hwmgr->pptable);
+       struct phm_tdp_table *tdp_table = pp_table_info->tdp_table;
        struct amdgpu_device *adev = hwmgr->adev;
-       int low = VEGA10_THERMAL_MINIMUM_ALERT_TEMP *
-                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-       int high = VEGA10_THERMAL_MAXIMUM_ALERT_TEMP *
-                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       int low = VEGA10_THERMAL_MINIMUM_ALERT_TEMP;
+       int high = VEGA10_THERMAL_MAXIMUM_ALERT_TEMP;
        uint32_t val;
 
-       if (low < range->min)
-               low = range->min;
-       if (high > range->max)
-               high = range->max;
+       /* compare them in unit celsius degree */
+       if (low < range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)
+               low = range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+       /*
+        * As a common sense, usSoftwareShutdownTemp should be bigger
+        * than ThotspotLimit. For any invalid usSoftwareShutdownTemp,
+        * we will just use the max possible setting VEGA10_THERMAL_MAXIMUM_ALERT_TEMP
+        * to avoid false alarms.
+        */
+       if ((tdp_table->usSoftwareShutdownTemp >
+            range->hotspot_crit_max / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)) {
+               if (high > tdp_table->usSoftwareShutdownTemp)
+                       high = tdp_table->usSoftwareShutdownTemp;
+       }
 
        if (low > high)
                return -EINVAL;
@@ -382,8 +394,8 @@ static int vega10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
 
        val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5);
        val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1);
-       val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-       val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+       val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, high);
+       val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, low);
        val &= (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK) &
                        (~THM_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK) &
                        (~THM_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK);
index c15b975..7ace439 100644 (file)
@@ -170,17 +170,18 @@ int vega12_thermal_get_temperature(struct pp_hwmgr *hwmgr)
 static int vega12_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
                struct PP_TemperatureRange *range)
 {
+       struct phm_ppt_v3_information *pptable_information =
+               (struct phm_ppt_v3_information *)hwmgr->pptable;
        struct amdgpu_device *adev = hwmgr->adev;
-       int low = VEGA12_THERMAL_MINIMUM_ALERT_TEMP *
-                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-       int high = VEGA12_THERMAL_MAXIMUM_ALERT_TEMP *
-                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       int low = VEGA12_THERMAL_MINIMUM_ALERT_TEMP;
+       int high = VEGA12_THERMAL_MAXIMUM_ALERT_TEMP;
        uint32_t val;
 
-       if (low < range->min)
-               low = range->min;
-       if (high > range->max)
-               high = range->max;
+       /* compare them in unit celsius degree */
+       if (low < range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)
+               low = range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       if (high > pptable_information->us_software_shutdown_temp)
+               high = pptable_information->us_software_shutdown_temp;
 
        if (low > high)
                return -EINVAL;
@@ -189,8 +190,8 @@ static int vega12_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
 
        val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5);
        val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1);
-       val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-       val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+       val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, high);
+       val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, low);
        val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
 
        WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val);
index 7add2f6..364162d 100644 (file)
@@ -240,17 +240,18 @@ int vega20_thermal_get_temperature(struct pp_hwmgr *hwmgr)
 static int vega20_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
                struct PP_TemperatureRange *range)
 {
+       struct phm_ppt_v3_information *pptable_information =
+               (struct phm_ppt_v3_information *)hwmgr->pptable;
        struct amdgpu_device *adev = hwmgr->adev;
-       int low = VEGA20_THERMAL_MINIMUM_ALERT_TEMP *
-                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
-       int high = VEGA20_THERMAL_MAXIMUM_ALERT_TEMP *
-                       PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       int low = VEGA20_THERMAL_MINIMUM_ALERT_TEMP;
+       int high = VEGA20_THERMAL_MAXIMUM_ALERT_TEMP;
        uint32_t val;
 
-       if (low < range->min)
-               low = range->min;
-       if (high > range->max)
-               high = range->max;
+       /* compare them in unit celsius degree */
+       if (low < range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)
+               low = range->min / PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       if (high > pptable_information->us_software_shutdown_temp)
+               high = pptable_information->us_software_shutdown_temp;
 
        if (low > high)
                return -EINVAL;
@@ -259,8 +260,8 @@ static int vega20_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
 
        val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5);
        val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1);
-       val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
-       val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
+       val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, high);
+       val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, low);
        val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
 
        WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val);
index 9f62af9..b1547a8 100644 (file)
@@ -1331,10 +1331,14 @@ static bool navi10_is_dpm_running(struct smu_context *smu)
 {
        int ret = 0;
        uint32_t feature_mask[2];
-       unsigned long feature_enabled;
+       uint64_t feature_enabled;
+
        ret = smu_cmn_get_enabled_mask(smu, feature_mask, 2);
-       feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
-                          ((uint64_t)feature_mask[1] << 32));
+       if (ret)
+               return false;
+
+       feature_enabled = (uint64_t)feature_mask[1] << 32 | feature_mask[0];
+
        return !!(feature_enabled & SMC_DPM_FEATURE);
 }
 
@@ -2261,8 +2265,6 @@ static void navi10_fill_i2c_req(SwI2cRequest_t  *req, bool write,
 {
        int i;
 
-       BUG_ON(numbytes > MAX_SW_I2C_COMMANDS);
-
        req->I2CcontrollerPort = 0;
        req->I2CSpeed = 2;
        req->SlaveAddress = address;
@@ -2300,6 +2302,12 @@ static int navi10_i2c_read_data(struct i2c_adapter *control,
        struct smu_table_context *smu_table = &adev->smu.smu_table;
        struct smu_table *table = &smu_table->driver_table;
 
+       if (numbytes > MAX_SW_I2C_COMMANDS) {
+               dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n",
+                       numbytes, MAX_SW_I2C_COMMANDS);
+               return -EINVAL;
+       }
+
        memset(&req, 0, sizeof(req));
        navi10_fill_i2c_req(&req, false, address, numbytes, data);
 
@@ -2336,6 +2344,12 @@ static int navi10_i2c_write_data(struct i2c_adapter *control,
        SwI2cRequest_t req;
        struct amdgpu_device *adev = to_amdgpu_device(control);
 
+       if (numbytes > MAX_SW_I2C_COMMANDS) {
+               dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n",
+                       numbytes, MAX_SW_I2C_COMMANDS);
+               return -EINVAL;
+       }
+
        memset(&req, 0, sizeof(req));
        navi10_fill_i2c_req(&req, true, address, numbytes, data);
 
index dbb676c..15263cf 100644 (file)
@@ -232,14 +232,16 @@ static int renoir_get_profiling_clk_mask(struct smu_context *smu,
                        *sclk_mask = 0;
        } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
                if (mclk_mask)
-                       *mclk_mask = 0;
+                       /* mclk levels are in reverse order */
+                       *mclk_mask = NUM_MEMCLK_DPM_LEVELS - 1;
        } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
                if(sclk_mask)
                        /* The sclk as gfxclk and has three level about max/min/current */
                        *sclk_mask = 3 - 1;
 
                if(mclk_mask)
-                       *mclk_mask = NUM_MEMCLK_DPM_LEVELS - 1;
+                       /* mclk levels are in reverse order */
+                       *mclk_mask = 0;
 
                if(soc_mask)
                        *soc_mask = NUM_SOCCLK_DPM_LEVELS - 1;
@@ -333,7 +335,7 @@ static int renoir_get_dpm_ultimate_freq(struct smu_context *smu,
                case SMU_UCLK:
                case SMU_FCLK:
                case SMU_MCLK:
-                       ret = renoir_get_dpm_clk_limited(smu, clk_type, 0, min);
+                       ret = renoir_get_dpm_clk_limited(smu, clk_type, NUM_MEMCLK_DPM_LEVELS - 1, min);
                        if (ret)
                                goto failed;
                        break;
index 3865dbe..ace682f 100644 (file)
@@ -68,7 +68,8 @@
        FEATURE_MASK(FEATURE_DPM_LINK_BIT)       | \
        FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT)     | \
        FEATURE_MASK(FEATURE_DPM_FCLK_BIT)       | \
-       FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT))
+       FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)    | \
+       FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT))
 
 #define SMU_11_0_7_GFX_BUSY_THRESHOLD 15
 
@@ -95,6 +96,7 @@ static struct cmn2asic_msg_mapping sienna_cichlid_message_map[SMU_MSG_MAX_COUNT]
        MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,       0),
        MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,       0),
        MSG_MAP(UseDefaultPPTable,              PPSMC_MSG_UseDefaultPPTable,           0),
+       MSG_MAP(RunDcBtc,                       PPSMC_MSG_RunDcBtc,                    0),
        MSG_MAP(EnterBaco,                      PPSMC_MSG_EnterBaco,                   0),
        MSG_MAP(SetSoftMinByFreq,               PPSMC_MSG_SetSoftMinByFreq,            0),
        MSG_MAP(SetSoftMaxByFreq,               PPSMC_MSG_SetSoftMaxByFreq,            0),
@@ -228,6 +230,7 @@ sienna_cichlid_get_allowed_feature_mask(struct smu_context *smu,
 
        *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT)
                                | FEATURE_MASK(FEATURE_DPM_FCLK_BIT)
+                               | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)
                                | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT)
                                | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT)
                                | FEATURE_MASK(FEATURE_DS_FCLK_BIT)
@@ -775,7 +778,7 @@ static int sienna_cichlid_dpm_set_vcn_enable(struct smu_context *smu, bool enabl
                        ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0, NULL);
                        if (ret)
                                return ret;
-                       if (adev->asic_type == CHIP_SIENNA_CICHLID) {
+                       if (adev->vcn.num_vcn_inst > 1) {
                                ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn,
                                                                  0x10000, NULL);
                                if (ret)
@@ -787,7 +790,7 @@ static int sienna_cichlid_dpm_set_vcn_enable(struct smu_context *smu, bool enabl
                        ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn, 0, NULL);
                        if (ret)
                                return ret;
-                       if (adev->asic_type == CHIP_SIENNA_CICHLID) {
+                       if (adev->vcn.num_vcn_inst > 1) {
                                ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn,
                                                                  0x10000, NULL);
                                if (ret)
@@ -1146,10 +1149,14 @@ static bool sienna_cichlid_is_dpm_running(struct smu_context *smu)
 {
        int ret = 0;
        uint32_t feature_mask[2];
-       unsigned long feature_enabled;
+       uint64_t feature_enabled;
+
        ret = smu_cmn_get_enabled_mask(smu, feature_mask, 2);
-       feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
-                          ((uint64_t)feature_mask[1] << 32));
+       if (ret)
+               return false;
+
+       feature_enabled = (uint64_t)feature_mask[1] << 32 | feature_mask[0];
+
        return !!(feature_enabled & SMC_DPM_FEATURE);
 }
 
@@ -1732,6 +1739,11 @@ static int sienna_cichlid_get_dpm_ultimate_freq(struct smu_context *smu,
        return ret;
 }
 
+static int sienna_cichlid_run_btc(struct smu_context *smu)
+{
+       return smu_cmn_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL);
+}
+
 static bool sienna_cichlid_is_baco_supported(struct smu_context *smu)
 {
        struct amdgpu_device *adev = smu->adev;
@@ -2433,8 +2445,6 @@ static void sienna_cichlid_fill_i2c_req(SwI2cRequest_t  *req, bool write,
 {
        int i;
 
-       BUG_ON(numbytes > MAX_SW_I2C_COMMANDS);
-
        req->I2CcontrollerPort = 0;
        req->I2CSpeed = 2;
        req->SlaveAddress = address;
@@ -2472,6 +2482,12 @@ static int sienna_cichlid_i2c_read_data(struct i2c_adapter *control,
        struct smu_table_context *smu_table = &adev->smu.smu_table;
        struct smu_table *table = &smu_table->driver_table;
 
+       if (numbytes > MAX_SW_I2C_COMMANDS) {
+               dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n",
+                       numbytes, MAX_SW_I2C_COMMANDS);
+               return -EINVAL;
+       }
+
        memset(&req, 0, sizeof(req));
        sienna_cichlid_fill_i2c_req(&req, false, address, numbytes, data);
 
@@ -2508,6 +2524,12 @@ static int sienna_cichlid_i2c_write_data(struct i2c_adapter *control,
        SwI2cRequest_t req;
        struct amdgpu_device *adev = to_amdgpu_device(control);
 
+       if (numbytes > MAX_SW_I2C_COMMANDS) {
+               dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n",
+                       numbytes, MAX_SW_I2C_COMMANDS);
+               return -EINVAL;
+       }
+
        memset(&req, 0, sizeof(req));
        sienna_cichlid_fill_i2c_req(&req, true, address, numbytes, data);
 
@@ -2719,6 +2741,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
        .mode1_reset = smu_v11_0_mode1_reset,
        .get_dpm_ultimate_freq = sienna_cichlid_get_dpm_ultimate_freq,
        .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
+       .run_btc = sienna_cichlid_run_btc,
        .get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
        .set_pp_feature_mask = smu_cmn_set_pp_feature_mask,
 };
index c18169a..e4d1f3d 100644 (file)
@@ -37,6 +37,7 @@
 #include "cgs_common.h"
 #include "atombios.h"
 #include "pppcielanes.h"
+#include "smu7_smumgr.h"
 
 #include "smu/smu_7_0_1_d.h"
 #include "smu/smu_7_0_1_sh_mask.h"
@@ -2948,6 +2949,7 @@ const struct pp_smumgr_func ci_smu_funcs = {
        .request_smu_load_specific_fw = NULL,
        .send_msg_to_smc = ci_send_msg_to_smc,
        .send_msg_to_smc_with_parameter = ci_send_msg_to_smc_with_parameter,
+       .get_argument = smu7_get_argument,
        .download_pptable_settings = NULL,
        .upload_pptable_settings = NULL,
        .get_offsetof = ci_get_offsetof,
index ca570b1..e9de542 100644 (file)
@@ -532,7 +532,7 @@ static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
                malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
                malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
                malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
-               /* fall through */
+               fallthrough;
        case 1:
                malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
                malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
@@ -869,7 +869,7 @@ static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
                malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
                malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
                malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
-               /* fall through */
+               fallthrough;
        case 1:
                malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
                malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
@@ -1324,7 +1324,7 @@ static irqreturn_t malidp_se_irq(int irq, void *arg)
                        break;
                case MW_RESTART:
                        drm_writeback_signal_completion(&malidp->mw_connector, 0);
-                       /* fall through - to a new start */
+                       fallthrough;    /* to a new start */
                case MW_START:
                        /* writeback started, need to emulate one-shot mode */
                        hw->disable_memwrite(hwdev);
index dd12b55..6a9fba0 100644 (file)
@@ -238,7 +238,7 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
                                        ast->dp501_fw_addr = NULL;
                                }
                        }
-                       /* fallthrough */
+                       fallthrough;
                case 0x0c:
                        ast->tx_chip_type = AST_TX_DP501;
                }
index ce94f79..66b6740 100644 (file)
@@ -409,7 +409,6 @@ static bool nwl_dsi_read_packet(struct nwl_dsi *dsi, u32 status)
 
                switch (data_type) {
                case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
-                       fallthrough;
                case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
                        if (xfer->msg->rx_len > 1) {
                                /* read second byte */
@@ -418,7 +417,6 @@ static bool nwl_dsi_read_packet(struct nwl_dsi *dsi, u32 status)
                        }
                        fallthrough;
                case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
-                       fallthrough;
                case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
                        if (xfer->msg->rx_len > 0) {
                                /* read first byte */
index d7e65c8..9fef641 100644 (file)
@@ -61,10 +61,10 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
        switch (hparms->channels) {
        case 7 ... 8:
                conf0 |= HDMI_AUD_CONF0_I2S_EN3;
-               /* Fall-thru */
+               fallthrough;
        case 5 ... 6:
                conf0 |= HDMI_AUD_CONF0_I2S_EN2;
-               /* Fall-thru */
+               fallthrough;
        case 3 ... 4:
                conf0 |= HDMI_AUD_CONF0_I2S_EN1;
                /* Fall-thru */
index 86b9f0f..5b6e19e 100644 (file)
@@ -604,13 +604,13 @@ static void ti_sn_bridge_read_valid_rates(struct ti_sn_bridge *pdata,
                DRM_DEV_ERROR(pdata->dev,
                              "Unexpected max rate (%#x); assuming 5.4 GHz\n",
                              (int)dpcd_val);
-               /* fall through */
+               fallthrough;
        case DP_LINK_BW_5_4:
                rate_valid[7] = 1;
-               /* fall through */
+               fallthrough;
        case DP_LINK_BW_2_7:
                rate_valid[4] = 1;
-               /* fall through */
+               fallthrough;
        case DP_LINK_BW_1_62:
                rate_valid[1] = 1;
                break;
index f68c69a..9e1ad49 100644 (file)
@@ -34,6 +34,7 @@
 #include <drm/drm_bridge.h>
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_device.h>
+#include <drm/drm_drv.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_print.h>
 #include <drm/drm_self_refresh_helper.h>
@@ -3106,7 +3107,7 @@ void drm_atomic_helper_shutdown(struct drm_device *dev)
        if (ret)
                DRM_ERROR("Disabling all crtc's during unload failed with %i\n", ret);
 
-       DRM_MODESET_LOCK_ALL_END(ctx, ret);
+       DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
 }
 EXPORT_SYMBOL(drm_atomic_helper_shutdown);
 
@@ -3246,7 +3247,7 @@ struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev)
        }
 
 unlock:
-       DRM_MODESET_LOCK_ALL_END(ctx, err);
+       DRM_MODESET_LOCK_ALL_END(dev, ctx, err);
        if (err)
                return ERR_PTR(err);
 
@@ -3327,7 +3328,7 @@ int drm_atomic_helper_resume(struct drm_device *dev,
 
        err = drm_atomic_helper_commit_duplicated_state(state, &ctx);
 
-       DRM_MODESET_LOCK_ALL_END(ctx, err);
+       DRM_MODESET_LOCK_ALL_END(dev, ctx, err);
        drm_atomic_state_put(state);
 
        return err;
index a0735fb..7a01d09 100644 (file)
@@ -537,7 +537,7 @@ int drm_legacy_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
        switch (map->type) {
        case _DRM_REGISTERS:
                iounmap(map->handle);
-               /* FALLTHROUGH */
+               fallthrough;
        case _DRM_FRAME_BUFFER:
                arch_phys_wc_del(map->mtrr);
                break;
index c93123f..138ff34 100644 (file)
@@ -294,7 +294,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
                                     crtc->gamma_size, &ctx);
 
 out:
-       DRM_MODESET_LOCK_ALL_END(ctx, ret);
+       DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
        return ret;
 
 }
index 283bcc4..aecdd7e 100644 (file)
@@ -588,7 +588,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
        if (crtc_req->mode_valid && !drm_lease_held(file_priv, plane->base.id))
                return -EACCES;
 
-       mutex_lock(&crtc->dev->mode_config.mutex);
        DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx,
                                   DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
 
@@ -756,8 +755,7 @@ out:
        fb = NULL;
        mode = NULL;
 
-       DRM_MODESET_LOCK_ALL_END(ctx, ret);
-       mutex_unlock(&crtc->dev->mode_config.mutex);
+       DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
 
        return ret;
 }
index a3c82e7..092c8c9 100644 (file)
@@ -492,7 +492,7 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
                case DP_DS_16BPC:
                        return 16;
                }
-               /* fall through */
+               fallthrough;
        default:
                return 0;
        }
index b23cb2f..67dd72e 100644 (file)
@@ -5040,8 +5040,8 @@ int drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, struct drm
 
                crtc = conn_state->crtc;
 
-               if (WARN_ON(!crtc))
-                       return -EINVAL;
+               if (!crtc)
+                       continue;
 
                if (!drm_dp_mst_dsc_aux_for_port(pos->port))
                        continue;
index 901b078..db05f38 100644 (file)
@@ -428,7 +428,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 out_unref:
        drm_mode_object_put(obj);
 out:
-       DRM_MODESET_LOCK_ALL_END(ctx, ret);
+       DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
        return ret;
 }
 
@@ -470,7 +470,7 @@ static int set_property_legacy(struct drm_mode_object *obj,
                break;
        }
        drm_property_change_valid_put(prop, ref);
-       DRM_MODESET_LOCK_ALL_END(ctx, ret);
+       DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
 
        return ret;
 }
index 14b6f76..501b4fe 100644 (file)
@@ -1930,7 +1930,7 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
        default:
                WARN(1, "Invalid aspect ratio (0%x) on mode\n",
                     in->picture_aspect_ratio);
-               /* fall through */
+               fallthrough;
        case HDMI_PICTURE_ASPECT_NONE:
                out->flags |= DRM_MODE_FLAG_PIC_AR_NONE;
                break;
index b7b90b3..affe1cf 100644 (file)
@@ -792,7 +792,7 @@ static int setplane_internal(struct drm_plane *plane,
                                          crtc_x, crtc_y, crtc_w, crtc_h,
                                          src_x, src_y, src_w, src_h, &ctx);
 
-       DRM_MODESET_LOCK_ALL_END(ctx, ret);
+       DRM_MODESET_LOCK_ALL_END(plane->dev, ctx, ret);
 
        return ret;
 }
index d5a4cd8..c6404b8 100644 (file)
@@ -337,9 +337,16 @@ static void etnaviv_hw_identify(struct etnaviv_gpu *gpu)
 
                gpu->identity.model = gpu_read(gpu, VIVS_HI_CHIP_MODEL);
                gpu->identity.revision = gpu_read(gpu, VIVS_HI_CHIP_REV);
-               gpu->identity.product_id = gpu_read(gpu, VIVS_HI_CHIP_PRODUCT_ID);
                gpu->identity.customer_id = gpu_read(gpu, VIVS_HI_CHIP_CUSTOMER_ID);
-               gpu->identity.eco_id = gpu_read(gpu, VIVS_HI_CHIP_ECO_ID);
+
+               /*
+                * Reading these two registers on GC600 rev 0x19 result in a
+                * unhandled fault: external abort on non-linefetch
+                */
+               if (!etnaviv_is_model_rev(gpu, GC600, 0x19)) {
+                       gpu->identity.product_id = gpu_read(gpu, VIVS_HI_CHIP_PRODUCT_ID);
+                       gpu->identity.eco_id = gpu_read(gpu, VIVS_HI_CHIP_ECO_ID);
+               }
 
                /*
                 * !!!! HACK ALERT !!!!
index 4e3e95d..cd46c88 100644 (file)
@@ -89,12 +89,15 @@ static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job)
        u32 dma_addr;
        int change;
 
+       /* block scheduler */
+       drm_sched_stop(&gpu->sched, sched_job);
+
        /*
         * If the GPU managed to complete this jobs fence, the timout is
         * spurious. Bail out.
         */
        if (dma_fence_is_signaled(submit->out_fence))
-               return;
+               goto out_no_timeout;
 
        /*
         * If the GPU is still making forward progress on the front-end (which
@@ -105,12 +108,9 @@ static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job)
        change = dma_addr - gpu->hangcheck_dma_addr;
        if (change < 0 || change > 16) {
                gpu->hangcheck_dma_addr = dma_addr;
-               return;
+               goto out_no_timeout;
        }
 
-       /* block scheduler */
-       drm_sched_stop(&gpu->sched, sched_job);
-
        if(sched_job)
                drm_sched_increase_karma(sched_job);
 
@@ -120,6 +120,7 @@ static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job)
 
        drm_sched_resubmit_jobs(&gpu->sched);
 
+out_no_timeout:
        /* restart scheduler after GPU is usable again */
        drm_sched_start(&gpu->sched, true);
 }
index 7a6f6df..b38e9b5 100644 (file)
@@ -987,10 +987,10 @@ static void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi,
        switch (length) {
        case 3:
                reg |= payload[2] << 16;
-               /* Fall through */
+               fallthrough;
        case 2:
                reg |= payload[1] << 8;
-               /* Fall through */
+               fallthrough;
        case 1:
                reg |= payload[0];
                exynos_dsi_write(dsi, DSIM_PAYLOAD_REG, reg);
@@ -1038,7 +1038,7 @@ static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi,
                                payload[1] = reg >> 16;
                                ++xfer->rx_done;
                        }
-                       /* Fall through */
+                       fallthrough;
                case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
                case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
                        payload[0] = reg >> 8;
@@ -1082,10 +1082,10 @@ static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi,
                switch (length) {
                case 3:
                        payload[2] = (reg >> 16) & 0xff;
-                       /* Fall through */
+                       fallthrough;
                case 2:
                        payload[1] = (reg >> 8) & 0xff;
-                       /* Fall through */
+                       fallthrough;
                case 1:
                        payload[0] = reg & 0xff;
                }
index 56a2b47..5147f59 100644 (file)
@@ -92,7 +92,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
        offset = fbi->var.xoffset * fb->format->cpp[0];
        offset += fbi->var.yoffset * fb->pitches[0];
 
-       fbi->screen_base = exynos_gem->kvaddr + offset;
+       fbi->screen_buffer = exynos_gem->kvaddr + offset;
        fbi->screen_size = size;
        fbi->fix.smem_len = size;
 
index 7445748..74e926a 100644 (file)
@@ -40,7 +40,7 @@ struct exynos_drm_gem {
        unsigned int            flags;
        unsigned long           size;
        void                    *cookie;
-       void __iomem            *kvaddr;
+       void                    *kvaddr;
        dma_addr_t              dma_addr;
        unsigned long           dma_attrs;
        struct sg_table         *sgt;
index 86fac67..3c6d9f3 100644 (file)
@@ -101,19 +101,19 @@ static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
                break;
        case DRM_FORMAT_ARGB8888:
                alpha = DCU_LAYER_AB_WHOLE_FRAME;
-               /* fall-through */
+               fallthrough;
        case DRM_FORMAT_XRGB8888:
                bpp = FSL_DCU_ARGB8888;
                break;
        case DRM_FORMAT_ARGB4444:
                alpha = DCU_LAYER_AB_WHOLE_FRAME;
-               /* fall-through */
+               fallthrough;
        case DRM_FORMAT_XRGB4444:
                bpp = FSL_DCU_ARGB4444;
                break;
        case DRM_FORMAT_ARGB1555:
                alpha = DCU_LAYER_AB_WHOLE_FRAME;
-               /* fall-through */
+               fallthrough;
        case DRM_FORMAT_XRGB1555:
                bpp = FSL_DCU_ARGB1555;
                break;
index 8c55f5b..f4053dd 100644 (file)
@@ -712,7 +712,7 @@ gen11_dsi_configure_transcoder(struct intel_encoder *encoder,
                        switch (intel_dsi->pixel_format) {
                        default:
                                MISSING_CASE(intel_dsi->pixel_format);
-                               /* fallthrough */
+                               fallthrough;
                        case MIPI_DSI_FMT_RGB565:
                                tmp |= PIX_FMT_RGB565;
                                break;
@@ -739,7 +739,7 @@ gen11_dsi_configure_transcoder(struct intel_encoder *encoder,
                        switch (intel_dsi->video_mode_format) {
                        default:
                                MISSING_CASE(intel_dsi->video_mode_format);
-                               /* fallthrough */
+                               fallthrough;
                        case VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS:
                                tmp |= VIDEO_MODE_SYNC_EVENT;
                                break;
@@ -792,7 +792,7 @@ gen11_dsi_configure_transcoder(struct intel_encoder *encoder,
                switch (pipe) {
                default:
                        MISSING_CASE(pipe);
-                       /* fallthrough */
+                       fallthrough;
                case PIPE_A:
                        tmp |= TRANS_DDI_EDP_INPUT_A_ON;
                        break;
index c53c85d..a0a41ec 100644 (file)
@@ -905,7 +905,7 @@ parse_psr(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
                        drm_dbg_kms(&dev_priv->drm,
                                    "VBT tp1 wakeup time value %d is outside range[0-3], defaulting to max value 2500us\n",
                                    psr_table->tp1_wakeup_time);
-                       /* fallthrough */
+                       fallthrough;
                case 2:
                        dev_priv->vbt.psr.tp1_wakeup_time_us = 2500;
                        break;
@@ -925,7 +925,7 @@ parse_psr(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
                        drm_dbg_kms(&dev_priv->drm,
                                    "VBT tp2_tp3 wakeup time value %d is outside range[0-3], defaulting to max value 2500us\n",
                                    psr_table->tp2_tp3_wakeup_time);
-                       /* fallthrough */
+                       fallthrough;
                case 2:
                        dev_priv->vbt.psr.tp2_tp3_wakeup_time_us = 2500;
                break;
@@ -1775,7 +1775,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv,
                switch (child->hdmi_max_data_rate) {
                default:
                        MISSING_CASE(child->hdmi_max_data_rate);
-                       /* fall through */
+                       fallthrough;
                case HDMI_MAX_DATA_RATE_PLATFORM:
                        max_tmds_clock = 0;
                        break;
index bb91dac..91a8161 100644 (file)
@@ -326,7 +326,7 @@ static void pnv_get_cdclk(struct drm_i915_private *dev_priv,
        default:
                drm_err(&dev_priv->drm,
                        "Unknown pnv display core clock 0x%04x\n", gcfgc);
-               /* fall through */
+               fallthrough;
        case GC_DISPLAY_CLOCK_133_MHZ_PNV:
                cdclk_config->cdclk = 133333;
                break;
@@ -766,7 +766,7 @@ static void bdw_set_cdclk(struct drm_i915_private *dev_priv,
        switch (cdclk) {
        default:
                MISSING_CASE(cdclk);
-               /* fall through */
+               fallthrough;
        case 337500:
                val |= LCPLL_CLK_FREQ_337_5_BDW;
                break;
@@ -1042,7 +1042,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv,
                drm_WARN_ON(&dev_priv->drm,
                            cdclk != dev_priv->cdclk.hw.bypass);
                drm_WARN_ON(&dev_priv->drm, vco != 0);
-               /* fall through */
+               fallthrough;
        case 308571:
        case 337500:
                freq_select = CDCLK_FREQ_337_308;
@@ -1333,7 +1333,7 @@ static void icl_readout_refclk(struct drm_i915_private *dev_priv,
        switch (dssm) {
        default:
                MISSING_CASE(dssm);
-               /* fall through */
+               fallthrough;
        case ICL_DSSM_CDCLK_PLL_REFCLK_24MHz:
                cdclk_config->ref = 24000;
                break;
@@ -1561,7 +1561,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
                drm_WARN_ON(&dev_priv->drm,
                            cdclk != dev_priv->cdclk.hw.bypass);
                drm_WARN_ON(&dev_priv->drm, vco != 0);
-               /* fall through */
+               fallthrough;
        case 2:
                divider = BXT_CDCLK_CD2X_DIV_SEL_1;
                break;
index eccaa79..157d8c8 100644 (file)
@@ -52,7 +52,7 @@ cnl_get_procmon_ref_values(struct drm_i915_private *dev_priv, enum phy phy)
        switch (val & (PROCESS_INFO_MASK | VOLTAGE_INFO_MASK)) {
        default:
                MISSING_CASE(val);
-               /* fall through */
+               fallthrough;
        case VOLTAGE_INFO_0_85V | PROCESS_INFO_DOT_0:
                procmon = &cnl_procmon_values[PROCMON_0_85V_DOT_0];
                break;
@@ -258,7 +258,7 @@ static bool phy_is_master(struct drm_i915_private *dev_priv, enum phy phy)
 static bool icl_combo_phy_verify_state(struct drm_i915_private *dev_priv,
                                       enum phy phy)
 {
-       bool ret;
+       bool ret = true;
        u32 expected_val = 0;
 
        if (!icl_combo_phy_enabled(dev_priv, phy))
@@ -276,7 +276,7 @@ static bool icl_combo_phy_verify_state(struct drm_i915_private *dev_priv,
                                     DCC_MODE_SELECT_CONTINUOSLY);
        }
 
-       ret = cnl_verify_procmon_ref_values(dev_priv, phy);
+       ret &= cnl_verify_procmon_ref_values(dev_priv, phy);
 
        if (phy_is_master(dev_priv, phy)) {
                ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW8(phy),
@@ -320,7 +320,7 @@ void intel_combo_phy_power_up_lanes(struct drm_i915_private *dev_priv,
                        break;
                default:
                        MISSING_CASE(lane_count);
-                       /* fall-through */
+                       fallthrough;
                case 4:
                        lane_mask = PWR_UP_ALL_LANES;
                        break;
@@ -337,7 +337,7 @@ void intel_combo_phy_power_up_lanes(struct drm_i915_private *dev_priv,
                        break;
                default:
                        MISSING_CASE(lane_count);
-                       /* fall-through */
+                       fallthrough;
                case 4:
                        lane_mask = PWR_UP_ALL_LANES;
                        break;
index 2c484b5..a49ff3a 100644 (file)
@@ -1888,7 +1888,7 @@ static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
                switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
                default:
                        MISSING_CASE(tmp & TRANS_DDI_EDP_INPUT_MASK);
-                       /* fallthrough */
+                       fallthrough;
                case TRANS_DDI_EDP_INPUT_A_ON:
                case TRANS_DDI_EDP_INPUT_A_ONOFF:
                        *pipe_mask = BIT(PIPE_A);
@@ -4268,7 +4268,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
                        pipe_config->hdmi_scrambling = true;
                if (temp & TRANS_DDI_HIGH_TMDS_CHAR_RATE)
                        pipe_config->hdmi_high_tmds_clock_ratio = true;
-               /* fall through */
+               fallthrough;
        case TRANS_DDI_MODE_SELECT_DVI:
                pipe_config->output_types |= BIT(INTEL_OUTPUT_HDMI);
                pipe_config->lane_count = 4;
index b2ec3a5..b18c5ac 100644 (file)
@@ -2029,12 +2029,12 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
        case I915_FORMAT_MOD_Y_TILED_CCS:
                if (is_ccs_plane(fb, color_plane))
                        return 128;
-               /* fall through */
+               fallthrough;
        case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
        case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
                if (is_ccs_plane(fb, color_plane))
                        return 64;
-               /* fall through */
+               fallthrough;
        case I915_FORMAT_MOD_Y_TILED:
                if (IS_GEN(dev_priv, 2) || HAS_128_BYTE_Y_TILING(dev_priv))
                        return 128;
@@ -2043,7 +2043,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
        case I915_FORMAT_MOD_Yf_TILED_CCS:
                if (is_ccs_plane(fb, color_plane))
                        return 128;
-               /* fall through */
+               fallthrough;
        case I915_FORMAT_MOD_Yf_TILED:
                switch (cpp) {
                case 1:
@@ -2185,7 +2185,7 @@ static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
        case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
                if (is_semiplanar_uv_plane(fb, color_plane))
                        return intel_tile_row_size(fb, color_plane);
-               /* Fall-through */
+               fallthrough;
        case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
                return 16 * 1024;
        case I915_FORMAT_MOD_Y_TILED_CCS:
@@ -2194,7 +2194,7 @@ static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
                if (INTEL_GEN(dev_priv) >= 12 &&
                    is_semiplanar_uv_plane(fb, color_plane))
                        return intel_tile_row_size(fb, color_plane);
-               /* Fall-through */
+               fallthrough;
        case I915_FORMAT_MOD_Yf_TILED:
                return 1 * 1024 * 1024;
        default:
@@ -6211,7 +6211,7 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
        case DRM_FORMAT_ARGB16161616F:
                if (INTEL_GEN(dev_priv) >= 11)
                        break;
-               /* fall through */
+               fallthrough;
        default:
                drm_dbg_kms(&dev_priv->drm,
                            "[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n",
@@ -10896,7 +10896,7 @@ static void hsw_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
                break;
        default:
                MISSING_CASE(ddi_pll_sel);
-               /* fall through */
+               fallthrough;
        case PORT_CLK_SEL_NONE:
                return;
        }
@@ -10956,10 +10956,10 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
                        drm_WARN(dev, 1,
                                 "unknown pipe linked to transcoder %s\n",
                                 transcoder_name(panel_transcoder));
-                       /* fall through */
+                       fallthrough;
                case TRANS_DDI_EDP_INPUT_A_ONOFF:
                        force_thru = true;
-                       /* fall through */
+                       fallthrough;
                case TRANS_DDI_EDP_INPUT_A_ON:
                        trans_pipe = PIPE_A;
                        break;
@@ -13183,7 +13183,7 @@ static bool check_digital_port_conflicts(struct intel_atomic_state *state)
                case INTEL_OUTPUT_DDI:
                        if (drm_WARN_ON(dev, !HAS_DDI(to_i915(dev))))
                                break;
-                       /* else, fall through */
+                       fallthrough;
                case INTEL_OUTPUT_DP:
                case INTEL_OUTPUT_HDMI:
                case INTEL_OUTPUT_EDP:
@@ -14956,12 +14956,6 @@ static int intel_atomic_check(struct drm_device *dev,
        if (dev_priv->wm.distrust_bios_wm)
                any_ms = true;
 
-       if (any_ms) {
-               ret = intel_modeset_checks(state);
-               if (ret)
-                       goto fail;
-       }
-
        intel_fbc_choose_crtc(dev_priv, state);
        ret = calc_watermark_data(state);
        if (ret)
@@ -14976,6 +14970,10 @@ static int intel_atomic_check(struct drm_device *dev,
                goto fail;
 
        if (any_ms) {
+               ret = intel_modeset_checks(state);
+               if (ret)
+                       goto fail;
+
                ret = intel_modeset_calc_cdclk(state);
                if (ret)
                        return ret;
index aeb6ee3..afa7a37 100644 (file)
@@ -892,7 +892,7 @@ static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv,
                        refclk = dev_priv->dpll.ref_clks.nssc;
                        break;
                }
-               /* fall through */
+               fallthrough;
        case WRPLL_REF_PCH_SSC:
                /*
                 * We could calculate spread here, but our checking
@@ -2977,7 +2977,7 @@ static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
                switch (dev_priv->dpll.ref_clks.nssc) {
                default:
                        MISSING_CASE(dev_priv->dpll.ref_clks.nssc);
-                       /* fall-through */
+                       fallthrough;
                case 19200:
                        *pll_params = tgl_tbt_pll_19_2MHz_values;
                        break;
@@ -2992,7 +2992,7 @@ static bool icl_calc_tbt_pll(struct intel_crtc_state *crtc_state,
                switch (dev_priv->dpll.ref_clks.nssc) {
                default:
                        MISSING_CASE(dev_priv->dpll.ref_clks.nssc);
-                       /* fall-through */
+                       fallthrough;
                case 19200:
                case 38400:
                        *pll_params = icl_tbt_pll_19_2MHz_values;
@@ -3120,7 +3120,7 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc,
                        switch (div1) {
                        default:
                                MISSING_CASE(div1);
-                               /* fall through */
+                               fallthrough;
                        case 2:
                                hsdiv = MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_2;
                                break;
index 89a4d29..1a0d49a 100644 (file)
@@ -336,8 +336,10 @@ int intel_hdcp_validate_v_prime(struct intel_connector *connector,
 
                /* Fill up the empty slots in sha_text and write it out */
                sha_empty = sizeof(sha_text) - sha_leftovers;
-               for (j = 0; j < sha_empty; j++)
-                       sha_text |= ksv[j] << ((sizeof(sha_text) - j - 1) * 8);
+               for (j = 0; j < sha_empty; j++) {
+                       u8 off = ((sizeof(sha_text) - j - 1 - sha_leftovers) * 8);
+                       sha_text |= ksv[j] << off;
+               }
 
                ret = intel_write_sha_text(dev_priv, sha_text);
                if (ret < 0)
@@ -435,7 +437,7 @@ int intel_hdcp_validate_v_prime(struct intel_connector *connector,
                /* Write 32 bits of text */
                intel_de_write(dev_priv, HDCP_REP_CTL,
                               rep_ctl | HDCP_SHA1_TEXT_32);
-               sha_text |= bstatus[0] << 24 | bstatus[1] << 16;
+               sha_text |= bstatus[0] << 8 | bstatus[1];
                ret = intel_write_sha_text(dev_priv, sha_text);
                if (ret < 0)
                        return ret;
@@ -450,17 +452,29 @@ int intel_hdcp_validate_v_prime(struct intel_connector *connector,
                                return ret;
                        sha_idx += sizeof(sha_text);
                }
+
+               /*
+                * Terminate the SHA-1 stream by hand. For the other leftover
+                * cases this is appended by the hardware.
+                */
+               intel_de_write(dev_priv, HDCP_REP_CTL,
+                              rep_ctl | HDCP_SHA1_TEXT_32);
+               sha_text = DRM_HDCP_SHA1_TERMINATOR << 24;
+               ret = intel_write_sha_text(dev_priv, sha_text);
+               if (ret < 0)
+                       return ret;
+               sha_idx += sizeof(sha_text);
        } else if (sha_leftovers == 3) {
-               /* Write 32 bits of text */
+               /* Write 32 bits of text (filled from LSB) */
                intel_de_write(dev_priv, HDCP_REP_CTL,
                               rep_ctl | HDCP_SHA1_TEXT_32);
-               sha_text |= bstatus[0] << 24;
+               sha_text |= bstatus[0];
                ret = intel_write_sha_text(dev_priv, sha_text);
                if (ret < 0)
                        return ret;
                sha_idx += sizeof(sha_text);
 
-               /* Write 8 bits of text, 24 bits of M0 */
+               /* Write 8 bits of text (filled from LSB), 24 bits of M0 */
                intel_de_write(dev_priv, HDCP_REP_CTL,
                               rep_ctl | HDCP_SHA1_TEXT_8);
                ret = intel_write_sha_text(dev_priv, bstatus[1]);
@@ -781,6 +795,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
        struct intel_hdcp *hdcp = &connector->hdcp;
        enum port port = dig_port->base.port;
        enum transcoder cpu_transcoder = hdcp->cpu_transcoder;
+       u32 repeater_ctl;
        int ret;
 
        drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being disabled...\n",
@@ -796,6 +811,11 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
                return -ETIMEDOUT;
        }
 
+       repeater_ctl = intel_hdcp_get_repeater_ctl(dev_priv, cpu_transcoder,
+                                                  port);
+       intel_de_write(dev_priv, HDCP_REP_CTL,
+                      intel_de_read(dev_priv, HDCP_REP_CTL) & ~repeater_ctl);
+
        ret = hdcp->shim->toggle_signalling(dig_port, false);
        if (ret) {
                drm_err(&dev_priv->drm, "Failed to disable HDCP signalling\n");
index bbde3b1..4072d70 100644 (file)
@@ -229,7 +229,7 @@ int intel_pch_panel_fitting(struct intel_crtc_state *crtc_state,
        case DRM_MODE_SCALE_NONE:
                WARN_ON(adjusted_mode->crtc_hdisplay != crtc_state->pipe_src_w);
                WARN_ON(adjusted_mode->crtc_vdisplay != crtc_state->pipe_src_h);
-               /* fall through */
+               fallthrough;
        case DRM_MODE_SCALE_FULLSCREEN:
                x = y = 0;
                width = adjusted_mode->crtc_hdisplay;
index 2da4388..5e9fb34 100644 (file)
@@ -1531,7 +1531,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state,
        default:
                drm_WARN(&dev_priv->drm, 1,
                         "unknown pixel multiplier specified\n");
-               /* fall through */
+               fallthrough;
        case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
        case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
        case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -2549,19 +2549,19 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)
        switch (sdvo->controlled_output) {
        case SDVO_OUTPUT_LVDS1:
                mask |= SDVO_OUTPUT_LVDS1;
-               /* fall through */
+               fallthrough;
        case SDVO_OUTPUT_LVDS0:
                mask |= SDVO_OUTPUT_LVDS0;
-               /* fall through */
+               fallthrough;
        case SDVO_OUTPUT_TMDS1:
                mask |= SDVO_OUTPUT_TMDS1;
-               /* fall through */
+               fallthrough;
        case SDVO_OUTPUT_TMDS0:
                mask |= SDVO_OUTPUT_TMDS0;
-               /* fall through */
+               fallthrough;
        case SDVO_OUTPUT_RGB1:
                mask |= SDVO_OUTPUT_RGB1;
-               /* fall through */
+               fallthrough;
        case SDVO_OUTPUT_RGB0:
                mask |= SDVO_OUTPUT_RGB0;
                break;
index d03860f..c89f5f7 100644 (file)
@@ -2147,7 +2147,7 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
                case DRM_FORMAT_RGB565:
                        if (INTEL_GEN(dev_priv) >= 11)
                                break;
-                       /* fall through */
+                       fallthrough;
                case DRM_FORMAT_C8:
                case DRM_FORMAT_XRGB16161616F:
                case DRM_FORMAT_XBGR16161616F:
@@ -2702,7 +2702,7 @@ static bool g4x_sprite_format_mod_supported(struct drm_plane *_plane,
                if (modifier == DRM_FORMAT_MOD_LINEAR ||
                    modifier == I915_FORMAT_MOD_X_TILED)
                        return true;
-               /* fall through */
+               fallthrough;
        default:
                return false;
        }
@@ -2733,7 +2733,7 @@ static bool snb_sprite_format_mod_supported(struct drm_plane *_plane,
                if (modifier == DRM_FORMAT_MOD_LINEAR ||
                    modifier == I915_FORMAT_MOD_X_TILED)
                        return true;
-               /* fall through */
+               fallthrough;
        default:
                return false;
        }
@@ -2768,7 +2768,7 @@ static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane,
                if (modifier == DRM_FORMAT_MOD_LINEAR ||
                    modifier == I915_FORMAT_MOD_X_TILED)
                        return true;
-               /* fall through */
+               fallthrough;
        default:
                return false;
        }
@@ -2801,7 +2801,7 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
        case DRM_FORMAT_ABGR8888:
                if (is_ccs_modifier(modifier))
                        return true;
-               /* fall through */
+               fallthrough;
        case DRM_FORMAT_RGB565:
        case DRM_FORMAT_XRGB2101010:
        case DRM_FORMAT_XBGR2101010:
@@ -2819,7 +2819,7 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
        case DRM_FORMAT_XVYU2101010:
                if (modifier == I915_FORMAT_MOD_Yf_TILED)
                        return true;
-               /* fall through */
+               fallthrough;
        case DRM_FORMAT_C8:
        case DRM_FORMAT_XBGR16161616F:
        case DRM_FORMAT_ABGR16161616F:
@@ -2834,7 +2834,7 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
                    modifier == I915_FORMAT_MOD_X_TILED ||
                    modifier == I915_FORMAT_MOD_Y_TILED)
                        return true;
-               /* fall through */
+               fallthrough;
        default:
                return false;
        }
@@ -2860,7 +2860,7 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
        case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
                if (!gen12_plane_supports_mc_ccs(dev_priv, plane->id))
                        return false;
-               /* fall through */
+               fallthrough;
        case DRM_FORMAT_MOD_LINEAR:
        case I915_FORMAT_MOD_X_TILED:
        case I915_FORMAT_MOD_Y_TILED:
@@ -2877,7 +2877,7 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
        case DRM_FORMAT_ABGR8888:
                if (is_ccs_modifier(modifier))
                        return true;
-               /* fall through */
+               fallthrough;
        case DRM_FORMAT_YUYV:
        case DRM_FORMAT_YVYU:
        case DRM_FORMAT_UYVY:
@@ -2889,7 +2889,7 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
        case DRM_FORMAT_P016:
                if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)
                        return true;
-               /* fall through */
+               fallthrough;
        case DRM_FORMAT_RGB565:
        case DRM_FORMAT_XRGB2101010:
        case DRM_FORMAT_XBGR2101010:
@@ -2910,7 +2910,7 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
                    modifier == I915_FORMAT_MOD_X_TILED ||
                    modifier == I915_FORMAT_MOD_Y_TILED)
                        return true;
-               /* fall through */
+               fallthrough;
        default:
                return false;
        }
index 5b5dc86..8f67aef 100644 (file)
@@ -159,7 +159,7 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port)
        switch (lane_mask) {
        default:
                MISSING_CASE(lane_mask);
-               /* fall-through */
+               fallthrough;
        case 0x1:
        case 0x2:
        case 0x4:
index d0bdb6d..ef755dd 100644 (file)
@@ -439,29 +439,36 @@ static bool __cancel_engine(struct intel_engine_cs *engine)
        return __reset_engine(engine);
 }
 
-static struct intel_engine_cs *__active_engine(struct i915_request *rq)
+static bool
+__active_engine(struct i915_request *rq, struct intel_engine_cs **active)
 {
        struct intel_engine_cs *engine, *locked;
+       bool ret = false;
 
        /*
         * Serialise with __i915_request_submit() so that it sees
         * is-banned?, or we know the request is already inflight.
+        *
+        * Note that rq->engine is unstable, and so we double
+        * check that we have acquired the lock on the final engine.
         */
        locked = READ_ONCE(rq->engine);
        spin_lock_irq(&locked->active.lock);
        while (unlikely(locked != (engine = READ_ONCE(rq->engine)))) {
                spin_unlock(&locked->active.lock);
-               spin_lock(&engine->active.lock);
                locked = engine;
+               spin_lock(&locked->active.lock);
        }
 
-       engine = NULL;
-       if (i915_request_is_active(rq) && rq->fence.error != -EIO)
-               engine = rq->engine;
+       if (!i915_request_completed(rq)) {
+               if (i915_request_is_active(rq) && rq->fence.error != -EIO)
+                       *active = locked;
+               ret = true;
+       }
 
        spin_unlock_irq(&locked->active.lock);
 
-       return engine;
+       return ret;
 }
 
 static struct intel_engine_cs *active_engine(struct intel_context *ce)
@@ -472,17 +479,16 @@ static struct intel_engine_cs *active_engine(struct intel_context *ce)
        if (!ce->timeline)
                return NULL;
 
-       mutex_lock(&ce->timeline->mutex);
-       list_for_each_entry_reverse(rq, &ce->timeline->requests, link) {
-               if (i915_request_completed(rq))
-                       break;
+       rcu_read_lock();
+       list_for_each_entry_rcu(rq, &ce->timeline->requests, link) {
+               if (i915_request_is_active(rq) && i915_request_completed(rq))
+                       continue;
 
                /* Check with the backend if the request is inflight */
-               engine = __active_engine(rq);
-               if (engine)
+               if (__active_engine(rq, &engine))
                        break;
        }
-       mutex_unlock(&ce->timeline->mutex);
+       rcu_read_unlock();
 
        return engine;
 }
@@ -713,6 +719,7 @@ __create_context(struct drm_i915_private *i915)
        ctx->i915 = i915;
        ctx->sched.priority = I915_USER_PRIORITY(I915_PRIORITY_NORMAL);
        mutex_init(&ctx->mutex);
+       INIT_LIST_HEAD(&ctx->link);
 
        spin_lock_init(&ctx->stale.lock);
        INIT_LIST_HEAD(&ctx->stale.engines);
@@ -740,10 +747,6 @@ __create_context(struct drm_i915_private *i915)
        for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
                ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
 
-       spin_lock(&i915->gem.contexts.lock);
-       list_add_tail(&ctx->link, &i915->gem.contexts.list);
-       spin_unlock(&i915->gem.contexts.lock);
-
        return ctx;
 
 err_free:
@@ -931,6 +934,7 @@ static int gem_context_register(struct i915_gem_context *ctx,
                                struct drm_i915_file_private *fpriv,
                                u32 *id)
 {
+       struct drm_i915_private *i915 = ctx->i915;
        struct i915_address_space *vm;
        int ret;
 
@@ -949,8 +953,16 @@ static int gem_context_register(struct i915_gem_context *ctx,
        /* And finally expose ourselves to userspace via the idr */
        ret = xa_alloc(&fpriv->context_xa, id, ctx, xa_limit_32b, GFP_KERNEL);
        if (ret)
-               put_pid(fetch_and_zero(&ctx->pid));
+               goto err_pid;
+
+       spin_lock(&i915->gem.contexts.lock);
+       list_add_tail(&ctx->link, &i915->gem.contexts.list);
+       spin_unlock(&i915->gem.contexts.lock);
+
+       return 0;
 
+err_pid:
+       put_pid(fetch_and_zero(&ctx->pid));
        return ret;
 }
 
index 6b4ec66..446e76e 100644 (file)
@@ -45,6 +45,13 @@ struct eb_vma_array {
        struct eb_vma vma[];
 };
 
+enum {
+       FORCE_CPU_RELOC = 1,
+       FORCE_GTT_RELOC,
+       FORCE_GPU_RELOC,
+#define DBG_FORCE_RELOC 0 /* choose one of the above! */
+};
+
 #define __EXEC_OBJECT_HAS_PIN          BIT(31)
 #define __EXEC_OBJECT_HAS_FENCE                BIT(30)
 #define __EXEC_OBJECT_NEEDS_MAP                BIT(29)
@@ -253,6 +260,8 @@ struct i915_execbuffer {
         */
        struct reloc_cache {
                struct drm_mm_node node; /** temporary GTT binding */
+               unsigned long vaddr; /** Current kmap address */
+               unsigned long page; /** Currently mapped page index */
                unsigned int gen; /** Cached value of INTEL_GEN */
                bool use_64bit_reloc : 1;
                bool has_llc : 1;
@@ -596,6 +605,23 @@ eb_add_vma(struct i915_execbuffer *eb,
        }
 }
 
+static inline int use_cpu_reloc(const struct reloc_cache *cache,
+                               const struct drm_i915_gem_object *obj)
+{
+       if (!i915_gem_object_has_struct_page(obj))
+               return false;
+
+       if (DBG_FORCE_RELOC == FORCE_CPU_RELOC)
+               return true;
+
+       if (DBG_FORCE_RELOC == FORCE_GTT_RELOC)
+               return false;
+
+       return (cache->has_llc ||
+               obj->cache_dirty ||
+               obj->cache_level != I915_CACHE_NONE);
+}
+
 static int eb_reserve_vma(const struct i915_execbuffer *eb,
                          struct eb_vma *ev,
                          u64 pin_flags)
@@ -926,6 +952,8 @@ relocation_target(const struct drm_i915_gem_relocation_entry *reloc,
 static void reloc_cache_init(struct reloc_cache *cache,
                             struct drm_i915_private *i915)
 {
+       cache->page = -1;
+       cache->vaddr = 0;
        /* Must be a variable in the struct to allow GCC to unroll. */
        cache->gen = INTEL_GEN(i915);
        cache->has_llc = HAS_LLC(i915);
@@ -937,6 +965,25 @@ static void reloc_cache_init(struct reloc_cache *cache,
        cache->target = NULL;
 }
 
+static inline void *unmask_page(unsigned long p)
+{
+       return (void *)(uintptr_t)(p & PAGE_MASK);
+}
+
+static inline unsigned int unmask_flags(unsigned long p)
+{
+       return p & ~PAGE_MASK;
+}
+
+#define KMAP 0x4 /* after CLFLUSH_FLAGS */
+
+static inline struct i915_ggtt *cache_to_ggtt(struct reloc_cache *cache)
+{
+       struct drm_i915_private *i915 =
+               container_of(cache, struct i915_execbuffer, reloc_cache)->i915;
+       return &i915->ggtt;
+}
+
 #define RELOC_TAIL 4
 
 static int reloc_gpu_chain(struct reloc_cache *cache)
@@ -1049,6 +1096,181 @@ static int reloc_gpu_flush(struct reloc_cache *cache)
        return err;
 }
 
+static void reloc_cache_reset(struct reloc_cache *cache)
+{
+       void *vaddr;
+
+       if (!cache->vaddr)
+               return;
+
+       vaddr = unmask_page(cache->vaddr);
+       if (cache->vaddr & KMAP) {
+               if (cache->vaddr & CLFLUSH_AFTER)
+                       mb();
+
+               kunmap_atomic(vaddr);
+               i915_gem_object_finish_access((struct drm_i915_gem_object *)cache->node.mm);
+       } else {
+               struct i915_ggtt *ggtt = cache_to_ggtt(cache);
+
+               intel_gt_flush_ggtt_writes(ggtt->vm.gt);
+               io_mapping_unmap_atomic((void __iomem *)vaddr);
+
+               if (drm_mm_node_allocated(&cache->node)) {
+                       ggtt->vm.clear_range(&ggtt->vm,
+                                            cache->node.start,
+                                            cache->node.size);
+                       mutex_lock(&ggtt->vm.mutex);
+                       drm_mm_remove_node(&cache->node);
+                       mutex_unlock(&ggtt->vm.mutex);
+               } else {
+                       i915_vma_unpin((struct i915_vma *)cache->node.mm);
+               }
+       }
+
+       cache->vaddr = 0;
+       cache->page = -1;
+}
+
+static void *reloc_kmap(struct drm_i915_gem_object *obj,
+                       struct reloc_cache *cache,
+                       unsigned long page)
+{
+       void *vaddr;
+
+       if (cache->vaddr) {
+               kunmap_atomic(unmask_page(cache->vaddr));
+       } else {
+               unsigned int flushes;
+               int err;
+
+               err = i915_gem_object_prepare_write(obj, &flushes);
+               if (err)
+                       return ERR_PTR(err);
+
+               BUILD_BUG_ON(KMAP & CLFLUSH_FLAGS);
+               BUILD_BUG_ON((KMAP | CLFLUSH_FLAGS) & PAGE_MASK);
+
+               cache->vaddr = flushes | KMAP;
+               cache->node.mm = (void *)obj;
+               if (flushes)
+                       mb();
+       }
+
+       vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj, page));
+       cache->vaddr = unmask_flags(cache->vaddr) | (unsigned long)vaddr;
+       cache->page = page;
+
+       return vaddr;
+}
+
+static void *reloc_iomap(struct drm_i915_gem_object *obj,
+                        struct reloc_cache *cache,
+                        unsigned long page)
+{
+       struct i915_ggtt *ggtt = cache_to_ggtt(cache);
+       unsigned long offset;
+       void *vaddr;
+
+       if (cache->vaddr) {
+               intel_gt_flush_ggtt_writes(ggtt->vm.gt);
+               io_mapping_unmap_atomic((void __force __iomem *) unmask_page(cache->vaddr));
+       } else {
+               struct i915_vma *vma;
+               int err;
+
+               if (i915_gem_object_is_tiled(obj))
+                       return ERR_PTR(-EINVAL);
+
+               if (use_cpu_reloc(cache, obj))
+                       return NULL;
+
+               i915_gem_object_lock(obj);
+               err = i915_gem_object_set_to_gtt_domain(obj, true);
+               i915_gem_object_unlock(obj);
+               if (err)
+                       return ERR_PTR(err);
+
+               vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0,
+                                              PIN_MAPPABLE |
+                                              PIN_NONBLOCK /* NOWARN */ |
+                                              PIN_NOEVICT);
+               if (IS_ERR(vma)) {
+                       memset(&cache->node, 0, sizeof(cache->node));
+                       mutex_lock(&ggtt->vm.mutex);
+                       err = drm_mm_insert_node_in_range
+                               (&ggtt->vm.mm, &cache->node,
+                                PAGE_SIZE, 0, I915_COLOR_UNEVICTABLE,
+                                0, ggtt->mappable_end,
+                                DRM_MM_INSERT_LOW);
+                       mutex_unlock(&ggtt->vm.mutex);
+                       if (err) /* no inactive aperture space, use cpu reloc */
+                               return NULL;
+               } else {
+                       cache->node.start = vma->node.start;
+                       cache->node.mm = (void *)vma;
+               }
+       }
+
+       offset = cache->node.start;
+       if (drm_mm_node_allocated(&cache->node)) {
+               ggtt->vm.insert_page(&ggtt->vm,
+                                    i915_gem_object_get_dma_address(obj, page),
+                                    offset, I915_CACHE_NONE, 0);
+       } else {
+               offset += page << PAGE_SHIFT;
+       }
+
+       vaddr = (void __force *)io_mapping_map_atomic_wc(&ggtt->iomap,
+                                                        offset);
+       cache->page = page;
+       cache->vaddr = (unsigned long)vaddr;
+
+       return vaddr;
+}
+
+static void *reloc_vaddr(struct drm_i915_gem_object *obj,
+                        struct reloc_cache *cache,
+                        unsigned long page)
+{
+       void *vaddr;
+
+       if (cache->page == page) {
+               vaddr = unmask_page(cache->vaddr);
+       } else {
+               vaddr = NULL;
+               if ((cache->vaddr & KMAP) == 0)
+                       vaddr = reloc_iomap(obj, cache, page);
+               if (!vaddr)
+                       vaddr = reloc_kmap(obj, cache, page);
+       }
+
+       return vaddr;
+}
+
+static void clflush_write32(u32 *addr, u32 value, unsigned int flushes)
+{
+       if (unlikely(flushes & (CLFLUSH_BEFORE | CLFLUSH_AFTER))) {
+               if (flushes & CLFLUSH_BEFORE) {
+                       clflushopt(addr);
+                       mb();
+               }
+
+               *addr = value;
+
+               /*
+                * Writes to the same cacheline are serialised by the CPU
+                * (including clflush). On the write path, we only require
+                * that it hits memory in an orderly fashion and place
+                * mb barriers at the start and end of the relocation phase
+                * to ensure ordering of clflush wrt to the system.
+                */
+               if (flushes & CLFLUSH_AFTER)
+                       clflushopt(addr);
+       } else
+               *addr = value;
+}
+
 static int reloc_move_to_gpu(struct i915_request *rq, struct i915_vma *vma)
 {
        struct drm_i915_gem_object *obj = vma->obj;
@@ -1214,6 +1436,17 @@ static u32 *reloc_gpu(struct i915_execbuffer *eb,
        return cmd;
 }
 
+static inline bool use_reloc_gpu(struct i915_vma *vma)
+{
+       if (DBG_FORCE_RELOC == FORCE_GPU_RELOC)
+               return true;
+
+       if (DBG_FORCE_RELOC)
+               return false;
+
+       return !dma_resv_test_signaled_rcu(vma->resv, true);
+}
+
 static unsigned long vma_phys_addr(struct i915_vma *vma, u32 offset)
 {
        struct page *page;
@@ -1228,10 +1461,10 @@ static unsigned long vma_phys_addr(struct i915_vma *vma, u32 offset)
        return addr + offset_in_page(offset);
 }
 
-static int __reloc_entry_gpu(struct i915_execbuffer *eb,
-                            struct i915_vma *vma,
-                            u64 offset,
-                            u64 target_addr)
+static bool __reloc_entry_gpu(struct i915_execbuffer *eb,
+                             struct i915_vma *vma,
+                             u64 offset,
+                             u64 target_addr)
 {
        const unsigned int gen = eb->reloc_cache.gen;
        unsigned int len;
@@ -1247,7 +1480,7 @@ static int __reloc_entry_gpu(struct i915_execbuffer *eb,
 
        batch = reloc_gpu(eb, vma, len);
        if (IS_ERR(batch))
-               return PTR_ERR(batch);
+               return false;
 
        addr = gen8_canonical_addr(vma->node.start + offset);
        if (gen >= 8) {
@@ -1296,21 +1529,55 @@ static int __reloc_entry_gpu(struct i915_execbuffer *eb,
                *batch++ = target_addr;
        }
 
-       return 0;
+       return true;
+}
+
+static bool reloc_entry_gpu(struct i915_execbuffer *eb,
+                           struct i915_vma *vma,
+                           u64 offset,
+                           u64 target_addr)
+{
+       if (eb->reloc_cache.vaddr)
+               return false;
+
+       if (!use_reloc_gpu(vma))
+               return false;
+
+       return __reloc_entry_gpu(eb, vma, offset, target_addr);
 }
 
 static u64
-relocate_entry(struct i915_execbuffer *eb,
-              struct i915_vma *vma,
+relocate_entry(struct i915_vma *vma,
               const struct drm_i915_gem_relocation_entry *reloc,
+              struct i915_execbuffer *eb,
               const struct i915_vma *target)
 {
        u64 target_addr = relocation_target(reloc, target);
-       int err;
-
-       err = __reloc_entry_gpu(eb, vma, reloc->offset, target_addr);
-       if (err)
-               return err;
+       u64 offset = reloc->offset;
+
+       if (!reloc_entry_gpu(eb, vma, offset, target_addr)) {
+               bool wide = eb->reloc_cache.use_64bit_reloc;
+               void *vaddr;
+
+repeat:
+               vaddr = reloc_vaddr(vma->obj,
+                                   &eb->reloc_cache,
+                                   offset >> PAGE_SHIFT);
+               if (IS_ERR(vaddr))
+                       return PTR_ERR(vaddr);
+
+               GEM_BUG_ON(!IS_ALIGNED(offset, sizeof(u32)));
+               clflush_write32(vaddr + offset_in_page(offset),
+                               lower_32_bits(target_addr),
+                               eb->reloc_cache.vaddr);
+
+               if (wide) {
+                       offset += sizeof(u32);
+                       target_addr >>= 32;
+                       wide = false;
+                       goto repeat;
+               }
+       }
 
        return target->node.start | UPDATE;
 }
@@ -1375,7 +1642,8 @@ eb_relocate_entry(struct i915_execbuffer *eb,
         * If the relocation already has the right value in it, no
         * more work needs to be done.
         */
-       if (gen8_canonical_addr(target->vma->node.start) == reloc->presumed_offset)
+       if (!DBG_FORCE_RELOC &&
+           gen8_canonical_addr(target->vma->node.start) == reloc->presumed_offset)
                return 0;
 
        /* Check that the relocation address is valid... */
@@ -1407,7 +1675,7 @@ eb_relocate_entry(struct i915_execbuffer *eb,
        ev->flags &= ~EXEC_OBJECT_ASYNC;
 
        /* and update the user's relocation entry */
-       return relocate_entry(eb, ev->vma, reloc, target->vma);
+       return relocate_entry(ev->vma, reloc, eb, target->vma);
 }
 
 static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
@@ -1445,8 +1713,10 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
                 * this is bad and so lockdep complains vehemently.
                 */
                copied = __copy_from_user(r, urelocs, count * sizeof(r[0]));
-               if (unlikely(copied))
-                       return -EFAULT;
+               if (unlikely(copied)) {
+                       remain = -EFAULT;
+                       goto out;
+               }
 
                remain -= count;
                do {
@@ -1454,7 +1724,8 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
 
                        if (likely(offset == 0)) {
                        } else if ((s64)offset < 0) {
-                               return (int)offset;
+                               remain = (int)offset;
+                               goto out;
                        } else {
                                /*
                                 * Note that reporting an error now
@@ -1484,8 +1755,9 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
                } while (r++, --count);
                urelocs += ARRAY_SIZE(stack);
        } while (remain);
-
-       return 0;
+out:
+       reloc_cache_reset(&eb->reloc_cache);
+       return remain;
 }
 
 static int eb_relocate(struct i915_execbuffer *eb)
@@ -2392,7 +2664,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
        eb.i915 = i915;
        eb.file = file;
        eb.args = args;
-       if (!(args->flags & I915_EXEC_NO_RELOC))
+       if (DBG_FORCE_RELOC || !(args->flags & I915_EXEC_NO_RELOC))
                args->flags |= __EXEC_HAS_RELOC;
 
        eb.exec = exec;
index b233685..753f82d 100644 (file)
@@ -209,7 +209,7 @@ static vm_fault_t i915_error_to_vmf_fault(int err)
        switch (err) {
        default:
                WARN_ONCE(err, "unhandled error in %s: %i\n", __func__, err);
-               /* fallthrough */
+               fallthrough;
        case -EIO: /* shmemfs failure from swap device */
        case -EFAULT: /* purged object */
        case -ENODEV: /* bad object, how did you get here! */
index e5b9276..9cf4ad7 100644 (file)
@@ -258,6 +258,10 @@ struct page *
 i915_gem_object_get_page(struct drm_i915_gem_object *obj,
                         unsigned int n);
 
+struct page *
+i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj,
+                              unsigned int n);
+
 dma_addr_t
 i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj,
                                    unsigned long n,
index 7050519..e8a0837 100644 (file)
@@ -276,7 +276,7 @@ static void *i915_gem_object_map(struct drm_i915_gem_object *obj,
        switch (type) {
        default:
                MISSING_CASE(type);
-               /* fallthrough - to use PAGE_KERNEL anyway */
+               fallthrough;    /* to use PAGE_KERNEL anyway */
        case I915_MAP_WB:
                pgprot = PAGE_KERNEL;
                break;
@@ -548,6 +548,20 @@ i915_gem_object_get_page(struct drm_i915_gem_object *obj, unsigned int n)
        return nth_page(sg_page(sg), offset);
 }
 
+/* Like i915_gem_object_get_page(), but mark the returned page dirty */
+struct page *
+i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj,
+                              unsigned int n)
+{
+       struct page *page;
+
+       page = i915_gem_object_get_page(obj, n);
+       if (!obj->mm.dirty)
+               set_page_dirty(page);
+
+       return page;
+}
+
 dma_addr_t
 i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj,
                                    unsigned long n,
index e0f21f1..0be5e86 100644 (file)
@@ -249,7 +249,7 @@ static void vlv_get_stolen_reserved(struct drm_i915_private *i915,
        switch (reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK) {
        default:
                MISSING_CASE(reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK);
-               /* fall through */
+               fallthrough;
        case GEN7_STOLEN_RESERVED_1M:
                *size = 1024 * 1024;
                break;
@@ -416,7 +416,7 @@ static int i915_gem_init_stolen(struct drm_i915_private *i915)
        case 4:
                if (!IS_G4X(i915))
                        break;
-               /* fall through */
+               fallthrough;
        case 5:
                g4x_get_stolen_reserved(i915, uncore,
                                        &reserved_base, &reserved_size);
@@ -445,7 +445,7 @@ static int i915_gem_init_stolen(struct drm_i915_private *i915)
                break;
        default:
                MISSING_CASE(INTEL_GEN(i915));
-               /* fall-through */
+               fallthrough;
        case 11:
        case 12:
                icl_get_stolen_reserved(i915, uncore,
index 2c2bf24..12b3007 100644 (file)
@@ -596,14 +596,6 @@ static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
                                      GFP_KERNEL |
                                      __GFP_NORETRY |
                                      __GFP_NOWARN);
-               /*
-                * Using __get_user_pages_fast() with a read-only
-                * access is questionable. A read-only page may be
-                * COW-broken, and then this might end up giving
-                * the wrong side of the COW..
-                *
-                * We may or may not care.
-                */
                if (pvec) {
                        /* defer to worker if malloc fails */
                        if (!i915_gem_object_is_readonly(obj))
index 57c14d3..a49016f 100644 (file)
@@ -37,14 +37,20 @@ static int __igt_gpu_reloc(struct i915_execbuffer *eb,
                return err;
 
        /* 8-Byte aligned */
-       err = __reloc_entry_gpu(eb, vma, offsets[0] * sizeof(u32), 0);
-       if (err)
+       if (!__reloc_entry_gpu(eb, vma,
+                              offsets[0] * sizeof(u32),
+                              0)) {
+               err = -EIO;
                goto unpin_vma;
+       }
 
        /* !8-Byte aligned */
-       err = __reloc_entry_gpu(eb, vma, offsets[1] * sizeof(u32), 1);
-       if (err)
+       if (!__reloc_entry_gpu(eb, vma,
+                              offsets[1] * sizeof(u32),
+                              1)) {
+               err = -EIO;
                goto unpin_vma;
+       }
 
        /* Skip to the end of the cmd page */
        i = PAGE_SIZE / sizeof(u32) - RELOC_TAIL - 1;
@@ -54,9 +60,12 @@ static int __igt_gpu_reloc(struct i915_execbuffer *eb,
        eb->reloc_cache.rq_size += i;
 
        /* Force batch chaining */
-       err = __reloc_entry_gpu(eb, vma, offsets[2] * sizeof(u32), 2);
-       if (err)
+       if (!__reloc_entry_gpu(eb, vma,
+                              offsets[2] * sizeof(u32),
+                              2)) {
+               err = -EIO;
                goto unpin_vma;
+       }
 
        GEM_BUG_ON(!eb->reloc_cache.rq);
        rq = i915_request_get(eb->reloc_cache.rq);
index dd1a42c..26087dd 100644 (file)
@@ -213,7 +213,7 @@ u32 intel_engine_context_size(struct intel_gt *gt, u8 class)
                break;
        default:
                MISSING_CASE(class);
-               /* fall through */
+               fallthrough;
        case VIDEO_DECODE_CLASS:
        case VIDEO_ENHANCEMENT_CLASS:
        case COPY_ENGINE_CLASS:
index 62979ea..99e28d9 100644 (file)
@@ -1437,7 +1437,7 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
        switch (vma->ggtt_view.type) {
        default:
                GEM_BUG_ON(vma->ggtt_view.type);
-               /* fall through */
+               fallthrough;
        case I915_GGTT_VIEW_NORMAL:
                vma->pages = vma->obj->mm.pages;
                return 0;
index 24322ef..9eeaca9 100644 (file)
@@ -2060,6 +2060,14 @@ static inline void clear_ports(struct i915_request **ports, int count)
        memset_p((void **)ports, NULL, count);
 }
 
+static inline void
+copy_ports(struct i915_request **dst, struct i915_request **src, int count)
+{
+       /* A memcpy_p() would be very useful here! */
+       while (count--)
+               WRITE_ONCE(*dst++, *src++); /* avoid write tearing */
+}
+
 static void execlists_dequeue(struct intel_engine_cs *engine)
 {
        struct intel_engine_execlists * const execlists = &engine->execlists;
@@ -2648,10 +2656,9 @@ static void process_csb(struct intel_engine_cs *engine)
 
                        /* switch pending to inflight */
                        GEM_BUG_ON(!assert_pending_valid(execlists, "promote"));
-                       memcpy(execlists->inflight,
-                              execlists->pending,
-                              execlists_num_ports(execlists) *
-                              sizeof(*execlists->pending));
+                       copy_ports(execlists->inflight,
+                                  execlists->pending,
+                                  execlists_num_ports(execlists));
                        smp_wmb(); /* complete the seqlock */
                        WRITE_ONCE(execlists->active, execlists->inflight);
 
index 94915f6..898593c 100644 (file)
@@ -100,7 +100,7 @@ static void set_hwsp(struct intel_engine_cs *engine, u32 offset)
                 */
                default:
                        GEM_BUG_ON(engine->id);
-                       /* fallthrough */
+                       fallthrough;
                case RCS0:
                        hwsp = RENDER_HWS_PGA_GEN7;
                        break;
index 63bba7b..05f3bc9 100644 (file)
@@ -1226,7 +1226,7 @@ static int handle_g2v_notification(struct intel_vgpu *vgpu, int notification)
        switch (notification) {
        case VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE:
                root_entry_type = GTT_TYPE_PPGTT_ROOT_L3_ENTRY;
-               /* fall through */
+               fallthrough;
        case VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE:
                mm = intel_vgpu_get_ppgtt_mm(vgpu, root_entry_type, pdps);
                return PTR_ERR_OR_ZERO(mm);
index 8fa9b31..f6d7e33 100644 (file)
@@ -368,6 +368,7 @@ void intel_gvt_destroy_idle_vgpu(struct intel_vgpu *vgpu)
 static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
                struct intel_vgpu_creation_params *param)
 {
+       struct drm_i915_private *dev_priv = gvt->gt->i915;
        struct intel_vgpu *vgpu;
        int ret;
 
@@ -436,7 +437,10 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
        if (ret)
                goto out_clean_sched_policy;
 
-       ret = intel_gvt_hypervisor_set_edid(vgpu, PORT_D);
+       if (IS_BROADWELL(dev_priv))
+               ret = intel_gvt_hypervisor_set_edid(vgpu, PORT_B);
+       else
+               ret = intel_gvt_hypervisor_set_edid(vgpu, PORT_D);
        if (ret)
                goto out_clean_sched_policy;
 
index d960d0b..839bd53 100644 (file)
@@ -81,7 +81,7 @@ static void *active_debug_hint(void *addr)
        return (void *)ref->active ?: (void *)ref->retire ?: (void *)ref;
 }
 
-static struct debug_obj_descr active_debug_desc = {
+static const struct debug_obj_descr active_debug_desc = {
        .name = "i915_active",
        .debug_hint = active_debug_hint,
 };
index 372354d..5ac4a99 100644 (file)
@@ -1204,6 +1204,12 @@ static u32 *copy_batch(struct drm_i915_gem_object *dst_obj,
        return dst;
 }
 
+static inline bool cmd_desc_is(const struct drm_i915_cmd_descriptor * const desc,
+                              const u32 cmd)
+{
+       return desc->cmd.value == (cmd & desc->cmd.mask);
+}
+
 static bool check_cmd(const struct intel_engine_cs *engine,
                      const struct drm_i915_cmd_descriptor *desc,
                      const u32 *cmd, u32 length)
@@ -1242,19 +1248,19 @@ static bool check_cmd(const struct intel_engine_cs *engine,
                         * allowed mask/value pair given in the whitelist entry.
                         */
                        if (reg->mask) {
-                               if (desc->cmd.value == MI_LOAD_REGISTER_MEM) {
+                               if (cmd_desc_is(desc, MI_LOAD_REGISTER_MEM)) {
                                        DRM_DEBUG("CMD: Rejected LRM to masked register 0x%08X\n",
                                                  reg_addr);
                                        return false;
                                }
 
-                               if (desc->cmd.value == MI_LOAD_REGISTER_REG) {
+                               if (cmd_desc_is(desc, MI_LOAD_REGISTER_REG)) {
                                        DRM_DEBUG("CMD: Rejected LRR to masked register 0x%08X\n",
                                                  reg_addr);
                                        return false;
                                }
 
-                               if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1) &&
+                               if (cmd_desc_is(desc, MI_LOAD_REGISTER_IMM(1)) &&
                                    (offset + 2 > length ||
                                     (cmd[offset + 1] & reg->mask) != reg->value)) {
                                        DRM_DEBUG("CMD: Rejected LRI to masked register 0x%08X\n",
@@ -1478,7 +1484,7 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,
                        break;
                }
 
-               if (desc->cmd.value == MI_BATCH_BUFFER_START) {
+               if (cmd_desc_is(desc, MI_BATCH_BUFFER_START)) {
                        ret = check_bbstart(cmd, offset, length, batch_length,
                                            batch_addr, shadow_addr,
                                            jump_whitelist);
index 6a3a2ce..3e6cbb0 100644 (file)
@@ -1159,7 +1159,7 @@ static void engine_record_registers(struct intel_engine_coredump *ee)
                        switch (engine->id) {
                        default:
                                MISSING_CASE(engine->id);
-                               /* fall through */
+                               fallthrough;
                        case RCS0:
                                mmio = RENDER_HWS_PGA_GEN7;
                                break;
index 0569942..69c0fa2 100644 (file)
@@ -474,7 +474,7 @@ config_status(struct drm_i915_private *i915, u64 config)
                if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
                        /* Requires a mutex for sampling! */
                        return -ENODEV;
-               /* Fall-through. */
+               fallthrough;
        case I915_PMU_REQUESTED_FREQUENCY:
                if (INTEL_GEN(i915) < 6)
                        return -ENODEV;
index 0b2fe55..781a678 100644 (file)
@@ -388,17 +388,38 @@ static bool __request_in_flight(const struct i915_request *signal)
         * As we know that there are always preemption points between
         * requests, we know that only the currently executing request
         * may be still active even though we have cleared the flag.
-        * However, we can't rely on our tracking of ELSP[0] to known
+        * However, we can't rely on our tracking of ELSP[0] to know
         * which request is currently active and so maybe stuck, as
         * the tracking maybe an event behind. Instead assume that
         * if the context is still inflight, then it is still active
         * even if the active flag has been cleared.
+        *
+        * To further complicate matters, if there a pending promotion, the HW
+        * may either perform a context switch to the second inflight execlists,
+        * or it may switch to the pending set of execlists. In the case of the
+        * latter, it may send the ACK and we process the event copying the
+        * pending[] over top of inflight[], _overwriting_ our *active. Since
+        * this implies the HW is arbitrating and not struck in *active, we do
+        * not worry about complete accuracy, but we do require no read/write
+        * tearing of the pointer [the read of the pointer must be valid, even
+        * as the array is being overwritten, for which we require the writes
+        * to avoid tearing.]
+        *
+        * Note that the read of *execlists->active may race with the promotion
+        * of execlists->pending[] to execlists->inflight[], overwritting
+        * the value at *execlists->active. This is fine. The promotion implies
+        * that we received an ACK from the HW, and so the context is not
+        * stuck -- if we do not see ourselves in *active, the inflight status
+        * is valid. If instead we see ourselves being copied into *active,
+        * we are inflight and may signal the callback.
         */
        if (!intel_context_inflight(signal->context))
                return false;
 
        rcu_read_lock();
-       for (port = __engine_active(signal->engine); (rq = *port); port++) {
+       for (port = __engine_active(signal->engine);
+            (rq = READ_ONCE(*port)); /* may race with promotion of pending[] */
+            port++) {
                if (rq->context == signal->context) {
                        inflight = i915_seqno_passed(rq->fence.seqno,
                                                     signal->fence.seqno);
index 295b982..038d4c6 100644 (file)
@@ -34,7 +34,7 @@ static void *i915_sw_fence_debug_hint(void *addr)
 
 #ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS
 
-static struct debug_obj_descr i915_sw_fence_debug_descr = {
+static const struct debug_obj_descr i915_sw_fence_debug_descr = {
        .name = "i915_sw_fence",
        .debug_hint = i915_sw_fence_debug_hint,
 };
@@ -164,9 +164,13 @@ static void __i915_sw_fence_wake_up_all(struct i915_sw_fence *fence,
 
                do {
                        list_for_each_entry_safe(pos, next, &x->head, entry) {
-                               pos->func(pos,
-                                         TASK_NORMAL, fence->error,
-                                         &extra);
+                               int wake_flags;
+
+                               wake_flags = fence->error;
+                               if (pos->func == autoremove_wake_function)
+                                       wake_flags = 0;
+
+                               pos->func(pos, TASK_NORMAL, wake_flags, &extra);
                        }
 
                        if (list_empty(&extra))
index f127e63..397c313 100644 (file)
@@ -118,11 +118,11 @@ static struct dev_pm_domain pm_domain = {
 
 struct drm_i915_private *mock_gem_device(void)
 {
-       struct drm_i915_private *i915;
-       struct pci_dev *pdev;
 #if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU)
-       struct dev_iommu iommu;
+       static struct dev_iommu fake_iommu = { .priv = (void *)-1 };
 #endif
+       struct drm_i915_private *i915;
+       struct pci_dev *pdev;
        int err;
 
        pdev = kzalloc(sizeof(*pdev), GFP_KERNEL);
@@ -141,10 +141,8 @@ struct drm_i915_private *mock_gem_device(void)
        dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
 
 #if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU)
-       /* HACK HACK HACK to disable iommu for the fake device; force identity mapping */
-       memset(&iommu, 0, sizeof(iommu));
-       iommu.priv = (void *)-1;
-       pdev->dev.iommu = &iommu;
+       /* HACK to disable iommu for the fake device; force identity mapping */
+       pdev->dev.iommu = &fake_iommu;
 #endif
 
        pci_set_drvdata(pdev, i915);
index 6776ebb..8a4235d 100644 (file)
@@ -447,7 +447,7 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
                if (fb->pitches[1] != fb->pitches[2])
                        return -EINVAL;
 
-               /* fall-through */
+               fallthrough;
        case DRM_FORMAT_NV12:
        case DRM_FORMAT_NV16:
                ubo = drm_plane_state_to_ubo(state);
index ada990a..b707416 100644 (file)
@@ -673,7 +673,7 @@ static void ingenic_drm_unbind_all(void *d)
        component_unbind_all(priv->dev, &priv->drm);
 }
 
-static int ingenic_drm_bind(struct device *dev)
+static int ingenic_drm_bind(struct device *dev, bool has_components)
 {
        struct platform_device *pdev = to_platform_device(dev);
        const struct jz_soc_info *soc_info;
@@ -808,7 +808,7 @@ static int ingenic_drm_bind(struct device *dev)
                        return ret;
                }
 
-               if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU)) {
+               if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && has_components) {
                        ret = component_bind_all(dev, drm);
                        if (ret) {
                                if (ret != -EPROBE_DEFER)
@@ -939,6 +939,11 @@ err_pixclk_disable:
        return ret;
 }
 
+static int ingenic_drm_bind_with_components(struct device *dev)
+{
+       return ingenic_drm_bind(dev, true);
+}
+
 static int compare_of(struct device *dev, void *data)
 {
        return dev->of_node == data;
@@ -957,7 +962,7 @@ static void ingenic_drm_unbind(struct device *dev)
 }
 
 static const struct component_master_ops ingenic_master_ops = {
-       .bind = ingenic_drm_bind,
+       .bind = ingenic_drm_bind_with_components,
        .unbind = ingenic_drm_unbind,
 };
 
@@ -968,16 +973,15 @@ static int ingenic_drm_probe(struct platform_device *pdev)
        struct device_node *np;
 
        if (!IS_ENABLED(CONFIG_DRM_INGENIC_IPU))
-               return ingenic_drm_bind(dev);
+               return ingenic_drm_bind(dev, false);
 
        /* IPU is at port address 8 */
        np = of_graph_get_remote_node(dev->of_node, 8, 0);
-       if (!np) {
-               dev_err(dev, "Unable to get IPU node\n");
-               return -EINVAL;
-       }
+       if (!np)
+               return ingenic_drm_bind(dev, false);
 
        drm_of_component_match_add(dev, &match, compare_of, np);
+       of_node_put(np);
 
        return component_master_add_with_match(dev, &ingenic_master_ops, match);
 }
index 3fc5511..4d29568 100644 (file)
@@ -831,13 +831,19 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
                        drm_crtc_index(&mtk_crtc->base));
                mtk_crtc->cmdq_client = NULL;
        }
-       ret = of_property_read_u32_index(priv->mutex_node,
-                                        "mediatek,gce-events",
-                                        drm_crtc_index(&mtk_crtc->base),
-                                        &mtk_crtc->cmdq_event);
-       if (ret)
-               dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n",
-                       drm_crtc_index(&mtk_crtc->base));
+
+       if (mtk_crtc->cmdq_client) {
+               ret = of_property_read_u32_index(priv->mutex_node,
+                                                "mediatek,gce-events",
+                                                drm_crtc_index(&mtk_crtc->base),
+                                                &mtk_crtc->cmdq_event);
+               if (ret) {
+                       dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n",
+                               drm_crtc_index(&mtk_crtc->base));
+                       cmdq_mbox_destroy(mtk_crtc->cmdq_client);
+                       mtk_crtc->cmdq_client = NULL;
+               }
+       }
 #endif
        return 0;
 }
index 57c88de..5266488 100644 (file)
@@ -496,6 +496,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
        if (of_address_to_resource(node, 0, &res) != 0) {
                dev_err(dev, "Missing reg in %s node\n", node->full_name);
+               put_device(&larb_pdev->dev);
                return -EINVAL;
        }
        comp->regs_pa = res.start;
index 040a8f3..2d98274 100644 (file)
@@ -27,7 +27,6 @@
 
 #include "mtk_drm_crtc.h"
 #include "mtk_drm_ddp.h"
-#include "mtk_drm_ddp.h"
 #include "mtk_drm_ddp_comp.h"
 #include "mtk_drm_drv.h"
 #include "mtk_drm_gem.h"
@@ -165,7 +164,7 @@ static int mtk_drm_kms_init(struct drm_device *drm)
 
        ret = drmm_mode_config_init(drm);
        if (ret)
-               return ret;
+               goto put_mutex_dev;
 
        drm->mode_config.min_width = 64;
        drm->mode_config.min_height = 64;
@@ -182,7 +181,7 @@ static int mtk_drm_kms_init(struct drm_device *drm)
 
        ret = component_bind_all(drm->dev, drm);
        if (ret)
-               return ret;
+               goto put_mutex_dev;
 
        /*
         * We currently support two fixed data streams, each optional,
@@ -229,7 +228,7 @@ static int mtk_drm_kms_init(struct drm_device *drm)
        }
        if (!dma_dev->dma_parms) {
                ret = -ENOMEM;
-               goto err_component_unbind;
+               goto put_dma_dev;
        }
 
        ret = dma_set_max_seg_size(dma_dev, (unsigned int)DMA_BIT_MASK(32));
@@ -256,9 +255,12 @@ static int mtk_drm_kms_init(struct drm_device *drm)
 err_unset_dma_parms:
        if (private->dma_parms_allocated)
                dma_dev->dma_parms = NULL;
+put_dma_dev:
+       put_device(private->dma_dev);
 err_component_unbind:
        component_unbind_all(drm->dev, drm);
-
+put_mutex_dev:
+       put_device(private->mutex_dev);
        return ret;
 }
 
@@ -544,8 +546,13 @@ err_pm:
        pm_runtime_disable(dev);
 err_node:
        of_node_put(private->mutex_node);
-       for (i = 0; i < DDP_COMPONENT_ID_MAX; i++)
+       for (i = 0; i < DDP_COMPONENT_ID_MAX; i++) {
                of_node_put(private->comp_node[i]);
+               if (private->ddp_comp[i]) {
+                       put_device(private->ddp_comp[i]->larb_dev);
+                       private->ddp_comp[i] = NULL;
+               }
+       }
        return ret;
 }
 
index 16fd99d..80b7a08 100644 (file)
@@ -466,14 +466,13 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
        horizontal_sync_active_byte = (vm->hsync_len * dsi_tmp_buf_bpp - 10);
 
        if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
-               horizontal_backporch_byte =
-                       (vm->hback_porch * dsi_tmp_buf_bpp - 10);
+               horizontal_backporch_byte = vm->hback_porch * dsi_tmp_buf_bpp;
        else
-               horizontal_backporch_byte = ((vm->hback_porch + vm->hsync_len) *
-                       dsi_tmp_buf_bpp - 10);
+               horizontal_backporch_byte = (vm->hback_porch + vm->hsync_len) *
+                                           dsi_tmp_buf_bpp;
 
        data_phy_cycles = timing->lpx + timing->da_hs_prepare +
-                         timing->da_hs_zero + timing->da_hs_exit + 3;
+                         timing->da_hs_zero + timing->da_hs_exit;
 
        if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
                if ((vm->hfront_porch + vm->hback_porch) * dsi_tmp_buf_bpp >
index f2e9b42..a977256 100644 (file)
@@ -1507,25 +1507,30 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
                dev_err(dev,
                        "Failed to get system configuration registers: %d\n",
                        ret);
-               return ret;
+               goto put_device;
        }
        hdmi->sys_regmap = regmap;
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        hdmi->regs = devm_ioremap_resource(dev, mem);
-       if (IS_ERR(hdmi->regs))
-               return PTR_ERR(hdmi->regs);
+       if (IS_ERR(hdmi->regs)) {
+               ret = PTR_ERR(hdmi->regs);
+               goto put_device;
+       }
 
        remote = of_graph_get_remote_node(np, 1, 0);
-       if (!remote)
-               return -EINVAL;
+       if (!remote) {
+               ret = -EINVAL;
+               goto put_device;
+       }
 
        if (!of_device_is_compatible(remote, "hdmi-connector")) {
                hdmi->next_bridge = of_drm_find_bridge(remote);
                if (!hdmi->next_bridge) {
                        dev_err(dev, "Waiting for external bridge\n");
                        of_node_put(remote);
-                       return -EPROBE_DEFER;
+                       ret = -EPROBE_DEFER;
+                       goto put_device;
                }
        }
 
@@ -1534,7 +1539,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
                dev_err(dev, "Failed to find ddc-i2c-bus node in %pOF\n",
                        remote);
                of_node_put(remote);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_device;
        }
        of_node_put(remote);
 
@@ -1542,10 +1548,14 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
        of_node_put(i2c_np);
        if (!hdmi->ddc_adpt) {
                dev_err(dev, "Failed to get ddc i2c adapter by node\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_device;
        }
 
        return 0;
+put_device:
+       put_device(hdmi->cec_dev);
+       return ret;
 }
 
 /*
index f12e027..ffc6b58 100644 (file)
@@ -205,7 +205,7 @@ static int meson_g12a_afbcd_pixel_fmt(u64 modifier, uint32_t format)
                /* YTR is forbidden for non XBGR formats */
                if (modifier & AFBC_FORMAT_MOD_YTR)
                        return -EINVAL;
-       /* fall through */
+               fallthrough;
        case DRM_FORMAT_XBGR8888:
        case DRM_FORMAT_ABGR8888:
                return MAFBC_FMT_RGBA8888;
index a8bcc70..1ffbbec 100644 (file)
@@ -654,7 +654,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
                         priv->viu.vd1_addr2,
                         priv->viu.vd1_stride2,
                         priv->viu.vd1_height2);
-       /* fallthrough */
+               fallthrough;
        case 2:
                gem = drm_fb_cma_get_gem_obj(fb, 1);
                priv->viu.vd1_addr1 = gem->paddr + fb->offsets[1];
@@ -666,7 +666,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane,
                         priv->viu.vd1_addr1,
                         priv->viu.vd1_stride1,
                         priv->viu.vd1_height1);
-       /* fallthrough */
+               fallthrough;
        case 1:
                gem = drm_fb_cma_get_gem_obj(fb, 0);
                priv->viu.vd1_addr0 = gem->paddr + fb->offsets[0];
index 6021f8d..48fa49f 100644 (file)
@@ -164,6 +164,11 @@ static int a2xx_hw_init(struct msm_gpu *gpu)
        if (ret)
                return ret;
 
+       gpu_write(gpu, REG_AXXX_CP_RB_CNTL,
+               MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
+
+       gpu_write(gpu, REG_AXXX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
+
        /* NOTE: PM4/micro-engine firmware registers look to be the same
         * for a2xx and a3xx.. we could possibly push that part down to
         * adreno_gpu base class.  Or push both PM4 and PFP but
index 0a5ea9f..f647114 100644 (file)
@@ -211,6 +211,16 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
        if (ret)
                return ret;
 
+       /*
+        * Use the default ringbuffer size and block size but disable the RPTR
+        * shadow
+        */
+       gpu_write(gpu, REG_AXXX_CP_RB_CNTL,
+               MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
+
+       /* Set the ringbuffer address */
+       gpu_write(gpu, REG_AXXX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
+
        /* setup access protection: */
        gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007);
 
index b9b26b2..9547536 100644 (file)
@@ -267,6 +267,16 @@ static int a4xx_hw_init(struct msm_gpu *gpu)
        if (ret)
                return ret;
 
+       /*
+        * Use the default ringbuffer size and block size but disable the RPTR
+        * shadow
+        */
+       gpu_write(gpu, REG_A4XX_CP_RB_CNTL,
+               MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
+
+       /* Set the ringbuffer address */
+       gpu_write(gpu, REG_A4XX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
+
        /* Load PM4: */
        ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
        len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
index 9e63a19..91726da 100644 (file)
@@ -59,7 +59,7 @@ static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit
                case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
                        if (priv->lastctx == ctx)
                                break;
-                       /* fall-thru */
+                       fallthrough;
                case MSM_SUBMIT_CMD_BUF:
                        /* copy commands into RB: */
                        obj = submit->bos[submit->cmd[i].idx].obj;
@@ -150,7 +150,7 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
                        if (priv->lastctx == ctx)
                                break;
-                       /* fall-thru */
+                       fallthrough;
                case MSM_SUBMIT_CMD_BUF:
                        OUT_PKT7(ring, CP_INDIRECT_BUFFER_PFE, 3);
                        OUT_RING(ring, lower_32_bits(submit->cmd[i].iova));
@@ -703,8 +703,6 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
        if (ret)
                return ret;
 
-       a5xx_preempt_hw_init(gpu);
-
        if (!adreno_is_a510(adreno_gpu))
                a5xx_gpmu_ucode_init(gpu);
 
@@ -712,6 +710,15 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
        if (ret)
                return ret;
 
+       /* Set the ringbuffer address */
+       gpu_write64(gpu, REG_A5XX_CP_RB_BASE, REG_A5XX_CP_RB_BASE_HI,
+               gpu->rb[0]->iova);
+
+       gpu_write(gpu, REG_A5XX_CP_RB_CNTL,
+               MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
+
+       a5xx_preempt_hw_init(gpu);
+
        /* Disable the interrupts through the initial bringup stage */
        gpu_write(gpu, REG_A5XX_RBBM_INT_0_MASK, A5XX_INT_MASK);
 
@@ -1511,7 +1518,8 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
 
        check_speed_bin(&pdev->dev);
 
-       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 4);
+       /* Restricting nr_rings to 1 to temporarily disable preemption */
+       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
        if (ret) {
                a5xx_destroy(&(a5xx_gpu->base.base));
                return ERR_PTR(ret);
index 54868d4..1e5b1a1 100644 (file)
@@ -31,6 +31,7 @@ struct a5xx_gpu {
        struct msm_ringbuffer *next_ring;
 
        struct drm_gem_object *preempt_bo[MSM_GPU_MAX_RINGS];
+       struct drm_gem_object *preempt_counters_bo[MSM_GPU_MAX_RINGS];
        struct a5xx_preempt_record *preempt[MSM_GPU_MAX_RINGS];
        uint64_t preempt_iova[MSM_GPU_MAX_RINGS];
 
index 9cf9353..9f3fe17 100644 (file)
@@ -226,19 +226,31 @@ static int preempt_init_ring(struct a5xx_gpu *a5xx_gpu,
        struct adreno_gpu *adreno_gpu = &a5xx_gpu->base;
        struct msm_gpu *gpu = &adreno_gpu->base;
        struct a5xx_preempt_record *ptr;
-       struct drm_gem_object *bo = NULL;
-       u64 iova = 0;
+       void *counters;
+       struct drm_gem_object *bo = NULL, *counters_bo = NULL;
+       u64 iova = 0, counters_iova = 0;
 
        ptr = msm_gem_kernel_new(gpu->dev,
                A5XX_PREEMPT_RECORD_SIZE + A5XX_PREEMPT_COUNTER_SIZE,
-               MSM_BO_UNCACHED, gpu->aspace, &bo, &iova);
+               MSM_BO_UNCACHED | MSM_BO_MAP_PRIV, gpu->aspace, &bo, &iova);
 
        if (IS_ERR(ptr))
                return PTR_ERR(ptr);
 
+       /* The buffer to store counters needs to be unprivileged */
+       counters = msm_gem_kernel_new(gpu->dev,
+               A5XX_PREEMPT_COUNTER_SIZE,
+               MSM_BO_UNCACHED, gpu->aspace, &counters_bo, &counters_iova);
+       if (IS_ERR(counters)) {
+               msm_gem_kernel_put(bo, gpu->aspace, true);
+               return PTR_ERR(counters);
+       }
+
        msm_gem_object_set_name(bo, "preempt");
+       msm_gem_object_set_name(counters_bo, "preempt_counters");
 
        a5xx_gpu->preempt_bo[ring->id] = bo;
+       a5xx_gpu->preempt_counters_bo[ring->id] = counters_bo;
        a5xx_gpu->preempt_iova[ring->id] = iova;
        a5xx_gpu->preempt[ring->id] = ptr;
 
@@ -249,7 +261,7 @@ static int preempt_init_ring(struct a5xx_gpu *a5xx_gpu,
        ptr->data = 0;
        ptr->cntl = MSM_GPU_RB_CNTL_DEFAULT;
        ptr->rptr_addr = rbmemptr(ring, rptr);
-       ptr->counter = iova + A5XX_PREEMPT_RECORD_SIZE;
+       ptr->counter = counters_iova;
 
        return 0;
 }
@@ -260,8 +272,11 @@ void a5xx_preempt_fini(struct msm_gpu *gpu)
        struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
        int i;
 
-       for (i = 0; i < gpu->nr_rings; i++)
+       for (i = 0; i < gpu->nr_rings; i++) {
                msm_gem_kernel_put(a5xx_gpu->preempt_bo[i], gpu->aspace, true);
+               msm_gem_kernel_put(a5xx_gpu->preempt_counters_bo[i],
+                       gpu->aspace, true);
+       }
 }
 
 void a5xx_preempt_init(struct msm_gpu *gpu)
index b67b38c..e1c7bcd 100644 (file)
@@ -133,7 +133,7 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp)
 
        if (!gmu->legacy) {
                a6xx_hfi_set_freq(gmu, perf_index);
-               icc_set_bw(gpu->icc_path, 0, MBps_to_icc(7216));
+               dev_pm_opp_set_bw(&gpu->pdev->dev, opp);
                pm_runtime_put(gmu->dev);
                return;
        }
@@ -157,11 +157,7 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp)
        if (ret)
                dev_err(gmu->dev, "GMU set GPU frequency error: %d\n", ret);
 
-       /*
-        * Eventually we will want to scale the path vote with the frequency but
-        * for now leave it at max so that the performance is nominal.
-        */
-       icc_set_bw(gpu->icc_path, 0, MBps_to_icc(7216));
+       dev_pm_opp_set_bw(&gpu->pdev->dev, opp);
        pm_runtime_put(gmu->dev);
 }
 
@@ -204,6 +200,16 @@ static int a6xx_gmu_start(struct a6xx_gmu *gmu)
 {
        int ret;
        u32 val;
+       u32 mask, reset_val;
+
+       val = gmu_read(gmu, REG_A6XX_GMU_CM3_DTCM_START + 0xff8);
+       if (val <= 0x20010004) {
+               mask = 0xffffffff;
+               reset_val = 0xbabeface;
+       } else {
+               mask = 0x1ff;
+               reset_val = 0x100;
+       }
 
        gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1);
 
@@ -215,7 +221,7 @@ static int a6xx_gmu_start(struct a6xx_gmu *gmu)
        gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 0);
 
        ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_CM3_FW_INIT_RESULT, val,
-               val == 0xbabeface, 100, 10000);
+               (val & mask) == reset_val, 100, 10000);
 
        if (ret)
                DRM_DEV_ERROR(gmu->dev, "GMU firmware initialization timed out\n");
@@ -602,7 +608,7 @@ static void a6xx_gmu_power_config(struct a6xx_gmu *gmu)
                gmu_rmw(gmu, REG_A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0,
                        A6XX_GMU_PWR_COL_INTER_FRAME_CTRL_IFPC_ENABLE |
                        A6XX_GMU_PWR_COL_INTER_FRAME_CTRL_HM_POWER_COLLAPSE_ENABLE);
-               /* Fall through */
+               fallthrough;
        case GMU_IDLE_STATE_SPTP:
                gmu_write(gmu, REG_A6XX_GMU_PWR_COL_SPTPRAC_HYST,
                        GMU_PWR_COL_HYST);
@@ -845,10 +851,24 @@ static void a6xx_gmu_set_initial_freq(struct msm_gpu *gpu, struct a6xx_gmu *gmu)
        if (IS_ERR_OR_NULL(gpu_opp))
                return;
 
+       gmu->freq = 0; /* so a6xx_gmu_set_freq() doesn't exit early */
        a6xx_gmu_set_freq(gpu, gpu_opp);
        dev_pm_opp_put(gpu_opp);
 }
 
+static void a6xx_gmu_set_initial_bw(struct msm_gpu *gpu, struct a6xx_gmu *gmu)
+{
+       struct dev_pm_opp *gpu_opp;
+       unsigned long gpu_freq = gmu->gpu_freqs[gmu->current_perf_index];
+
+       gpu_opp = dev_pm_opp_find_freq_exact(&gpu->pdev->dev, gpu_freq, true);
+       if (IS_ERR_OR_NULL(gpu_opp))
+               return;
+
+       dev_pm_opp_set_bw(&gpu->pdev->dev, gpu_opp);
+       dev_pm_opp_put(gpu_opp);
+}
+
 int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
 {
        struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
@@ -882,7 +902,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
        }
 
        /* Set the bus quota to a reasonable value for boot */
-       icc_set_bw(gpu->icc_path, 0, MBps_to_icc(3072));
+       a6xx_gmu_set_initial_bw(gpu, gmu);
 
        /* Enable the GMU interrupt */
        gmu_write(gmu, REG_A6XX_GMU_AO_HOST_INTERRUPT_CLR, ~0);
@@ -1051,7 +1071,7 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
                a6xx_gmu_shutdown(gmu);
 
        /* Remove the bus vote */
-       icc_set_bw(gpu->icc_path, 0, 0);
+       dev_pm_opp_set_bw(&gpu->pdev->dev, NULL);
 
        /*
         * Make sure the GX domain is off before turning off the GMU (CX)
index c5a3e4d..66a95e2 100644 (file)
@@ -117,7 +117,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
                        if (priv->lastctx == ctx)
                                break;
-                       /* fall-thru */
+                       fallthrough;
                case MSM_SUBMIT_CMD_BUF:
                        OUT_PKT7(ring, CP_INDIRECT_BUFFER_PFE, 3);
                        OUT_RING(ring, lower_32_bits(submit->cmd[i].iova));
@@ -678,7 +678,8 @@ static int a6xx_hw_init(struct msm_gpu *gpu)
                        A6XX_PROTECT_RDONLY(0x980, 0x4));
        gpu_write(gpu, REG_A6XX_CP_PROTECT(25), A6XX_PROTECT_RW(0xa630, 0x0));
 
-       if (adreno_is_a650(adreno_gpu)) {
+       /* Enable expanded apriv for targets that support it */
+       if (gpu->hw_apriv) {
                gpu_write(gpu, REG_A6XX_CP_APRIV_CNTL,
                        (1 << 6) | (1 << 5) | (1 << 3) | (1 << 2) | (1 << 1));
        }
@@ -694,6 +695,13 @@ static int a6xx_hw_init(struct msm_gpu *gpu)
        if (ret)
                goto out;
 
+       /* Set the ringbuffer address */
+       gpu_write64(gpu, REG_A6XX_CP_RB_BASE, REG_A6XX_CP_RB_BASE_HI,
+               gpu->rb[0]->iova);
+
+       gpu_write(gpu, REG_A6XX_CP_RB_CNTL,
+               MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
+
        /* Always come up on rb 0 */
        a6xx_gpu->cur_ring = gpu->rb[0];
 
@@ -1056,6 +1064,9 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
        adreno_gpu->registers = NULL;
        adreno_gpu->reg_offsets = a6xx_register_offsets;
 
+       if (adreno_is_a650(adreno_gpu))
+               adreno_gpu->base.hw_apriv = true;
+
        ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
        if (ret) {
                a6xx_destroy(&(a6xx_gpu->base.base));
index 959656a..b12f5b4 100644 (file)
@@ -938,7 +938,8 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
                msm_gem_kernel_put(dumper.bo, gpu->aspace, true);
        }
 
-       a6xx_get_debugbus(gpu, a6xx_state);
+       if (snapshot_debugbus)
+               a6xx_get_debugbus(gpu, a6xx_state);
 
        return  &a6xx_state->base;
 }
index 846fd5b..2fb58b7 100644 (file)
@@ -372,7 +372,7 @@ static const struct a6xx_indexed_registers {
        u32 data;
        u32 count;
 } a6xx_indexed_reglist[] = {
-       { "CP_SEQ_STAT", REG_A6XX_CP_SQE_STAT_ADDR,
+       { "CP_SQE_STAT", REG_A6XX_CP_SQE_STAT_ADDR,
                REG_A6XX_CP_SQE_STAT_DATA, 0x33 },
        { "CP_DRAW_STATE", REG_A6XX_CP_DRAW_STATE_ADDR,
                REG_A6XX_CP_DRAW_STATE_DATA, 0x100 },
index 4e84f3c..9eeb46b 100644 (file)
@@ -14,6 +14,10 @@ bool hang_debug = false;
 MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)");
 module_param_named(hang_debug, hang_debug, bool, 0600);
 
+bool snapshot_debugbus = false;
+MODULE_PARM_DESC(snapshot_debugbus, "Include debugbus sections in GPU devcoredump (if not fused off)");
+module_param_named(snapshot_debugbus, snapshot_debugbus, bool, 0600);
+
 static const struct adreno_info gpulist[] = {
        {
                .rev   = ADRENO_REV(2, 0, 0, 0),
index e23641a..862dd35 100644 (file)
@@ -396,30 +396,10 @@ int adreno_hw_init(struct msm_gpu *gpu)
                ring->next = ring->start;
 
                /* reset completed fence seqno: */
-               ring->memptrs->fence = ring->seqno;
+               ring->memptrs->fence = ring->fctx->completed_fence;
                ring->memptrs->rptr = 0;
        }
 
-       /*
-        * Setup REG_CP_RB_CNTL.  The same value is used across targets (with
-        * the excpetion of A430 that disables the RPTR shadow) - the cacluation
-        * for the ringbuffer size and block size is moved to msm_gpu.h for the
-        * pre-processor to deal with and the A430 variant is ORed in here
-        */
-       adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_CNTL,
-               MSM_GPU_RB_CNTL_DEFAULT |
-               (adreno_is_a430(adreno_gpu) ? AXXX_CP_RB_CNTL_NO_UPDATE : 0));
-
-       /* Setup ringbuffer address - use ringbuffer[0] for GPU init */
-       adreno_gpu_write64(adreno_gpu, REG_ADRENO_CP_RB_BASE,
-               REG_ADRENO_CP_RB_BASE_HI, gpu->rb[0]->iova);
-
-       if (!adreno_is_a430(adreno_gpu)) {
-               adreno_gpu_write64(adreno_gpu, REG_ADRENO_CP_RB_RPTR_ADDR,
-                       REG_ADRENO_CP_RB_RPTR_ADDR_HI,
-                       rbmemptr(gpu->rb[0], rptr));
-       }
-
        return 0;
 }
 
@@ -427,11 +407,8 @@ int adreno_hw_init(struct msm_gpu *gpu)
 static uint32_t get_rptr(struct adreno_gpu *adreno_gpu,
                struct msm_ringbuffer *ring)
 {
-       if (adreno_is_a430(adreno_gpu))
-               return ring->memptrs->rptr = adreno_gpu_read(
-                       adreno_gpu, REG_ADRENO_CP_RB_RPTR);
-       else
-               return ring->memptrs->rptr;
+       return ring->memptrs->rptr = adreno_gpu_read(
+               adreno_gpu, REG_ADRENO_CP_RB_RPTR);
 }
 
 struct msm_ringbuffer *adreno_active_ring(struct msm_gpu *gpu)
@@ -474,7 +451,7 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                        /* ignore if there has not been a ctx switch: */
                        if (priv->lastctx == ctx)
                                break;
-                       /* fall-thru */
+                       fallthrough;
                case MSM_SUBMIT_CMD_BUF:
                        OUT_PKT3(ring, adreno_is_a4xx(adreno_gpu) ?
                                CP_INDIRECT_BUFFER_PFE : CP_INDIRECT_BUFFER_PFD, 2);
index 99bb468..e55abae 100644 (file)
@@ -21,6 +21,8 @@
 #define REG_SKIP ~0
 #define REG_ADRENO_SKIP(_offset) [_offset] = REG_SKIP
 
+extern bool snapshot_debugbus;
+
 /**
  * adreno_regs: List of registers that are used in across all
  * 3D devices. Each device type has different offset value for the same
index f272a8d..c2729f7 100644 (file)
@@ -827,7 +827,7 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
 {
        struct dpu_crtc *dpu_crtc;
        struct drm_encoder *encoder;
-       bool request_bandwidth;
+       bool request_bandwidth = false;
 
        if (!crtc) {
                DPU_ERROR("invalid crtc\n");
index a97f6d2..bd6def4 100644 (file)
@@ -599,7 +599,10 @@ static int dpu_encoder_virt_atomic_check(
        dpu_kms = to_dpu_kms(priv->kms);
        mode = &crtc_state->mode;
        adj_mode = &crtc_state->adjusted_mode;
-       global_state = dpu_kms_get_existing_global_state(dpu_kms);
+       global_state = dpu_kms_get_global_state(crtc_state->state);
+       if (IS_ERR(global_state))
+               return PTR_ERR(global_state);
+
        trace_dpu_enc_atomic_check(DRMID(drm_enc));
 
        /* perform atomic check on the first physical encoder (master) */
@@ -625,12 +628,15 @@ static int dpu_encoder_virt_atomic_check(
        /* Reserve dynamic resources now. */
        if (!ret) {
                /*
-                * Avoid reserving resources when mode set is pending. Topology
-                * info may not be available to complete reservation.
+                * Release and Allocate resources on every modeset
+                * Dont allocate when active is false.
                 */
                if (drm_atomic_crtc_needs_modeset(crtc_state)) {
-                       ret = dpu_rm_reserve(&dpu_kms->rm, global_state,
-                                       drm_enc, crtc_state, topology);
+                       dpu_rm_release(global_state, drm_enc);
+
+                       if (!crtc_state->active_changed || crtc_state->active)
+                               ret = dpu_rm_reserve(&dpu_kms->rm, global_state,
+                                               drm_enc, crtc_state, topology);
                }
        }
 
@@ -1181,7 +1187,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
        struct dpu_encoder_virt *dpu_enc = NULL;
        struct msm_drm_private *priv;
        struct dpu_kms *dpu_kms;
-       struct dpu_global_state *global_state;
        int i = 0;
 
        if (!drm_enc) {
@@ -1200,7 +1205,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
 
        priv = drm_enc->dev->dev_private;
        dpu_kms = to_dpu_kms(priv->kms);
-       global_state = dpu_kms_get_existing_global_state(dpu_kms);
 
        trace_dpu_enc_disable(DRMID(drm_enc));
 
@@ -1230,8 +1234,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
 
        DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n");
 
-       dpu_rm_release(global_state, drm_enc);
-
        mutex_unlock(&dpu_enc->enc_lock);
 }
 
index 33f6c56..29e373d 100644 (file)
@@ -866,9 +866,9 @@ static int dpu_plane_atomic_check(struct drm_plane *plane,
                crtc_state = drm_atomic_get_new_crtc_state(state->state,
                                                           state->crtc);
 
-       min_scale = FRAC_16_16(1, pdpu->pipe_sblk->maxdwnscale);
+       min_scale = FRAC_16_16(1, pdpu->pipe_sblk->maxupscale);
        ret = drm_atomic_helper_check_plane_state(state, crtc_state, min_scale,
-                                         pdpu->pipe_sblk->maxupscale << 16,
+                                         pdpu->pipe_sblk->maxdwnscale << 16,
                                          true, true);
        if (ret) {
                DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret);
index 5ccfad7..561bfa4 100644 (file)
@@ -27,6 +27,34 @@ int msm_atomic_prepare_fb(struct drm_plane *plane,
        return msm_framebuffer_prepare(new_state->fb, kms->aspace);
 }
 
+/*
+ * Helpers to control vblanks while we flush.. basically just to ensure
+ * that vblank accounting is switched on, so we get valid seqn/timestamp
+ * on pageflip events (if requested)
+ */
+
+static void vblank_get(struct msm_kms *kms, unsigned crtc_mask)
+{
+       struct drm_crtc *crtc;
+
+       for_each_crtc_mask(kms->dev, crtc, crtc_mask) {
+               if (!crtc->state->active)
+                       continue;
+               drm_crtc_vblank_get(crtc);
+       }
+}
+
+static void vblank_put(struct msm_kms *kms, unsigned crtc_mask)
+{
+       struct drm_crtc *crtc;
+
+       for_each_crtc_mask(kms->dev, crtc, crtc_mask) {
+               if (!crtc->state->active)
+                       continue;
+               drm_crtc_vblank_put(crtc);
+       }
+}
+
 static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx)
 {
        unsigned crtc_mask = BIT(crtc_idx);
@@ -44,6 +72,8 @@ static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx)
 
        kms->funcs->enable_commit(kms);
 
+       vblank_get(kms, crtc_mask);
+
        /*
         * Flush hardware updates:
         */
@@ -58,6 +88,8 @@ static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx)
        kms->funcs->wait_flush(kms, crtc_mask);
        trace_msm_atomic_wait_flush_finish(crtc_mask);
 
+       vblank_put(kms, crtc_mask);
+
        mutex_lock(&kms->commit_lock);
        kms->funcs->complete_commit(kms, crtc_mask);
        mutex_unlock(&kms->commit_lock);
@@ -221,6 +253,8 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state)
         */
        kms->pending_crtc_mask &= ~crtc_mask;
 
+       vblank_get(kms, crtc_mask);
+
        /*
         * Flush hardware updates:
         */
@@ -235,6 +269,8 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state)
        kms->funcs->wait_flush(kms, crtc_mask);
        trace_msm_atomic_wait_flush_finish(crtc_mask);
 
+       vblank_put(kms, crtc_mask);
+
        mutex_lock(&kms->commit_lock);
        kms->funcs->complete_commit(kms, crtc_mask);
        mutex_unlock(&kms->commit_lock);
index 7d641c7..7933384 100644 (file)
@@ -1320,6 +1320,13 @@ static int msm_pdev_remove(struct platform_device *pdev)
        return 0;
 }
 
+static void msm_pdev_shutdown(struct platform_device *pdev)
+{
+       struct drm_device *drm = platform_get_drvdata(pdev);
+
+       drm_atomic_helper_shutdown(drm);
+}
+
 static const struct of_device_id dt_match[] = {
        { .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 },
        { .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 },
@@ -1332,6 +1339,7 @@ MODULE_DEVICE_TABLE(of, dt_match);
 static struct platform_driver msm_platform_driver = {
        .probe      = msm_pdev_probe,
        .remove     = msm_pdev_remove,
+       .shutdown   = msm_pdev_shutdown,
        .driver     = {
                .name   = "msm",
                .of_match_table = dt_match,
index d564547..57ddc94 100644 (file)
@@ -908,7 +908,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
 
        memptrs = msm_gem_kernel_new(drm,
                sizeof(struct msm_rbmemptrs) * nr_rings,
-               MSM_BO_UNCACHED, gpu->aspace, &gpu->memptrs_bo,
+               check_apriv(gpu, MSM_BO_UNCACHED), gpu->aspace, &gpu->memptrs_bo,
                &memptrs_iova);
 
        if (IS_ERR(memptrs)) {
index 0db117a..37cffac 100644 (file)
@@ -15,6 +15,7 @@
 #include "msm_drv.h"
 #include "msm_fence.h"
 #include "msm_ringbuffer.h"
+#include "msm_gem.h"
 
 struct msm_gem_submit;
 struct msm_gpu_perfcntr;
@@ -139,6 +140,8 @@ struct msm_gpu {
        } devfreq;
 
        struct msm_gpu_state *crashstate;
+       /* True if the hardware supports expanded apriv (a650 and newer) */
+       bool hw_apriv;
 };
 
 /* It turns out that all targets use the same ringbuffer size */
@@ -327,4 +330,12 @@ static inline void msm_gpu_crashstate_put(struct msm_gpu *gpu)
        mutex_unlock(&gpu->dev->struct_mutex);
 }
 
+/*
+ * Simple macro to semi-cleanly add the MAP_PRIV flag for targets that can
+ * support expanded privileges
+ */
+#define check_apriv(gpu, flags) \
+       (((gpu)->hw_apriv ? MSM_BO_MAP_PRIV : 0) | (flags))
+
+
 #endif /* __MSM_GPU_H__ */
index e397c44..935bf9b 100644 (file)
@@ -27,7 +27,8 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id,
        ring->id = id;
 
        ring->start = msm_gem_kernel_new(gpu->dev, MSM_GPU_RINGBUFFER_SZ,
-               MSM_BO_WC, gpu->aspace, &ring->bo, &ring->iova);
+               check_apriv(gpu, MSM_BO_WC | MSM_BO_GPU_READONLY),
+               gpu->aspace, &ring->bo, &ring->iova);
 
        if (IS_ERR(ring->start)) {
                ret = PTR_ERR(ring->start);
index ad1f09a..248edf6 100644 (file)
@@ -50,7 +50,10 @@ core507d_update(struct nv50_core *core, u32 *interlock, bool ntfy)
                                        interlock[NV50_DISP_INTERLOCK_OVLY] |
                  NVDEF(NV507D, UPDATE, NOT_DRIVER_FRIENDLY, FALSE) |
                  NVDEF(NV507D, UPDATE, NOT_DRIVER_UNFRIENDLY, FALSE) |
-                 NVDEF(NV507D, UPDATE, INHIBIT_INTERRUPTS, FALSE));
+                 NVDEF(NV507D, UPDATE, INHIBIT_INTERRUPTS, FALSE),
+
+                               SET_NOTIFIER_CONTROL,
+                 NVDEF(NV507D, SET_NOTIFIER_CONTROL, NOTIFY, DISABLE));
 
        return PUSH_KICK(push);
 }
index 9afe9a8..814e5bd 100644 (file)
@@ -6,7 +6,7 @@
 #include "disp.h"
 #include "head.h"
 
-#include <nvif/push507c.h>
+#include <nvif/pushc37b.h>
 
 #include <nvhw/class/clc37d.h>
 
index e787487..1ed2420 100644 (file)
@@ -257,6 +257,12 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
        dmac->push->end = dmac->push->bgn;
        dmac->max = 0x1000/4 - 1;
 
+       /* EVO channels are affected by a HW bug where the last 12 DWORDs
+        * of the push buffer aren't able to be used safely.
+        */
+       if (disp->oclass < GV100_DISP)
+               dmac->max -= 12;
+
        args->pushbuf = nvif_handle(&dmac->_push.mem.object);
 
        ret = nv50_chan_create(device, disp, oclass, head, data, size,
index 889467f..7917bea 100644 (file)
@@ -20,6 +20,6 @@
         PUSH_ASSERT(!((o) & ~DRF_SMASK(NV507C_DMA_JUMP_OFFSET)), "offset"); \
        PUSH_DATA__((p), NVDEF(NV507C, DMA, OPCODE, JUMP) |                 \
                         NVVAL(NV507C, DMA, JUMP_OFFSET, (o) >> 2),         \
-                   "jump 0x%08x - %s", (u32)(o), __func__);                \
+                   " jump 0x%08x - %s", (u32)(o), __func__);               \
 } while(0)
 #endif
index b1bb542..e5fae57 100644 (file)
@@ -176,6 +176,8 @@ void
 nouveau_mem_del(struct ttm_mem_reg *reg)
 {
        struct nouveau_mem *mem = nouveau_mem(reg);
+       if (!mem)
+               return;
        nouveau_mem_fini(mem);
        kfree(reg->mm_node);
        reg->mm_node = NULL;
index 9f4ac26..dcb7067 100644 (file)
@@ -3149,6 +3149,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
                case 0x168: device->chip = &nv168_chipset; break;
                default:
                        nvdev_error(device, "unknown chipset (%08x)\n", boot0);
+                       ret = -ENODEV;
                        goto done;
                }
 
index e081793..bd12eae 100644 (file)
@@ -597,7 +597,7 @@ static void venc_bridge_mode_set(struct drm_bridge *bridge,
        switch (venc_mode) {
        default:
                WARN_ON_ONCE(1);
-               /* Fall-through */
+               fallthrough;
        case VENC_MODE_PAL:
                venc->config = &venc_config_pal_trm;
                break;
index 6d40914..328a4a7 100644 (file)
@@ -451,11 +451,12 @@ static void omap_crtc_atomic_enable(struct drm_crtc *crtc,
        if (omap_state->manually_updated)
                return;
 
-       spin_lock_irq(&crtc->dev->event_lock);
        drm_crtc_vblank_on(crtc);
+
        ret = drm_crtc_vblank_get(crtc);
        WARN_ON(ret != 0);
 
+       spin_lock_irq(&crtc->dev->event_lock);
        omap_crtc_arm_event(crtc);
        spin_unlock_irq(&crtc->dev->event_lock);
 }
index ba20c6f..886e995 100644 (file)
@@ -4856,7 +4856,7 @@ static void ci_request_link_speed_change_before_state_change(struct radeon_devic
                        pi->force_pcie_gen = RADEON_PCIE_GEN2;
                        if (current_link_speed == RADEON_PCIE_GEN2)
                                break;
-                       /* fall through */
+                       fallthrough;
                case RADEON_PCIE_GEN2:
                        if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, false) == 0)
                                break;
index 3b7ead5..73f67bf 100644 (file)
@@ -820,7 +820,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                                          ((idx_value >> 21) & 0xF));
                                return -EINVAL;
                        }
-                       /* Fall through. */
+                       fallthrough;
                case 6:
                        track->cb[i].cpp = 4;
                        break;
@@ -971,7 +971,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                                return -EINVAL;
                        }
                        /* The same rules apply as for DXT3/5. */
-                       /* Fall through. */
+                       fallthrough;
                case R300_TX_FORMAT_DXT3:
                case R300_TX_FORMAT_DXT5:
                        track->textures[i].cpp = 1;
index 1d4c04e..50b89b6 100644 (file)
@@ -115,7 +115,7 @@ void r420_pipes_init(struct radeon_device *rdev)
        default:
                /* force to 1 pipe */
                num_pipes = 1;
-               /* fall through */
+               fallthrough;
        case 1:
                tmp = (0 << 1);
                break;
index 49e8266..390a962 100644 (file)
@@ -487,7 +487,7 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
                                return -EINVAL;
                        }
                }
-               /* fall through */
+               fallthrough;
        case V_0280A0_CLEAR_ENABLE:
        {
                uint32_t block_max = G_028100_CMASK_BLOCK_MAX(track->cb_color_mask[i]);
@@ -1535,7 +1535,7 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                break;
        case V_038000_SQ_TEX_DIM_2D_ARRAY_MSAA:
                is_array = true;
-               /* fall through */
+               fallthrough;
        case V_038000_SQ_TEX_DIM_2D_MSAA:
                array_check.nsamples = 1 << llevel;
                llevel = 0;
index 1ad5c3b..57fb3eb 100644 (file)
@@ -454,7 +454,7 @@ static int radeon_uvd_validate_codec(struct radeon_cs_parser *p,
                if (p->rdev->family >= CHIP_PALM)
                        return 0;
 
-               /* fall through */
+               fallthrough;
        default:
                DRM_ERROR("UVD codec not supported by hardware %d!\n",
                          stream_type);
index a167e1c..d1c73e9 100644 (file)
@@ -5744,7 +5744,7 @@ static void si_request_link_speed_change_before_state_change(struct radeon_devic
                        si_pi->force_pcie_gen = RADEON_PCIE_GEN2;
                        if (current_link_speed == RADEON_PCIE_GEN2)
                                break;
-                       /* fall through */
+                       fallthrough;
                case RADEON_PCIE_GEN2:
                        if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, false) == 0)
                                break;
index f858d8d..8007211 100644 (file)
@@ -219,7 +219,7 @@ done:
                        WREG32(RS_DQ_RD_RET_CONF, 0x3f);
                        WREG32(MC_CONFIG, 0x1f);
 
-                       /* fall through */
+                       fallthrough;
                case CHIP_RV670:
                case CHIP_RV635:
 
index a2ac25c..e0d40ae 100644 (file)
@@ -306,7 +306,7 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
        case SAVAGE_PRIM_TRILIST_201:
                reorder = 1;
                prim = SAVAGE_PRIM_TRILIST;
-               /* fall through */
+               fallthrough;
        case SAVAGE_PRIM_TRILIST:
                if (n % 3 != 0) {
                        DRM_ERROR("wrong number of vertices %u in TRILIST\n",
@@ -444,7 +444,7 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
        case SAVAGE_PRIM_TRILIST_201:
                reorder = 1;
                prim = SAVAGE_PRIM_TRILIST;
-               /* fall through */
+               fallthrough;
        case SAVAGE_PRIM_TRILIST:
                if (n % 3 != 0) {
                        DRM_ERROR("wrong number of vertices %u in TRILIST\n",
@@ -566,7 +566,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
        case SAVAGE_PRIM_TRILIST_201:
                reorder = 1;
                prim = SAVAGE_PRIM_TRILIST;
-               /* fall through */
+               fallthrough;
        case SAVAGE_PRIM_TRILIST:
                if (n % 3 != 0) {
                        DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
@@ -705,7 +705,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
        case SAVAGE_PRIM_TRILIST_201:
                reorder = 1;
                prim = SAVAGE_PRIM_TRILIST;
-               /* fall through */
+               fallthrough;
        case SAVAGE_PRIM_TRILIST:
                if (n % 3 != 0) {
                        DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
@@ -1066,7 +1066,7 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_
                                ret = -EINVAL;
                                goto done;
                        }
-                       /* fall through */
+                       fallthrough;
                case SAVAGE_CMD_DMA_PRIM:
                case SAVAGE_CMD_VB_PRIM:
                        if (!first_draw_cmd)
index 008f079..38a5587 100644 (file)
@@ -850,13 +850,13 @@ static int hdmi_audio_configure(struct sti_hdmi *hdmi)
        switch (info->channels) {
        case 8:
                audio_cfg |= HDMI_AUD_CFG_CH78_VALID;
-               /* fall through */
+               fallthrough;
        case 6:
                audio_cfg |= HDMI_AUD_CFG_CH56_VALID;
-               /* fall through */
+               fallthrough;
        case 4:
                audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH;
-               /* fall through */
+               fallthrough;
        case 2:
                audio_cfg |= HDMI_AUD_CFG_CH12_VALID;
                break;
index 072ea11..ed5d866 100644 (file)
@@ -589,8 +589,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
 
        /* We can't have an alpha plane at the lowest position */
        if (!backend->quirks->supports_lowest_plane_alpha &&
-           (plane_states[0]->fb->format->has_alpha ||
-           (plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE)))
+           (plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE))
                return -EINVAL;
 
        for (i = 1; i < num_planes; i++) {
@@ -995,7 +994,6 @@ static const struct sun4i_backend_quirks sun6i_backend_quirks = {
 
 static const struct sun4i_backend_quirks sun7i_backend_quirks = {
        .needs_output_muxing = true,
-       .supports_lowest_plane_alpha = true,
 };
 
 static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = {
index 359b56e..e40c542 100644 (file)
@@ -195,7 +195,7 @@ void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
        switch (encoder->encoder_type) {
        case DRM_MODE_ENCODER_LVDS:
                is_lvds = true;
-               /* Fallthrough */
+               fallthrough;
        case DRM_MODE_ENCODER_DSI:
        case DRM_MODE_ENCODER_NONE:
                channel = 0;
@@ -342,7 +342,7 @@ static void sun4i_tcon0_mode_set_dithering(struct sun4i_tcon *tcon,
                /* R and B components are only 5 bits deep */
                val |= SUN4I_TCON0_FRM_CTL_MODE_R;
                val |= SUN4I_TCON0_FRM_CTL_MODE_B;
-               /* Fall through */
+               fallthrough;
        case MEDIA_BUS_FMT_RGB666_1X18:
        case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
                /* Fall through: enable dithering */
@@ -1433,14 +1433,18 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
        if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
            encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {
                ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);
-               if (ret)
+               if (ret) {
+                       put_device(&pdev->dev);
                        return ret;
+               }
        }
 
        if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP)) {
                ret = sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);
-               if (ret)
+               if (ret) {
+                       put_device(&pdev->dev);
                        return ret;
+               }
        }
 
        return 0;
index aa67cb0..de8a11a 100644 (file)
@@ -889,7 +889,7 @@ static int sun6i_dsi_dcs_write_long(struct sun6i_dsi *dsi,
        regmap_write(dsi->regs, SUN6I_DSI_CMD_TX_REG(0),
                     sun6i_dsi_dcs_build_pkt_hdr(dsi, msg));
 
-       bounce = kzalloc(msg->tx_len + sizeof(crc), GFP_KERNEL);
+       bounce = kzalloc(ALIGN(msg->tx_len + sizeof(crc), 4), GFP_KERNEL);
        if (!bounce)
                return -ENOMEM;
 
@@ -900,7 +900,7 @@ static int sun6i_dsi_dcs_write_long(struct sun6i_dsi *dsi,
        memcpy((u8 *)bounce + msg->tx_len, &crc, sizeof(crc));
        len += sizeof(crc);
 
-       regmap_bulk_write(dsi->regs, SUN6I_DSI_CMD_TX_REG(1), bounce, len);
+       regmap_bulk_write(dsi->regs, SUN6I_DSI_CMD_TX_REG(1), bounce, DIV_ROUND_UP(len, 4));
        regmap_write(dsi->regs, SUN6I_DSI_CMD_CTL_REG, len + 4 - 1);
        kfree(bounce);
 
@@ -1027,7 +1027,7 @@ static ssize_t sun6i_dsi_transfer(struct mipi_dsi_host *host,
                        ret = sun6i_dsi_dcs_read(dsi, msg);
                        break;
                }
-               /* Else, fall through */
+               fallthrough;
 
        default:
                ret = -EINVAL;
index f42441b..a55a38a 100644 (file)
@@ -12,7 +12,7 @@ struct sun8i_mixer;
 
 /* VI channel CSC units offsets */
 #define CCSC00_OFFSET 0xAA050
-#define CCSC01_OFFSET 0xFA000
+#define CCSC01_OFFSET 0xFA050
 #define CCSC10_OFFSET 0xA0000
 #define CCSC11_OFFSET 0xF0000
 
index cc4fb91..c330402 100644 (file)
@@ -307,7 +307,7 @@ static struct regmap_config sun8i_mixer_regmap_config = {
        .reg_bits       = 32,
        .val_bits       = 32,
        .reg_stride     = 4,
-       .max_register   = 0xbfffc, /* guessed */
+       .max_register   = 0xffffc, /* guessed */
 };
 
 static int sun8i_mixer_of_get_id(struct device_node *node)
index 22c8c53..c0147af 100644 (file)
@@ -211,7 +211,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
        return 0;
 }
 
-static bool sun8i_vi_layer_get_csc_mode(const struct drm_format_info *format)
+static u32 sun8i_vi_layer_get_csc_mode(const struct drm_format_info *format)
 {
        if (!format->is_yuv)
                return SUN8I_CSC_MODE_OFF;
index 9a0b324..424ad60 100644 (file)
@@ -135,7 +135,7 @@ static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v,
 
                default:
                        WARN_ON_ONCE(1);
-                       /* fallthrough */
+                       fallthrough;
                case 4:
                        max = 4;
                        break;
index 1856962..518220b 100644 (file)
@@ -386,7 +386,7 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
                case DRM_FORMAT_XBGR8888:
                case DRM_FORMAT_XRGB8888:
                        reg |= LCDC_V2_TFT_24BPP_UNPACK;
-                       /* fallthrough */
+                       fallthrough;
                case DRM_FORMAT_BGR888:
                case DRM_FORMAT_RGB888:
                        reg |= LCDC_V2_TFT_24BPP_MODE;
index 33526c5..4732dcc 100644 (file)
@@ -525,7 +525,7 @@ int ttm_bo_vm_access(struct vm_area_struct *vma, unsigned long addr,
                        if (unlikely(ret != 0))
                                return ret;
                }
-               /* fall through */
+               fallthrough;
        case TTM_PL_TT:
                ret = ttm_bo_vm_access_kmap(bo, offset, buf, len, write);
                break;
index d733bbc..17ff24d 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/version.h>
 #include <linux/dma-buf.h>
 #include <linux/of_graph.h>
+#include <linux/delay.h>
 
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fourcc.h>
@@ -130,9 +131,25 @@ static void tve200_display_enable(struct drm_simple_display_pipe *pipe,
        struct drm_connector *connector = priv->connector;
        u32 format = fb->format->format;
        u32 ctrl1 = 0;
+       int retries;
 
        clk_prepare_enable(priv->clk);
 
+       /* Reset the TVE200 and wait for it to come back online */
+       writel(TVE200_CTRL_4_RESET, priv->regs + TVE200_CTRL_4);
+       for (retries = 0; retries < 5; retries++) {
+               usleep_range(30000, 50000);
+               if (readl(priv->regs + TVE200_CTRL_4) & TVE200_CTRL_4_RESET)
+                       continue;
+               else
+                       break;
+       }
+       if (retries == 5 &&
+           readl(priv->regs + TVE200_CTRL_4) & TVE200_CTRL_4_RESET) {
+               dev_err(drm->dev, "can't get hardware out of reset\n");
+               return;
+       }
+
        /* Function 1 */
        ctrl1 |= TVE200_CTRL_CSMODE;
        /* Interlace mode for CCIR656: parameterize? */
@@ -230,8 +247,9 @@ static void tve200_display_disable(struct drm_simple_display_pipe *pipe)
 
        drm_crtc_vblank_off(crtc);
 
-       /* Disable and Power Down */
+       /* Disable put into reset and Power Down */
        writel(0, priv->regs + TVE200_CTRL);
+       writel(TVE200_CTRL_4_RESET, priv->regs + TVE200_CTRL_4);
 
        clk_disable_unprepare(priv->clk);
 }
@@ -279,6 +297,8 @@ static int tve200_display_enable_vblank(struct drm_simple_display_pipe *pipe)
        struct drm_device *drm = crtc->dev;
        struct tve200_drm_dev_private *priv = drm->dev_private;
 
+       /* Clear any IRQs and enable */
+       writel(0xFF, priv->regs + TVE200_INT_CLR);
        writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN);
        return 0;
 }
index 15a11cd..6339c6f 100644 (file)
@@ -1117,6 +1117,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
        card->num_links = 1;
        card->name = "vc4-hdmi";
        card->dev = dev;
+       card->owner = THIS_MODULE;
 
        /*
         * Be careful, snd_soc_register_card() calls dev_set_drvdata() and
index 551fa31..5771bb5 100644 (file)
@@ -179,21 +179,21 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
        switch (vsg->state) {
        case dr_via_device_mapped:
                via_unmap_blit_from_device(pdev, vsg);
-               /* fall through */
+               fallthrough;
        case dr_via_desc_pages_alloc:
                for (i = 0; i < vsg->num_desc_pages; ++i) {
                        if (vsg->desc_pages[i] != NULL)
                                free_page((unsigned long)vsg->desc_pages[i]);
                }
                kfree(vsg->desc_pages);
-               /* fall through */
+               fallthrough;
        case dr_via_pages_locked:
                unpin_user_pages_dirty_lock(vsg->pages, vsg->num_pages,
                                           (vsg->direction == DMA_FROM_DEVICE));
-               /* fall through */
+               fallthrough;
        case dr_via_pages_alloc:
                vfree(vsg->pages);
-               /* fall through */
+               fallthrough;
        default:
                vsg->state = dr_via_sg_init;
        }
index af55b33..afd0f92 100644 (file)
@@ -97,9 +97,6 @@ static void virtio_gpu_crtc_mode_set_nofb(struct drm_crtc *crtc)
 static void virtio_gpu_crtc_atomic_enable(struct drm_crtc *crtc,
                                          struct drm_crtc_state *old_state)
 {
-       struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc);
-
-       output->enabled = true;
 }
 
 static void virtio_gpu_crtc_atomic_disable(struct drm_crtc *crtc,
@@ -111,7 +108,6 @@ static void virtio_gpu_crtc_atomic_disable(struct drm_crtc *crtc,
 
        virtio_gpu_cmd_set_scanout(vgdev, output->index, 0, 0, 0, 0, 0);
        virtio_gpu_notify(vgdev);
-       output->enabled = false;
 }
 
 static int virtio_gpu_crtc_atomic_check(struct drm_crtc *crtc,
@@ -123,6 +119,17 @@ static int virtio_gpu_crtc_atomic_check(struct drm_crtc *crtc,
 static void virtio_gpu_crtc_atomic_flush(struct drm_crtc *crtc,
                                         struct drm_crtc_state *old_state)
 {
+       struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc);
+
+       /*
+        * virtio-gpu can't do modeset and plane update operations
+        * independent from each other.  So the actual modeset happens
+        * in the plane update callback, and here we just check
+        * whenever we must force the modeset.
+        */
+       if (drm_atomic_crtc_needs_modeset(crtc->state)) {
+               output->needs_modeset = true;
+       }
 }
 
 static const struct drm_crtc_helper_funcs virtio_gpu_crtc_helper_funcs = {
index 9ff9f4a..fbc0427 100644 (file)
@@ -137,7 +137,7 @@ struct virtio_gpu_output {
        struct edid *edid;
        int cur_x;
        int cur_y;
-       bool enabled;
+       bool needs_modeset;
 };
 #define drm_crtc_to_virtio_gpu_output(x) \
        container_of(x, struct virtio_gpu_output, crtc)
index e83651b..842f8b6 100644 (file)
@@ -151,7 +151,13 @@ static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev,
        if (ret < 0)
                return -EINVAL;
 
-       shmem->pages = drm_gem_shmem_get_pages_sgt(&bo->base.base);
+       /*
+        * virtio_gpu uses drm_gem_shmem_get_sg_table instead of
+        * drm_gem_shmem_get_pages_sgt because virtio has it's own set of
+        * dma-ops. This is discouraged for other drivers, but should be fine
+        * since virtio_gpu doesn't support dma-buf import from other devices.
+        */
+       shmem->pages = drm_gem_shmem_get_sg_table(&bo->base.base);
        if (!shmem->pages) {
                drm_gem_shmem_unpin(&bo->base.base);
                return -EINVAL;
index 52d2417..6a311cd 100644 (file)
@@ -142,7 +142,7 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
        if (WARN_ON(!output))
                return;
 
-       if (!plane->state->fb || !output->enabled) {
+       if (!plane->state->fb || !output->crtc.state->active) {
                DRM_DEBUG("nofb\n");
                virtio_gpu_cmd_set_scanout(vgdev, output->index, 0,
                                           plane->state->src_w >> 16,
@@ -163,7 +163,9 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
            plane->state->src_w != old_state->src_w ||
            plane->state->src_h != old_state->src_h ||
            plane->state->src_x != old_state->src_x ||
-           plane->state->src_y != old_state->src_y) {
+           plane->state->src_y != old_state->src_y ||
+           output->needs_modeset) {
+               output->needs_modeset = false;
                DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n",
                          bo->hw_res_handle,
                          plane->state->crtc_w, plane->state->crtc_h,
index 4a76fc7..f8bdd4e 100644 (file)
@@ -55,7 +55,7 @@ static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
 
        id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL);
        if (id < 0)
-               return (id != -ENOMEM ? 0 : id);
+               return id;
 
        spin_lock(&gman->lock);
 
index b7c816b..c8b9335 100644 (file)
@@ -95,7 +95,7 @@ found_unlock:
                mem->start = node->start;
        }
 
-       return 0;
+       return ret;
 }
 
 
index 013c9e0..cc93a8c 100644 (file)
@@ -649,9 +649,7 @@ static void displback_changed(struct xenbus_device *xb_dev,
 
        switch (backend_state) {
        case XenbusStateReconfiguring:
-               /* fall through */
        case XenbusStateReconfigured:
-               /* fall through */
        case XenbusStateInitialised:
                break;
 
@@ -701,7 +699,6 @@ static void displback_changed(struct xenbus_device *xb_dev,
                break;
 
        case XenbusStateUnknown:
-               /* fall through */
        case XenbusStateClosed:
                if (xb_dev->state == XenbusStateClosed)
                        break;
index 39ff95b..534daf3 100644 (file)
@@ -18,6 +18,7 @@
 #include <drm/drm_probe_helper.h>
 
 #include <xen/balloon.h>
+#include <xen/xen.h>
 
 #include "xen_drm_front.h"
 #include "xen_drm_front_gem.h"
@@ -99,8 +100,8 @@ static struct xen_gem_object *gem_create(struct drm_device *dev, size_t size)
                 * allocate ballooned pages which will be used to map
                 * grant references provided by the backend
                 */
-               ret = alloc_xenballooned_pages(xen_obj->num_pages,
-                                              xen_obj->pages);
+               ret = xen_alloc_unpopulated_pages(xen_obj->num_pages,
+                                                 xen_obj->pages);
                if (ret < 0) {
                        DRM_ERROR("Cannot allocate %zu ballooned pages: %d\n",
                                  xen_obj->num_pages, ret);
@@ -152,8 +153,8 @@ void xen_drm_front_gem_free_object_unlocked(struct drm_gem_object *gem_obj)
        } else {
                if (xen_obj->pages) {
                        if (xen_obj->be_alloc) {
-                               free_xenballooned_pages(xen_obj->num_pages,
-                                                       xen_obj->pages);
+                               xen_free_unpopulated_pages(xen_obj->num_pages,
+                                                          xen_obj->pages);
                                gem_free_pages_array(xen_obj);
                        } else {
                                drm_gem_put_pages(&xen_obj->base,
index aa6cd88..b52c6cd 100644 (file)
@@ -2,6 +2,7 @@ config DRM_ZYNQMP_DPSUB
        tristate "ZynqMP DisplayPort Controller Driver"
        depends on ARCH_ZYNQMP || COMPILE_TEST
        depends on COMMON_CLK && DRM && OF
+       depends on DMADEVICES
        select DMA_ENGINE
        select DRM_GEM_CMA_HELPER
        select DRM_KMS_CMA_HELPER
index dbcc167..34b4075 100644 (file)
@@ -141,7 +141,7 @@ static int ipu_bus_format_to_map(u32 fmt)
        switch (fmt) {
        default:
                WARN_ON(1);
-               /* fall-through */
+               fallthrough;
        case MEDIA_BUS_FMT_RGB888_1X24:
                return IPU_DC_MAP_RGB24;
        case MEDIA_BUS_FMT_RGB565_1X16:
index 359616e..d2ecc9c 100644 (file)
@@ -1598,6 +1598,17 @@ static void hid_output_field(const struct hid_device *hid,
 }
 
 /*
+ * Compute the size of a report.
+ */
+static size_t hid_compute_report_size(struct hid_report *report)
+{
+       if (report->size)
+               return ((report->size - 1) >> 3) + 1;
+
+       return 0;
+}
+
+/*
  * Create a report. 'data' has to be allocated using
  * hid_alloc_report_buf() so that it has proper size.
  */
@@ -1609,7 +1620,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
        if (report->id > 0)
                *data++ = report->id;
 
-       memset(data, 0, ((report->size - 1) >> 3) + 1);
+       memset(data, 0, hid_compute_report_size(report));
        for (n = 0; n < report->maxfield; n++)
                hid_output_field(report->device, report->field[n], data);
 }
@@ -1739,7 +1750,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
                csize--;
        }
 
-       rsize = ((report->size - 1) >> 3) + 1;
+       rsize = hid_compute_report_size(report);
 
        if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE)
                rsize = HID_MAX_BUFFER_SIZE - 1;
index 4ff3bc1..28d671c 100644 (file)
@@ -321,7 +321,7 @@ static const struct kernel_param_ops cougar_g6_is_space_ops = {
 };
 module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644);
 
-static struct hid_device_id cougar_id_table[] = {
+static const struct hid_device_id cougar_id_table[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
                         USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
index 45c4f88..dae1937 100644 (file)
@@ -188,6 +188,7 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
        ret = input_mt_init_slots(input, ELAN_MAX_FINGERS, INPUT_MT_POINTER);
        if (ret) {
                hid_err(hdev, "Failed to init elan MT slots: %d\n", ret);
+               input_free_device(input);
                return ret;
        }
 
@@ -198,6 +199,7 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
        if (ret) {
                hid_err(hdev, "Failed to register elan input device: %d\n",
                        ret);
+               input_mt_destroy_slots(input);
                input_free_device(input);
                return ret;
        }
index 6221888..74fc1df 100644 (file)
 #define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
 #define USB_DEVICE_ID_LENOVO_X1_COVER  0x6085
 #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D     0x608d
+#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019     0x6019
+#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E     0x602e
+#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093     0x6093
 
 #define USB_VENDOR_ID_LG               0x1fd2
 #define USB_DEVICE_ID_LG_MULTITOUCH    0x0064
 #define USB_DEVICE_ID_MS_POWER_COVER     0x07da
 #define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd
 #define USB_DEVICE_ID_MS_PIXART_MOUSE    0x00cb
+#define USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS      0x02e0
 
 #define USB_VENDOR_ID_MOJO             0x8282
 #define USB_DEVICE_ID_RETRO_ADAPTER    0x3201
 #define USB_DEVICE_ID_SAITEK_RAT9      0x0cfa
 #define USB_DEVICE_ID_SAITEK_MMO7      0x0cd0
 #define USB_DEVICE_ID_SAITEK_X52       0x075c
+#define USB_DEVICE_ID_SAITEK_X52_2     0x0255
+#define USB_DEVICE_ID_SAITEK_X52_PRO   0x0762
 
 #define USB_VENDOR_ID_SAMSUNG          0x0419
 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE        0x0001
index b8eabf2..88e1999 100644 (file)
@@ -1132,6 +1132,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
        }
 
 mapped:
+       /* Mapping failed, bail out */
+       if (!bit)
+               return;
+
        if (device->driver->input_mapped &&
            device->driver->input_mapped(device, hidinput, field, usage,
                                         &bit, &max) < 0) {
index ef0cbcd..fcaf846 100644 (file)
@@ -680,7 +680,7 @@ static int lg_g15_register_led(struct lg_g15_data *g15, int i)
                         * but it does have a separate power-on (reset) value.
                         */
                        g15->leds[i].cdev.name = "g15::power_on_backlight_val";
-                       /* fall through */
+                       fallthrough;
                case LG_G15_KBD_BRIGHTNESS:
                        g15->leds[i].cdev.brightness_set_blocking =
                                lg_g510_kbd_led_set;
index a78c13c..38ee25a 100644 (file)
@@ -844,7 +844,7 @@ static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
                        workitem.type = WORKITEM_TYPE_EMPTY;
                        break;
                }
-               /* fall-through */
+               fallthrough;
        case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
                workitem.quad_id_msb =
                        dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB];
index 9a4fc7d..aea46e5 100644 (file)
@@ -29,7 +29,7 @@ static __u8 *macally_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        return rdesc;
 }
 
-static struct hid_device_id macally_id_table[] = {
+static const struct hid_device_id macally_id_table[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
                         USB_DEVICE_ID_MACALLY_IKEY_KEYBOARD) },
        { }
index 2d8b589..071fd09 100644 (file)
@@ -163,16 +163,13 @@ static int ms_surface_dial_quirk(struct hid_input *hi, struct hid_field *field,
 {
        switch (usage->hid & HID_USAGE_PAGE) {
        case 0xff070000:
-               /* fall-through */
        case HID_UP_DIGITIZER:
                /* ignore those axis */
                return -1;
        case HID_UP_GENDESK:
                switch (usage->hid) {
                case HID_GD_X:
-                       /* fall-through */
                case HID_GD_Y:
-                       /* fall-through */
                case HID_GD_RFKILL_BTN:
                        /* ignore those axis */
                        return -1;
@@ -451,6 +448,8 @@ static const struct hid_device_id ms_devices[] = {
                .driver_data = MS_SURFACE_DIAL },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER),
                .driver_data = MS_QUIRK_FF },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS),
+               .driver_data = MS_QUIRK_FF },
        { }
 };
 MODULE_DEVICE_TABLE(hid, ms_devices);
index 3f94b49..e315215 100644 (file)
@@ -856,6 +856,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        code = BTN_0  + ((usage->hid - 1) & HID_USAGE);
 
                hid_map_usage(hi, usage, bit, max, EV_KEY, code);
+               if (!*bit)
+                       return -1;
                input_set_capability(hi->input, EV_KEY, code);
                return 1;
 
index c242150..7a2be02 100644 (file)
@@ -105,6 +105,9 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET },
@@ -147,6 +150,8 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_PRO), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
        { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
index 8cffa84..7f41213 100644 (file)
@@ -428,7 +428,6 @@ static void rmi_report(struct hid_device *hid, struct hid_report *report)
 
        switch (report->id) {
        case RMI_READ_DATA_REPORT_ID:
-               /* fall-through */
        case RMI_ATTN_REPORT_ID:
                return;
        }
index 1a6e600..2ff4c8e 100644 (file)
@@ -780,7 +780,7 @@ static void kone_keep_values_up_to_date(struct kone_device *kone,
        case kone_mouse_event_switch_profile:
                kone->actual_dpi = kone->profiles[event->value - 1].
                                startup_dpi;
-               /* fall through */
+               fallthrough;
        case kone_mouse_event_osd_profile:
                kone->actual_profile = event->value;
                break;
index 78a364a..7d20d1f 100644 (file)
@@ -974,7 +974,7 @@ int uclogic_params_init(struct uclogic_params *params,
                        }
                        break;
                }
-               /* FALL THROUGH */
+               fallthrough;
        case VID_PID(USB_VENDOR_ID_HUION,
                     USB_DEVICE_ID_HUION_TABLET):
        case VID_PID(USB_VENDOR_ID_HUION,
index 679e142..e484c36 100644 (file)
@@ -1672,7 +1672,6 @@ static ssize_t wiimote_ext_show(struct device *dev,
        case WIIMOTE_EXT_GUITAR:
                return sprintf(buf, "guitar\n");
        case WIIMOTE_EXT_UNKNOWN:
-               /* fallthrough */
        default:
                return sprintf(buf, "unknown\n");
        }
@@ -1722,7 +1721,6 @@ static ssize_t wiimote_dev_show(struct device *dev,
        case WIIMOTE_DEV_PENDING:
                return sprintf(buf, "pending\n");
        case WIIMOTE_DEV_UNKNOWN:
-               /* fallthrough */
        default:
                return sprintf(buf, "unknown\n");
        }
index 294c84e..dbd0449 100644 (file)
@@ -420,6 +420,19 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
                dev_err(&client->dev, "failed to change power setting.\n");
 
 set_pwr_exit:
+
+       /*
+        * The HID over I2C specification states that if a DEVICE needs time
+        * after the PWR_ON request, it should utilise CLOCK stretching.
+        * However, it has been observered that the Windows driver provides a
+        * 1ms sleep between the PWR_ON and RESET requests.
+        * According to Goodix Windows even waits 60 ms after (other?)
+        * PWR_ON requests. Testing has confirmed that several devices
+        * will not work properly without a delay after a PWR_ON request.
+        */
+       if (!ret && power_state == I2C_HID_PWR_ON)
+               msleep(60);
+
        return ret;
 }
 
@@ -441,15 +454,6 @@ static int i2c_hid_hwreset(struct i2c_client *client)
        if (ret)
                goto out_unlock;
 
-       /*
-        * The HID over I2C specification states that if a DEVICE needs time
-        * after the PWR_ON request, it should utilise CLOCK stretching.
-        * However, it has been observered that the Windows driver provides a
-        * 1ms sleep between the PWR_ON and RESET requests and that some devices
-        * rely on this.
-        */
-       usleep_range(1000, 5000);
-
        i2c_hid_dbg(ihid, "resetting...\n");
 
        ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0);
index 492dd64..17a29ee 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/string.h>
-#include <linux/timekeeping.h>
 
 #include <linux/usb.h>
 
@@ -96,18 +95,6 @@ static int hid_start_in(struct hid_device *hid)
                                set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
                } else {
                        clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
-
-                       if (test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
-                               /*
-                                * In case events are generated while nobody was
-                                * listening, some are released when the device
-                                * is re-opened. Wait 50 msec for the queue to
-                                * empty before allowing events to go through
-                                * hid.
-                                */
-                               usbhid->input_start_time =
-                                       ktime_add_ms(ktime_get_coarse(), 50);
-                       }
                }
        }
        spin_unlock_irqrestore(&usbhid->lock, flags);
@@ -293,23 +280,20 @@ static void hid_irq_in(struct urb *urb)
                if (!test_bit(HID_OPENED, &usbhid->iofl))
                        break;
                usbhid_mark_busy(usbhid);
-               if (test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
-                       if (ktime_before(ktime_get_coarse(),
-                                        usbhid->input_start_time))
-                               break;
-                       clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
+               if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
+                       hid_input_report(urb->context, HID_INPUT_REPORT,
+                                        urb->transfer_buffer,
+                                        urb->actual_length, 1);
+                       /*
+                        * autosuspend refused while keys are pressed
+                        * because most keyboards don't wake up when
+                        * a key is released
+                        */
+                       if (hid_check_keys_pressed(hid))
+                               set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
+                       else
+                               clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
                }
-               hid_input_report(urb->context, HID_INPUT_REPORT,
-                                urb->transfer_buffer, urb->actual_length, 1);
-               /*
-                * autosuspend refused while keys are pressed
-                * because most keyboards don't wake up when
-                * a key is released
-                */
-               if (hid_check_keys_pressed(hid))
-                       set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
-               else
-                       clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
                break;
        case -EPIPE:            /* stall */
                usbhid_mark_busy(usbhid);
@@ -736,6 +720,17 @@ static int usbhid_open(struct hid_device *hid)
 
        usb_autopm_put_interface(usbhid->intf);
 
+       /*
+        * In case events are generated while nobody was listening,
+        * some are released when the device is re-opened.
+        * Wait 50 msec for the queue to empty before allowing events
+        * to go through hid.
+        */
+       if (res == 0)
+               msleep(50);
+
+       clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
+
  Done:
        mutex_unlock(&usbhid->mutex);
        return res;
index 4140dea..45e0b1c 100644 (file)
@@ -519,12 +519,16 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
 
                switch (cmd) {
                case HIDIOCGUSAGE:
+                       if (uref->usage_index >= field->report_count)
+                               goto inval;
                        uref->value = field->value[uref->usage_index];
                        if (copy_to_user(user_arg, uref, sizeof(*uref)))
                                goto fault;
                        goto goodreturn;
 
                case HIDIOCSUSAGE:
+                       if (uref->usage_index >= field->report_count)
+                               goto inval;
                        field->value[uref->usage_index] = uref->value;
                        goto goodreturn;
 
@@ -781,7 +785,6 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                break;
 
        case HIDIOCGUCODE:
-               /* fall through */
        case HIDIOCGUSAGE:
        case HIDIOCSUSAGE:
        case HIDIOCGUSAGES:
index c6ad684..75fe85d 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/types.h>
 #include <linux/slab.h>
-#include <linux/ktime.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/timer.h>
@@ -84,7 +83,6 @@ struct usbhid_device {
        struct mutex mutex;                                             /* start/stop/open/close */
        spinlock_t lock;                                                /* fifo spinlock */
        unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
-       ktime_t input_start_time;                                       /* When to start handling input */
        struct timer_list io_retry;                                     /* Retry timer */
        unsigned long stop_retry;                                       /* Time to give up, in jiffies */
        unsigned int retry_delay;                                       /* Delay length in ms */
index 1c96809..83dfec3 100644 (file)
@@ -341,7 +341,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
 
                        case 2: /* Mouse with wheel */
                                input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
-                               /* fall through */
+                               fallthrough;
 
                        case 3: /* Mouse without wheel */
                                wacom->tool[0] = BTN_TOOL_MOUSE;
@@ -1201,7 +1201,7 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
        case 0x04:
                wacom_intuos_bt_process_data(wacom, data + i);
                i += 10;
-               /* fall through */
+               fallthrough;
        case 0x03:
                wacom_intuos_bt_process_data(wacom, data + i);
                i += 10;
@@ -2148,7 +2148,7 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
                for (i = 0; i < wacom->led.count; i++)
                        wacom_update_led(wacom, features->numbered_buttons,
                                         value, i);
-                /* fall through*/
+               fallthrough;
        default:
                do_report = true;
                break;
@@ -3602,14 +3602,14 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
        switch (features->type) {
        case GRAPHIRE_BT:
                __clear_bit(ABS_MISC, input_dev->absbit);
-               /* fall through */
+               fallthrough;
 
        case WACOM_MO:
        case WACOM_G4:
                input_set_abs_params(input_dev, ABS_DISTANCE, 0,
                                              features->distance_max,
                                              features->distance_fuzz, 0);
-               /* fall through */
+               fallthrough;
 
        case GRAPHIRE:
                input_set_capability(input_dev, EV_REL, REL_WHEEL);
@@ -3649,7 +3649,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
        case INTUOS4S:
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                input_abs_set_res(input_dev, ABS_Z, 287);
-               /* fall through */
+               fallthrough;
 
        case INTUOS:
                wacom_setup_intuos(wacom_wac);
@@ -3682,7 +3682,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
        case TABLETPC:
        case TABLETPCE:
                __clear_bit(ABS_MISC, input_dev->absbit);
-               /* fall through */
+               fallthrough;
 
        case DTUS:
        case DTUSX:
@@ -3696,7 +3696,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
 
        case PTU:
                __set_bit(BTN_STYLUS2, input_dev->keybit);
-               /* fall through */
+               fallthrough;
 
        case PENPARTNER:
                __set_bit(BTN_TOOL_PEN, input_dev->keybit);
@@ -3799,7 +3799,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
                input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
                input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 40);
 
-               /* fall through */
+               fallthrough;
 
        case INTUOS5:
        case INTUOS5L:
@@ -3817,7 +3817,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
                input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, features->x_max, 0, 0);
                input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, 0, features->y_max, 0, 0);
                input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
-               /* fall through */
+               fallthrough;
 
        case WACOM_27QHDT:
                if (wacom_wac->shared->touch->product == 0x32C ||
@@ -3826,14 +3826,14 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
                        __set_bit(SW_MUTE_DEVICE, input_dev->swbit);
                        wacom_wac->shared->has_mute_touch_switch = true;
                }
-               /* fall through */
+               fallthrough;
 
        case MTSCREEN:
        case MTTPC:
        case MTTPC_B:
        case TABLETPC2FG:
                input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT);
-               /*fall through */
+               fallthrough;
 
        case TABLETPC:
        case TABLETPCE:
@@ -3843,7 +3843,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
        case INTUOSHT2:
                input_dev->evbit[0] |= BIT_MASK(EV_SW);
                __set_bit(SW_MUTE_DEVICE, input_dev->swbit);
-               /* fall through */
+               fallthrough;
 
        case BAMBOO_PT:
        case BAMBOO_TOUCH:
@@ -4099,7 +4099,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
 
                __set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
                __set_bit(KEY_INFO, input_dev->keybit);
-               /* fall through */
+               fallthrough;
 
        case WACOM_21UX2:
        case WACOM_BEE:
@@ -4115,7 +4115,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
        case INTUOS3:
        case INTUOS3L:
                input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
-               /* fall through */
+               fallthrough;
 
        case INTUOS3S:
                input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
@@ -4139,7 +4139,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
                 * ID_INPUT_TABLET to be set.
                 */
                __set_bit(BTN_STYLUS, input_dev->keybit);
-               /* fall through */
+               fallthrough;
 
        case INTUOS4:
        case INTUOS4L:
index 365b5d5..96d0ecc 100644 (file)
@@ -291,7 +291,7 @@ static void ssip_set_rxstate(struct ssi_protocol *ssi, unsigned int state)
                /* CMT speech workaround */
                if (atomic_read(&ssi->tx_usecnt))
                        break;
-               /* Else, fall through */
+               fallthrough;
        case RECEIVING:
                mod_timer(&ssi->keep_alive, jiffies +
                                                msecs_to_jiffies(SSIP_KATOUT));
@@ -466,7 +466,7 @@ static void ssip_keep_alive(struct timer_list *t)
                case SEND_READY:
                        if (atomic_read(&ssi->tx_usecnt) == 0)
                                break;
-                       /* Fall through */
+                       fallthrough;
                        /*
                         * Workaround for cmt-speech in that case
                         * we relay on audio timers.
@@ -668,7 +668,7 @@ static void ssip_rx_bootinforeq(struct hsi_client *cl, u32 cmd)
        case ACTIVE:
                dev_err(&cl->device, "Boot info req on active state\n");
                ssip_error(cl);
-               /* Fall through */
+               fallthrough;
        case INIT:
        case HANDSHAKE:
                spin_lock_bh(&ssi->lock);
index 4bc4a20..fa69b94 100644 (file)
@@ -296,7 +296,7 @@ static int ssi_clk_event(struct notifier_block *nb, unsigned long event,
                break;
        case ABORT_RATE_CHANGE:
                dev_dbg(&ssi->device, "abort rate change\n");
-               /* Fall through */
+               fallthrough;
        case POST_RATE_CHANGE:
                dev_dbg(&ssi->device, "post rate change (%lu -> %lu)\n",
                        clk_data->old_rate, clk_data->new_rate);
index 591106c..1d44bb6 100644 (file)
@@ -731,7 +731,7 @@ static void vmbus_wait_for_unload(void)
        void *page_addr;
        struct hv_message *msg;
        struct vmbus_channel_message_header *hdr;
-       u32 message_type;
+       u32 message_type, i;
 
        /*
         * CHANNELMSG_UNLOAD_RESPONSE is always delivered to the CPU which was
@@ -741,8 +741,11 @@ static void vmbus_wait_for_unload(void)
         * functional and vmbus_unload_response() will complete
         * vmbus_connection.unload_event. If not, the last thing we can do is
         * read message pages for all CPUs directly.
+        *
+        * Wait no more than 10 seconds so that the panic path can't get
+        * hung forever in case the response message isn't seen.
         */
-       while (1) {
+       for (i = 0; i < 1000; i++) {
                if (completion_done(&vmbus_connection.unload_event))
                        break;
 
index e74b144..754d35a 100644 (file)
@@ -354,7 +354,7 @@ static void process_ib_ipinfo(void *in_msg, void *out_msg, int op)
 
                out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled;
 
-               /* fallthrough */
+               fallthrough;
 
        case KVP_OP_GET_IP_INFO:
                utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id,
index 92ee0fe..a4e8d96 100644 (file)
@@ -282,26 +282,52 @@ static struct {
        spinlock_t                      lock;
 } host_ts;
 
-static struct timespec64 hv_get_adj_host_time(void)
+static inline u64 reftime_to_ns(u64 reftime)
 {
-       struct timespec64 ts;
-       u64 newtime, reftime;
+       return (reftime - WLTIMEDELTA) * 100;
+}
+
+/*
+ * Hard coded threshold for host timesync delay: 600 seconds
+ */
+static const u64 HOST_TIMESYNC_DELAY_THRESH = 600 * (u64)NSEC_PER_SEC;
+
+static int hv_get_adj_host_time(struct timespec64 *ts)
+{
+       u64 newtime, reftime, timediff_adj;
        unsigned long flags;
+       int ret = 0;
 
        spin_lock_irqsave(&host_ts.lock, flags);
        reftime = hv_read_reference_counter();
-       newtime = host_ts.host_time + (reftime - host_ts.ref_time);
-       ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100);
+
+       /*
+        * We need to let the caller know that last update from host
+        * is older than the max allowable threshold. clock_gettime()
+        * and PTP ioctl do not have a documented error that we could
+        * return for this specific case. Use ESTALE to report this.
+        */
+       timediff_adj = reftime - host_ts.ref_time;
+       if (timediff_adj * 100 > HOST_TIMESYNC_DELAY_THRESH) {
+               pr_warn_once("TIMESYNC IC: Stale time stamp, %llu nsecs old\n",
+                            (timediff_adj * 100));
+               ret = -ESTALE;
+       }
+
+       newtime = host_ts.host_time + timediff_adj;
+       *ts = ns_to_timespec64(reftime_to_ns(newtime));
        spin_unlock_irqrestore(&host_ts.lock, flags);
 
-       return ts;
+       return ret;
 }
 
 static void hv_set_host_time(struct work_struct *work)
 {
-       struct timespec64 ts = hv_get_adj_host_time();
 
-       do_settimeofday64(&ts);
+       struct timespec64 ts;
+
+       if (!hv_get_adj_host_time(&ts))
+               do_settimeofday64(&ts);
 }
 
 /*
@@ -361,10 +387,23 @@ static void timesync_onchannelcallback(void *context)
        struct ictimesync_ref_data *refdata;
        u8 *time_txf_buf = util_timesynch.recv_buffer;
 
-       vmbus_recvpacket(channel, time_txf_buf,
-                        HV_HYP_PAGE_SIZE, &recvlen, &requestid);
+       /*
+        * Drain the ring buffer and use the last packet to update
+        * host_ts
+        */
+       while (1) {
+               int ret = vmbus_recvpacket(channel, time_txf_buf,
+                                          HV_HYP_PAGE_SIZE, &recvlen,
+                                          &requestid);
+               if (ret) {
+                       pr_warn_once("TimeSync IC pkt recv failed (Err: %d)\n",
+                                    ret);
+                       break;
+               }
+
+               if (!recvlen)
+                       break;
 
-       if (recvlen > 0) {
                icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
                                sizeof(struct vmbuspipe_hdr)];
 
@@ -622,9 +661,7 @@ static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 
 static int hv_ptp_gettime(struct ptp_clock_info *info, struct timespec64 *ts)
 {
-       *ts = hv_get_adj_host_time();
-
-       return 0;
+       return hv_get_adj_host_time(ts);
 }
 
 static struct ptp_clock_info ptp_hyperv_info = {
index 910b6e9..946d0ab 100644 (file)
@@ -2382,7 +2382,10 @@ static int vmbus_bus_suspend(struct device *dev)
        if (atomic_read(&vmbus_connection.nr_chan_close_on_suspend) > 0)
                wait_for_completion(&vmbus_connection.ready_for_suspend_event);
 
-       WARN_ON(atomic_read(&vmbus_connection.nr_chan_fixup_on_resume) != 0);
+       if (atomic_read(&vmbus_connection.nr_chan_fixup_on_resume) != 0) {
+               pr_err("Can not suspend due to a previous failed resuming\n");
+               return -EBUSY;
+       }
 
        mutex_lock(&vmbus_connection.channel_mutex);
 
@@ -2456,7 +2459,9 @@ static int vmbus_bus_resume(struct device *dev)
 
        vmbus_request_offers();
 
-       wait_for_completion(&vmbus_connection.ready_for_resume_event);
+       if (wait_for_completion_timeout(
+               &vmbus_connection.ready_for_resume_event, 10 * HZ) == 0)
+               pr_err("Some vmbus device is missing after suspending?\n");
 
        /* Reset the event for the next suspend. */
        reinit_completion(&vmbus_connection.ready_for_suspend_event);
index 319a051..2088131 100644 (file)
@@ -435,7 +435,7 @@ static const char *voltage_label(struct adt7462_data *data, int which)
                case 3:
                        return "+1.5V";
                }
-               /* fall through */
+               fallthrough;
        case 2:
                if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
                        return "+12V3";
@@ -493,7 +493,7 @@ static const char *voltage_label(struct adt7462_data *data, int which)
                case 3:
                        return "+1.5";
                }
-               /* fall through */
+               fallthrough;
        case 11:
                if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
                                        ADT7462_PIN28_VOLT &&
@@ -531,7 +531,7 @@ static int voltage_multiplier(struct adt7462_data *data, int which)
                case 3:
                        return 7800;
                }
-               /* fall through */
+               fallthrough;
        case 2:
                if (!(data->pin_cfg[1] & ADT7462_PIN22_INPUT))
                        return 62500;
@@ -589,7 +589,7 @@ static int voltage_multiplier(struct adt7462_data *data, int which)
                case 3:
                        return 7800;
                }
-               /* fall through */
+               fallthrough;
        case 11:
        case 12:
                if (data->pin_cfg[3] >> ADT7462_PIN28_SHIFT ==
index 3166184..a188879 100644 (file)
@@ -753,15 +753,18 @@ static ssize_t applesmc_light_show(struct device *dev,
        }
 
        ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
+       if (ret)
+               goto out;
        /* newer macbooks report a single 10-bit bigendian value */
        if (data_length == 10) {
                left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
                goto out;
        }
        left = buffer[2];
+
+       ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
        if (ret)
                goto out;
-       ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
        right = buffer[2];
 
 out:
@@ -810,12 +813,11 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
                  to_index(attr));
 
        ret = applesmc_read_key(newkey, buffer, 2);
-       speed = ((buffer[0] << 8 | buffer[1]) >> 2);
-
        if (ret)
                return ret;
-       else
-               return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
+
+       speed = ((buffer[0] << 8 | buffer[1]) >> 2);
+       return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
 }
 
 static ssize_t applesmc_store_fan_speed(struct device *dev,
@@ -851,12 +853,11 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
        u8 buffer[2];
 
        ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
-       manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
-
        if (ret)
                return ret;
-       else
-               return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
+
+       manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
+       return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
 }
 
 static ssize_t applesmc_store_fan_manual(struct device *dev,
@@ -872,10 +873,11 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
                return -EINVAL;
 
        ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
-       val = (buffer[0] << 8 | buffer[1]);
        if (ret)
                goto out;
 
+       val = (buffer[0] << 8 | buffer[1]);
+
        if (input)
                val = val | (0x01 << to_index(attr));
        else
@@ -951,13 +953,12 @@ static ssize_t applesmc_key_count_show(struct device *dev,
        u32 count;
 
        ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
-       count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
-                                               ((u32)buffer[2]<<8) + buffer[3];
-
        if (ret)
                return ret;
-       else
-               return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
+
+       count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
+                                               ((u32)buffer[2]<<8) + buffer[3];
+       return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
 }
 
 static ssize_t applesmc_key_at_index_read_show(struct device *dev,
index cf0962f..e9c0bbc 100644 (file)
@@ -406,10 +406,10 @@ static int emc1403_probe(struct i2c_client *client,
        switch (id->driver_data) {
        case emc1404:
                data->groups[2] = &emc1404_group;
-               /* fall through */
+               fallthrough;
        case emc1403:
                data->groups[1] = &emc1403_group;
-               /* fall through */
+               fallthrough;
        case emc1402:
                data->groups[0] = &emc1402_group;
        }
index d09deb4..4dec793 100644 (file)
@@ -1285,7 +1285,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                                data->pwm_auto_point_pwm[nr][0] =
                                        f71882fg_read8(data,
                                                F71882FG_REG_POINT_PWM(nr, 0));
-                               /* Fall through */
+                               fallthrough;
                        case f71862fg:
                                data->pwm_auto_point_pwm[nr][1] =
                                        f71882fg_read8(data,
@@ -2442,7 +2442,7 @@ static int f71882fg_probe(struct platform_device *pdev)
                case f71869a:
                        /* These always have signed auto point temps */
                        data->auto_point_temp_signed = 1;
-                       /* Fall through - to select correct fan/pwm reg bank! */
+                       fallthrough;    /* to select correct fan/pwm reg bank! */
                case f71889fg:
                case f71889ed:
                case f71889a:
index 3dfe2ca..c6d4567 100644 (file)
@@ -172,6 +172,7 @@ gsc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
        case mode_temperature:
                if (tmp > 0x8000)
                        tmp -= 0xffff;
+               tmp *= 100; /* convert to millidegrees celsius */
                break;
        case mode_voltage_raw:
                tmp = clamp_val(tmp, 0, BIT(GSC_HWMON_RESOLUTION));
index eb72e39..6d1175a 100644 (file)
@@ -96,7 +96,7 @@ int vid_from_reg(int val, u8 vrm)
                val &= 0x1f;
                if (val == 0x1f)
                        return 0;
-                               /* fall through */
+               fallthrough;
        case 25:                /* AMD NPT 0Fh */
                val &= 0x3f;
                return (val < 32) ? 1550 - 25 * val
@@ -122,7 +122,7 @@ int vid_from_reg(int val, u8 vrm)
 
        case 84:                /* VRM 8.4 */
                val &= 0x0f;
-                               /* fall through */
+               fallthrough;
        case 82:                /* VRM 8.2 */
                val &= 0x1f;
                return val == 0x1f ? 0 :
index 7fc5b06..81e1556 100644 (file)
@@ -352,7 +352,7 @@ static int ina3221_read_curr(struct device *dev, u32 attr,
                if (ret)
                        return ret;
 
-               /* fall through */
+               fallthrough;
        case hwmon_curr_crit:
        case hwmon_curr_max:
                if (!resistance_uo)
index 750b087..5bd1562 100644 (file)
@@ -2669,7 +2669,7 @@ static void pwm_update_registers(struct nct6775_data *data, int nr)
        case thermal_cruise:
                nct6775_write_value(data, data->REG_TARGET[nr],
                                    data->target_temp[nr]);
-               /* fall through  */
+               fallthrough;
        default:
                reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
                reg = (reg & ~data->tolerance_mask) |
index b042569..242ff8b 100644 (file)
@@ -231,7 +231,7 @@ static int nct7904_read_fan(struct device *dev, u32 attr, int channel,
                if (ret < 0)
                        return ret;
                cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f);
-               if (cnt == 0x1fff)
+               if (cnt == 0 || cnt == 0x1fff)
                        rpm = 0;
                else
                        rpm = 1350000 / cnt;
@@ -243,7 +243,7 @@ static int nct7904_read_fan(struct device *dev, u32 attr, int channel,
                if (ret < 0)
                        return ret;
                cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f);
-               if (cnt == 0x1fff)
+               if (cnt == 0 || cnt == 0x1fff)
                        rpm = 0;
                else
                        rpm = 1350000 / cnt;
index 30e18eb..a717779 100644 (file)
@@ -752,7 +752,7 @@ static int occ_setup_sensor_attrs(struct occ *occ)
        switch (sensors->freq.version) {
        case 2:
                show_freq = occ_show_freq_2;
-               /* fall through */
+               fallthrough;
        case 1:
                num_attrs += (sensors->freq.num_sensors * 2);
                break;
@@ -763,7 +763,7 @@ static int occ_setup_sensor_attrs(struct occ *occ)
        switch (sensors->power.version) {
        case 2:
                show_power = occ_show_power_2;
-               /* fall through */
+               fallthrough;
        case 1:
                num_attrs += (sensors->power.num_sensors * 4);
                break;
@@ -781,7 +781,7 @@ static int occ_setup_sensor_attrs(struct occ *occ)
                break;
        case 3:
                show_caps = occ_show_caps_3;
-               /* fall through */
+               fallthrough;
        case 2:
                num_attrs += (sensors->caps.num_sensors * 8);
                break;
index 0c62271..58aa95a 100644 (file)
@@ -67,6 +67,7 @@ enum variants {
        raa_dmpvr1_2rail,
        raa_dmpvr2_1rail,
        raa_dmpvr2_2rail,
+       raa_dmpvr2_2rail_nontc,
        raa_dmpvr2_3rail,
        raa_dmpvr2_hv,
 };
@@ -241,6 +242,10 @@ static int isl68137_probe(struct i2c_client *client,
                info->pages = 1;
                info->read_word_data = raa_dmpvr2_read_word_data;
                break;
+       case raa_dmpvr2_2rail_nontc:
+               info->func[0] &= ~PMBUS_HAVE_TEMP;
+               info->func[1] &= ~PMBUS_HAVE_TEMP;
+               fallthrough;
        case raa_dmpvr2_2rail:
                info->pages = 2;
                info->read_word_data = raa_dmpvr2_read_word_data;
@@ -304,7 +309,7 @@ static const struct i2c_device_id raa_dmpvr_id[] = {
        {"raa228000", raa_dmpvr2_hv},
        {"raa228004", raa_dmpvr2_hv},
        {"raa228006", raa_dmpvr2_hv},
-       {"raa228228", raa_dmpvr2_2rail},
+       {"raa228228", raa_dmpvr2_2rail_nontc},
        {"raa229001", raa_dmpvr2_2rail},
        {"raa229004", raa_dmpvr2_2rail},
        {}
index e1d10a6..a07b974 100644 (file)
@@ -1213,7 +1213,7 @@ temp_type_store(struct device *dev, struct device_attribute *devattr,
        case W83781D_DEFAULT_BETA:
                dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
                         "instead\n", W83781D_DEFAULT_BETA);
-               /* fall through */
+               fallthrough;
        case 4:         /* thermistor */
                tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
                w83627hf_write_value(data, W83781D_REG_SCFG1,
index 015f1ea..d833a4f 100644 (file)
@@ -814,7 +814,7 @@ store_sensor(struct device *dev, struct device_attribute *da,
                dev_warn(dev,
                         "Sensor type %d is deprecated, please use 4 instead\n",
                         W83781D_DEFAULT_BETA);
-               /* fall through */
+               fallthrough;
        case 4:         /* thermistor */
                tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
                w83781d_write_value(data, W83781D_REG_SCFG1,
index 44f68b9..6d52b53 100644 (file)
@@ -2127,7 +2127,7 @@ static void w83795_apply_temp_config(struct w83795_data *data, u8 config,
                if (temp_chan >= 4)
                        break;
                data->temp_mode |= 1 << temp_chan;
-               /* fall through */
+               fallthrough;
        case 0x3: /* Thermistor */
                data->has_temp |= 1 << temp_chan;
                break;
index 96544b3..7e642fb 100644 (file)
@@ -346,10 +346,10 @@ static void debug_init_arch_data(void *info)
        switch (mode) {
        case EDDEVID_IMPL_FULL:
                drvdata->edvidsr_present = true;
-               /* Fall through */
+               fallthrough;
        case EDDEVID_IMPL_EDPCSR_EDCIDSR:
                drvdata->edcidsr_present = true;
-               /* Fall through */
+               fallthrough;
        case EDDEVID_IMPL_EDPCSR:
                /*
                 * In ARM DDI 0487A.k, the EDDEVID1.PCSROffset is used to
index 6d7d216..96425e8 100644 (file)
@@ -1382,7 +1382,6 @@ static int etm4_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
                                return NOTIFY_BAD;
                break;
        case CPU_PM_EXIT:
-               /* fallthrough */
        case CPU_PM_ENTER_FAILED:
                if (drvdata->state_needs_restore)
                        etm4_cpu_restore(drvdata);
index 7040d58..9ca3aaa 100644 (file)
@@ -84,9 +84,7 @@ u32 tmc_get_memwidth_mask(struct tmc_drvdata *drvdata)
         */
        switch (drvdata->memwidth) {
        case TMC_MEM_INTF_WIDTH_32BITS:
-       /* fallthrough */
        case TMC_MEM_INTF_WIDTH_64BITS:
-       /* fallthrough */
        case TMC_MEM_INTF_WIDTH_128BITS:
                mask = GENMASK(31, 4);
                break;
index a1529f5..9ca8c4e 100644 (file)
@@ -84,11 +84,11 @@ static ssize_t notrace sth_stm_packet(struct stm_data *stm_data,
        /* Global packets (GERR, XSYNC, TRIG) are sent with register writes */
        case STP_PACKET_GERR:
                reg += 4;
-               /* fall through */
+               fallthrough;
 
        case STP_PACKET_XSYNC:
                reg += 8;
-               /* fall through */
+               fallthrough;
 
        case STP_PACKET_TRIG:
                if (flags & STP_PACKET_TIMESTAMPED)
index 710fbef..384af88 100644 (file)
@@ -41,8 +41,22 @@ static void pca_reset(struct i2c_algo_pca_data *adap)
                pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
                pca_outw(adap, I2C_PCA_IND, 0xA5);
                pca_outw(adap, I2C_PCA_IND, 0x5A);
+
+               /*
+                * After a reset we need to re-apply any configuration
+                * (calculated in pca_init) to get the bus in a working state.
+                */
+               pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IMODE);
+               pca_outw(adap, I2C_PCA_IND, adap->bus_settings.mode);
+               pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_ISCLL);
+               pca_outw(adap, I2C_PCA_IND, adap->bus_settings.tlow);
+               pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_ISCLH);
+               pca_outw(adap, I2C_PCA_IND, adap->bus_settings.thi);
+
+               pca_set_con(adap, I2C_PCA_CON_ENSIO);
        } else {
                adap->reset_chip(adap->data);
+               pca_set_con(adap, I2C_PCA_CON_ENSIO | adap->bus_settings.clock_freq);
        }
 }
 
@@ -423,13 +437,14 @@ static int pca_init(struct i2c_adapter *adap)
                                " Use the nominal frequency.\n", adap->name);
                }
 
-               pca_reset(pca_data);
-
                clock = pca_clock(pca_data);
                printk(KERN_INFO "%s: Clock frequency is %dkHz\n",
                     adap->name, freqs[clock]);
 
-               pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock);
+               /* Store settings as these will be needed when the PCA chip is reset */
+               pca_data->bus_settings.clock_freq = clock;
+
+               pca_reset(pca_data);
        } else {
                int clock;
                int mode;
@@ -496,19 +511,15 @@ static int pca_init(struct i2c_adapter *adap)
                        thi = tlow * min_thi / min_tlow;
                }
 
+               /* Store settings as these will be needed when the PCA chip is reset */
+               pca_data->bus_settings.mode = mode;
+               pca_data->bus_settings.tlow = tlow;
+               pca_data->bus_settings.thi = thi;
+
                pca_reset(pca_data);
 
                printk(KERN_INFO
                     "%s: Clock frequency is %dHz\n", adap->name, clock * 100);
-
-               pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IMODE);
-               pca_outw(pca_data, I2C_PCA_IND, mode);
-               pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLL);
-               pca_outw(pca_data, I2C_PCA_IND, tlow);
-               pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLH);
-               pca_outw(pca_data, I2C_PCA_IND, thi);
-
-               pca_set_con(pca_data, I2C_PCA_CON_ENSIO);
        }
        udelay(500); /* 500 us for oscillator to stabilise */
 
index 3126807..724bf30 100644 (file)
@@ -69,6 +69,7 @@
  * These share bit definitions, so use the same values for the enable &
  * status bits.
  */
+#define ASPEED_I2CD_INTR_RECV_MASK                     0xf000ffff
 #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT                        BIT(14)
 #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE              BIT(13)
 #define ASPEED_I2CD_INTR_SLAVE_MATCH                   BIT(7)
@@ -604,6 +605,7 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
        writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE,
               bus->base + ASPEED_I2C_INTR_STS_REG);
        readl(bus->base + ASPEED_I2C_INTR_STS_REG);
+       irq_received &= ASPEED_I2CD_INTR_RECV_MASK;
        irq_remaining = irq_received;
 
 #if IS_ENABLED(CONFIG_I2C_SLAVE)
index 688e928..d8295b1 100644 (file)
@@ -720,7 +720,7 @@ static int bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev *iproc_i2c,
 
                        /* mark the last byte */
                        if (!process_call && (i == msg->len - 1))
-                               val |= 1 << M_TX_WR_STATUS_SHIFT;
+                               val |= BIT(M_TX_WR_STATUS_SHIFT);
 
                        iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val);
                }
@@ -738,7 +738,7 @@ static int bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev *iproc_i2c,
                 */
                addr = i2c_8bit_addr_from_msg(msg);
                /* mark it the last byte out */
-               val = addr | (1 << M_TX_WR_STATUS_SHIFT);
+               val = addr | BIT(M_TX_WR_STATUS_SHIFT);
                iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val);
        }
 
index 1213e19..24d584a 100644 (file)
@@ -65,6 +65,9 @@ struct i2c_ram {
        char    res1[4];        /* Reserved */
        ushort  rpbase;         /* Relocation pointer */
        char    res2[2];        /* Reserved */
+       /* The following elements are only for CPM2 */
+       char    res3[4];        /* Reserved */
+       uint    sdmatmp;        /* Internal */
 };
 
 #define I2COM_START    0x80
index e32ef3f..bffca72 100644 (file)
@@ -1709,6 +1709,16 @@ static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
 static inline void i801_acpi_remove(struct i801_priv *priv) { }
 #endif
 
+static unsigned char i801_setup_hstcfg(struct i801_priv *priv)
+{
+       unsigned char hstcfg = priv->original_hstcfg;
+
+       hstcfg &= ~SMBHSTCFG_I2C_EN;    /* SMBus timing */
+       hstcfg |= SMBHSTCFG_HST_EN;
+       pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg);
+       return hstcfg;
+}
+
 static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        unsigned char temp;
@@ -1830,14 +1840,10 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
                return err;
        }
 
-       pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
-       priv->original_hstcfg = temp;
-       temp &= ~SMBHSTCFG_I2C_EN;      /* SMBus timing */
-       if (!(temp & SMBHSTCFG_HST_EN)) {
+       pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg);
+       temp = i801_setup_hstcfg(priv);
+       if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN))
                dev_info(&dev->dev, "Enabling SMBus device\n");
-               temp |= SMBHSTCFG_HST_EN;
-       }
-       pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
 
        if (temp & SMBHSTCFG_SMB_SMI_EN) {
                dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
@@ -1911,6 +1917,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
        pci_set_drvdata(dev, priv);
 
+       dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE);
        pm_runtime_set_autosuspend_delay(&dev->dev, 1000);
        pm_runtime_use_autosuspend(&dev->dev);
        pm_runtime_put_autosuspend(&dev->dev);
@@ -1952,10 +1959,9 @@ static void i801_shutdown(struct pci_dev *dev)
 #ifdef CONFIG_PM_SLEEP
 static int i801_suspend(struct device *dev)
 {
-       struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct i801_priv *priv = pci_get_drvdata(pci_dev);
+       struct i801_priv *priv = dev_get_drvdata(dev);
 
-       pci_write_config_byte(pci_dev, SMBHSTCFG, priv->original_hstcfg);
+       pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg);
        return 0;
 }
 
@@ -1963,6 +1969,7 @@ static int i801_resume(struct device *dev)
 {
        struct i801_priv *priv = dev_get_drvdata(dev);
 
+       i801_setup_hstcfg(priv);
        i801_enable_host_notify(&priv->adapter);
 
        return 0;
index c5dec57..ef73a42 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/i2c.h>
 #define REG_CTRL_ACK_IGNORE    BIT(1)
 #define REG_CTRL_STATUS                BIT(2)
 #define REG_CTRL_ERROR         BIT(3)
-#define REG_CTRL_CLKDIV_SHIFT  12
-#define REG_CTRL_CLKDIV_MASK   GENMASK(21, 12)
-#define REG_CTRL_CLKDIVEXT_SHIFT 28
-#define REG_CTRL_CLKDIVEXT_MASK        GENMASK(29, 28)
+#define REG_CTRL_CLKDIV                GENMASK(21, 12)
+#define REG_CTRL_CLKDIVEXT     GENMASK(29, 28)
+
+#define REG_SLV_ADDR           GENMASK(7, 0)
+#define REG_SLV_SDA_FILTER     GENMASK(10, 8)
+#define REG_SLV_SCL_FILTER     GENMASK(13, 11)
+#define REG_SLV_SCL_LOW                GENMASK(27, 16)
+#define REG_SLV_SCL_LOW_EN     BIT(28)
 
 #define I2C_TIMEOUT_MS         500
+#define FILTER_DELAY           15
 
 enum {
        TOKEN_END = 0,
@@ -133,19 +139,24 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
        unsigned long clk_rate = clk_get_rate(i2c->clk);
        unsigned int div;
 
-       div = DIV_ROUND_UP(clk_rate, freq * i2c->data->div_factor);
+       div = DIV_ROUND_UP(clk_rate, freq);
+       div -= FILTER_DELAY;
+       div = DIV_ROUND_UP(div, i2c->data->div_factor);
 
        /* clock divider has 12 bits */
-       if (div >= (1 << 12)) {
+       if (div > GENMASK(11, 0)) {
                dev_err(i2c->dev, "requested bus frequency too low\n");
-               div = (1 << 12) - 1;
+               div = GENMASK(11, 0);
        }
 
-       meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
-                          (div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT);
+       meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV,
+                          FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0)));
+
+       meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT,
+                          FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10));
 
-       meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
-                          (div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
+       /* Disable HIGH/LOW mode */
+       meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0);
 
        dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__,
                clk_rate, freq, div);
@@ -280,7 +291,10 @@ static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
        token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ :
                TOKEN_SLAVE_ADDR_WRITE;
 
-       writel(msg->addr << 1, i2c->regs + REG_SLAVE_ADDR);
+
+       meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR,
+                          FIELD_PREP(REG_SLV_ADDR, msg->addr << 1));
+
        meson_i2c_add_token(i2c, TOKEN_START);
        meson_i2c_add_token(i2c, token);
 }
@@ -357,16 +371,12 @@ static int meson_i2c_xfer_messages(struct i2c_adapter *adap,
        struct meson_i2c *i2c = adap->algo_data;
        int i, ret = 0;
 
-       clk_enable(i2c->clk);
-
        for (i = 0; i < num; i++) {
                ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1, atomic);
                if (ret)
                        break;
        }
 
-       clk_disable(i2c->clk);
-
        return ret ?: i;
 }
 
@@ -435,7 +445,7 @@ static int meson_i2c_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = clk_prepare(i2c->clk);
+       ret = clk_prepare_enable(i2c->clk);
        if (ret < 0) {
                dev_err(&pdev->dev, "can't prepare clock\n");
                return ret;
@@ -457,10 +467,14 @@ static int meson_i2c_probe(struct platform_device *pdev)
 
        ret = i2c_add_adapter(&i2c->adap);
        if (ret < 0) {
-               clk_unprepare(i2c->clk);
+               clk_disable_unprepare(i2c->clk);
                return ret;
        }
 
+       /* Disable filtering */
+       meson_i2c_set_mask(i2c, REG_SLAVE_ADDR,
+                          REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0);
+
        meson_i2c_set_clk_div(i2c, timings.bus_freq_hz);
 
        return 0;
@@ -471,7 +485,7 @@ static int meson_i2c_remove(struct platform_device *pdev)
        struct meson_i2c *i2c = platform_get_drvdata(pdev);
 
        i2c_del_adapter(&i2c->adap);
-       clk_unprepare(i2c->clk);
+       clk_disable_unprepare(i2c->clk);
 
        return 0;
 }
index efc1404..0cbdfbe 100644 (file)
@@ -681,8 +681,8 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
        unsigned int cnt_mul;
        int ret = -EINVAL;
 
-       if (target_speed > I2C_MAX_FAST_MODE_PLUS_FREQ)
-               target_speed = I2C_MAX_FAST_MODE_PLUS_FREQ;
+       if (target_speed > I2C_MAX_HIGH_SPEED_MODE_FREQ)
+               target_speed = I2C_MAX_HIGH_SPEED_MODE_FREQ;
 
        max_step_cnt = mtk_i2c_max_step_cnt(target_speed);
        base_step_cnt = max_step_cnt;
@@ -759,7 +759,7 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
        for (clk_div = 1; clk_div <= max_clk_div; clk_div++) {
                clk_src = parent_clk / clk_div;
 
-               if (target_speed > I2C_MAX_FAST_MODE_FREQ) {
+               if (target_speed > I2C_MAX_FAST_MODE_PLUS_FREQ) {
                        /* Set master code speed register */
                        ret = mtk_i2c_calculate_speed(i2c, clk_src,
                                                      I2C_MAX_FAST_MODE_FREQ,
index 9587347..c4b08a9 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/of_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
+#include <linux/dma/mxs-dma.h>
 
 #define DRIVER_NAME "mxs-i2c"
 
@@ -200,7 +201,8 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
                dma_map_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
                desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1,
                                        DMA_MEM_TO_DEV,
-                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+                                       DMA_PREP_INTERRUPT |
+                                       MXS_DMA_CTRL_WAIT4END);
                if (!desc) {
                        dev_err(i2c->dev,
                                "Failed to get DMA data write descriptor.\n");
@@ -228,7 +230,8 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
                dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
                desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1,
                                        DMA_DEV_TO_MEM,
-                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+                                       DMA_PREP_INTERRUPT |
+                                       MXS_DMA_CTRL_WAIT4END);
                if (!desc) {
                        dev_err(i2c->dev,
                                "Failed to get DMA data write descriptor.\n");
@@ -260,7 +263,8 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
                dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
                desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2,
                                        DMA_MEM_TO_DEV,
-                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+                                       DMA_PREP_INTERRUPT |
+                                       MXS_DMA_CTRL_WAIT4END);
                if (!desc) {
                        dev_err(i2c->dev,
                                "Failed to get DMA data write descriptor.\n");
index 75f0713..2ad1663 100644 (file)
@@ -2093,8 +2093,12 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
                }
        }
 
-       /* Adaptive TimeOut: astimated time in usec + 100% margin */
-       timeout_usec = (2 * 10000 / bus->bus_freq) * (2 + nread + nwrite);
+       /*
+        * Adaptive TimeOut: estimated time in usec + 100% margin:
+        * 2: double the timeout for clock stretching case
+        * 9: bits per transaction (including the ack/nack)
+        */
+       timeout_usec = (2 * 9 * USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite);
        timeout = max(msecs_to_jiffies(35), usecs_to_jiffies(timeout_usec));
        if (nwrite >= 32 * 1024 || nread >= 32 * 1024) {
                dev_err(bus->dev, "i2c%d buffer too big\n", bus->num);
@@ -2159,6 +2163,15 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
        if (bus->cmd_err == -EAGAIN)
                ret = i2c_recover_bus(adap);
 
+       /*
+        * After any type of error, check if LAST bit is still set,
+        * due to a HW issue.
+        * It cannot be cleared without resetting the module.
+        */
+       if (bus->cmd_err &&
+           (NPCM_I2CRXF_CTL_LAST_PEC & ioread8(bus->reg + NPCM_I2CRXF_CTL)))
+               npcm_i2c_reset(bus);
+
 #if IS_ENABLED(CONFIG_I2C_SLAVE)
        /* reenable slave if it was enabled */
        if (bus->slave)
index 175c590..12ac421 100644 (file)
@@ -1425,7 +1425,6 @@ omap_i2c_probe(struct platform_device *pdev)
                major = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev);
                break;
        case OMAP_I2C_SCHEME_1:
-               /* FALLTHROUGH */
        default:
                omap->regs = (u8 *)reg_map_ip_v2;
                rev = (rev << 16) |
index 1c4c9bb..6eb0f50 100644 (file)
@@ -125,7 +125,7 @@ static int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr,
        case I2C_SMBUS_BYTE:
                req.buffer_ra = cpu_to_be64(__pa(&data->byte));
                req.size = cpu_to_be32(1);
-               /* Fall through */
+               fallthrough;
        case I2C_SMBUS_QUICK:
                req.type = (read_write == I2C_SMBUS_READ) ?
                        OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
index 672f1f2..a163b8f 100644 (file)
@@ -176,6 +176,9 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
        fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT);
        if (fifostat & OWL_I2C_FIFOSTAT_RNB) {
                i2c_dev->err = -ENXIO;
+               /* Clear NACK error bit by writing "1" */
+               owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
+                                  OWL_I2C_FIFOSTAT_RNB, true);
                goto stop;
        }
 
@@ -183,6 +186,9 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
        stat = readl(i2c_dev->base + OWL_I2C_REG_STAT);
        if (stat & OWL_I2C_STAT_BEB) {
                i2c_dev->err = -EIO;
+               /* Clear BUS error bit by writing "1" */
+               owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
+                                  OWL_I2C_STAT_BEB, true);
                goto stop;
        }
 
index 9e88347..c7c5434 100644 (file)
@@ -590,6 +590,7 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
        /* master sent stop */
        if (ssr_filtered & SSR) {
                i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
+               rcar_i2c_write(priv, ICSCR, SIE | SDBS); /* clear our NACK */
                rcar_i2c_write(priv, ICSIER, SAR);
                rcar_i2c_write(priv, ICSSR, ~SSR & 0xff);
        }
index 2ade99b..e627d7b 100644 (file)
@@ -276,16 +276,6 @@ void i2c_acpi_register_devices(struct i2c_adapter *adap)
                dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
 }
 
-const struct acpi_device_id *
-i2c_acpi_match_device(const struct acpi_device_id *matches,
-                     struct i2c_client *client)
-{
-       if (!(client && matches))
-               return NULL;
-
-       return acpi_match_device(matches, &client->dev);
-}
-
 static const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = {
        /*
         * These Silead touchscreen controllers only work at 400KHz, for
index 34a9609..573b5da 100644 (file)
@@ -480,7 +480,7 @@ static int i2c_device_probe(struct device *dev)
         * or ACPI ID table is supplied for the probing device.
         */
        if (!driver->id_table &&
-           !i2c_acpi_match_device(dev->driver->acpi_match_table, client) &&
+           !acpi_driver_match_device(dev, dev->driver) &&
            !i2c_of_match_device(dev->driver->of_match_table, client)) {
                status = -ENODEV;
                goto put_sync_adapter;
@@ -1464,8 +1464,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 
        /* create pre-declared device nodes */
        of_i2c_register_devices(adap);
-       i2c_acpi_register_devices(adap);
        i2c_acpi_install_space_handler(adap);
+       i2c_acpi_register_devices(adap);
 
        if (adap->nr < __i2c_first_dynamic_bus_num)
                i2c_scan_static_board_info(adap);
index 94ff169..8ce2611 100644 (file)
@@ -59,20 +59,11 @@ static inline int __i2c_check_suspended(struct i2c_adapter *adap)
 }
 
 #ifdef CONFIG_ACPI
-const struct acpi_device_id *
-i2c_acpi_match_device(const struct acpi_device_id *matches,
-                     struct i2c_client *client);
 void i2c_acpi_register_devices(struct i2c_adapter *adap);
 
 int i2c_acpi_get_irq(struct i2c_client *client);
 #else /* CONFIG_ACPI */
 static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { }
-static inline const struct acpi_device_id *
-i2c_acpi_match_device(const struct acpi_device_id *matches,
-                     struct i2c_client *client)
-{
-       return NULL;
-}
 
 static inline int i2c_acpi_get_irq(struct i2c_client *client)
 {
index 5c5306c..8513bd3 100644 (file)
@@ -603,7 +603,7 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
                ret = dw_i2c_clk_cfg(master);
                if (ret)
                        return ret;
-               /* fall through */
+               fallthrough;
        case I3C_BUS_MODE_PURE:
                ret = dw_i3c_clk_cfg(master);
                if (ret)
index 973ed4b..19abf11 100644 (file)
@@ -744,9 +744,10 @@ config BLK_DEV_MAC_IDE
        depends on MAC
        help
          This is the IDE driver for the on-board IDE interface on some m68k
-         Macintosh models. It supports both the `Quadra style' (used in
-         Quadra/ Centris 630 and Performa 588 models) and `Powerbook style'
-         (used in the Powerbook 150 and 190 models) IDE interface.
+         Macintosh models, namely Quadra/Centris 630, Performa 588 and
+         Powerbook 150. The IDE interface on the Powerbook 190 is not
+         supported by this driver and requires BLK_DEV_PLATFORM or
+         PATA_PLATFORM.
 
          Say Y if you have such an Macintosh model and want to use IDE
          devices (hard disks, CD-ROM drives, etc.) that are connected to the
index fd3b5da..50c9a41 100644 (file)
@@ -575,14 +575,14 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive)
                if (!HPT370_ALLOW_ATA100_5 ||
                    check_in_drive_list(drive, bad_ata100_5))
                        return ATA_UDMA4;
-               /* fall through */
+               fallthrough;
        case HPT372 :
        case HPT372A:
        case HPT372N:
        case HPT374 :
                if (ata_id_is_sata(drive->id))
                        mask &= ~0x0e;
-               /* fall through */
+               fallthrough;
        default:
                return mask;
        }
@@ -602,7 +602,7 @@ static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
        case HPT374 :
                if (ata_id_is_sata(drive->id))
                        return 0x00;
-               /* fall through */
+               fallthrough;
        default:
                return 0x07;
        }
index 7f17f83..212bb2d 100644 (file)
@@ -350,7 +350,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
                 */
                if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT)
                        break;
-               /* fall-through */
+               fallthrough;
        case DATA_PROTECT:
                /*
                 * No point in retrying after an illegal request or data
@@ -750,7 +750,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        case REQ_OP_DRV_IN:
        case REQ_OP_DRV_OUT:
                expiry = ide_cd_expiry;
-               /*FALLTHRU*/
+               fallthrough;
        default:
                timeout = ATAPI_WAIT_PC;
                break;
index 1fe1f9d..af7503b 100644 (file)
@@ -428,7 +428,7 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
                                 * (maintains previous driver behaviour)
                                 */
                                break;
-                       /* fall through */
+                       fallthrough;
                case CAPACITY_CURRENT:
                        /* Normal Zip/LS-120 disks */
                        if (memcmp(cap_desc, &floppy->cap_desc, 8))
index e867129..1ddc45a 100644 (file)
@@ -143,7 +143,7 @@ static void ide_classify_atapi_dev(ide_drive_t *drive)
                }
                /* Early cdrom models used zero */
                type = ide_cdrom;
-               /* fall through */
+               fallthrough;
        case ide_cdrom:
                drive->dev_flags |= IDE_DFLAG_REMOVABLE;
 #ifdef CONFIG_PPC
index a26f85a..d016cbe 100644 (file)
@@ -129,7 +129,7 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
                        return pre_task_out_intr(drive, cmd);
                }
                handler = task_pio_intr;
-               /* fall through */
+               fallthrough;
        case ATA_PROT_NODATA:
                if (handler == NULL)
                        handler = task_no_data_intr;
@@ -141,7 +141,7 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
                hwif->expiry = dma_ops->dma_timer_expiry;
                ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD);
                dma_ops->dma_start(drive);
-               /* fall through */
+               fallthrough;
        default:
                return ide_started;
        }
@@ -579,10 +579,10 @@ int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
                        goto abort;
                }
                cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
-               /* fall through */
+               fallthrough;
        case TASKFILE_OUT:
                cmd.protocol = ATA_PROT_PIO;
-               /* fall through */
+               fallthrough;
        case TASKFILE_OUT_DMAQ:
        case TASKFILE_OUT_DMA:
                cmd.tf_flags |= IDE_TFLAG_WRITE;
@@ -598,10 +598,10 @@ int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
                        goto abort;
                }
                cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
-               /* fall through */
+               fallthrough;
        case TASKFILE_IN:
                cmd.protocol = ATA_PROT_PIO;
-               /* fall through */
+               fallthrough;
        case TASKFILE_IN_DMAQ:
        case TASKFILE_IN_DMA:
                nsect = taskin / SECTOR_SIZE;
index adc5fe9..8d2bf73 100644 (file)
 #include <linux/delay.h>
 #include <linux/ide.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include <asm/macintosh.h>
-#include <asm/macints.h>
-#include <asm/mac_baboon.h>
+
+#define DRV_NAME "mac_ide"
 
 #define IDE_BASE 0x50F1A000    /* Base address of IDE controller */
 
@@ -100,42 +101,61 @@ static const char *mac_ide_name[] =
  * Probe for a Macintosh IDE interface
  */
 
-static int __init macide_init(void)
+static int mac_ide_probe(struct platform_device *pdev)
 {
-       unsigned long base;
-       int irq;
+       struct resource *mem, *irq;
        struct ide_hw hw, *hws[] = { &hw };
        struct ide_port_info d = macide_port_info;
+       struct ide_host *host;
+       int rc;
 
        if (!MACH_IS_MAC)
                return -ENODEV;
 
-       switch (macintosh_config->ide_type) {
-       case MAC_IDE_QUADRA:
-               base = IDE_BASE;
-               irq = IRQ_NUBUS_F;
-               break;
-       case MAC_IDE_PB:
-               base = IDE_BASE;
-               irq = IRQ_NUBUS_C;
-               break;
-       case MAC_IDE_BABOON:
-               base = BABOON_BASE;
-               d.port_ops = NULL;
-               irq = IRQ_BABOON_1;
-               break;
-       default:
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem)
+               return -ENODEV;
+
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq)
                return -ENODEV;
+
+       if (!devm_request_mem_region(&pdev->dev, mem->start,
+                                    resource_size(mem), DRV_NAME)) {
+               dev_err(&pdev->dev, "resources busy\n");
+               return -EBUSY;
        }
 
        printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
                         mac_ide_name[macintosh_config->ide_type - 1]);
 
-       macide_setup_ports(&hw, base, irq);
+       macide_setup_ports(&hw, mem->start, irq->start);
 
-       return ide_host_add(&d, hws, 1, NULL);
+       rc = ide_host_add(&d, hws, 1, &host);
+       if (rc)
+               return rc;
+
+       platform_set_drvdata(pdev, host);
+       return 0;
 }
 
-module_init(macide_init);
+static int mac_ide_remove(struct platform_device *pdev)
+{
+       struct ide_host *host = platform_get_drvdata(pdev);
+
+       ide_host_remove(host);
+       return 0;
+}
+
+static struct platform_driver mac_ide_driver = {
+       .driver = {
+               .name = DRV_NAME,
+       },
+       .probe  = mac_ide_probe,
+       .remove = mac_ide_remove,
+};
+
+module_platform_driver(mac_ide_driver);
 
+MODULE_ALIAS("platform:" DRV_NAME);
 MODULE_LICENSE("GPL");
index 024bc7b..1a700be 100644 (file)
@@ -494,7 +494,7 @@ static int init_chipset_sis5513(struct pci_dev *dev)
                pci_read_config_byte(dev, 0x09, &reg);
                if ((reg & 0x0f) != 0x00)
                        pci_write_config_byte(dev, 0x09, reg&0xf0);
-               /* fall through */
+               fallthrough;
        case ATA_16:
                /* force per drive recovery and active timings
                   needed on ATA_33 and below chips */
index 8e0fb1a..9a810e4 100644 (file)
@@ -90,14 +90,6 @@ static unsigned int mwait_substates __initdata;
 #define CPUIDLE_FLAG_ALWAYS_ENABLE     BIT(15)
 
 /*
- * Set this flag for states where the HW flushes the TLB for us
- * and so we don't need cross-calls to keep it consistent.
- * If this flag is set, SW flushes the TLB, so even if the
- * HW doesn't do the flushing, this flag is safe to use.
- */
-#define CPUIDLE_FLAG_TLB_FLUSHED       BIT(16)
-
-/*
  * MWAIT takes an 8-bit "hint" in EAX "suggesting"
  * the C-state (top nibble) and sub-state (bottom nibble)
  * 0x00 means "MWAIT(C1)", 0x10 means "MWAIT(C2)" etc.
@@ -131,14 +123,6 @@ static __cpuidle int intel_idle(struct cpuidle_device *dev,
        unsigned long eax = flg2MWAIT(state->flags);
        unsigned long ecx = 1; /* break on interrupt flag */
        bool tick;
-       int cpu = smp_processor_id();
-
-       /*
-        * leave_mm() to avoid costly and often unnecessary wakeups
-        * for flushing the user TLB's associated with the active mm.
-        */
-       if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
-               leave_mm(cpu);
 
        if (!static_cpu_has(X86_FEATURE_ARAT)) {
                /*
index 24864d9..4843586 100644 (file)
@@ -189,6 +189,14 @@ struct bmc150_accel_data {
        struct mutex mutex;
        u8 fifo_mode, watermark;
        s16 buffer[8];
+       /*
+        * Ensure there is sufficient space and correct alignment for
+        * the timestamp if enabled
+        */
+       struct {
+               __le16 channels[3];
+               s64 ts __aligned(8);
+       } scan;
        u8 bw_bits;
        u32 slope_dur;
        u32 slope_thres;
@@ -922,15 +930,16 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
         * now.
         */
        for (i = 0; i < count; i++) {
-               u16 sample[8];
                int j, bit;
 
                j = 0;
                for_each_set_bit(bit, indio_dev->active_scan_mask,
                                 indio_dev->masklength)
-                       memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
+                       memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit],
+                              sizeof(data->scan.channels[0]));
 
-               iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp);
+               iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+                                                  tstamp);
 
                tstamp += sample_period;
        }
index 66b2e4c..0e18b92 100644 (file)
@@ -209,14 +209,20 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
        const struct iio_poll_func *pf = p;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct kxsd9_state *st = iio_priv(indio_dev);
+       /*
+        * Ensure correct positioning and alignment of timestamp.
+        * No need to zero initialize as all elements written.
+        */
+       struct {
+               __be16 chan[4];
+               s64 ts __aligned(8);
+       } hw_values;
        int ret;
-       /* 4 * 16bit values AND timestamp */
-       __be16 hw_values[8];
 
        ret = regmap_bulk_read(st->map,
                               KXSD9_REG_X,
-                              &hw_values,
-                              8);
+                              hw_values.chan,
+                              sizeof(hw_values.chan));
        if (ret) {
                dev_err(st->dev,
                        "error reading data\n");
@@ -224,7 +230,7 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
        }
 
        iio_push_to_buffers_with_timestamp(indio_dev,
-                                          hw_values,
+                                          &hw_values,
                                           iio_get_time_ns(indio_dev));
        iio_trigger_notify_done(indio_dev->trig);
 
index 7e99bcb..922bd38 100644 (file)
 
 struct mma7455_data {
        struct regmap *regmap;
+       /*
+        * Used to reorganize data.  Will ensure correct alignment of
+        * the timestamp if present
+        */
+       struct {
+               __le16 channels[3];
+               s64 ts __aligned(8);
+       } scan;
 };
 
 static int mma7455_drdy(struct mma7455_data *mma7455)
@@ -82,19 +90,19 @@ static irqreturn_t mma7455_trigger_handler(int irq, void *p)
        struct iio_poll_func *pf = p;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct mma7455_data *mma7455 = iio_priv(indio_dev);
-       u8 buf[16]; /* 3 x 16-bit channels + padding + ts */
        int ret;
 
        ret = mma7455_drdy(mma7455);
        if (ret)
                goto done;
 
-       ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL, buf,
-                              sizeof(__le16) * 3);
+       ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL,
+                              mma7455->scan.channels,
+                              sizeof(mma7455->scan.channels));
        if (ret)
                goto done;
 
-       iio_push_to_buffers_with_timestamp(indio_dev, buf,
+       iio_push_to_buffers_with_timestamp(indio_dev, &mma7455->scan,
                                           iio_get_time_ns(indio_dev));
 
 done:
index ba27f86..853febc 100644 (file)
@@ -110,6 +110,12 @@ struct mma8452_data {
        int sleep_val;
        struct regulator *vdd_reg;
        struct regulator *vddio_reg;
+
+       /* Ensure correct alignment of time stamp when present */
+       struct {
+               __be16 channels[3];
+               s64 ts __aligned(8);
+       } buffer;
 };
 
  /**
@@ -1091,14 +1097,13 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p)
        struct iio_poll_func *pf = p;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct mma8452_data *data = iio_priv(indio_dev);
-       u8 buffer[16]; /* 3 16-bit channels + padding + ts */
        int ret;
 
-       ret = mma8452_read(data, (__be16 *)buffer);
+       ret = mma8452_read(data, data->buffer.channels);
        if (ret < 0)
                goto done;
 
-       iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+       iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
                                           iio_get_time_ns(indio_dev));
 
 done:
@@ -1580,7 +1585,7 @@ static int mma8452_probe(struct i2c_client *client,
        case FXLS8471_DEVICE_ID:
                if (ret == data->chip_info->chip_id)
                        break;
-               /* fall through */
+               fallthrough;
        default:
                ret = -ENODEV;
                goto disable_regulators;
index 66d9cc0..d94dc80 100644 (file)
@@ -865,6 +865,8 @@ config ROCKCHIP_SARADC
        tristate "Rockchip SARADC driver"
        depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
        depends on RESET_CONTROLLER
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
        help
          Say yes here to build support for the SARADC found in SoCs from
          Rockchip.
index 7fdc5d2..1bb987a 100644 (file)
@@ -484,7 +484,7 @@ static int ab8500_gpadc_read(struct ab8500_gpadc *gpadc,
                        delay_max = 10000; /* large range optimises sleepmode */
                        break;
                }
-               /* Fall through */
+               fallthrough;
        default:
                ctrl1 |= AB8500_GPADC_CTRL1_BUF_ENA;
                break;
index 8dce06e..766c733 100644 (file)
@@ -177,12 +177,12 @@ static const struct iio_chan_spec ad7124_channel_template = {
 
 static struct ad7124_chip_info ad7124_chip_info_tbl[] = {
        [ID_AD7124_4] = {
-               .name = "ad7127-4",
+               .name = "ad7124-4",
                .chip_id = CHIPID_AD7124_4,
                .num_inputs = 8,
        },
        [ID_AD7124_8] = {
-               .name = "ad7127-8",
+               .name = "ad7124-8",
                .chip_id = CHIPID_AD7124_8,
                .num_inputs = 16,
        },
index 84a1733..64c3cc3 100644 (file)
@@ -690,7 +690,7 @@ static void cpcap_adc_phase(struct cpcap_adc_request *req)
                break;
        case CPCAP_ADC_BATTI_PI17:
                index = req->bank_index;
-               /* fallthrough */
+               fallthrough;
        default:
                req->result += conv_tbl[index].cal_offset;
                req->result += conv_tbl[index].align_offset;
index 5ed63e8..b573ec6 100644 (file)
@@ -146,6 +146,11 @@ struct ina2xx_chip_info {
        int range_vbus; /* Bus voltage maximum in V */
        int pga_gain_vshunt; /* Shunt voltage PGA gain */
        bool allow_async_readout;
+       /* data buffer needs space for channel data and timestamp */
+       struct {
+               u16 chan[4];
+               u64 ts __aligned(8);
+       } scan;
 };
 
 static const struct ina2xx_config ina2xx_config[] = {
@@ -738,8 +743,6 @@ static int ina2xx_conversion_ready(struct iio_dev *indio_dev)
 static int ina2xx_work_buffer(struct iio_dev *indio_dev)
 {
        struct ina2xx_chip_info *chip = iio_priv(indio_dev);
-       /* data buffer needs space for channel data and timestap */
-       unsigned short data[4 + sizeof(s64)/sizeof(short)];
        int bit, ret, i = 0;
        s64 time;
 
@@ -758,10 +761,10 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
                if (ret < 0)
                        return ret;
 
-               data[i++] = val;
+               chip->scan.chan[i++] = val;
        }
 
-       iio_push_to_buffers_with_timestamp(indio_dev, data, time);
+       iio_push_to_buffers_with_timestamp(indio_dev, &chip->scan, time);
 
        return 0;
 };
index 01b20e4..6efb0b4 100644 (file)
@@ -36,6 +36,11 @@ struct max1118 {
        struct spi_device *spi;
        struct mutex lock;
        struct regulator *reg;
+       /* Ensure natural alignment of buffer elements */
+       struct {
+               u8 channels[2];
+               s64 ts __aligned(8);
+       } scan;
 
        u8 data ____cacheline_aligned;
 };
@@ -166,7 +171,6 @@ static irqreturn_t max1118_trigger_handler(int irq, void *p)
        struct iio_poll_func *pf = p;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct max1118 *adc = iio_priv(indio_dev);
-       u8 data[16] = { }; /* 2x 8-bit ADC data + padding + 8 bytes timestamp */
        int scan_index;
        int i = 0;
 
@@ -184,10 +188,10 @@ static irqreturn_t max1118_trigger_handler(int irq, void *p)
                        goto out;
                }
 
-               data[i] = ret;
+               adc->scan.channels[i] = ret;
                i++;
        }
-       iio_push_to_buffers_with_timestamp(indio_dev, data,
+       iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
                                           iio_get_time_ns(indio_dev));
 out:
        mutex_unlock(&adc->lock);
index 5f1706d..da353dc 100644 (file)
@@ -96,16 +96,12 @@ static int mcp3422_update_config(struct mcp3422 *adc, u8 newconfig)
 {
        int ret;
 
-       mutex_lock(&adc->lock);
-
        ret = i2c_master_send(adc->i2c, &newconfig, 1);
        if (ret > 0) {
                adc->config = newconfig;
                ret = 0;
        }
 
-       mutex_unlock(&adc->lock);
-
        return ret;
 }
 
@@ -138,6 +134,8 @@ static int mcp3422_read_channel(struct mcp3422 *adc,
        u8 config;
        u8 req_channel = channel->channel;
 
+       mutex_lock(&adc->lock);
+
        if (req_channel != MCP3422_CHANNEL(adc->config)) {
                config = adc->config;
                config &= ~MCP3422_CHANNEL_MASK;
@@ -145,12 +143,18 @@ static int mcp3422_read_channel(struct mcp3422 *adc,
                config &= ~MCP3422_PGA_MASK;
                config |= MCP3422_PGA_VALUE(adc->pga[req_channel]);
                ret = mcp3422_update_config(adc, config);
-               if (ret < 0)
+               if (ret < 0) {
+                       mutex_unlock(&adc->lock);
                        return ret;
+               }
                msleep(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]);
        }
 
-       return mcp3422_read(adc, value, &config);
+       ret = mcp3422_read(adc, value, &config);
+
+       mutex_unlock(&adc->lock);
+
+       return ret;
 }
 
 static int mcp3422_read_raw(struct iio_dev *iio,
index 93c2252..1a9189b 100644 (file)
@@ -707,7 +707,7 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
        size_t read_len;
        int ret;
 
-       temperature_calib = devm_nvmem_cell_get(&indio_dev->dev,
+       temperature_calib = devm_nvmem_cell_get(indio_dev->dev.parent,
                                                "temperature_calib");
        if (IS_ERR(temperature_calib)) {
                ret = PTR_ERR(temperature_calib);
index b4b73c9..c10aa28 100644 (file)
@@ -982,7 +982,7 @@ static int adc5_probe(struct platform_device *pdev)
 
 static struct platform_driver adc5_driver = {
        .driver = {
-               .name = "qcom-spmi-adc5.c",
+               .name = "qcom-spmi-adc5",
                .of_match_table = adc5_match_table,
        },
        .probe = adc5_probe,
index 9426f70..cf63983 100644 (file)
@@ -33,6 +33,12 @@ struct adc081c {
 
        /* 8, 10 or 12 */
        int bits;
+
+       /* Ensure natural alignment of buffer elements */
+       struct {
+               u16 channel;
+               s64 ts __aligned(8);
+       } scan;
 };
 
 #define REG_CONV_RES 0x00
@@ -128,14 +134,13 @@ static irqreturn_t adc081c_trigger_handler(int irq, void *p)
        struct iio_poll_func *pf = p;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct adc081c *data = iio_priv(indio_dev);
-       u16 buf[8]; /* 2 bytes data + 6 bytes padding + 8 bytes timestamp */
        int ret;
 
        ret = i2c_smbus_read_word_swapped(data->i2c, REG_CONV_RES);
        if (ret < 0)
                goto out;
-       buf[0] = ret;
-       iio_push_to_buffers_with_timestamp(indio_dev, buf,
+       data->scan.channel = ret;
+       iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
                                           iio_get_time_ns(indio_dev));
 out:
        iio_trigger_notify_done(indio_dev->trig);
index 9017e1e..dfba348 100644 (file)
@@ -26,6 +26,11 @@ struct adc084s021 {
        struct spi_transfer spi_trans;
        struct regulator *reg;
        struct mutex lock;
+       /* Buffer used to align data */
+       struct {
+               __be16 channels[4];
+               s64 ts __aligned(8);
+       } scan;
        /*
         * DMA (thus cache coherency maintenance) requires the
         * transfer buffers to live in their own cache line.
@@ -141,14 +146,13 @@ static irqreturn_t adc084s021_buffer_trigger_handler(int irq, void *pollfunc)
        struct iio_poll_func *pf = pollfunc;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct adc084s021 *adc = iio_priv(indio_dev);
-       __be16 data[8] = {0}; /* 4 * 16-bit words of data + 8 bytes timestamp */
 
        mutex_lock(&adc->lock);
 
-       if (adc084s021_adc_conversion(adc, &data) < 0)
+       if (adc084s021_adc_conversion(adc, adc->scan.channels) < 0)
                dev_err(&adc->spi->dev, "Failed to read data\n");
 
-       iio_push_to_buffers_with_timestamp(indio_dev, data,
+       iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
                                           iio_get_time_ns(indio_dev));
        mutex_unlock(&adc->lock);
        iio_trigger_notify_done(indio_dev->trig);
index f42ab11..9fef39b 100644 (file)
@@ -316,6 +316,7 @@ static const struct iio_chan_spec ads1115_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
 };
 
+#ifdef CONFIG_PM
 static int ads1015_set_power_state(struct ads1015_data *data, bool on)
 {
        int ret;
@@ -333,6 +334,15 @@ static int ads1015_set_power_state(struct ads1015_data *data, bool on)
        return ret < 0 ? ret : 0;
 }
 
+#else /* !CONFIG_PM */
+
+static int ads1015_set_power_state(struct ads1015_data *data, bool on)
+{
+       return 0;
+}
+
+#endif /* !CONFIG_PM */
+
 static
 int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val)
 {
index 2b007e7..60dd87e 100644 (file)
@@ -78,6 +78,11 @@ struct ccs811_data {
        struct iio_trigger *drdy_trig;
        struct gpio_desc *wakeup_gpio;
        bool drdy_trig_on;
+       /* Ensures correct alignment of timestamp if present */
+       struct {
+               s16 channels[2];
+               s64 ts __aligned(8);
+       } scan;
 };
 
 static const struct iio_chan_spec ccs811_channels[] = {
@@ -327,17 +332,17 @@ static irqreturn_t ccs811_trigger_handler(int irq, void *p)
        struct iio_dev *indio_dev = pf->indio_dev;
        struct ccs811_data *data = iio_priv(indio_dev);
        struct i2c_client *client = data->client;
-       s16 buf[8]; /* s16 eCO2 + s16 TVOC + padding + 8 byte timestamp */
        int ret;
 
-       ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA, 4,
-                                           (u8 *)&buf);
+       ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA,
+                                           sizeof(data->scan.channels),
+                                           (u8 *)data->scan.channels);
        if (ret != 4) {
                dev_err(&client->dev, "cannot read sensor data\n");
                goto err;
        }
 
-       iio_push_to_buffers_with_timestamp(indio_dev, buf,
+       iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
                                           iio_get_time_ns(indio_dev));
 
 err:
index 5a29e32..2ea9a5c 100644 (file)
@@ -118,7 +118,7 @@ static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size)
        case SPS30_READ_AUTO_CLEANING_PERIOD:
                buf[0] = SPS30_AUTO_CLEANING_PERIOD >> 8;
                buf[1] = (u8)(SPS30_AUTO_CLEANING_PERIOD & 0xff);
-               /* fall through */
+               fallthrough;
        case SPS30_READ_DATA_READY_FLAG:
        case SPS30_READ_DATA:
        case SPS30_READ_SERIAL:
index ea480c1..1bc6efa 100644 (file)
@@ -72,10 +72,13 @@ static void get_default_min_max_freq(enum motionsensor_type type,
 
        switch (type) {
        case MOTIONSENSE_TYPE_ACCEL:
-       case MOTIONSENSE_TYPE_GYRO:
                *min_freq = 12500;
                *max_freq = 100000;
                break;
+       case MOTIONSENSE_TYPE_GYRO:
+               *min_freq = 25000;
+               *max_freq = 100000;
+               break;
        case MOTIONSENSE_TYPE_MAG:
                *min_freq = 5000;
                *max_freq = 25000;
index cc48756..1fd75c0 100644 (file)
@@ -220,7 +220,6 @@ static int ad5592r_set_channel_modes(struct ad5592r_state *st)
                        break;
 
                case CH_MODE_UNUSED:
-                       /* fall-through */
                default:
                        switch (st->channel_offstate[i]) {
                        case CH_OFFSTATE_OUT_TRISTATE:
@@ -237,7 +236,6 @@ static int ad5592r_set_channel_modes(struct ad5592r_state *st)
                                break;
 
                        case CH_OFFSTATE_PULLDOWN:
-                               /* fall-through */
                        default:
                                pulldown |= BIT(i);
                                break;
index b3835fb..1a9609e 100644 (file)
@@ -74,11 +74,12 @@ static int dpot_dac_read_raw(struct iio_dev *indio_dev,
                case IIO_VAL_INT:
                        /*
                         * Convert integer scale to fractional scale by
-                        * setting the denominator (val2) to one, and...
+                        * setting the denominator (val2) to one...
                         */
                        *val2 = 1;
                        ret = IIO_VAL_FRACTIONAL;
-                       /* fall through */
+                       /* ...and fall through. Say it again for GCC. */
+                       fallthrough;
                case IIO_VAL_FRACTIONAL:
                        *val *= regulator_get_voltage(dac->vref) / 1000;
                        *val2 *= dac->max_ohms;
index 9b47d94..d9b2ed8 100644 (file)
@@ -273,10 +273,10 @@ static int max30102_read_measurement(struct max30102_data *data,
        switch (measurements) {
        case 3:
                MAX30102_COPY_DATA(2);
-               /* fall through */
+               fallthrough;
        case 2:
                MAX30102_COPY_DATA(1);
-               /* fall through */
+               fallthrough;
        case 1:
                MAX30102_COPY_DATA(0);
                break;
index c539dfa..319b64b 100644 (file)
@@ -97,11 +97,11 @@ int __adis_write_reg(struct adis *adis, unsigned int reg,
                adis->tx[9] = (value >> 24) & 0xff;
                adis->tx[6] = ADIS_WRITE_REG(reg + 2);
                adis->tx[7] = (value >> 16) & 0xff;
-               /* fall through */
+               fallthrough;
        case 2:
                adis->tx[4] = ADIS_WRITE_REG(reg + 1);
                adis->tx[5] = (value >> 8) & 0xff;
-               /* fall through */
+               fallthrough;
        case 1:
                adis->tx[2] = ADIS_WRITE_REG(reg);
                adis->tx[3] = value & 0xff;
@@ -191,7 +191,7 @@ int __adis_read_reg(struct adis *adis, unsigned int reg,
                adis->tx[2] = ADIS_READ_REG(reg + 2);
                adis->tx[3] = 0;
                spi_message_add_tail(&xfers[1], &msg);
-               /* fall through */
+               fallthrough;
        case 2:
                adis->tx[4] = ADIS_READ_REG(reg);
                adis->tx[5] = 0;
index 606d5e6..cdcd16f 100644 (file)
@@ -599,7 +599,7 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
                return scnprintf(buf, len, "%d", vals[0]);
        case IIO_VAL_INT_PLUS_MICRO_DB:
                scale_db = true;
-               /* fall through */
+               fallthrough;
        case IIO_VAL_INT_PLUS_MICRO:
                if (vals[1] < 0)
                        return scnprintf(buf, len, "-%d.%06u%s", abs(vals[0]),
@@ -918,7 +918,7 @@ static ssize_t iio_write_channel_info(struct device *dev,
                        break;
                case IIO_VAL_INT_PLUS_MICRO_DB:
                        scale_db = true;
-                       /* fall through */
+                       fallthrough;
                case IIO_VAL_INT_PLUS_MICRO:
                        fract_mult = 100000;
                        break;
index 4bac064..b4323d2 100644 (file)
@@ -1243,13 +1243,16 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p)
        struct iio_poll_func *pf = p;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct ltr501_data *data = iio_priv(indio_dev);
-       u16 buf[8];
+       struct {
+               u16 channels[3];
+               s64 ts __aligned(8);
+       } scan;
        __le16 als_buf[2];
        u8 mask = 0;
        int j = 0;
        int ret, psdata;
 
-       memset(buf, 0, sizeof(buf));
+       memset(&scan, 0, sizeof(scan));
 
        /* figure out which data needs to be ready */
        if (test_bit(0, indio_dev->active_scan_mask) ||
@@ -1268,9 +1271,9 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p)
                if (ret < 0)
                        return ret;
                if (test_bit(0, indio_dev->active_scan_mask))
-                       buf[j++] = le16_to_cpu(als_buf[1]);
+                       scan.channels[j++] = le16_to_cpu(als_buf[1]);
                if (test_bit(1, indio_dev->active_scan_mask))
-                       buf[j++] = le16_to_cpu(als_buf[0]);
+                       scan.channels[j++] = le16_to_cpu(als_buf[0]);
        }
 
        if (mask & LTR501_STATUS_PS_RDY) {
@@ -1278,10 +1281,10 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p)
                                       &psdata, 2);
                if (ret < 0)
                        goto done;
-               buf[j++] = psdata & LTR501_PS_DATA_MASK;
+               scan.channels[j++] = psdata & LTR501_PS_DATA_MASK;
        }
 
-       iio_push_to_buffers_with_timestamp(indio_dev, buf,
+       iio_push_to_buffers_with_timestamp(indio_dev, &scan,
                                           iio_get_time_ns(indio_dev));
 
 done:
index aa8ed1e..b8e721b 100644 (file)
 struct max44000_data {
        struct mutex lock;
        struct regmap *regmap;
+       /* Ensure naturally aligned timestamp */
+       struct {
+               u16 channels[2];
+               s64 ts __aligned(8);
+       } scan;
 };
 
 /* Default scale is set to the minimum of 0.03125 or 1 / (1 << 5) lux */
@@ -488,7 +493,6 @@ static irqreturn_t max44000_trigger_handler(int irq, void *p)
        struct iio_poll_func *pf = p;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct max44000_data *data = iio_priv(indio_dev);
-       u16 buf[8]; /* 2x u16 + padding + 8 bytes timestamp */
        int index = 0;
        unsigned int regval;
        int ret;
@@ -498,17 +502,17 @@ static irqreturn_t max44000_trigger_handler(int irq, void *p)
                ret = max44000_read_alsval(data);
                if (ret < 0)
                        goto out_unlock;
-               buf[index++] = ret;
+               data->scan.channels[index++] = ret;
        }
        if (test_bit(MAX44000_SCAN_INDEX_PRX, indio_dev->active_scan_mask)) {
                ret = regmap_read(data->regmap, MAX44000_REG_PRX_DATA, &regval);
                if (ret < 0)
                        goto out_unlock;
-               buf[index] = regval;
+               data->scan.channels[index] = regval;
        }
        mutex_unlock(&data->lock);
 
-       iio_push_to_buffers_with_timestamp(indio_dev, buf,
+       iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
                                           iio_get_time_ns(indio_dev));
        iio_trigger_notify_done(indio_dev->trig);
        return IRQ_HANDLED;
index 155faae..8f5f857 100644 (file)
@@ -1042,7 +1042,7 @@ static int si1145_initialize(struct si1145_data *data)
                                                SI1145_LED_CURRENT_45mA);
                if (ret < 0)
                        return ret;
-               /* fallthrough */
+               fallthrough;
        case 2:
                ret = i2c_smbus_write_byte_data(client,
                                                SI1145_REG_PS_LED21,
index 6a8ae14..cbb44e4 100644 (file)
@@ -499,7 +499,7 @@ static int ak8974_detect(struct ak8974 *ak8974)
        switch (whoami) {
        case AK8974_WHOAMI_VALUE_AMI306:
                name = "ami306";
-               /* fall-through */
+               fallthrough;
        case AK8974_WHOAMI_VALUE_AMI305:
                ret = regmap_read(ak8974->map, AMI305_VER, &fw);
                if (ret)
index 03d71f7..623766f 100644 (file)
@@ -366,6 +366,12 @@ struct ak8975_data {
        struct iio_mount_matrix orientation;
        struct regulator        *vdd;
        struct regulator        *vid;
+
+       /* Ensure natural alignment of timestamp */
+       struct {
+               s16 channels[3];
+               s64 ts __aligned(8);
+       } scan;
 };
 
 /* Enable attached power regulator if any. */
@@ -793,7 +799,6 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev)
        const struct i2c_client *client = data->client;
        const struct ak_def *def = data->def;
        int ret;
-       s16 buff[8]; /* 3 x 16 bits axis values + 1 aligned 64 bits timestamp */
        __le16 fval[3];
 
        mutex_lock(&data->lock);
@@ -816,12 +821,13 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev)
        mutex_unlock(&data->lock);
 
        /* Clamp to valid range. */
-       buff[0] = clamp_t(s16, le16_to_cpu(fval[0]), -def->range, def->range);
-       buff[1] = clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range);
-       buff[2] = clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range);
+       data->scan.channels[0] = clamp_t(s16, le16_to_cpu(fval[0]), -def->range, def->range);
+       data->scan.channels[1] = clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range);
+       data->scan.channels[2] = clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range);
 
-       iio_push_to_buffers_with_timestamp(indio_dev, buff,
+       iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
                                           iio_get_time_ns(indio_dev));
+
        return;
 
 unlock:
index 654564c..ad4b1fb 100644 (file)
@@ -40,6 +40,11 @@ struct mb1232_data {
         */
        struct completion       ranging;
        int                     irqnr;
+       /* Ensure correct alignment of data to push to IIO buffer */
+       struct {
+               s16 distance;
+               s64 ts __aligned(8);
+       } scan;
 };
 
 static irqreturn_t mb1232_handle_irq(int irq, void *dev_id)
@@ -113,17 +118,13 @@ static irqreturn_t mb1232_trigger_handler(int irq, void *p)
        struct iio_poll_func *pf = p;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct mb1232_data *data = iio_priv(indio_dev);
-       /*
-        * triggered buffer
-        * 16-bit channel + 48-bit padding + 64-bit timestamp
-        */
-       s16 buffer[8] = { 0 };
 
-       buffer[0] = mb1232_read_distance(data);
-       if (buffer[0] < 0)
+       data->scan.distance = mb1232_read_distance(data);
+       if (data->scan.distance < 0)
                goto err;
 
-       iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
+       iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+                                          pf->timestamp);
 
 err:
        iio_trigger_notify_done(indio_dev->trig);
index ffad73b..5a76611 100644 (file)
@@ -1320,9 +1320,10 @@ struct net_device *rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr)
 }
 EXPORT_SYMBOL(rdma_read_gid_attr_ndev_rcu);
 
-static int get_lower_dev_vlan(struct net_device *lower_dev, void *data)
+static int get_lower_dev_vlan(struct net_device *lower_dev,
+                             struct netdev_nested_priv *priv)
 {
-       u16 *vlan_id = data;
+       u16 *vlan_id = (u16 *)priv->data;
 
        if (is_vlan_dev(lower_dev))
                *vlan_id = vlan_dev_vlan_id(lower_dev);
@@ -1348,6 +1349,9 @@ static int get_lower_dev_vlan(struct net_device *lower_dev, void *data)
 int rdma_read_gid_l2_fields(const struct ib_gid_attr *attr,
                            u16 *vlan_id, u8 *smac)
 {
+       struct netdev_nested_priv priv = {
+               .data = (void *)vlan_id,
+       };
        struct net_device *ndev;
 
        rcu_read_lock();
@@ -1368,7 +1372,7 @@ int rdma_read_gid_l2_fields(const struct ib_gid_attr *attr,
                         * the lower vlan device for this gid entry.
                         */
                        netdev_walk_all_lower_dev_rcu(attr->ndev,
-                                       get_lower_dev_vlan, vlan_id);
+                                       get_lower_dev_vlan, &priv);
                }
        }
        rcu_read_unlock();
index dc0558b..fbc28f1 100644 (file)
@@ -3034,7 +3034,7 @@ static int cm_rej_handler(struct cm_work *work)
        case IB_CM_REP_SENT:
        case IB_CM_MRA_REP_RCVD:
                ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
-               /* fall through */
+               fallthrough;
        case IB_CM_REQ_RCVD:
        case IB_CM_MRA_REQ_SENT:
                if (IBA_GET(CM_REJ_REASON, rej_msg) == IB_CM_REJ_STALE_CONN)
@@ -3044,7 +3044,7 @@ static int cm_rej_handler(struct cm_work *work)
                break;
        case IB_CM_DREQ_SENT:
                ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
-               /* fall through */
+               fallthrough;
        case IB_CM_REP_RCVD:
        case IB_CM_MRA_REP_SENT:
                cm_enter_timewait(cm_id_priv);
@@ -3058,7 +3058,7 @@ static int cm_rej_handler(struct cm_work *work)
                        cm_enter_timewait(cm_id_priv);
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                pr_debug("%s: local_id %d, cm_id_priv->id.state: %d\n",
                         __func__, be32_to_cpu(cm_id_priv->id.local_id),
@@ -3116,7 +3116,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
                        msg_response = CM_MSG_RESPONSE_OTHER;
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                pr_debug("%s: local_id %d, cm_id_priv->id.state: %d\n",
                         __func__, be32_to_cpu(cm_id_priv->id.local_id),
@@ -3227,7 +3227,7 @@ static int cm_mra_handler(struct cm_work *work)
        case IB_CM_MRA_REP_RCVD:
                atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
                                counter[CM_MRA_COUNTER]);
-               /* fall through */
+               fallthrough;
        default:
                pr_debug("%s local_id %d, cm_id_priv->id.state: %d\n",
                         __func__, be32_to_cpu(cm_id_priv->id.local_id),
@@ -4214,7 +4214,7 @@ static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv,
                                qp_attr->retry_cnt = cm_id_priv->retry_count;
                                qp_attr->rnr_retry = cm_id_priv->rnr_retry_count;
                                qp_attr->max_rd_atomic = cm_id_priv->initiator_depth;
-                               /* fall through */
+                               fallthrough;
                        case IB_QPT_XRC_TGT:
                                *qp_attr_mask |= IB_QP_TIMEOUT;
                                qp_attr->timeout = cm_id_priv->av.timeout;
index 26de0da..5888311 100644 (file)
@@ -1985,7 +1985,8 @@ static int cma_ib_handler(struct ib_cm_id *cm_id,
                event.event = RDMA_CM_EVENT_ESTABLISHED;
                break;
        case IB_CM_DREQ_ERROR:
-               event.status = -ETIMEDOUT; /* fall through */
+               event.status = -ETIMEDOUT;
+               fallthrough;
        case IB_CM_DREQ_RECEIVED:
        case IB_CM_DREP_RECEIVED:
                if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT,
@@ -2864,9 +2865,10 @@ struct iboe_prio_tc_map {
        bool found;
 };
 
-static int get_lower_vlan_dev_tc(struct net_device *dev, void *data)
+static int get_lower_vlan_dev_tc(struct net_device *dev,
+                                struct netdev_nested_priv *priv)
 {
-       struct iboe_prio_tc_map *map = data;
+       struct iboe_prio_tc_map *map = (struct iboe_prio_tc_map *)priv->data;
 
        if (is_vlan_dev(dev))
                map->output_tc = get_vlan_ndev_tc(dev, map->input_prio);
@@ -2885,16 +2887,18 @@ static int iboe_tos_to_sl(struct net_device *ndev, int tos)
 {
        struct iboe_prio_tc_map prio_tc_map = {};
        int prio = rt_tos2priority(tos);
+       struct netdev_nested_priv priv;
 
        /* If VLAN device, get it directly from the VLAN netdev */
        if (is_vlan_dev(ndev))
                return get_vlan_ndev_tc(ndev, prio);
 
        prio_tc_map.input_prio = prio;
+       priv.data = (void *)&prio_tc_map;
        rcu_read_lock();
        netdev_walk_all_lower_dev_rcu(ndev,
                                      get_lower_vlan_dev_tc,
-                                     &prio_tc_map);
+                                     &priv);
        rcu_read_unlock();
        /* If map is found from lower device, use it; Otherwise
         * continue with the current netdevice to get priority to tc map.
index 513825e..a92fc3f 100644 (file)
@@ -379,7 +379,7 @@ static int ib_alloc_cqs(struct ib_device *dev, unsigned int nr_cqes,
 {
        LIST_HEAD(tmp_list);
        unsigned int nr_cqs, i;
-       struct ib_cq *cq;
+       struct ib_cq *cq, *n;
        int ret;
 
        if (poll_ctx > IB_POLL_LAST_POOL_TYPE) {
@@ -412,7 +412,7 @@ static int ib_alloc_cqs(struct ib_device *dev, unsigned int nr_cqes,
        return 0;
 
 out_free_cqs:
-       list_for_each_entry(cq, &tmp_list, pool_entry) {
+       list_for_each_entry_safe(cq, n, &tmp_list, pool_entry) {
                cq->shared = false;
                ib_free_cq(cq);
        }
index c36b4d2..23ee65a 100644 (file)
@@ -1285,6 +1285,8 @@ static void disable_device(struct ib_device *device)
                remove_client_context(device, cid);
        }
 
+       ib_cq_pool_destroy(device);
+
        /* Pairs with refcount_set in enable_device */
        ib_device_put(device);
        wait_for_completion(&device->unreg_completion);
@@ -1328,6 +1330,8 @@ static int enable_device_and_get(struct ib_device *device)
                        goto out;
        }
 
+       ib_cq_pool_init(device);
+
        down_read(&clients_rwsem);
        xa_for_each_marked (&clients, index, client, CLIENT_REGISTERED) {
                ret = add_client_context(device, client);
@@ -1400,7 +1404,6 @@ int ib_register_device(struct ib_device *device, const char *name)
                goto dev_cleanup;
        }
 
-       ib_cq_pool_init(device);
        ret = enable_device_and_get(device);
        dev_set_uevent_suppress(&device->dev, false);
        /* Mark for userspace that device is ready */
@@ -1455,7 +1458,6 @@ static void __ib_unregister_device(struct ib_device *ib_dev)
                goto out;
 
        disable_device(ib_dev);
-       ib_cq_pool_destroy(ib_dev);
 
        /* Expedite removing unregistered pointers from the hash table */
        free_netdevs(ib_dev);
index 2860def..6b8364b 100644 (file)
@@ -531,10 +531,11 @@ struct upper_list {
        struct net_device *upper;
 };
 
-static int netdev_upper_walk(struct net_device *upper, void *data)
+static int netdev_upper_walk(struct net_device *upper,
+                            struct netdev_nested_priv *priv)
 {
        struct upper_list *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
-       struct list_head *upper_list = data;
+       struct list_head *upper_list = (struct list_head *)priv->data;
 
        if (!entry)
                return 0;
@@ -553,12 +554,14 @@ static void handle_netdev_upper(struct ib_device *ib_dev, u8 port,
                                                      struct net_device *ndev))
 {
        struct net_device *ndev = cookie;
+       struct netdev_nested_priv priv;
        struct upper_list *upper_iter;
        struct upper_list *upper_temp;
        LIST_HEAD(upper_list);
 
+       priv.data = &upper_list;
        rcu_read_lock();
-       netdev_walk_all_upper_dev_rcu(ndev, netdev_upper_walk, &upper_list);
+       netdev_walk_all_upper_dev_rcu(ndev, netdev_upper_walk, &priv);
        rcu_read_unlock();
 
        handle_netdev(ib_dev, port, ndev);
index 614cff8..13f43ab 100644 (file)
@@ -510,7 +510,6 @@ struct ib_send_wr *rdma_rw_ctx_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
        switch (ctx->type) {
        case RDMA_RW_SIG_MR:
        case RDMA_RW_MR:
-               /* fallthrough */
                for (i = 0; i < ctx->nr_ops; i++) {
                        rdma_rw_update_lkey(&ctx->reg[i],
                                ctx->reg[i].wr.wr.opcode !=
index d03daca..1d184ea 100644 (file)
@@ -794,7 +794,7 @@ static void ucma_copy_ib_route(struct rdma_ucm_query_route_resp *resp,
        case 2:
                ib_copy_path_rec_to_user(&resp->ib_route[1],
                                         &route->path_rec[1]);
-               /* fall through */
+               fallthrough;
        case 1:
                ib_copy_path_rec_to_user(&resp->ib_route[0],
                                         &route->path_rec[0]);
@@ -820,7 +820,7 @@ static void ucma_copy_iboe_route(struct rdma_ucm_query_route_resp *resp,
        case 2:
                ib_copy_path_rec_to_user(&resp->ib_route[1],
                                         &route->path_rec[1]);
-               /* fall through */
+               fallthrough;
        case 1:
                ib_copy_path_rec_to_user(&resp->ib_route[0],
                                         &route->path_rec[0]);
index ef04a26..e47c594 100644 (file)
@@ -259,7 +259,7 @@ static int uverbs_process_attr(struct bundle_priv *pbundle,
                        return -EOPNOTSUPP;
 
                e->ptr_attr.enum_id = uattr->attr_data.enum_data.elem_id;
-       /* fall through */
+               fallthrough;
        case UVERBS_ATTR_TYPE_PTR_IN:
                /* Ensure that any data provided by userspace beyond the known
                 * struct is zero. Userspace that knows how to use some future
@@ -271,7 +271,7 @@ static int uverbs_process_attr(struct bundle_priv *pbundle,
                    !uverbs_is_attr_cleared(uattr, val_spec->u.ptr.len))
                        return -EOPNOTSUPP;
 
-       /* fall through */
+               fallthrough;
        case UVERBS_ATTR_TYPE_PTR_OUT:
                if (uattr->len < val_spec->u.ptr.min_len ||
                    (!val_spec->zero_trailing &&
index 3096e73..3078867 100644 (file)
@@ -1801,7 +1801,7 @@ int ib_get_eth_speed(struct ib_device *dev, u8 port_num, u8 *speed, u8 *width)
 
        dev_put(netdev);
 
-       if (!rc) {
+       if (!rc && lksettings.base.speed != (u32)SPEED_UNKNOWN) {
                netdev_speed = lksettings.base.speed;
        } else {
                netdev_speed = SPEED_1000;
index 3f18efc..1d7a9ca 100644 (file)
@@ -752,12 +752,6 @@ static int bnxt_re_destroy_gsi_sqp(struct bnxt_re_qp *qp)
        gsi_sqp = rdev->gsi_ctx.gsi_sqp;
        gsi_sah = rdev->gsi_ctx.gsi_sah;
 
-       /* remove from active qp list */
-       mutex_lock(&rdev->qp_lock);
-       list_del(&gsi_sqp->list);
-       mutex_unlock(&rdev->qp_lock);
-       atomic_dec(&rdev->qp_count);
-
        ibdev_dbg(&rdev->ibdev, "Destroy the shadow AH\n");
        bnxt_qplib_destroy_ah(&rdev->qplib_res,
                              &gsi_sah->qplib_ah,
@@ -772,6 +766,12 @@ static int bnxt_re_destroy_gsi_sqp(struct bnxt_re_qp *qp)
        }
        bnxt_qplib_free_qp_res(&rdev->qplib_res, &gsi_sqp->qplib_qp);
 
+       /* remove from active qp list */
+       mutex_lock(&rdev->qp_lock);
+       list_del(&gsi_sqp->list);
+       mutex_unlock(&rdev->qp_lock);
+       atomic_dec(&rdev->qp_count);
+
        kfree(rdev->gsi_ctx.sqp_tbl);
        kfree(gsi_sah);
        kfree(gsi_sqp);
@@ -792,11 +792,6 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
        unsigned int flags;
        int rc;
 
-       mutex_lock(&rdev->qp_lock);
-       list_del(&qp->list);
-       mutex_unlock(&rdev->qp_lock);
-       atomic_dec(&rdev->qp_count);
-
        bnxt_qplib_flush_cqn_wq(&qp->qplib_qp);
 
        rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
@@ -819,6 +814,11 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
                        goto sh_fail;
        }
 
+       mutex_lock(&rdev->qp_lock);
+       list_del(&qp->list);
+       mutex_unlock(&rdev->qp_lock);
+       atomic_dec(&rdev->qp_count);
+
        ib_umem_release(qp->rumem);
        ib_umem_release(qp->sumem);
 
@@ -2657,7 +2657,7 @@ int bnxt_re_post_send(struct ib_qp *ib_qp, const struct ib_send_wr *wr,
                        default:
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
                case IB_WR_SEND_WITH_INV:
                        rc = bnxt_re_build_send_wqe(qp, wr, &wqe);
                        break;
@@ -3264,6 +3264,19 @@ static void bnxt_re_process_res_rawqp1_wc(struct ib_wc *wc,
        wc->wc_flags |= IB_WC_GRH;
 }
 
+static bool bnxt_re_check_if_vlan_valid(struct bnxt_re_dev *rdev,
+                                       u16 vlan_id)
+{
+       /*
+        * Check if the vlan is configured in the host.  If not configured, it
+        * can be a transparent VLAN. So dont report the vlan id.
+        */
+       if (!__vlan_find_dev_deep_rcu(rdev->netdev,
+                                     htons(ETH_P_8021Q), vlan_id))
+               return false;
+       return true;
+}
+
 static bool bnxt_re_is_vlan_pkt(struct bnxt_qplib_cqe *orig_cqe,
                                u16 *vid, u8 *sl)
 {
@@ -3332,9 +3345,11 @@ static void bnxt_re_process_res_shadow_qp_wc(struct bnxt_re_qp *gsi_sqp,
        wc->src_qp = orig_cqe->src_qp;
        memcpy(wc->smac, orig_cqe->smac, ETH_ALEN);
        if (bnxt_re_is_vlan_pkt(orig_cqe, &vlan_id, &sl)) {
-               wc->vlan_id = vlan_id;
-               wc->sl = sl;
-               wc->wc_flags |= IB_WC_WITH_VLAN;
+               if (bnxt_re_check_if_vlan_valid(rdev, vlan_id)) {
+                       wc->vlan_id = vlan_id;
+                       wc->sl = sl;
+                       wc->wc_flags |= IB_WC_WITH_VLAN;
+               }
        }
        wc->port_num = 1;
        wc->vendor_err = orig_cqe->status;
index 17ac8b7..53aee5a 100644 (file)
@@ -1009,7 +1009,6 @@ static void bnxt_re_free_res(struct bnxt_re_dev *rdev)
 static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev)
 {
        struct bnxt_re_ring_attr rattr = {};
-       struct bnxt_qplib_ctx *qplib_ctx;
        int num_vec_created = 0;
        int rc = 0, i;
        u8 type;
@@ -1032,13 +1031,11 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev)
        if (rc)
                goto dealloc_res;
 
-       qplib_ctx = &rdev->qplib_ctx;
        for (i = 0; i < rdev->num_msix - 1; i++) {
                struct bnxt_qplib_nq *nq;
 
                nq = &rdev->nq[i];
-               nq->hwq.max_elements = (qplib_ctx->cq_count +
-                                       qplib_ctx->srqc_count + 2);
+               nq->hwq.max_elements = BNXT_QPLIB_NQE_MAX_CNT;
                rc = bnxt_qplib_alloc_nq(&rdev->qplib_res, &rdev->nq[i]);
                if (rc) {
                        ibdev_err(&rdev->ibdev, "Alloc Failed NQ%d rc:%#x",
index 117b423..f78da54 100644 (file)
@@ -818,6 +818,7 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
        u16 cmd_flags = 0;
        u32 qp_flags = 0;
        u8 pg_sz_lvl;
+       u32 tbl_indx;
        int rc;
 
        RCFW_CMD_PREP(req, CREATE_QP1, cmd_flags);
@@ -907,8 +908,9 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
                rq->dbinfo.db = qp->dpi->dbr;
                rq->dbinfo.max_slot = bnxt_qplib_set_rq_max_slot(rq->wqe_size);
        }
-       rcfw->qp_tbl[qp->id].qp_id = qp->id;
-       rcfw->qp_tbl[qp->id].qp_handle = (void *)qp;
+       tbl_indx = map_qp_id_to_tbl_indx(qp->id, rcfw);
+       rcfw->qp_tbl[tbl_indx].qp_id = qp->id;
+       rcfw->qp_tbl[tbl_indx].qp_handle = (void *)qp;
 
        return 0;
 
@@ -935,10 +937,10 @@ static void bnxt_qplib_init_psn_ptr(struct bnxt_qplib_qp *qp, int size)
 
        sq = &qp->sq;
        hwq = &sq->hwq;
+       /* First psn entry */
        fpsne = (u64)bnxt_qplib_get_qe(hwq, hwq->depth, &psn_pg);
        if (!IS_ALIGNED(fpsne, PAGE_SIZE))
-               indx_pad = ALIGN(fpsne, PAGE_SIZE) / size;
-
+               indx_pad = (fpsne & ~PAGE_MASK) / size;
        hwq->pad_pgofft = indx_pad;
        hwq->pad_pg = (u64 *)psn_pg;
        hwq->pad_stride = size;
@@ -959,6 +961,7 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
        u16 cmd_flags = 0;
        u32 qp_flags = 0;
        u8 pg_sz_lvl;
+       u32 tbl_indx;
        u16 nsge;
 
        RCFW_CMD_PREP(req, CREATE_QP, cmd_flags);
@@ -1111,8 +1114,9 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
                rq->dbinfo.db = qp->dpi->dbr;
                rq->dbinfo.max_slot = bnxt_qplib_set_rq_max_slot(rq->wqe_size);
        }
-       rcfw->qp_tbl[qp->id].qp_id = qp->id;
-       rcfw->qp_tbl[qp->id].qp_handle = (void *)qp;
+       tbl_indx = map_qp_id_to_tbl_indx(qp->id, rcfw);
+       rcfw->qp_tbl[tbl_indx].qp_id = qp->id;
+       rcfw->qp_tbl[tbl_indx].qp_handle = (void *)qp;
 
        return 0;
 fail:
@@ -1457,10 +1461,12 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res,
        struct cmdq_destroy_qp req;
        struct creq_destroy_qp_resp resp;
        u16 cmd_flags = 0;
+       u32 tbl_indx;
        int rc;
 
-       rcfw->qp_tbl[qp->id].qp_id = BNXT_QPLIB_QP_ID_INVALID;
-       rcfw->qp_tbl[qp->id].qp_handle = NULL;
+       tbl_indx = map_qp_id_to_tbl_indx(qp->id, rcfw);
+       rcfw->qp_tbl[tbl_indx].qp_id = BNXT_QPLIB_QP_ID_INVALID;
+       rcfw->qp_tbl[tbl_indx].qp_handle = NULL;
 
        RCFW_CMD_PREP(req, DESTROY_QP, cmd_flags);
 
@@ -1468,8 +1474,8 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res,
        rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
                                          (void *)&resp, NULL, 0);
        if (rc) {
-               rcfw->qp_tbl[qp->id].qp_id = qp->id;
-               rcfw->qp_tbl[qp->id].qp_handle = qp;
+               rcfw->qp_tbl[tbl_indx].qp_id = qp->id;
+               rcfw->qp_tbl[tbl_indx].qp_handle = qp;
                return rc;
        }
 
@@ -1779,7 +1785,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
 
                        break;
                }
-               /* fall thru */
+               fallthrough;
        case BNXT_QPLIB_SWQE_TYPE_SEND_WITH_IMM:
        case BNXT_QPLIB_SWQE_TYPE_SEND_WITH_INV:
        {
index 4e21116..f7736e3 100644 (file)
@@ -307,14 +307,15 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
        __le16  mcookie;
        u16 cookie;
        int rc = 0;
-       u32 qp_id;
+       u32 qp_id, tbl_indx;
 
        pdev = rcfw->pdev;
        switch (qp_event->event) {
        case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION:
                err_event = (struct creq_qp_error_notification *)qp_event;
                qp_id = le32_to_cpu(err_event->xid);
-               qp = rcfw->qp_tbl[qp_id].qp_handle;
+               tbl_indx = map_qp_id_to_tbl_indx(qp_id, rcfw);
+               qp = rcfw->qp_tbl[tbl_indx].qp_handle;
                dev_dbg(&pdev->dev, "Received QP error notification\n");
                dev_dbg(&pdev->dev,
                        "qpid 0x%x, req_err=0x%x, resp_err=0x%x\n",
@@ -615,8 +616,9 @@ int bnxt_qplib_alloc_rcfw_channel(struct bnxt_qplib_res *res,
 
        cmdq->bmap_size = bmap_size;
 
-       rcfw->qp_tbl_size = qp_tbl_sz;
-       rcfw->qp_tbl = kcalloc(qp_tbl_sz, sizeof(struct bnxt_qplib_qp_node),
+       /* Allocate one extra to hold the QP1 entries */
+       rcfw->qp_tbl_size = qp_tbl_sz + 1;
+       rcfw->qp_tbl = kcalloc(rcfw->qp_tbl_size, sizeof(struct bnxt_qplib_qp_node),
                               GFP_KERNEL);
        if (!rcfw->qp_tbl)
                goto fail;
index 1573876..5f2f0a5 100644 (file)
@@ -216,4 +216,9 @@ int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw);
 int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
                         struct bnxt_qplib_ctx *ctx, int is_virtfn);
 void bnxt_qplib_mark_qp_error(void *qp_handle);
+static inline u32 map_qp_id_to_tbl_indx(u32 qid, struct bnxt_qplib_rcfw *rcfw)
+{
+       /* Last index of the qp_tbl is for QP1 ie. qp_tbl_size - 1*/
+       return (qid == 1) ? rcfw->qp_tbl_size - 1 : qid % rcfw->qp_tbl_size - 2;
+}
 #endif /* __BNXT_QPLIB_RCFW_H__ */
index 4cd475e..64d44f5 100644 (file)
@@ -149,7 +149,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
        attr->max_inline_data = le32_to_cpu(sb->max_inline_data);
        attr->l2_db_size = (sb->l2_db_space_size + 1) *
                            (0x01 << RCFW_DBR_BASE_PAGE_SHIFT);
-       attr->max_sgid = le32_to_cpu(sb->max_gid);
+       attr->max_sgid = BNXT_QPLIB_NUM_GIDS_SUPPORTED;
 
        bnxt_qplib_query_version(rcfw, attr->fw_ver);
 
index 6404f0d..967890c 100644 (file)
@@ -47,6 +47,7 @@
 struct bnxt_qplib_dev_attr {
 #define FW_VER_ARR_LEN                 4
        u8                              fw_ver[FW_VER_ARR_LEN];
+#define BNXT_QPLIB_NUM_GIDS_SUPPORTED  256
        u16                             max_sgid;
        u16                             max_mrw;
        u32                             max_qp;
index 77bc02a..1f288c7 100644 (file)
@@ -2885,7 +2885,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
        case MORIBUND:
        case CLOSING:
                stop_ep_timer(ep);
-               /*FALLTHROUGH*/
+               fallthrough;
        case FPDU_MODE:
                if (ep->com.qp && ep->com.qp->srq) {
                        srqidx = ABORT_RSS_SRQIDX_G(
@@ -3759,7 +3759,7 @@ static void active_ofld_conn_reply(struct c4iw_dev *dev, struct sk_buff *skb,
                        send_fw_act_open_req(ep, atid);
                        return;
                }
-               /* fall through */
+               fallthrough;
        case FW_EADDRINUSE:
                set_bit(ACT_RETRY_INUSE, &ep->com.history);
                if (ep->retry_count++ < ACT_OPEN_RETRY_COUNT) {
index ac48012..cbddb20 100644 (file)
@@ -1165,7 +1165,7 @@ int c4iw_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
                                break;
                        }
                        fw_flags |= FW_RI_RDMA_WRITE_WITH_IMMEDIATE;
-                       /*FALLTHROUGH*/
+                       fallthrough;
                case IB_WR_RDMA_WRITE:
                        fw_opcode = FW_RI_RDMA_WRITE_WR;
                        swsqe->opcode = FW_RI_RDMA_WRITE;
index b12e466..4a4ec23 100644 (file)
@@ -209,7 +209,6 @@ static inline void jcopy(u8 *dest, const u8 *src, u32 n)
                fallthrough;
        case 1:
                *dest++ = *src++;
-               /* fall through */
        }
 }
 
index fa7a5ff..a3b9580 100644 (file)
@@ -2443,7 +2443,7 @@ static void i40iw_handle_rst_pkt(struct i40iw_cm_node *cm_node,
        case I40IW_CM_STATE_FIN_WAIT1:
        case I40IW_CM_STATE_LAST_ACK:
                cm_node->cm_id->rem_ref(cm_node->cm_id);
-               /* fall through */
+               fallthrough;
        case I40IW_CM_STATE_TIME_WAIT:
                cm_node->state = I40IW_CM_STATE_CLOSED;
                i40iw_rem_ref_cm_node(cm_node);
index 688f196..86d3f8a 100644 (file)
@@ -1964,7 +1964,6 @@ static enum i40iw_status_code i40iw_sc_get_next_aeqe(struct i40iw_sc_aeq *aeq,
                info->out_rdrsp = true;
                break;
        case I40IW_AE_SOURCE_RSVD:
-               /* fallthrough */
        default:
                break;
        }
@@ -3762,14 +3761,14 @@ static enum i40iw_status_code cqp_sds_wqe_fill(struct i40iw_sc_cqp *cqp,
                                        LS_64(1, I40IW_CQPSQ_UPESD_ENTRY_VALID)));
 
                set_64bit_val(wqe, 56, info->entry[2].data);
-               /* fallthrough */
+               fallthrough;
        case 2:
                set_64bit_val(wqe, 32,
                              (LS_64(info->entry[1].cmd, I40IW_CQPSQ_UPESD_SDCMD) |
                                        LS_64(1, I40IW_CQPSQ_UPESD_ENTRY_VALID)));
 
                set_64bit_val(wqe, 40, info->entry[1].data);
-               /* fallthrough */
+               fallthrough;
        case 1:
                set_64bit_val(wqe, 0,
                              LS_64(info->entry[0].cmd, I40IW_CQPSQ_UPESD_SDCMD));
index ae8b97c..e108563 100644 (file)
@@ -353,7 +353,6 @@ void i40iw_process_aeq(struct i40iw_device *iwdev)
                                i40iw_cm_disconn(iwqp);
                        break;
                case I40IW_AE_BAD_CLOSE:
-                       /* fall through */
                case I40IW_AE_RESET_SENT:
                        i40iw_next_iw_state(iwqp, I40IW_QP_STATE_ERROR, 1, 0, 0);
                        i40iw_cm_disconn(iwqp);
@@ -413,7 +412,7 @@ void i40iw_process_aeq(struct i40iw_device *iwdev)
                case I40IW_AE_UDA_XMIT_DGRAM_TOO_LONG:
                case I40IW_AE_UDA_XMIT_DGRAM_TOO_SHORT:
                        ctx_info->err_rq_idx_valid = false;
-                       /* fall through */
+                       fallthrough;
                default:
                        if (!info->sq && ctx_info->err_rq_idx_valid) {
                                ctx_info->err_rq_idx = info->wqe_idx;
index 9c96ece..58a4331 100644 (file)
@@ -1489,36 +1489,35 @@ static void i40iw_deinit_device(struct i40iw_device *iwdev)
                iwdev->iw_status = 0;
                i40iw_port_ibevent(iwdev);
                i40iw_destroy_rdma_device(iwdev->iwibdev);
-               /* fallthrough */
+               fallthrough;
        case IP_ADDR_REGISTERED:
                if (!iwdev->reset)
                        i40iw_del_macip_entry(iwdev, (u8)iwdev->mac_ip_table_idx);
-               /* fallthrough */
-               /* fallthrough */
+               fallthrough;
        case PBLE_CHUNK_MEM:
                i40iw_destroy_pble_pool(dev, iwdev->pble_rsrc);
-               /* fallthrough */
+               fallthrough;
        case CEQ_CREATED:
                i40iw_dele_ceqs(iwdev);
-               /* fallthrough */
+               fallthrough;
        case AEQ_CREATED:
                i40iw_destroy_aeq(iwdev);
-               /* fallthrough */
+               fallthrough;
        case IEQ_CREATED:
                i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_IEQ, iwdev->reset);
-               /* fallthrough */
+               fallthrough;
        case ILQ_CREATED:
                i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_ILQ, iwdev->reset);
-               /* fallthrough */
+               fallthrough;
        case CCQ_CREATED:
                i40iw_destroy_ccq(iwdev);
-               /* fallthrough */
+               fallthrough;
        case HMC_OBJS_CREATED:
                i40iw_del_hmc_objects(dev, dev->hmc_info, true, iwdev->reset);
-               /* fallthrough */
+               fallthrough;
        case CQP_CREATED:
                i40iw_destroy_cqp(iwdev, true);
-               /* fallthrough */
+               fallthrough;
        case INITIAL_STATE:
                i40iw_cleanup_cm_core(&iwdev->cm_core);
                if (iwdev->vsi.pestat) {
@@ -1528,7 +1527,6 @@ static void i40iw_deinit_device(struct i40iw_device *iwdev)
                i40iw_del_init_mem(iwdev);
                break;
        case INVALID_STATE:
-               /* fallthrough */
        default:
                i40iw_pr_err("bad init_state = %d\n", iwdev->init_state);
                break;
index d9c7ae6..924be4b 100644 (file)
@@ -814,13 +814,13 @@ void i40iw_puda_dele_resources(struct i40iw_sc_vsi *vsi,
        switch (rsrc->completion) {
        case PUDA_HASH_CRC_COMPLETE:
                i40iw_free_hash_desc(rsrc->hash_desc);
-               /* fall through */
+               fallthrough;
        case PUDA_QP_CREATED:
                if (!reset)
                        i40iw_puda_free_qp(rsrc);
 
                i40iw_free_dma_mem(dev->hw, &rsrc->qpmem);
-               /* fallthrough */
+               fallthrough;
        case PUDA_CQ_CREATED:
                if (!reset)
                        i40iw_puda_free_cq(rsrc);
index 0165246..e07fb37 100644 (file)
@@ -190,9 +190,8 @@ int i40iw_inetaddr_event(struct notifier_block *notifier,
        switch (event) {
        case NETDEV_DOWN:
                action = I40IW_ARP_DELETE;
-               /* Fall through */
+               fallthrough;
        case NETDEV_UP:
-               /* Fall through */
        case NETDEV_CHANGEADDR:
 
                /* Just skip if no need to handle ARP cache */
@@ -247,9 +246,8 @@ int i40iw_inet6addr_event(struct notifier_block *notifier,
        switch (event) {
        case NETDEV_DOWN:
                action = I40IW_ARP_DELETE;
-               /* Fall through */
+               fallthrough;
        case NETDEV_UP:
-               /* Fall through */
        case NETDEV_CHANGEADDR:
                i40iw_manage_arp_cache(iwdev,
                                       netdev->dev_addr,
@@ -344,7 +342,7 @@ int i40iw_netdevice_event(struct notifier_block *notifier,
        switch (event) {
        case NETDEV_DOWN:
                iwdev->iw_status = 0;
-               /* Fall through */
+               fallthrough;
        case NETDEV_UP:
                i40iw_port_ibevent(iwdev);
                break;
index 6957e4f..b513393 100644 (file)
@@ -810,7 +810,7 @@ void i40iw_hw_modify_qp(struct i40iw_device *iwdev, struct i40iw_qp *iwqp,
        case I40IW_QP_STATE_RTS:
                if (iwqp->iwarp_state == I40IW_QP_STATE_IDLE)
                        i40iw_send_reset(iwqp->cm_node);
-               /* fall through */
+               fallthrough;
        case I40IW_QP_STATE_IDLE:
        case I40IW_QP_STATE_TERMINATE:
        case I40IW_QP_STATE_CLOSING:
@@ -2144,7 +2144,6 @@ static int i40iw_post_send(struct ib_qp *ibqp,
 
                switch (ib_wr->opcode) {
                case IB_WR_SEND:
-                       /* fall-through */
                case IB_WR_SEND_WITH_INV:
                        if (ib_wr->opcode == IB_WR_SEND) {
                                if (ib_wr->send_flags & IB_SEND_SOLICITED)
@@ -2201,7 +2200,7 @@ static int i40iw_post_send(struct ib_qp *ibqp,
                        break;
                case IB_WR_RDMA_READ_WITH_INV:
                        inv_stag = true;
-                       /* fall-through*/
+                       fallthrough;
                case IB_WR_RDMA_READ:
                        if (ib_wr->num_sge > I40IW_MAX_SGE_RD) {
                                err = -EINVAL;
index f8b936b..8a34369 100644 (file)
@@ -765,13 +765,13 @@ repoll:
                switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) {
                case MLX4_OPCODE_RDMA_WRITE_IMM:
                        wc->wc_flags |= IB_WC_WITH_IMM;
-                       /* fall through */
+                       fallthrough;
                case MLX4_OPCODE_RDMA_WRITE:
                        wc->opcode    = IB_WC_RDMA_WRITE;
                        break;
                case MLX4_OPCODE_SEND_IMM:
                        wc->wc_flags |= IB_WC_WITH_IMM;
-                       /* fall through */
+                       fallthrough;
                case MLX4_OPCODE_SEND:
                case MLX4_OPCODE_SEND_INVAL:
                        wc->opcode    = IB_WC_SEND;
index 5e7910a..bd4f975 100644 (file)
@@ -784,7 +784,8 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port,
        props->ip_gids = true;
        props->gid_tbl_len      = mdev->dev->caps.gid_table_len[port];
        props->max_msg_sz       = mdev->dev->caps.max_msg_sz;
-       props->pkey_tbl_len     = 1;
+       if (mdev->dev->caps.pkey_table_len[port])
+               props->pkey_tbl_len = 1;
        props->max_mtu          = IB_MTU_4096;
        props->max_vl_num       = 2;
        props->state            = IB_PORT_DOWN;
index d844831..5e4ec97 100644 (file)
@@ -944,7 +944,7 @@ int mlx4_ib_mcg_multiplex_handler(struct ib_device *ibdev, int port,
        switch (sa_mad->mad_hdr.method) {
        case IB_MGMT_METHOD_SET:
                may_create = 1;
-               /* fall through */
+               fallthrough;
        case IB_SA_METHOD_DELETE:
                req = kzalloc(sizeof *req, GFP_KERNEL);
                if (!req)
index f9ca6e0..2975f35 100644 (file)
@@ -1578,12 +1578,12 @@ static struct ib_qp *_mlx4_ib_create_qp(struct ib_pd *pd,
                pd = to_mxrcd(init_attr->xrcd)->pd;
                xrcdn = to_mxrcd(init_attr->xrcd)->xrcdn;
                init_attr->send_cq = to_mxrcd(init_attr->xrcd)->cq;
-               /* fall through */
+               fallthrough;
        case IB_QPT_XRC_INI:
                if (!(to_mdev(pd->device)->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC))
                        return ERR_PTR(-ENOSYS);
                init_attr->recv_cq = init_attr->send_cq;
-               /* fall through */
+               fallthrough;
        case IB_QPT_RC:
        case IB_QPT_UC:
        case IB_QPT_RAW_PACKET:
@@ -1592,7 +1592,7 @@ static struct ib_qp *_mlx4_ib_create_qp(struct ib_pd *pd,
                        return ERR_PTR(-ENOMEM);
                qp->pri.vid = 0xFFFF;
                qp->alt.vid = 0xFFFF;
-               /* fall through */
+               fallthrough;
        case IB_QPT_UD:
        {
                err = create_qp_common(pd, init_attr, udata, 0, &qp);
index 0133ebb..dceb0eb 100644 (file)
@@ -121,13 +121,13 @@ static void handle_good_req(struct ib_wc *wc, struct mlx5_cqe64 *cqe,
        switch (be32_to_cpu(cqe->sop_drop_qpn) >> 24) {
        case MLX5_OPCODE_RDMA_WRITE_IMM:
                wc->wc_flags |= IB_WC_WITH_IMM;
-               /* fall through */
+               fallthrough;
        case MLX5_OPCODE_RDMA_WRITE:
                wc->opcode    = IB_WC_RDMA_WRITE;
                break;
        case MLX5_OPCODE_SEND_IMM:
                wc->wc_flags |= IB_WC_WITH_IMM;
-               /* fall through */
+               fallthrough;
        case MLX5_OPCODE_SEND:
        case MLX5_OPCODE_SEND_INVAL:
                wc->opcode    = IB_WC_SEND;
index 454ce5d..9bb9bb0 100644 (file)
@@ -250,9 +250,8 @@ int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
                if (MLX5_CAP_GEN(dev->mdev, vport_counters) &&
                    method == IB_MGMT_METHOD_GET)
                        return process_pma_cmd(dev, port_num, in, out);
-               /* fallthrough */
+               fallthrough;
        case MLX5_IB_VENDOR_CLASS1:
-               /* fallthrough */
        case MLX5_IB_VENDOR_CLASS2:
        case IB_MGMT_CLASS_CONG_MGMT: {
                if (method != IB_MGMT_METHOD_GET &&
index fbc45a5..d60d632 100644 (file)
@@ -2872,7 +2872,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work)
                break;
        case MLX5_EVENT_TYPE_GENERAL_EVENT:
                handle_general_event(ibdev, work->param, &ibev);
-               /* fall through */
+               fallthrough;
        default:
                goto out;
        }
index 59fce5f..5758dbe 100644 (file)
@@ -416,7 +416,7 @@ static int sq_overhead(struct ib_qp_init_attr *attr)
        switch (attr->qp_type) {
        case IB_QPT_XRC_INI:
                size += sizeof(struct mlx5_wqe_xrc_seg);
-               /* fall through */
+               fallthrough;
        case IB_QPT_RC:
                size += sizeof(struct mlx5_wqe_ctrl_seg) +
                        max(sizeof(struct mlx5_wqe_atomic_seg) +
@@ -441,7 +441,7 @@ static int sq_overhead(struct ib_qp_init_attr *attr)
                if (attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO)
                        size += sizeof(struct mlx5_wqe_eth_pad) +
                                sizeof(struct mlx5_wqe_eth_seg);
-               /* fall through */
+               fallthrough;
        case IB_QPT_SMI:
        case MLX5_IB_QPT_HW_GSI:
                size += sizeof(struct mlx5_wqe_ctrl_seg) +
index 0823c0b..f051f4e 100644 (file)
@@ -115,7 +115,7 @@ static u8 ib_rate_to_memfree(u8 req_rate, u8 cur_rate)
        switch ((cur_rate - 1) / req_rate) {
        case 0:  return MTHCA_RATE_MEMFREE_FULL;
        case 1:  return MTHCA_RATE_MEMFREE_HALF;
-       case 2:  /* fall through */
+       case 2:
        case 3:  return MTHCA_RATE_MEMFREE_QUARTER;
        default: return MTHCA_RATE_MEMFREE_EIGHTH;
        }
index 6cdbec1..c1751c9 100644 (file)
@@ -2134,7 +2134,7 @@ int ocrdma_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
                case IB_WR_SEND_WITH_IMM:
                        hdr->cw |= (OCRDMA_FLAG_IMM << OCRDMA_WQE_FLAGS_SHIFT);
                        hdr->immdt = ntohl(wr->ex.imm_data);
-                       /* fall through */
+                       fallthrough;
                case IB_WR_SEND:
                        hdr->cw |= (OCRDMA_SEND << OCRDMA_WQE_OPCODE_SHIFT);
                        ocrdma_build_send(qp, hdr, wr);
@@ -2148,7 +2148,7 @@ int ocrdma_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
                case IB_WR_RDMA_WRITE_WITH_IMM:
                        hdr->cw |= (OCRDMA_FLAG_IMM << OCRDMA_WQE_FLAGS_SHIFT);
                        hdr->immdt = ntohl(wr->ex.imm_data);
-                       /* fall through */
+                       fallthrough;
                case IB_WR_RDMA_WRITE:
                        hdr->cw |= (OCRDMA_WRITE << OCRDMA_WQE_OPCODE_SHIFT);
                        status = ocrdma_build_write(qp, hdr, wr);
index 4ce4e2e..b49bef9 100644 (file)
@@ -3528,7 +3528,7 @@ static int __qedr_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
                break;
        case IB_WR_RDMA_READ_WITH_INV:
                SET_FIELD2(wqe->flags, RDMA_SQ_RDMA_WQE_1ST_READ_INV_FLG, 1);
-               /* fallthrough -- same is identical to RDMA READ */
+               fallthrough;    /* same is identical to RDMA READ */
 
        case IB_WR_RDMA_READ:
                wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_RD;
index ca5ea73..44150be 100644 (file)
@@ -2973,11 +2973,11 @@ static u32 qib_6120_iblink_state(u64 ibcs)
                state = IB_PORT_ARMED;
                break;
        case IB_6120_L_STATE_ACTIVE:
-               /* fall through */
        case IB_6120_L_STATE_ACT_DEFER:
                state = IB_PORT_ACTIVE;
                break;
-       default: /* fall through */
+       default:
+               fallthrough;
        case IB_6120_L_STATE_DOWN:
                state = IB_PORT_DOWN;
                break;
index ea3ddb0..0a6f26d 100644 (file)
@@ -3586,11 +3586,11 @@ static u32 qib_7220_iblink_state(u64 ibcs)
                state = IB_PORT_ARMED;
                break;
        case IB_7220_L_STATE_ACTIVE:
-               /* fall through */
        case IB_7220_L_STATE_ACT_DEFER:
                state = IB_PORT_ACTIVE;
                break;
-       default: /* fall through */
+       default:
+               fallthrough;
        case IB_7220_L_STATE_DOWN:
                state = IB_PORT_DOWN;
                break;
index 8bcbc88..a10eab8 100644 (file)
@@ -5508,11 +5508,11 @@ static u32 qib_7322_iblink_state(u64 ibcs)
                state = IB_PORT_ARMED;
                break;
        case IB_7322_L_STATE_ACTIVE:
-               /* fall through */
        case IB_7322_L_STATE_ACT_DEFER:
                state = IB_PORT_ACTIVE;
                break;
-       default: /* fall through */
+       default:
+               fallthrough;
        case IB_7322_L_STATE_DOWN:
                state = IB_PORT_DOWN;
                break;
@@ -6533,7 +6533,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
                                    "Invalid num_vls %u, using 4 VLs\n",
                                    qib_num_cfg_vls);
                        qib_num_cfg_vls = 4;
-                       /* fall through */
+                       fallthrough;
                case 4:
                        ppd->vls_supported = IB_VL_VL0_3;
                        break;
index 79bb832..e7789e7 100644 (file)
@@ -433,7 +433,7 @@ static int check_mkey(struct qib_ibport *ibp, struct ib_smp *smp, int mad_flags)
                        /* Bad mkey not a violation below level 2 */
                        if (ibp->rvp.mkeyprot < 2)
                                break;
-                       /* fall through */
+                       fallthrough;
                case IB_MGMT_METHOD_SET:
                case IB_MGMT_METHOD_TRAP_REPRESS:
                        if (ibp->rvp.mkey_violations != 0xFFFF)
@@ -828,7 +828,7 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
        case IB_PORT_NOP:
                if (lstate == 0)
                        break;
-               /* FALLTHROUGH */
+               fallthrough;
        case IB_PORT_DOWN:
                if (lstate == 0)
                        lstate = QIB_IB_LINKDOWN_ONLY;
@@ -1928,7 +1928,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
                                ret = IB_MAD_RESULT_SUCCESS;
                                goto bail;
                        }
-                       /* FALLTHROUGH */
+                       fallthrough;
                default:
                        smp->status |= IB_SMP_UNSUP_METH_ATTR;
                        ret = reply(smp);
@@ -1962,7 +1962,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
                                ret = IB_MAD_RESULT_SUCCESS;
                                goto bail;
                        }
-                       /* FALLTHROUGH */
+                       fallthrough;
                default:
                        smp->status |= IB_SMP_UNSUP_METH_ATTR;
                        ret = reply(smp);
@@ -2322,7 +2322,7 @@ static int process_cc(struct ib_device *ibdev, int mad_flags,
                        ret = cc_get_congestion_control_table(ccp, ibdev, port);
                        goto bail;
 
-                       /* FALLTHROUGH */
+                       fallthrough;
                default:
                        ccp->status |= IB_SMP_UNSUP_METH_ATTR;
                        ret = reply((struct ib_smp *) ccp);
@@ -2339,7 +2339,7 @@ static int process_cc(struct ib_device *ibdev, int mad_flags,
                        ret = cc_set_congestion_control_table(ccp, ibdev, port);
                        goto bail;
 
-                       /* FALLTHROUGH */
+                       fallthrough;
                default:
                        ccp->status |= IB_SMP_UNSUP_METH_ATTR;
                        ret = reply((struct ib_smp *) ccp);
index aaf7438..3915e5b 100644 (file)
@@ -83,7 +83,7 @@ static int qib_make_rc_ack(struct qib_ibdev *dev, struct rvt_qp *qp,
                        rvt_put_mr(e->rdma_sge.mr);
                        e->rdma_sge.mr = NULL;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(ATOMIC_ACKNOWLEDGE):
                /*
                 * We can increment the tail pointer now that the last
@@ -92,7 +92,7 @@ static int qib_make_rc_ack(struct qib_ibdev *dev, struct rvt_qp *qp,
                 */
                if (++qp->s_tail_ack_queue > QIB_MAX_RDMA_ATOMIC)
                        qp->s_tail_ack_queue = 0;
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(SEND_ONLY):
        case OP(ACKNOWLEDGE):
                /* Check for no next entry in the queue. */
@@ -149,7 +149,7 @@ static int qib_make_rc_ack(struct qib_ibdev *dev, struct rvt_qp *qp,
 
        case OP(RDMA_READ_RESPONSE_FIRST):
                qp->s_ack_state = OP(RDMA_READ_RESPONSE_MIDDLE);
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(RDMA_READ_RESPONSE_MIDDLE):
                qp->s_cur_sge = &qp->s_ack_rdma_sge;
                qp->s_rdma_mr = qp->s_ack_rdma_sge.sge.mr;
@@ -471,10 +471,10 @@ no_flow_control:
                 * See qib_restart_rc().
                 */
                qp->s_len = restart_sge(&qp->s_sge, wqe, qp->s_psn, pmtu);
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(SEND_FIRST):
                qp->s_state = OP(SEND_MIDDLE);
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(SEND_MIDDLE):
                bth2 = qp->s_psn++ & QIB_PSN_MASK;
                ss = &qp->s_sge;
@@ -510,10 +510,10 @@ no_flow_control:
                 * See qib_restart_rc().
                 */
                qp->s_len = restart_sge(&qp->s_sge, wqe, qp->s_psn, pmtu);
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(RDMA_WRITE_FIRST):
                qp->s_state = OP(RDMA_WRITE_MIDDLE);
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(RDMA_WRITE_MIDDLE):
                bth2 = qp->s_psn++ & QIB_PSN_MASK;
                ss = &qp->s_sge;
@@ -1807,7 +1807,7 @@ void qib_rc_rcv(struct qib_ctxtdata *rcd, struct ib_header *hdr,
                if (!ret)
                        goto rnr_nak;
                qp->r_rcv_len = 0;
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(SEND_MIDDLE):
        case OP(RDMA_WRITE_MIDDLE):
 send_middle:
@@ -1839,7 +1839,7 @@ send_middle:
                qp->r_rcv_len = 0;
                if (opcode == OP(SEND_ONLY))
                        goto no_immediate_data;
-               /* fall through -- for SEND_ONLY_WITH_IMMEDIATE */
+               fallthrough;    /* for SEND_ONLY_WITH_IMMEDIATE */
        case OP(SEND_LAST_WITH_IMMEDIATE):
 send_last_imm:
                wc.ex.imm_data = ohdr->u.imm_data;
index 99e11c3..8f8d617 100644 (file)
@@ -763,7 +763,7 @@ void __qib_sdma_process_event(struct qib_pportdata *ppd,
                         * bringing the link up with traffic active on
                         * 7220, e.g. */
                        ss->go_s99_running = 1;
-                       /* fall through -- and start dma engine */
+                       fallthrough;    /* and start dma engine */
                case qib_sdma_event_e10_go_hw_start:
                        /* This reference means the state machine is started */
                        sdma_get(&ppd->sdma_state);
index e17b91e..554af42 100644 (file)
@@ -161,7 +161,7 @@ int qib_make_uc_req(struct rvt_qp *qp, unsigned long *flags)
 
        case OP(SEND_FIRST):
                qp->s_state = OP(SEND_MIDDLE);
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(SEND_MIDDLE):
                len = qp->s_len;
                if (len > pmtu) {
@@ -185,7 +185,7 @@ int qib_make_uc_req(struct rvt_qp *qp, unsigned long *flags)
 
        case OP(RDMA_WRITE_FIRST):
                qp->s_state = OP(RDMA_WRITE_MIDDLE);
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(RDMA_WRITE_MIDDLE):
                len = qp->s_len;
                if (len > pmtu) {
@@ -351,7 +351,7 @@ send_first:
                        goto no_immediate_data;
                else if (opcode == OP(SEND_ONLY_WITH_IMMEDIATE))
                        goto send_last_imm;
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(SEND_MIDDLE):
                /* Check for invalid length PMTU or posted rwqe len. */
                if (unlikely(tlen != (hdrsize + pmtu + 4)))
@@ -440,7 +440,7 @@ rdma_first:
                        wc.ex.imm_data = ohdr->u.rc.imm_data;
                        goto rdma_last_imm;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case OP(RDMA_WRITE_MIDDLE):
                /* Check for invalid length PMTU or posted rwqe len. */
                if (unlikely(tlen != (hdrsize + pmtu + 4)))
index 7acf9ba..f6c01ba 100644 (file)
@@ -237,7 +237,7 @@ static void qib_qp_rcv(struct qib_ctxtdata *rcd, struct ib_header *hdr,
        case IB_QPT_GSI:
                if (ib_qib_disable_sma)
                        break;
-               /* FALLTHROUGH */
+               fallthrough;
        case IB_QPT_UD:
                qib_ud_rcv(ibp, hdr, has_grh, data, tlen, qp);
                break;
index afcc2ab..9a8f2a9 100644 (file)
@@ -238,7 +238,7 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd,
                        ret = -EINVAL;
                        goto err_qp;
                }
-               /* fall through */
+               fallthrough;
        case IB_QPT_RC:
        case IB_QPT_UD:
                qp = kzalloc(sizeof(*qp), GFP_KERNEL);
index 332a8ba..ee48bef 100644 (file)
@@ -1111,7 +1111,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
                if (init_attr->port_num == 0 ||
                    init_attr->port_num > ibpd->device->phys_port_cnt)
                        return ERR_PTR(-EINVAL);
-               /* fall through */
+               fallthrough;
        case IB_QPT_UC:
        case IB_QPT_RC:
        case IB_QPT_UD:
index 907203a..77f2c7c 100644 (file)
@@ -40,6 +40,8 @@ MODULE_AUTHOR("Bob Pearson, Frank Zago, John Groves, Kamal Heib");
 MODULE_DESCRIPTION("Soft RDMA transport");
 MODULE_LICENSE("Dual BSD/GPL");
 
+bool rxe_initialized;
+
 /* free resources for a rxe device all objects created for this device must
  * have been destroyed
  */
@@ -315,6 +317,7 @@ static int __init rxe_module_init(void)
                return err;
 
        rdma_link_register(&rxe_link_ops);
+       rxe_initialized = true;
        pr_info("loaded\n");
        return 0;
 }
@@ -326,6 +329,7 @@ static void __exit rxe_module_exit(void)
        rxe_net_exit();
        rxe_cache_exit();
 
+       rxe_initialized = false;
        pr_info("unloaded\n");
 }
 
index fb07eed..cae1b0a 100644 (file)
@@ -67,6 +67,8 @@
 
 #define RXE_ROCE_V2_SPORT              (0xc000)
 
+extern bool rxe_initialized;
+
 static inline u32 rxe_crc32(struct rxe_dev *rxe,
                            u32 crc, void *next, size_t len)
 {
index 4bc8870..7b4df00 100644 (file)
@@ -282,7 +282,7 @@ static inline enum comp_state check_ack(struct rxe_qp *qp,
                if ((syn & AETH_TYPE_MASK) != AETH_ACK)
                        return COMPST_ERROR;
 
-               /* fall through */
+               fallthrough;
                /* (IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE doesn't have an AETH)
                 */
        case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE:
index cdd811a..ce24144 100644 (file)
@@ -205,6 +205,7 @@ int rxe_mem_init_user(struct rxe_pd *pd, u64 start,
                        vaddr = page_address(sg_page_iter_page(&sg_iter));
                        if (!vaddr) {
                                pr_warn("null vaddr\n");
+                               ib_umem_release(umem);
                                err = -ENOMEM;
                                goto err1;
                        }
index ccda5f5..2af31d4 100644 (file)
@@ -61,6 +61,11 @@ static int rxe_param_set_add(const char *val, const struct kernel_param *kp)
        struct net_device *ndev;
        struct rxe_dev *exists;
 
+       if (!rxe_initialized) {
+               pr_err("Module parameters are not supported, use rdma link add or rxe_cfg\n");
+               return -EAGAIN;
+       }
+
        len = sanitize_arg(val, intf, sizeof(intf));
        if (!len) {
                pr_err("add: invalid interface name\n");
index 08f05ac..ecdac3f 100644 (file)
@@ -71,7 +71,7 @@ void rxe_do_task(unsigned long data)
 
        case TASK_STATE_BUSY:
                task->state = TASK_STATE_ARMED;
-               /* fall through */
+               fallthrough;
        case TASK_STATE_ARMED:
                spin_unlock_irqrestore(&task->state_lock, flags);
                return;
index bb61e53..8522e9a 100644 (file)
@@ -540,7 +540,7 @@ static void init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr,
                switch (wr->opcode) {
                case IB_WR_RDMA_WRITE_WITH_IMM:
                        wr->ex.imm_data = ibwr->ex.imm_data;
-                       /* fall through */
+                       fallthrough;
                case IB_WR_RDMA_READ:
                case IB_WR_RDMA_WRITE:
                        wr->wr.rdma.remote_addr = rdma_wr(ibwr)->remote_addr;
@@ -1056,7 +1056,7 @@ static ssize_t parent_show(struct device *device,
        struct rxe_dev *rxe =
                rdma_device_to_drv_device(device, struct rxe_dev, ib_dev);
 
-       return snprintf(buf, 16, "%s\n", rxe_parent_name(rxe, 1));
+       return scnprintf(buf, PAGE_SIZE, "%s\n", rxe_parent_name(rxe, 1));
 }
 
 static DEVICE_ATTR_RO(parent);
index 1662216..66764f7 100644 (file)
@@ -1224,12 +1224,10 @@ static void siw_cm_llp_data_ready(struct sock *sk)
 
        switch (cep->state) {
        case SIW_EPSTATE_RDMA_MODE:
-               /* fall through */
        case SIW_EPSTATE_LISTENING:
                break;
 
        case SIW_EPSTATE_AWAIT_MPAREQ:
-               /* fall through */
        case SIW_EPSTATE_AWAIT_MPAREP:
                siw_cm_queue_work(cep, SIW_CM_WORK_READ_MPAHDR);
                break;
index 857be5a..4bd1f1f 100644 (file)
@@ -1215,7 +1215,7 @@ static int siw_rdmap_complete(struct siw_qp *qp, int error)
        case RDMAP_SEND_SE:
        case RDMAP_SEND_SE_INVAL:
                wqe->rqe.flags |= SIW_WQE_SOLICITED;
-               /* Fall through */
+               fallthrough;
 
        case RDMAP_SEND:
        case RDMAP_SEND_INVAL:
@@ -1386,7 +1386,7 @@ int siw_tcp_rx_data(read_descriptor_t *rd_desc, struct sk_buff *skb,
                         * DDP segment.
                         */
                        qp->rx_fpdu->first_ddp_seg = 0;
-                       /* Fall through */
+                       fallthrough;
 
                case SIW_GET_DATA_START:
                        /*
index 9f53aa4..d19d832 100644 (file)
@@ -1042,7 +1042,7 @@ next_wqe:
                case SIW_OP_SEND_REMOTE_INV:
                case SIW_OP_WRITE:
                        siw_wqe_put_mem(wqe, tx_type);
-                       /* Fall through */
+                       fallthrough;
 
                case SIW_OP_INVAL_STAG:
                case SIW_OP_REG_MR:
@@ -1128,7 +1128,7 @@ next_wqe:
                case SIW_OP_READ:
                case SIW_OP_READ_LOCAL_INV:
                        siw_wqe_put_mem(wqe, tx_type);
-                       /* Fall through */
+                       fallthrough;
 
                case SIW_OP_INVAL_STAG:
                case SIW_OP_REG_MR:
index 9bf0fa3..7c41fb0 100644 (file)
@@ -512,13 +512,13 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id,
                return ipoib_cm_req_handler(cm_id, event);
        case IB_CM_DREQ_RECEIVED:
                ib_send_cm_drep(cm_id, NULL, 0);
-               /* Fall through */
+               fallthrough;
        case IB_CM_REJ_RECEIVED:
                p = cm_id->context;
                priv = ipoib_priv(p->dev);
                if (ib_modify_qp(p->qp, &ipoib_cm_err_attr, IB_QP_STATE))
                        ipoib_warn(priv, "unable to move qp to error state\n");
-               /* Fall through */
+               fallthrough;
        default:
                return 0;
        }
index 752581a..f772fe8 100644 (file)
@@ -342,9 +342,10 @@ struct ipoib_walk_data {
        struct net_device *result;
 };
 
-static int ipoib_upper_walk(struct net_device *upper, void *_data)
+static int ipoib_upper_walk(struct net_device *upper,
+                           struct netdev_nested_priv *priv)
 {
-       struct ipoib_walk_data *data = _data;
+       struct ipoib_walk_data *data = (struct ipoib_walk_data *)priv->data;
        int ret = 0;
 
        if (ipoib_is_dev_match_addr_rcu(data->addr, upper)) {
@@ -368,10 +369,12 @@ static int ipoib_upper_walk(struct net_device *upper, void *_data)
 static struct net_device *ipoib_get_net_dev_match_addr(
                const struct sockaddr *addr, struct net_device *dev)
 {
+       struct netdev_nested_priv priv;
        struct ipoib_walk_data data = {
                .addr = addr,
        };
 
+       priv.data = (void *)&data;
        rcu_read_lock();
        if (ipoib_is_dev_match_addr_rcu(addr, dev)) {
                dev_hold(dev);
@@ -379,7 +382,7 @@ static struct net_device *ipoib_get_net_dev_match_addr(
                goto out;
        }
 
-       netdev_walk_all_upper_dev_rcu(dev, ipoib_upper_walk, &data);
+       netdev_walk_all_upper_dev_rcu(dev, ipoib_upper_walk, &priv);
 out:
        rcu_read_unlock();
        return data.result;
@@ -502,7 +505,7 @@ static struct net_device *ipoib_get_net_dev_by_params(
        default:
                dev_warn_ratelimited(&dev->dev,
                                     "duplicate IP address detected\n");
-               /* Fall through */
+               fallthrough;
        case 1:
                return net_dev;
        }
index 699e075..2f3ebc0 100644 (file)
@@ -711,7 +711,7 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve
        case RDMA_CM_EVENT_REJECTED:
                iser_info("Connection rejected: %s\n",
                         rdma_reject_msg(cma_id, event->status));
-               /* FALLTHROUGH */
+               fallthrough;
        case RDMA_CM_EVENT_ADDR_ERROR:
        case RDMA_CM_EVENT_ROUTE_ERROR:
        case RDMA_CM_EVENT_CONNECT_ERROR:
index 61e2f7f..695f701 100644 (file)
@@ -140,15 +140,15 @@ isert_alloc_rx_descriptors(struct isert_conn *isert_conn)
        rx_desc = isert_conn->rx_descs;
 
        for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++)  {
-               dma_addr = ib_dma_map_single(ib_dev, (void *)rx_desc,
-                                       ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+               dma_addr = ib_dma_map_single(ib_dev, rx_desc->buf,
+                                       ISER_RX_SIZE, DMA_FROM_DEVICE);
                if (ib_dma_mapping_error(ib_dev, dma_addr))
                        goto dma_map_fail;
 
                rx_desc->dma_addr = dma_addr;
 
                rx_sg = &rx_desc->rx_sg;
-               rx_sg->addr = rx_desc->dma_addr;
+               rx_sg->addr = rx_desc->dma_addr + isert_get_hdr_offset(rx_desc);
                rx_sg->length = ISER_RX_PAYLOAD_SIZE;
                rx_sg->lkey = device->pd->local_dma_lkey;
                rx_desc->rx_cqe.done = isert_recv_done;
@@ -160,7 +160,7 @@ dma_map_fail:
        rx_desc = isert_conn->rx_descs;
        for (j = 0; j < i; j++, rx_desc++) {
                ib_dma_unmap_single(ib_dev, rx_desc->dma_addr,
-                                   ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+                                   ISER_RX_SIZE, DMA_FROM_DEVICE);
        }
        kfree(isert_conn->rx_descs);
        isert_conn->rx_descs = NULL;
@@ -181,7 +181,7 @@ isert_free_rx_descriptors(struct isert_conn *isert_conn)
        rx_desc = isert_conn->rx_descs;
        for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++)  {
                ib_dma_unmap_single(ib_dev, rx_desc->dma_addr,
-                                   ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+                                   ISER_RX_SIZE, DMA_FROM_DEVICE);
        }
 
        kfree(isert_conn->rx_descs);
@@ -299,10 +299,9 @@ isert_free_login_buf(struct isert_conn *isert_conn)
                            ISER_RX_PAYLOAD_SIZE, DMA_TO_DEVICE);
        kfree(isert_conn->login_rsp_buf);
 
-       ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma,
-                           ISER_RX_PAYLOAD_SIZE,
-                           DMA_FROM_DEVICE);
-       kfree(isert_conn->login_req_buf);
+       ib_dma_unmap_single(ib_dev, isert_conn->login_desc->dma_addr,
+                           ISER_RX_SIZE, DMA_FROM_DEVICE);
+       kfree(isert_conn->login_desc);
 }
 
 static int
@@ -311,25 +310,25 @@ isert_alloc_login_buf(struct isert_conn *isert_conn,
 {
        int ret;
 
-       isert_conn->login_req_buf = kzalloc(sizeof(*isert_conn->login_req_buf),
+       isert_conn->login_desc = kzalloc(sizeof(*isert_conn->login_desc),
                        GFP_KERNEL);
-       if (!isert_conn->login_req_buf)
+       if (!isert_conn->login_desc)
                return -ENOMEM;
 
-       isert_conn->login_req_dma = ib_dma_map_single(ib_dev,
-                               isert_conn->login_req_buf,
-                               ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
-       ret = ib_dma_mapping_error(ib_dev, isert_conn->login_req_dma);
+       isert_conn->login_desc->dma_addr = ib_dma_map_single(ib_dev,
+                               isert_conn->login_desc->buf,
+                               ISER_RX_SIZE, DMA_FROM_DEVICE);
+       ret = ib_dma_mapping_error(ib_dev, isert_conn->login_desc->dma_addr);
        if (ret) {
-               isert_err("login_req_dma mapping error: %d\n", ret);
-               isert_conn->login_req_dma = 0;
-               goto out_free_login_req_buf;
+               isert_err("login_desc dma mapping error: %d\n", ret);
+               isert_conn->login_desc->dma_addr = 0;
+               goto out_free_login_desc;
        }
 
        isert_conn->login_rsp_buf = kzalloc(ISER_RX_PAYLOAD_SIZE, GFP_KERNEL);
        if (!isert_conn->login_rsp_buf) {
                ret = -ENOMEM;
-               goto out_unmap_login_req_buf;
+               goto out_unmap_login_desc;
        }
 
        isert_conn->login_rsp_dma = ib_dma_map_single(ib_dev,
@@ -346,11 +345,11 @@ isert_alloc_login_buf(struct isert_conn *isert_conn,
 
 out_free_login_rsp_buf:
        kfree(isert_conn->login_rsp_buf);
-out_unmap_login_req_buf:
-       ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma,
-                           ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
-out_free_login_req_buf:
-       kfree(isert_conn->login_req_buf);
+out_unmap_login_desc:
+       ib_dma_unmap_single(ib_dev, isert_conn->login_desc->dma_addr,
+                           ISER_RX_SIZE, DMA_FROM_DEVICE);
+out_free_login_desc:
+       kfree(isert_conn->login_desc);
        return ret;
 }
 
@@ -476,7 +475,7 @@ isert_connect_release(struct isert_conn *isert_conn)
        if (isert_conn->qp)
                isert_destroy_qp(isert_conn);
 
-       if (isert_conn->login_req_buf)
+       if (isert_conn->login_desc)
                isert_free_login_buf(isert_conn);
 
        isert_device_put(device);
@@ -664,8 +663,8 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        case RDMA_CM_EVENT_ESTABLISHED:
                isert_connected_handler(cma_id);
                break;
-       case RDMA_CM_EVENT_ADDR_CHANGE:    /* FALLTHRU */
-       case RDMA_CM_EVENT_DISCONNECTED:   /* FALLTHRU */
+       case RDMA_CM_EVENT_ADDR_CHANGE:
+       case RDMA_CM_EVENT_DISCONNECTED:
        case RDMA_CM_EVENT_TIMEWAIT_EXIT:  /* FALLTHRU */
                ret = isert_disconnected_handler(cma_id, event->event);
                break;
@@ -684,7 +683,7 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        case RDMA_CM_EVENT_REJECTED:
                isert_info("Connection rejected: %s\n",
                           rdma_reject_msg(cma_id, event->status));
-               /* fall through */
+               fallthrough;
        case RDMA_CM_EVENT_UNREACHABLE:
        case RDMA_CM_EVENT_CONNECT_ERROR:
                ret = isert_connect_error(cma_id);
@@ -862,17 +861,18 @@ isert_login_post_recv(struct isert_conn *isert_conn)
        int ret;
 
        memset(&sge, 0, sizeof(struct ib_sge));
-       sge.addr = isert_conn->login_req_dma;
+       sge.addr = isert_conn->login_desc->dma_addr +
+               isert_get_hdr_offset(isert_conn->login_desc);
        sge.length = ISER_RX_PAYLOAD_SIZE;
        sge.lkey = isert_conn->device->pd->local_dma_lkey;
 
        isert_dbg("Setup sge: addr: %llx length: %d 0x%08x\n",
                sge.addr, sge.length, sge.lkey);
 
-       isert_conn->login_req_buf->rx_cqe.done = isert_login_recv_done;
+       isert_conn->login_desc->rx_cqe.done = isert_login_recv_done;
 
        memset(&rx_wr, 0, sizeof(struct ib_recv_wr));
-       rx_wr.wr_cqe = &isert_conn->login_req_buf->rx_cqe;
+       rx_wr.wr_cqe = &isert_conn->login_desc->rx_cqe;
        rx_wr.sg_list = &sge;
        rx_wr.num_sge = 1;
 
@@ -949,7 +949,7 @@ post_send:
 static void
 isert_rx_login_req(struct isert_conn *isert_conn)
 {
-       struct iser_rx_desc *rx_desc = isert_conn->login_req_buf;
+       struct iser_rx_desc *rx_desc = isert_conn->login_desc;
        int rx_buflen = isert_conn->login_req_len;
        struct iscsi_conn *conn = isert_conn->conn;
        struct iscsi_login *login = conn->conn_login;
@@ -961,7 +961,7 @@ isert_rx_login_req(struct isert_conn *isert_conn)
 
        if (login->first_request) {
                struct iscsi_login_req *login_req =
-                       (struct iscsi_login_req *)&rx_desc->iscsi_header;
+                       (struct iscsi_login_req *)isert_get_iscsi_hdr(rx_desc);
                /*
                 * Setup the initial iscsi_login values from the leading
                 * login request PDU.
@@ -980,13 +980,13 @@ isert_rx_login_req(struct isert_conn *isert_conn)
                login->tsih             = be16_to_cpu(login_req->tsih);
        }
 
-       memcpy(&login->req[0], (void *)&rx_desc->iscsi_header, ISCSI_HDR_LEN);
+       memcpy(&login->req[0], isert_get_iscsi_hdr(rx_desc), ISCSI_HDR_LEN);
 
        size = min(rx_buflen, MAX_KEY_VALUE_PAIRS);
        isert_dbg("Using login payload size: %d, rx_buflen: %d "
                  "MAX_KEY_VALUE_PAIRS: %d\n", size, rx_buflen,
                  MAX_KEY_VALUE_PAIRS);
-       memcpy(login->req_buf, &rx_desc->data[0], size);
+       memcpy(login->req_buf, isert_get_data(rx_desc), size);
 
        if (login->first_request) {
                complete(&isert_conn->login_comp);
@@ -1051,14 +1051,15 @@ isert_handle_scsi_cmd(struct isert_conn *isert_conn,
        if (imm_data_len != data_len) {
                sg_nents = max(1UL, DIV_ROUND_UP(imm_data_len, PAGE_SIZE));
                sg_copy_from_buffer(cmd->se_cmd.t_data_sg, sg_nents,
-                                   &rx_desc->data[0], imm_data_len);
+                                   isert_get_data(rx_desc), imm_data_len);
                isert_dbg("Copy Immediate sg_nents: %u imm_data_len: %d\n",
                          sg_nents, imm_data_len);
        } else {
                sg_init_table(&isert_cmd->sg, 1);
                cmd->se_cmd.t_data_sg = &isert_cmd->sg;
                cmd->se_cmd.t_data_nents = 1;
-               sg_set_buf(&isert_cmd->sg, &rx_desc->data[0], imm_data_len);
+               sg_set_buf(&isert_cmd->sg, isert_get_data(rx_desc),
+                               imm_data_len);
                isert_dbg("Transfer Immediate imm_data_len: %d\n",
                          imm_data_len);
        }
@@ -1127,9 +1128,9 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
        }
        isert_dbg("Copying DataOut: sg_start: %p, sg_off: %u "
                  "sg_nents: %u from %p %u\n", sg_start, sg_off,
-                 sg_nents, &rx_desc->data[0], unsol_data_len);
+                 sg_nents, isert_get_data(rx_desc), unsol_data_len);
 
-       sg_copy_from_buffer(sg_start, sg_nents, &rx_desc->data[0],
+       sg_copy_from_buffer(sg_start, sg_nents, isert_get_data(rx_desc),
                            unsol_data_len);
 
        rc = iscsit_check_dataout_payload(cmd, hdr, false);
@@ -1188,7 +1189,7 @@ isert_handle_text_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd
        }
        cmd->text_in_ptr = text_in;
 
-       memcpy(cmd->text_in_ptr, &rx_desc->data[0], payload_length);
+       memcpy(cmd->text_in_ptr, isert_get_data(rx_desc), payload_length);
 
        return iscsit_process_text_cmd(conn, cmd, hdr);
 }
@@ -1198,7 +1199,7 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                uint32_t read_stag, uint64_t read_va,
                uint32_t write_stag, uint64_t write_va)
 {
-       struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
+       struct iscsi_hdr *hdr = isert_get_iscsi_hdr(rx_desc);
        struct iscsi_conn *conn = isert_conn->conn;
        struct iscsi_cmd *cmd;
        struct isert_cmd *isert_cmd;
@@ -1296,8 +1297,8 @@ isert_recv_done(struct ib_cq *cq, struct ib_wc *wc)
        struct isert_conn *isert_conn = wc->qp->qp_context;
        struct ib_device *ib_dev = isert_conn->cm_id->device;
        struct iser_rx_desc *rx_desc = cqe_to_rx_desc(wc->wr_cqe);
-       struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
-       struct iser_ctrl *iser_ctrl = &rx_desc->iser_header;
+       struct iscsi_hdr *hdr = isert_get_iscsi_hdr(rx_desc);
+       struct iser_ctrl *iser_ctrl = isert_get_iser_hdr(rx_desc);
        uint64_t read_va = 0, write_va = 0;
        uint32_t read_stag = 0, write_stag = 0;
 
@@ -1311,7 +1312,7 @@ isert_recv_done(struct ib_cq *cq, struct ib_wc *wc)
        rx_desc->in_use = true;
 
        ib_dma_sync_single_for_cpu(ib_dev, rx_desc->dma_addr,
-                       ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+                       ISER_RX_SIZE, DMA_FROM_DEVICE);
 
        isert_dbg("DMA: 0x%llx, iSCSI opcode: 0x%02x, ITT: 0x%08x, flags: 0x%02x dlen: %d\n",
                 rx_desc->dma_addr, hdr->opcode, hdr->itt, hdr->flags,
@@ -1346,7 +1347,7 @@ isert_recv_done(struct ib_cq *cq, struct ib_wc *wc)
                        read_stag, read_va, write_stag, write_va);
 
        ib_dma_sync_single_for_device(ib_dev, rx_desc->dma_addr,
-                       ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+                       ISER_RX_SIZE, DMA_FROM_DEVICE);
 }
 
 static void
@@ -1360,8 +1361,8 @@ isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc)
                return;
        }
 
-       ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_req_dma,
-                       ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+       ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_desc->dma_addr,
+                       ISER_RX_SIZE, DMA_FROM_DEVICE);
 
        isert_conn->login_req_len = wc->byte_len - ISER_HEADERS_LEN;
 
@@ -1376,8 +1377,8 @@ isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc)
        complete(&isert_conn->login_req_comp);
        mutex_unlock(&isert_conn->mutex);
 
-       ib_dma_sync_single_for_device(ib_dev, isert_conn->login_req_dma,
-                               ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+       ib_dma_sync_single_for_device(ib_dev, isert_conn->login_desc->dma_addr,
+                               ISER_RX_SIZE, DMA_FROM_DEVICE);
 }
 
 static void
@@ -1470,7 +1471,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err)
                        transport_generic_free_cmd(&cmd->se_cmd, 0);
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                iscsit_release_cmd(cmd);
                break;
@@ -1648,7 +1649,7 @@ isert_do_control_comp(struct work_struct *work)
        switch (cmd->i_state) {
        case ISTATE_SEND_TASKMGTRSP:
                iscsit_tmr_post_handler(cmd, cmd->conn);
-               /* fall through */
+               fallthrough;
        case ISTATE_SEND_REJECT:
        case ISTATE_SEND_TEXTRSP:
                cmd->i_state = ISTATE_SENT_STATUS;
index c55f7d9..7fee4a6 100644 (file)
                                ISERT_MAX_TX_MISC_PDUS  + \
                                ISERT_MAX_RX_MISC_PDUS)
 
-#define ISER_RX_PAD_SIZE       (ISCSI_DEF_MAX_RECV_SEG_LEN + 4096 - \
-               (ISER_RX_PAYLOAD_SIZE + sizeof(u64) + sizeof(struct ib_sge) + \
-                sizeof(struct ib_cqe) + sizeof(bool)))
+/*
+ * RX size is default of 8k plus headers, but data needs to align to
+ * 512 boundary, so use 1024 to have the extra space for alignment.
+ */
+#define ISER_RX_SIZE           (ISCSI_DEF_MAX_RECV_SEG_LEN + 1024)
 
 /* Maximum support is 16MB I/O size */
 #define ISCSI_ISER_MAX_SG_TABLESIZE    4096
@@ -81,21 +83,41 @@ enum iser_conn_state {
 };
 
 struct iser_rx_desc {
-       struct iser_ctrl iser_header;
-       struct iscsi_hdr iscsi_header;
-       char            data[ISCSI_DEF_MAX_RECV_SEG_LEN];
+       char            buf[ISER_RX_SIZE];
        u64             dma_addr;
        struct ib_sge   rx_sg;
        struct ib_cqe   rx_cqe;
        bool            in_use;
-       char            pad[ISER_RX_PAD_SIZE];
-} __packed;
+};
 
 static inline struct iser_rx_desc *cqe_to_rx_desc(struct ib_cqe *cqe)
 {
        return container_of(cqe, struct iser_rx_desc, rx_cqe);
 }
 
+static void *isert_get_iser_hdr(struct iser_rx_desc *desc)
+{
+       return PTR_ALIGN(desc->buf + ISER_HEADERS_LEN, 512) - ISER_HEADERS_LEN;
+}
+
+static size_t isert_get_hdr_offset(struct iser_rx_desc *desc)
+{
+       return isert_get_iser_hdr(desc) - (void *)desc->buf;
+}
+
+static void *isert_get_iscsi_hdr(struct iser_rx_desc *desc)
+{
+       return isert_get_iser_hdr(desc) + sizeof(struct iser_ctrl);
+}
+
+static void *isert_get_data(struct iser_rx_desc *desc)
+{
+       void *data = isert_get_iser_hdr(desc) + ISER_HEADERS_LEN;
+
+       WARN_ON((uintptr_t)data & 511);
+       return data;
+}
+
 struct iser_tx_desc {
        struct iser_ctrl iser_header;
        struct iscsi_hdr iscsi_header;
@@ -142,9 +164,8 @@ struct isert_conn {
        u32                     responder_resources;
        u32                     initiator_depth;
        bool                    pi_support;
-       struct iser_rx_desc     *login_req_buf;
+       struct iser_rx_desc     *login_desc;
        char                    *login_rsp_buf;
-       u64                     login_req_dma;
        int                     login_req_len;
        u64                     login_rsp_dma;
        struct iser_rx_desc     *rx_descs;
index 874a8eb..4933085 100644 (file)
@@ -547,7 +547,6 @@ static void vema_get(struct opa_vnic_vema_port *port,
                vema_get_mac_entries(port, recvd_mad, rsp_mad);
                break;
        case OPA_EM_ATTR_IFACE_UCAST_MACS:
-               /* fall through */
        case OPA_EM_ATTR_IFACE_MCAST_MACS:
                vema_get_mac_list(port, recvd_mad, rsp_mad, attr_id);
                break;
index 3d78775..cf6a2be 100644 (file)
@@ -152,13 +152,6 @@ static struct attribute_group rtrs_srv_stats_attr_group = {
        .attrs = rtrs_srv_stats_attrs,
 };
 
-static void rtrs_srv_dev_release(struct device *dev)
-{
-       struct rtrs_srv *srv = container_of(dev, struct rtrs_srv, dev);
-
-       kfree(srv);
-}
-
 static int rtrs_srv_create_once_sysfs_root_folders(struct rtrs_srv_sess *sess)
 {
        struct rtrs_srv *srv = sess->srv;
@@ -172,7 +165,6 @@ static int rtrs_srv_create_once_sysfs_root_folders(struct rtrs_srv_sess *sess)
                goto unlock;
        }
        srv->dev.class = rtrs_dev_class;
-       srv->dev.release = rtrs_srv_dev_release;
        err = dev_set_name(&srv->dev, "%s", sess->s.sessname);
        if (err)
                goto unlock;
@@ -182,16 +174,16 @@ static int rtrs_srv_create_once_sysfs_root_folders(struct rtrs_srv_sess *sess)
         * sysfs files are created
         */
        dev_set_uevent_suppress(&srv->dev, true);
-       err = device_register(&srv->dev);
+       err = device_add(&srv->dev);
        if (err) {
-               pr_err("device_register(): %d\n", err);
+               pr_err("device_add(): %d\n", err);
                goto put;
        }
        srv->kobj_paths = kobject_create_and_add("paths", &srv->dev.kobj);
        if (!srv->kobj_paths) {
                err = -ENOMEM;
                pr_err("kobject_create_and_add(): %d\n", err);
-               device_unregister(&srv->dev);
+               device_del(&srv->dev);
                goto unlock;
        }
        dev_set_uevent_suppress(&srv->dev, false);
@@ -216,7 +208,7 @@ rtrs_srv_destroy_once_sysfs_root_folders(struct rtrs_srv_sess *sess)
                kobject_del(srv->kobj_paths);
                kobject_put(srv->kobj_paths);
                mutex_unlock(&srv->paths_mutex);
-               device_unregister(&srv->dev);
+               device_del(&srv->dev);
        } else {
                mutex_unlock(&srv->paths_mutex);
        }
index a219bd1..28f6414 100644 (file)
@@ -1319,6 +1319,13 @@ static int rtrs_srv_get_next_cq_vector(struct rtrs_srv_sess *sess)
        return sess->cur_cq_vector;
 }
 
+static void rtrs_srv_dev_release(struct device *dev)
+{
+       struct rtrs_srv *srv = container_of(dev, struct rtrs_srv, dev);
+
+       kfree(srv);
+}
+
 static struct rtrs_srv *__alloc_srv(struct rtrs_srv_ctx *ctx,
                                     const uuid_t *paths_uuid)
 {
@@ -1336,6 +1343,8 @@ static struct rtrs_srv *__alloc_srv(struct rtrs_srv_ctx *ctx,
        uuid_copy(&srv->paths_uuid, paths_uuid);
        srv->queue_depth = sess_queue_depth;
        srv->ctx = ctx;
+       device_initialize(&srv->dev);
+       srv->dev.release = rtrs_srv_dev_release;
 
        srv->chunks = kcalloc(srv->queue_depth, sizeof(*srv->chunks),
                              GFP_KERNEL);
index e78c4c7..76ffdec 100644 (file)
@@ -102,12 +102,12 @@ static irqreturn_t fsia6b_serio_irq(struct serio *serio,
                                        input_report_key(fsia6b->dev,
                                                         sw_id++,
                                                         sw_state == 0);
-                                       /* fall-through */
+                                       fallthrough;
                                case '2':
                                        input_report_key(fsia6b->dev,
                                                         sw_id++,
                                                         sw_state == 1);
-                                       /* fall-through */
+                                       fallthrough;
                                case '1':
                                        input_report_key(fsia6b->dev,
                                                         sw_id++,
index 88df68c..d37645e 100644 (file)
@@ -885,7 +885,6 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
 
        case GC_MULTI:
                input_set_capability(input_dev, EV_KEY, BTN_TRIGGER);
-               /* fall through */
                break;
 
        case GC_PSX:
index 3eefee2..ef2fa09 100644 (file)
 #include "trackpoint.h"
 
 static const char * const trackpoint_variants[] = {
-       [TP_VARIANT_IBM]        = "IBM",
-       [TP_VARIANT_ALPS]       = "ALPS",
-       [TP_VARIANT_ELAN]       = "Elan",
-       [TP_VARIANT_NXP]        = "NXP",
+       [TP_VARIANT_IBM]                = "IBM",
+       [TP_VARIANT_ALPS]               = "ALPS",
+       [TP_VARIANT_ELAN]               = "Elan",
+       [TP_VARIANT_NXP]                = "NXP",
+       [TP_VARIANT_JYT_SYNAPTICS]      = "JYT_Synaptics",
+       [TP_VARIANT_SYNAPTICS]          = "Synaptics",
 };
 
 /*
@@ -280,6 +282,8 @@ static int trackpoint_start_protocol(struct psmouse *psmouse,
        case TP_VARIANT_ALPS:
        case TP_VARIANT_ELAN:
        case TP_VARIANT_NXP:
+       case TP_VARIANT_JYT_SYNAPTICS:
+       case TP_VARIANT_SYNAPTICS:
                if (variant_id)
                        *variant_id = param[0];
                if (firmware_id)
index 5cb93ed..eb54129 100644 (file)
  * 0x01 was the original IBM trackpoint, others implement very limited
  * subset of trackpoint features.
  */
-#define TP_VARIANT_IBM         0x01
-#define TP_VARIANT_ALPS                0x02
-#define TP_VARIANT_ELAN                0x03
-#define TP_VARIANT_NXP         0x04
+#define TP_VARIANT_IBM                 0x01
+#define TP_VARIANT_ALPS                        0x02
+#define TP_VARIANT_ELAN                        0x03
+#define TP_VARIANT_NXP                 0x04
+#define TP_VARIANT_JYT_SYNAPTICS       0x05
+#define TP_VARIANT_SYNAPTICS           0x06
 
 /*
  * Commands
index 7d7f737..a4c9b96 100644 (file)
@@ -548,6 +548,14 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"),
                },
        },
+       {
+               /* Entroware Proteus */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Entroware"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"),
+               },
+       },
        { }
 };
 
@@ -676,6 +684,14 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "33474HU"),
                },
        },
+       {
+               /* Entroware Proteus */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Entroware"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"),
+               },
+       },
        { }
 };
 
@@ -705,6 +721,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nopnp_table[] = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
                },
        },
+       {
+               /* Acer Aspire 5 A515 */
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "Grumpy_PK"),
+                       DMI_MATCH(DMI_BOARD_VENDOR, "PK"),
+               },
+       },
        { }
 };
 
index 959c1d8..1cedb45 100644 (file)
@@ -213,7 +213,7 @@ static void wacom_handle_model_response(struct wacom *wacom)
                case 0x3731: /* PL-710 */
                        wacom->res_x = 2540;
                        wacom->res_y = 2540;
-                       /* fall through */
+                       fallthrough;
                case 0x3535: /* PL-550 */
                case 0x3830: /* PL-800 */
                        wacom->extra_z_bits = 2;
index 6b71b0a..98f17fa 100644 (file)
@@ -477,7 +477,7 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
                        bootloader = appmode - 0x24;
                        break;
                }
-               /* Fall through - for normal case */
+               fallthrough;    /* for normal case */
        case 0x4c:
        case 0x4d:
        case 0x5a:
index 607d1ae..bb1699e 100644 (file)
@@ -290,7 +290,7 @@ static int wm831x_ts_probe(struct platform_device *pdev)
                default:
                        dev_err(&pdev->dev, "Unsupported ISEL setting: %d\n",
                                pdata->isel);
-                       /* Fall through */
+                       fallthrough;
                case 200:
                case 0:
                        wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
index befd111..cf07491 100644 (file)
@@ -55,12 +55,18 @@ static int icc_summary_show(struct seq_file *s, void *data)
 
                        icc_summary_show_one(s, n);
                        hlist_for_each_entry(r, &n->req_list, req_node) {
+                               u32 avg_bw = 0, peak_bw = 0;
+
                                if (!r->dev)
                                        continue;
 
+                               if (r->enabled) {
+                                       avg_bw = r->avg_bw;
+                                       peak_bw = r->peak_bw;
+                               }
+
                                seq_printf(s, "  %-27s %12u %12u %12u\n",
-                                          dev_name(r->dev), r->tag, r->avg_bw,
-                                          r->peak_bw);
+                                          dev_name(r->dev), r->tag, avg_bw, peak_bw);
                        }
                }
        }
index a3d2ef1..609db9c 100644 (file)
@@ -52,8 +52,20 @@ static int cmp_vcd(void *priv, struct list_head *a, struct list_head *b)
                return 1;
 }
 
+static u64 bcm_div(u64 num, u32 base)
+{
+       /* Ensure that small votes aren't lost. */
+       if (num && num < base)
+               return 1;
+
+       do_div(num, base);
+
+       return num;
+}
+
 static void bcm_aggregate(struct qcom_icc_bcm *bcm)
 {
+       struct qcom_icc_node *node;
        size_t i, bucket;
        u64 agg_avg[QCOM_ICC_NUM_BUCKETS] = {0};
        u64 agg_peak[QCOM_ICC_NUM_BUCKETS] = {0};
@@ -61,22 +73,21 @@ static void bcm_aggregate(struct qcom_icc_bcm *bcm)
 
        for (bucket = 0; bucket < QCOM_ICC_NUM_BUCKETS; bucket++) {
                for (i = 0; i < bcm->num_nodes; i++) {
-                       temp = bcm->nodes[i]->sum_avg[bucket] * bcm->aux_data.width;
-                       do_div(temp, bcm->nodes[i]->buswidth * bcm->nodes[i]->channels);
+                       node = bcm->nodes[i];
+                       temp = bcm_div(node->sum_avg[bucket] * bcm->aux_data.width,
+                                      node->buswidth * node->channels);
                        agg_avg[bucket] = max(agg_avg[bucket], temp);
 
-                       temp = bcm->nodes[i]->max_peak[bucket] * bcm->aux_data.width;
-                       do_div(temp, bcm->nodes[i]->buswidth);
+                       temp = bcm_div(node->max_peak[bucket] * bcm->aux_data.width,
+                                      node->buswidth);
                        agg_peak[bucket] = max(agg_peak[bucket], temp);
                }
 
                temp = agg_avg[bucket] * 1000ULL;
-               do_div(temp, bcm->aux_data.unit);
-               bcm->vote_x[bucket] = temp;
+               bcm->vote_x[bucket] = bcm_div(temp, bcm->aux_data.unit);
 
                temp = agg_peak[bucket] * 1000ULL;
-               do_div(temp, bcm->aux_data.unit);
-               bcm->vote_y[bucket] = temp;
+               bcm->vote_y[bucket] = bcm_div(temp, bcm->aux_data.unit);
        }
 
        if (bcm->keepalive && bcm->vote_x[QCOM_ICC_BUCKET_AMC] == 0 &&
index 1f061d9..626b97d 100644 (file)
@@ -10,7 +10,7 @@ config AMD_IOMMU
        select IOMMU_API
        select IOMMU_IOVA
        select IOMMU_DMA
-       depends on X86_64 && PCI && ACPI
+       depends on X86_64 && PCI && ACPI && HAVE_CMPXCHG_DOUBLE
        help
          With this option you can enable support for AMD IOMMU hardware in
          your system. An IOMMU is a hardware component which provides
index 5730971..030ee90 100644 (file)
@@ -45,12 +45,12 @@ extern int amd_iommu_register_ppr_notifier(struct notifier_block *nb);
 extern int amd_iommu_unregister_ppr_notifier(struct notifier_block *nb);
 extern void amd_iommu_domain_direct_map(struct iommu_domain *dom);
 extern int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids);
-extern int amd_iommu_flush_page(struct iommu_domain *dom, int pasid,
+extern int amd_iommu_flush_page(struct iommu_domain *dom, u32 pasid,
                                u64 address);
-extern int amd_iommu_flush_tlb(struct iommu_domain *dom, int pasid);
-extern int amd_iommu_domain_set_gcr3(struct iommu_domain *dom, int pasid,
+extern int amd_iommu_flush_tlb(struct iommu_domain *dom, u32 pasid);
+extern int amd_iommu_domain_set_gcr3(struct iommu_domain *dom, u32 pasid,
                                     unsigned long cr3);
-extern int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, int pasid);
+extern int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, u32 pasid);
 extern struct iommu_domain *amd_iommu_get_v2_domain(struct pci_dev *pdev);
 
 #ifdef CONFIG_IRQ_REMAP
@@ -66,7 +66,7 @@ static inline int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
 #define PPR_INVALID                    0x1
 #define PPR_FAILURE                    0xf
 
-extern int amd_iommu_complete_ppr(struct pci_dev *pdev, int pasid,
+extern int amd_iommu_complete_ppr(struct pci_dev *pdev, u32 pasid,
                                  int status, int tag);
 
 static inline bool is_rd890_iommu(struct pci_dev *pdev)
index 958050c..1ba6b4c 100644 (file)
@@ -1104,25 +1104,6 @@ static int __init add_early_maps(void)
 }
 
 /*
- * Reads the device exclusion range from ACPI and initializes the IOMMU with
- * it
- */
-static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m)
-{
-       if (!(m->flags & IVMD_FLAG_EXCL_RANGE))
-               return;
-
-       /*
-        * Treat per-device exclusion ranges as r/w unity-mapped regions
-        * since some buggy BIOSes might lead to the overwritten exclusion
-        * range (exclusion_start and exclusion_length members). This
-        * happens when there are multiple exclusion ranges (IVMD entries)
-        * defined in ACPI table.
-        */
-       m->flags = (IVMD_FLAG_IW | IVMD_FLAG_IR | IVMD_FLAG_UNITY_MAP);
-}
-
-/*
  * Takes a pointer to an AMD IOMMU entry in the ACPI table and
  * initializes the hardware and our data structures with it.
  */
@@ -1511,7 +1492,14 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
                        iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
                else
                        iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
-               if (((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0))
+
+               /*
+                * Note: GA (128-bit IRTE) mode requires cmpxchg16b supports.
+                * GAM also requires GA mode. Therefore, we need to
+                * check cmpxchg16b support before enabling it.
+                */
+               if (!boot_cpu_has(X86_FEATURE_CX16) ||
+                   ((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0))
                        amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
                break;
        case 0x11:
@@ -1520,8 +1508,18 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
                        iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
                else
                        iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
-               if (((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0))
+
+               /*
+                * Note: GA (128-bit IRTE) mode requires cmpxchg16b supports.
+                * XT, GAM also requires GA mode. Therefore, we need to
+                * check cmpxchg16b support before enabling them.
+                */
+               if (!boot_cpu_has(X86_FEATURE_CX16) ||
+                   ((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0)) {
                        amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
+                       break;
+               }
+
                /*
                 * Note: Since iommu_update_intcapxt() leverages
                 * the IOMMU MMIO access to MSI capability block registers
@@ -2056,30 +2054,6 @@ static void __init free_unity_maps(void)
        }
 }
 
-/* called when we find an exclusion range definition in ACPI */
-static int __init init_exclusion_range(struct ivmd_header *m)
-{
-       int i;
-
-       switch (m->type) {
-       case ACPI_IVMD_TYPE:
-               set_device_exclusion_range(m->devid, m);
-               break;
-       case ACPI_IVMD_TYPE_ALL:
-               for (i = 0; i <= amd_iommu_last_bdf; ++i)
-                       set_device_exclusion_range(i, m);
-               break;
-       case ACPI_IVMD_TYPE_RANGE:
-               for (i = m->devid; i <= m->aux; ++i)
-                       set_device_exclusion_range(i, m);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
 /* called for unity map ACPI definition */
 static int __init init_unity_map_range(struct ivmd_header *m)
 {
@@ -2090,9 +2064,6 @@ static int __init init_unity_map_range(struct ivmd_header *m)
        if (e == NULL)
                return -ENOMEM;
 
-       if (m->flags & IVMD_FLAG_EXCL_RANGE)
-               init_exclusion_range(m);
-
        switch (m->type) {
        default:
                kfree(e);
@@ -2116,6 +2087,16 @@ static int __init init_unity_map_range(struct ivmd_header *m)
        e->address_end = e->address_start + PAGE_ALIGN(m->range_length);
        e->prot = m->flags >> 1;
 
+       /*
+        * Treat per-device exclusion ranges as r/w unity-mapped regions
+        * since some buggy BIOSes might lead to the overwritten exclusion
+        * range (exclusion_start and exclusion_length members). This
+        * happens when there are multiple exclusion ranges (IVMD entries)
+        * defined in ACPI table.
+        */
+       if (m->flags & IVMD_FLAG_EXCL_RANGE)
+               e->prot = (IVMD_FLAG_IW | IVMD_FLAG_IR) >> 1;
+
        DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x"
                    " range_start: %016llx range_end: %016llx flags: %x\n", s,
                    PCI_BUS_NUM(e->devid_start), PCI_SLOT(e->devid_start),
@@ -2258,7 +2239,7 @@ static void iommu_enable_ga(struct amd_iommu *iommu)
        switch (amd_iommu_guest_ir) {
        case AMD_IOMMU_GUEST_IR_VAPIC:
                iommu_feature_enable(iommu, CONTROL_GAM_EN);
-               /* Fall through */
+               fallthrough;
        case AMD_IOMMU_GUEST_IR_LEGACY_GA:
                iommu_feature_enable(iommu, CONTROL_GA_EN);
                iommu->irte_ops = &irte_128_ops;
index ba9f3db..9e231ca 100644 (file)
@@ -513,10 +513,11 @@ static void amd_iommu_report_page_fault(u16 devid, u16 domain_id,
 static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
 {
        struct device *dev = iommu->iommu.dev;
-       int type, devid, pasid, flags, tag;
+       int type, devid, flags, tag;
        volatile u32 *event = __evt;
        int count = 0;
        u64 address;
+       u32 pasid;
 
 retry:
        type    = (event[1] >> EVENT_TYPE_SHIFT)  & EVENT_TYPE_MASK;
@@ -729,7 +730,21 @@ static void iommu_poll_ga_log(struct amd_iommu *iommu)
                }
        }
 }
-#endif /* CONFIG_IRQ_REMAP */
+
+static void
+amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu)
+{
+       if (!irq_remapping_enabled || !dev_is_pci(dev) ||
+           pci_dev_has_special_msi_domain(to_pci_dev(dev)))
+               return;
+
+       dev_set_msi_domain(dev, iommu->msi_domain);
+}
+
+#else /* CONFIG_IRQ_REMAP */
+static inline void
+amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { }
+#endif /* !CONFIG_IRQ_REMAP */
 
 #define AMD_IOMMU_INT_MASK     \
        (MMIO_STATUS_EVT_INT_MASK | \
@@ -909,7 +924,7 @@ static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep,
                cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
 }
 
-static void build_inv_iommu_pasid(struct iommu_cmd *cmd, u16 domid, int pasid,
+static void build_inv_iommu_pasid(struct iommu_cmd *cmd, u16 domid, u32 pasid,
                                  u64 address, bool size)
 {
        memset(cmd, 0, sizeof(*cmd));
@@ -927,7 +942,7 @@ static void build_inv_iommu_pasid(struct iommu_cmd *cmd, u16 domid, int pasid,
        CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES);
 }
 
-static void build_inv_iotlb_pasid(struct iommu_cmd *cmd, u16 devid, int pasid,
+static void build_inv_iotlb_pasid(struct iommu_cmd *cmd, u16 devid, u32 pasid,
                                  int qdep, u64 address, bool size)
 {
        memset(cmd, 0, sizeof(*cmd));
@@ -947,7 +962,7 @@ static void build_inv_iotlb_pasid(struct iommu_cmd *cmd, u16 devid, int pasid,
        CMD_SET_TYPE(cmd, CMD_INV_IOTLB_PAGES);
 }
 
-static void build_complete_ppr(struct iommu_cmd *cmd, u16 devid, int pasid,
+static void build_complete_ppr(struct iommu_cmd *cmd, u16 devid, u32 pasid,
                               int status, int tag, bool gn)
 {
        memset(cmd, 0, sizeof(*cmd));
@@ -2157,6 +2172,7 @@ static struct iommu_device *amd_iommu_probe_device(struct device *dev)
                iommu_dev = ERR_PTR(ret);
                iommu_ignore_device(dev);
        } else {
+               amd_iommu_set_pci_msi_domain(dev, iommu);
                iommu_dev = &iommu->iommu;
        }
 
@@ -2659,7 +2675,12 @@ static int amd_iommu_def_domain_type(struct device *dev)
        if (!dev_data)
                return 0;
 
-       if (dev_data->iommu_v2)
+       /*
+        * Do not identity map IOMMUv2 capable devices when memory encryption is
+        * active, because some of those devices (AMD GPUs) don't have the
+        * encryption bit in their DMA-mask and require remapping.
+        */
+       if (!mem_encrypt_active() && dev_data->iommu_v2)
                return IOMMU_DOMAIN_IDENTITY;
 
        return 0;
@@ -2781,7 +2802,7 @@ out:
 }
 EXPORT_SYMBOL(amd_iommu_domain_enable_v2);
 
-static int __flush_pasid(struct protection_domain *domain, int pasid,
+static int __flush_pasid(struct protection_domain *domain, u32 pasid,
                         u64 address, bool size)
 {
        struct iommu_dev_data *dev_data;
@@ -2842,13 +2863,13 @@ out:
        return ret;
 }
 
-static int __amd_iommu_flush_page(struct protection_domain *domain, int pasid,
+static int __amd_iommu_flush_page(struct protection_domain *domain, u32 pasid,
                                  u64 address)
 {
        return __flush_pasid(domain, pasid, address, false);
 }
 
-int amd_iommu_flush_page(struct iommu_domain *dom, int pasid,
+int amd_iommu_flush_page(struct iommu_domain *dom, u32 pasid,
                         u64 address)
 {
        struct protection_domain *domain = to_pdomain(dom);
@@ -2863,13 +2884,13 @@ int amd_iommu_flush_page(struct iommu_domain *dom, int pasid,
 }
 EXPORT_SYMBOL(amd_iommu_flush_page);
 
-static int __amd_iommu_flush_tlb(struct protection_domain *domain, int pasid)
+static int __amd_iommu_flush_tlb(struct protection_domain *domain, u32 pasid)
 {
        return __flush_pasid(domain, pasid, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
                             true);
 }
 
-int amd_iommu_flush_tlb(struct iommu_domain *dom, int pasid)
+int amd_iommu_flush_tlb(struct iommu_domain *dom, u32 pasid)
 {
        struct protection_domain *domain = to_pdomain(dom);
        unsigned long flags;
@@ -2883,7 +2904,7 @@ int amd_iommu_flush_tlb(struct iommu_domain *dom, int pasid)
 }
 EXPORT_SYMBOL(amd_iommu_flush_tlb);
 
-static u64 *__get_gcr3_pte(u64 *root, int level, int pasid, bool alloc)
+static u64 *__get_gcr3_pte(u64 *root, int level, u32 pasid, bool alloc)
 {
        int index;
        u64 *pte;
@@ -2915,7 +2936,7 @@ static u64 *__get_gcr3_pte(u64 *root, int level, int pasid, bool alloc)
        return pte;
 }
 
-static int __set_gcr3(struct protection_domain *domain, int pasid,
+static int __set_gcr3(struct protection_domain *domain, u32 pasid,
                      unsigned long cr3)
 {
        struct domain_pgtable pgtable;
@@ -2934,7 +2955,7 @@ static int __set_gcr3(struct protection_domain *domain, int pasid,
        return __amd_iommu_flush_tlb(domain, pasid);
 }
 
-static int __clear_gcr3(struct protection_domain *domain, int pasid)
+static int __clear_gcr3(struct protection_domain *domain, u32 pasid)
 {
        struct domain_pgtable pgtable;
        u64 *pte;
@@ -2952,7 +2973,7 @@ static int __clear_gcr3(struct protection_domain *domain, int pasid)
        return __amd_iommu_flush_tlb(domain, pasid);
 }
 
-int amd_iommu_domain_set_gcr3(struct iommu_domain *dom, int pasid,
+int amd_iommu_domain_set_gcr3(struct iommu_domain *dom, u32 pasid,
                              unsigned long cr3)
 {
        struct protection_domain *domain = to_pdomain(dom);
@@ -2967,7 +2988,7 @@ int amd_iommu_domain_set_gcr3(struct iommu_domain *dom, int pasid,
 }
 EXPORT_SYMBOL(amd_iommu_domain_set_gcr3);
 
-int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, int pasid)
+int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, u32 pasid)
 {
        struct protection_domain *domain = to_pdomain(dom);
        unsigned long flags;
@@ -2981,7 +3002,7 @@ int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, int pasid)
 }
 EXPORT_SYMBOL(amd_iommu_domain_clear_gcr3);
 
-int amd_iommu_complete_ppr(struct pci_dev *pdev, int pasid,
+int amd_iommu_complete_ppr(struct pci_dev *pdev, u32 pasid,
                           int status, int tag)
 {
        struct iommu_dev_data *dev_data;
@@ -3292,6 +3313,7 @@ out:
 static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
                          struct amd_ir_data *data)
 {
+       bool ret;
        struct irq_remap_table *table;
        struct amd_iommu *iommu;
        unsigned long flags;
@@ -3309,10 +3331,18 @@ static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
 
        entry = (struct irte_ga *)table->table;
        entry = &entry[index];
-       entry->lo.fields_remap.valid = 0;
-       entry->hi.val = irte->hi.val;
-       entry->lo.val = irte->lo.val;
-       entry->lo.fields_remap.valid = 1;
+
+       ret = cmpxchg_double(&entry->lo.val, &entry->hi.val,
+                            entry->lo.val, entry->hi.val,
+                            irte->lo.val, irte->hi.val);
+       /*
+        * We use cmpxchg16 to atomically update the 128-bit IRTE,
+        * and it cannot be updated by the hardware or other processors
+        * behind us, so the return value of cmpxchg16 should be the
+        * same as the old value.
+        */
+       WARN_ON(!ret);
+
        if (data)
                data->ref = entry;
 
@@ -3505,69 +3535,51 @@ static void irte_ga_clear_allocated(struct irq_remap_table *table, int index)
 
 static int get_devid(struct irq_alloc_info *info)
 {
-       int devid = -1;
-
        switch (info->type) {
        case X86_IRQ_ALLOC_TYPE_IOAPIC:
-               devid     = get_ioapic_devid(info->ioapic_id);
-               break;
+       case X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT:
+               return get_ioapic_devid(info->devid);
        case X86_IRQ_ALLOC_TYPE_HPET:
-               devid     = get_hpet_devid(info->hpet_id);
-               break;
-       case X86_IRQ_ALLOC_TYPE_MSI:
-       case X86_IRQ_ALLOC_TYPE_MSIX:
-               devid = get_device_id(&info->msi_dev->dev);
-               break;
+       case X86_IRQ_ALLOC_TYPE_HPET_GET_PARENT:
+               return get_hpet_devid(info->devid);
+       case X86_IRQ_ALLOC_TYPE_PCI_MSI:
+       case X86_IRQ_ALLOC_TYPE_PCI_MSIX:
+               return get_device_id(msi_desc_to_dev(info->desc));
        default:
-               BUG_ON(1);
-               break;
+               WARN_ON_ONCE(1);
+               return -1;
        }
-
-       return devid;
 }
 
-static struct irq_domain *get_ir_irq_domain(struct irq_alloc_info *info)
+static struct irq_domain *get_irq_domain_for_devid(struct irq_alloc_info *info,
+                                                  int devid)
 {
-       struct amd_iommu *iommu;
-       int devid;
+       struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
 
-       if (!info)
+       if (!iommu)
                return NULL;
 
-       devid = get_devid(info);
-       if (devid >= 0) {
-               iommu = amd_iommu_rlookup_table[devid];
-               if (iommu)
-                       return iommu->ir_domain;
+       switch (info->type) {
+       case X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT:
+       case X86_IRQ_ALLOC_TYPE_HPET_GET_PARENT:
+               return iommu->ir_domain;
+       default:
+               WARN_ON_ONCE(1);
+               return NULL;
        }
-
-       return NULL;
 }
 
 static struct irq_domain *get_irq_domain(struct irq_alloc_info *info)
 {
-       struct amd_iommu *iommu;
        int devid;
 
        if (!info)
                return NULL;
 
-       switch (info->type) {
-       case X86_IRQ_ALLOC_TYPE_MSI:
-       case X86_IRQ_ALLOC_TYPE_MSIX:
-               devid = get_device_id(&info->msi_dev->dev);
-               if (devid < 0)
-                       return NULL;
-
-               iommu = amd_iommu_rlookup_table[devid];
-               if (iommu)
-                       return iommu->msi_domain;
-               break;
-       default:
-               break;
-       }
-
-       return NULL;
+       devid = get_devid(info);
+       if (devid < 0)
+               return NULL;
+       return get_irq_domain_for_devid(info, devid);
 }
 
 struct irq_remap_ops amd_iommu_irq_ops = {
@@ -3576,7 +3588,6 @@ struct irq_remap_ops amd_iommu_irq_ops = {
        .disable                = amd_iommu_disable,
        .reenable               = amd_iommu_reenable,
        .enable_faulting        = amd_iommu_enable_faulting,
-       .get_ir_irq_domain      = get_ir_irq_domain,
        .get_irq_domain         = get_irq_domain,
 };
 
@@ -3602,21 +3613,21 @@ static void irq_remapping_prepare_irte(struct amd_ir_data *data,
        switch (info->type) {
        case X86_IRQ_ALLOC_TYPE_IOAPIC:
                /* Setup IOAPIC entry */
-               entry = info->ioapic_entry;
-               info->ioapic_entry = NULL;
+               entry = info->ioapic.entry;
+               info->ioapic.entry = NULL;
                memset(entry, 0, sizeof(*entry));
                entry->vector        = index;
                entry->mask          = 0;
-               entry->trigger       = info->ioapic_trigger;
-               entry->polarity      = info->ioapic_polarity;
+               entry->trigger       = info->ioapic.trigger;
+               entry->polarity      = info->ioapic.polarity;
                /* Mask level triggered irqs. */
-               if (info->ioapic_trigger)
+               if (info->ioapic.trigger)
                        entry->mask = 1;
                break;
 
        case X86_IRQ_ALLOC_TYPE_HPET:
-       case X86_IRQ_ALLOC_TYPE_MSI:
-       case X86_IRQ_ALLOC_TYPE_MSIX:
+       case X86_IRQ_ALLOC_TYPE_PCI_MSI:
+       case X86_IRQ_ALLOC_TYPE_PCI_MSIX:
                msg->address_hi = MSI_ADDR_BASE_HI;
                msg->address_lo = MSI_ADDR_BASE_LO;
                msg->data = irte_info->index;
@@ -3660,15 +3671,15 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
 
        if (!info)
                return -EINVAL;
-       if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_MSI &&
-           info->type != X86_IRQ_ALLOC_TYPE_MSIX)
+       if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_PCI_MSI &&
+           info->type != X86_IRQ_ALLOC_TYPE_PCI_MSIX)
                return -EINVAL;
 
        /*
         * With IRQ remapping enabled, don't need contiguous CPU vectors
         * to support multiple MSI interrupts.
         */
-       if (info->type == X86_IRQ_ALLOC_TYPE_MSI)
+       if (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI)
                info->flags &= ~X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
 
        devid = get_devid(info);
@@ -3696,15 +3707,16 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
                                        iommu->irte_ops->set_allocated(table, i);
                        }
                        WARN_ON(table->min_index != 32);
-                       index = info->ioapic_pin;
+                       index = info->ioapic.pin;
                } else {
                        index = -ENOMEM;
                }
-       } else if (info->type == X86_IRQ_ALLOC_TYPE_MSI ||
-                  info->type == X86_IRQ_ALLOC_TYPE_MSIX) {
-               bool align = (info->type == X86_IRQ_ALLOC_TYPE_MSI);
+       } else if (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI ||
+                  info->type == X86_IRQ_ALLOC_TYPE_PCI_MSIX) {
+               bool align = (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI);
 
-               index = alloc_irq_index(devid, nr_irqs, align, info->msi_dev);
+               index = alloc_irq_index(devid, nr_irqs, align,
+                                       msi_desc_to_pci_dev(info->desc));
        } else {
                index = alloc_irq_index(devid, nr_irqs, false, NULL);
        }
@@ -3717,8 +3729,8 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
 
        for (i = 0; i < nr_irqs; i++) {
                irq_data = irq_domain_get_irq_data(domain, virq + i);
-               cfg = irqd_cfg(irq_data);
-               if (!irq_data || !cfg) {
+               cfg = irq_data ? irqd_cfg(irq_data) : NULL;
+               if (!cfg) {
                        ret = -EINVAL;
                        goto out_free_data;
                }
@@ -3826,14 +3838,18 @@ int amd_iommu_activate_guest_mode(void *data)
 {
        struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
        struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
+       u64 valid;
 
        if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) ||
            !entry || entry->lo.fields_vapic.guest_mode)
                return 0;
 
+       valid = entry->lo.fields_vapic.valid;
+
        entry->lo.val = 0;
        entry->hi.val = 0;
 
+       entry->lo.fields_vapic.valid       = valid;
        entry->lo.fields_vapic.guest_mode  = 1;
        entry->lo.fields_vapic.ga_log_intr = 1;
        entry->hi.fields.ga_root_ptr       = ir_data->ga_root_ptr;
@@ -3850,14 +3866,18 @@ int amd_iommu_deactivate_guest_mode(void *data)
        struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
        struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
        struct irq_cfg *cfg = ir_data->cfg;
+       u64 valid;
 
        if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) ||
            !entry || !entry->lo.fields_vapic.guest_mode)
                return 0;
 
+       valid = entry->lo.fields_remap.valid;
+
        entry->lo.val = 0;
        entry->hi.val = 0;
 
+       entry->lo.fields_remap.valid       = valid;
        entry->lo.fields_remap.dm          = apic->irq_dest_mode;
        entry->lo.fields_remap.int_type    = apic->irq_delivery_mode;
        entry->hi.fields.vector            = cfg->vector;
index c259108..5ecc0bc 100644 (file)
@@ -40,7 +40,7 @@ struct pasid_state {
        struct mmu_notifier mn;                 /* mmu_notifier handle */
        struct pri_queue pri[PRI_QUEUE_SIZE];   /* PRI tag states */
        struct device_state *device_state;      /* Link to our device_state */
-       int pasid;                              /* PASID index */
+       u32 pasid;                              /* PASID index */
        bool invalid;                           /* Used during setup and
                                                   teardown of the pasid */
        spinlock_t lock;                        /* Protect pri_queues and
@@ -70,7 +70,7 @@ struct fault {
        struct mm_struct *mm;
        u64 address;
        u16 devid;
-       u16 pasid;
+       u32 pasid;
        u16 tag;
        u16 finish;
        u16 flags;
@@ -150,7 +150,7 @@ static void put_device_state(struct device_state *dev_state)
 
 /* Must be called under dev_state->lock */
 static struct pasid_state **__get_pasid_state_ptr(struct device_state *dev_state,
-                                                 int pasid, bool alloc)
+                                                 u32 pasid, bool alloc)
 {
        struct pasid_state **root, **ptr;
        int level, index;
@@ -184,7 +184,7 @@ static struct pasid_state **__get_pasid_state_ptr(struct device_state *dev_state
 
 static int set_pasid_state(struct device_state *dev_state,
                           struct pasid_state *pasid_state,
-                          int pasid)
+                          u32 pasid)
 {
        struct pasid_state **ptr;
        unsigned long flags;
@@ -211,7 +211,7 @@ out_unlock:
        return ret;
 }
 
-static void clear_pasid_state(struct device_state *dev_state, int pasid)
+static void clear_pasid_state(struct device_state *dev_state, u32 pasid)
 {
        struct pasid_state **ptr;
        unsigned long flags;
@@ -229,7 +229,7 @@ out_unlock:
 }
 
 static struct pasid_state *get_pasid_state(struct device_state *dev_state,
-                                          int pasid)
+                                          u32 pasid)
 {
        struct pasid_state **ptr, *ret = NULL;
        unsigned long flags;
@@ -594,7 +594,7 @@ static struct notifier_block ppr_nb = {
        .notifier_call = ppr_notifier,
 };
 
-int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid,
+int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
                         struct task_struct *task)
 {
        struct pasid_state *pasid_state;
@@ -615,7 +615,7 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid,
                return -EINVAL;
 
        ret = -EINVAL;
-       if (pasid < 0 || pasid >= dev_state->max_pasids)
+       if (pasid >= dev_state->max_pasids)
                goto out;
 
        ret = -ENOMEM;
@@ -679,7 +679,7 @@ out:
 }
 EXPORT_SYMBOL(amd_iommu_bind_pasid);
 
-void amd_iommu_unbind_pasid(struct pci_dev *pdev, int pasid)
+void amd_iommu_unbind_pasid(struct pci_dev *pdev, u32 pasid)
 {
        struct pasid_state *pasid_state;
        struct device_state *dev_state;
@@ -695,7 +695,7 @@ void amd_iommu_unbind_pasid(struct pci_dev *pdev, int pasid)
        if (dev_state == NULL)
                return;
 
-       if (pasid < 0 || pasid >= dev_state->max_pasids)
+       if (pasid >= dev_state->max_pasids)
                goto out;
 
        pasid_state = get_pasid_state(dev_state, pasid);
@@ -737,6 +737,13 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
 
        might_sleep();
 
+       /*
+        * When memory encryption is active the device is likely not in a
+        * direct-mapped domain. Forbid using IOMMUv2 functionality for now.
+        */
+       if (mem_encrypt_active())
+               return -ENODEV;
+
        if (!amd_iommu_v2_supported())
                return -ENODEV;
 
index 7196207..c192544 100644 (file)
@@ -903,7 +903,7 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
                break;
        case CMDQ_OP_CFGI_CD:
                cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SSID, ent->cfgi.ssid);
-               /* Fallthrough */
+               fallthrough;
        case CMDQ_OP_CFGI_STE:
                cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SID, ent->cfgi.sid);
                cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_LEAF, ent->cfgi.leaf);
@@ -936,7 +936,7 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
                break;
        case CMDQ_OP_TLBI_NH_ASID:
                cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid);
-               /* Fallthrough */
+               fallthrough;
        case CMDQ_OP_TLBI_S12_VMALL:
                cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
                break;
@@ -1036,7 +1036,6 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
                 */
                return;
        case CMDQ_ERR_CERROR_ILL_IDX:
-               /* Fallthrough */
        default:
                break;
        }
@@ -3758,7 +3757,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
        switch (FIELD_GET(IDR0_STALL_MODEL, reg)) {
        case IDR0_STALL_MODEL_FORCE:
                smmu->features |= ARM_SMMU_FEAT_STALL_FORCE;
-               /* Fallthrough */
+               fallthrough;
        case IDR0_STALL_MODEL_STALL:
                smmu->features |= ARM_SMMU_FEAT_STALLS;
        }
@@ -3778,7 +3777,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
        switch (FIELD_GET(IDR0_TTF, reg)) {
        case IDR0_TTF_AARCH32_64:
                smmu->ias = 40;
-               /* Fallthrough */
+               fallthrough;
        case IDR0_TTF_AARCH64:
                break;
        default:
@@ -3875,7 +3874,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
        default:
                dev_info(smmu->dev,
                        "unknown output address size. Truncating to 48-bit\n");
-               /* Fallthrough */
+               fallthrough;
        case IDR5_OAS_48_BIT:
                smmu->oas = 48;
        }
index bad3c0c..de324b4 100644 (file)
@@ -1295,13 +1295,17 @@ static int exynos_iommu_of_xlate(struct device *dev,
                return -ENODEV;
 
        data = platform_get_drvdata(sysmmu);
-       if (!data)
+       if (!data) {
+               put_device(&sysmmu->dev);
                return -ENODEV;
+       }
 
        if (!owner) {
                owner = kzalloc(sizeof(*owner), GFP_KERNEL);
-               if (!owner)
+               if (!owner) {
+                       put_device(&sysmmu->dev);
                        return -ENOMEM;
+               }
 
                INIT_LIST_HEAD(&owner->controllers);
                mutex_init(&owner->rpm_lock);
index 8919c1c..e09e2d7 100644 (file)
@@ -101,7 +101,7 @@ static int hyperv_irq_remapping_alloc(struct irq_domain *domain,
         * in the chip_data and hyperv_irq_remapping_activate()/hyperv_ir_set_
         * affinity() set vector and dest_apicid directly into IO-APIC entry.
         */
-       irq_data->chip_data = info->ioapic_entry;
+       irq_data->chip_data = info->ioapic.entry;
 
        /*
         * Hypver-V IO APIC irq affinity should be in the scope of
@@ -182,9 +182,9 @@ static int __init hyperv_enable_irq_remapping(void)
        return IRQ_REMAP_X2APIC_MODE;
 }
 
-static struct irq_domain *hyperv_get_ir_irq_domain(struct irq_alloc_info *info)
+static struct irq_domain *hyperv_get_irq_domain(struct irq_alloc_info *info)
 {
-       if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC)
+       if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT)
                return ioapic_ir_domain;
        else
                return NULL;
@@ -193,7 +193,7 @@ static struct irq_domain *hyperv_get_ir_irq_domain(struct irq_alloc_info *info)
 struct irq_remap_ops hyperv_irq_remap_ops = {
        .prepare                = hyperv_prepare_irq_remapping,
        .enable                 = hyperv_enable_irq_remapping,
-       .get_ir_irq_domain      = hyperv_get_ir_irq_domain,
+       .get_irq_domain         = hyperv_get_irq_domain,
 };
 
 #endif
index 93e6345..a8fb82c 100644 (file)
@@ -316,6 +316,9 @@ static int dmar_pci_bus_add_dev(struct dmar_pci_notify_info *info)
        if (ret < 0 && dmar_dev_scope_status == 0)
                dmar_dev_scope_status = ret;
 
+       if (ret >= 0)
+               intel_irq_remap_add_device(info);
+
        return ret;
 }
 
@@ -1482,7 +1485,7 @@ void qi_flush_dev_iotlb_pasid(struct intel_iommu *iommu, u16 sid, u16 pfsid,
 }
 
 void qi_flush_pasid_cache(struct intel_iommu *iommu, u16 did,
-                         u64 granu, int pasid)
+                         u64 granu, u32 pasid)
 {
        struct qi_desc desc = {.qw1 = 0, .qw2 = 0, .qw3 = 0};
 
@@ -1796,7 +1799,7 @@ void dmar_msi_read(int irq, struct msi_msg *msg)
 }
 
 static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
-               u8 fault_reason, int pasid, u16 source_id,
+               u8 fault_reason, u32 pasid, u16 source_id,
                unsigned long long addr)
 {
        const char *reason;
@@ -1846,7 +1849,8 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
                u8 fault_reason;
                u16 source_id;
                u64 guest_addr;
-               int type, pasid;
+               u32 pasid;
+               int type;
                u32 data;
                bool pasid_present;
 
index e9864e5..342e42e 100644 (file)
@@ -123,29 +123,29 @@ static inline unsigned int level_to_offset_bits(int level)
        return (level - 1) * LEVEL_STRIDE;
 }
 
-static inline int pfn_level_offset(unsigned long pfn, int level)
+static inline int pfn_level_offset(u64 pfn, int level)
 {
        return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
 }
 
-static inline unsigned long level_mask(int level)
+static inline u64 level_mask(int level)
 {
-       return -1UL << level_to_offset_bits(level);
+       return -1ULL << level_to_offset_bits(level);
 }
 
-static inline unsigned long level_size(int level)
+static inline u64 level_size(int level)
 {
-       return 1UL << level_to_offset_bits(level);
+       return 1ULL << level_to_offset_bits(level);
 }
 
-static inline unsigned long align_to_level(unsigned long pfn, int level)
+static inline u64 align_to_level(u64 pfn, int level)
 {
        return (pfn + level_size(level) - 1) & level_mask(level);
 }
 
 static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
 {
-       return  1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
+       return 1UL << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
 }
 
 /* VT-d pages must always be _smaller_ than MM pages. Otherwise things
@@ -364,7 +364,6 @@ static int iommu_skip_te_disable;
 int intel_iommu_gfx_mapped;
 EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
 
-#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
 #define DEFER_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-2))
 struct device_domain_info *get_domain_info(struct device *dev)
 {
@@ -374,8 +373,7 @@ struct device_domain_info *get_domain_info(struct device *dev)
                return NULL;
 
        info = dev_iommu_priv_get(dev);
-       if (unlikely(info == DUMMY_DEVICE_DOMAIN_INFO ||
-                    info == DEFER_DEVICE_DOMAIN_INFO))
+       if (unlikely(info == DEFER_DEVICE_DOMAIN_INFO))
                return NULL;
 
        return info;
@@ -742,11 +740,6 @@ struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
        return &context[devfn];
 }
 
-static int iommu_dummy(struct device *dev)
-{
-       return dev_iommu_priv_get(dev) == DUMMY_DEVICE_DOMAIN_INFO;
-}
-
 static bool attach_deferred(struct device *dev)
 {
        return dev_iommu_priv_get(dev) == DEFER_DEVICE_DOMAIN_INFO;
@@ -779,6 +772,53 @@ is_downstream_to_pci_bridge(struct device *dev, struct device *bridge)
        return false;
 }
 
+static bool quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
+{
+       struct dmar_drhd_unit *drhd;
+       u32 vtbar;
+       int rc;
+
+       /* We know that this device on this chipset has its own IOMMU.
+        * If we find it under a different IOMMU, then the BIOS is lying
+        * to us. Hope that the IOMMU for this device is actually
+        * disabled, and it needs no translation...
+        */
+       rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
+       if (rc) {
+               /* "can't" happen */
+               dev_info(&pdev->dev, "failed to run vt-d quirk\n");
+               return false;
+       }
+       vtbar &= 0xffff0000;
+
+       /* we know that the this iommu should be at offset 0xa000 from vtbar */
+       drhd = dmar_find_matched_drhd_unit(pdev);
+       if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
+               pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
+               add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
+               return true;
+       }
+
+       return false;
+}
+
+static bool iommu_is_dummy(struct intel_iommu *iommu, struct device *dev)
+{
+       if (!iommu || iommu->drhd->ignored)
+               return true;
+
+       if (dev_is_pci(dev)) {
+               struct pci_dev *pdev = to_pci_dev(dev);
+
+               if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+                   pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SNB &&
+                   quirk_ioat_snb_local_iommu(pdev))
+                       return true;
+       }
+
+       return false;
+}
+
 struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
 {
        struct dmar_drhd_unit *drhd = NULL;
@@ -788,7 +828,7 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
        u16 segment = 0;
        int i;
 
-       if (!dev || iommu_dummy(dev))
+       if (!dev)
                return NULL;
 
        if (dev_is_pci(dev)) {
@@ -805,7 +845,7 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
                dev = &ACPI_COMPANION(dev)->dev;
 
        rcu_read_lock();
-       for_each_active_iommu(iommu, drhd) {
+       for_each_iommu(iommu, drhd) {
                if (pdev && segment != drhd->segment)
                        continue;
 
@@ -841,6 +881,9 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
        }
        iommu = NULL;
  out:
+       if (iommu_is_dummy(iommu, dev))
+               iommu = NULL;
+
        rcu_read_unlock();
 
        return iommu;
@@ -2447,7 +2490,7 @@ struct dmar_domain *find_domain(struct device *dev)
 {
        struct device_domain_info *info;
 
-       if (unlikely(attach_deferred(dev) || iommu_dummy(dev)))
+       if (unlikely(attach_deferred(dev)))
                return NULL;
 
        /* No lock here, assumes no domain exit in normal case */
@@ -2484,7 +2527,7 @@ dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
 static int domain_setup_first_level(struct intel_iommu *iommu,
                                    struct dmar_domain *domain,
                                    struct device *dev,
-                                   int pasid)
+                                   u32 pasid)
 {
        int flags = PASID_FLAG_SUPERVISOR_MODE;
        struct dma_pte *pgd = domain->pgd;
@@ -2621,7 +2664,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
                }
 
                /* Setup the PASID entry for requests without PASID: */
-               spin_lock(&iommu->lock);
+               spin_lock_irqsave(&iommu->lock, flags);
                if (hw_pass_through && domain_type_is_si(domain))
                        ret = intel_pasid_setup_pass_through(iommu, domain,
                                        dev, PASID_RID2PASID);
@@ -2631,7 +2674,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
                else
                        ret = intel_pasid_setup_second_level(iommu, domain,
                                        dev, PASID_RID2PASID);
-               spin_unlock(&iommu->lock);
+               spin_unlock_irqrestore(&iommu->lock, flags);
                if (ret) {
                        dev_err(dev, "Setup RID2PASID failed\n");
                        dmar_remove_one_dev_info(dev);
@@ -3989,35 +4032,6 @@ static void __init iommu_exit_mempool(void)
        iova_cache_put();
 }
 
-static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
-{
-       struct dmar_drhd_unit *drhd;
-       u32 vtbar;
-       int rc;
-
-       /* We know that this device on this chipset has its own IOMMU.
-        * If we find it under a different IOMMU, then the BIOS is lying
-        * to us. Hope that the IOMMU for this device is actually
-        * disabled, and it needs no translation...
-        */
-       rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
-       if (rc) {
-               /* "can't" happen */
-               dev_info(&pdev->dev, "failed to run vt-d quirk\n");
-               return;
-       }
-       vtbar &= 0xffff0000;
-
-       /* we know that the this iommu should be at offset 0xa000 from vtbar */
-       drhd = dmar_find_matched_drhd_unit(pdev);
-       if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
-               pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
-               add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
-               dev_iommu_priv_set(&pdev->dev, DUMMY_DEVICE_DOMAIN_INFO);
-       }
-}
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
-
 static void __init init_no_remapping_devices(void)
 {
        struct dmar_drhd_unit *drhd;
@@ -4049,12 +4063,8 @@ static void __init init_no_remapping_devices(void)
                /* This IOMMU has *only* gfx devices. Either bypass it or
                   set the gfx_mapped flag, as appropriate */
                drhd->gfx_dedicated = 1;
-               if (!dmar_map_gfx) {
+               if (!dmar_map_gfx)
                        drhd->ignored = 1;
-                       for_each_active_dev_scope(drhd->devices,
-                                                 drhd->devices_cnt, i, dev)
-                               dev_iommu_priv_set(dev, DUMMY_DEVICE_DOMAIN_INFO);
-               }
        }
 }
 
@@ -5070,7 +5080,6 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
 
        switch (type) {
        case IOMMU_DOMAIN_DMA:
-       /* fallthrough */
        case IOMMU_DOMAIN_UNMANAGED:
                dmar_domain = alloc_domain(0);
                if (!dmar_domain) {
@@ -5164,7 +5173,7 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
                return -ENODEV;
 
        if (domain->default_pasid <= 0) {
-               int pasid;
+               u32 pasid;
 
                /* No private data needed for the default pasid */
                pasid = ioasid_alloc(NULL, PASID_MIN,
index 23583b0..0cfce1d 100644 (file)
@@ -204,35 +204,40 @@ static int modify_irte(struct irq_2_iommu *irq_iommu,
        return rc;
 }
 
-static struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
+static struct irq_domain *map_hpet_to_ir(u8 hpet_id)
 {
        int i;
 
-       for (i = 0; i < MAX_HPET_TBS; i++)
+       for (i = 0; i < MAX_HPET_TBS; i++) {
                if (ir_hpet[i].id == hpet_id && ir_hpet[i].iommu)
-                       return ir_hpet[i].iommu;
+                       return ir_hpet[i].iommu->ir_domain;
+       }
        return NULL;
 }
 
-static struct intel_iommu *map_ioapic_to_ir(int apic)
+static struct intel_iommu *map_ioapic_to_iommu(int apic)
 {
        int i;
 
-       for (i = 0; i < MAX_IO_APICS; i++)
+       for (i = 0; i < MAX_IO_APICS; i++) {
                if (ir_ioapic[i].id == apic && ir_ioapic[i].iommu)
                        return ir_ioapic[i].iommu;
+       }
        return NULL;
 }
 
-static struct intel_iommu *map_dev_to_ir(struct pci_dev *dev)
+static struct irq_domain *map_ioapic_to_ir(int apic)
 {
-       struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu = map_ioapic_to_iommu(apic);
 
-       drhd = dmar_find_matched_drhd_unit(dev);
-       if (!drhd)
-               return NULL;
+       return iommu ? iommu->ir_domain : NULL;
+}
 
-       return drhd->iommu;
+static struct irq_domain *map_dev_to_ir(struct pci_dev *dev)
+{
+       struct dmar_drhd_unit *drhd = dmar_find_matched_drhd_unit(dev);
+
+       return drhd ? drhd->iommu->ir_msi_domain : NULL;
 }
 
 static int clear_entries(struct irq_2_iommu *irq_iommu)
@@ -508,12 +513,18 @@ static void iommu_enable_irq_remapping(struct intel_iommu *iommu)
 
        /* Enable interrupt-remapping */
        iommu->gcmd |= DMA_GCMD_IRE;
-       iommu->gcmd &= ~DMA_GCMD_CFI;  /* Block compatibility-format MSIs */
        writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
-
        IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
                      readl, (sts & DMA_GSTS_IRES), sts);
 
+       /* Block compatibility-format MSIs */
+       if (sts & DMA_GSTS_CFIS) {
+               iommu->gcmd &= ~DMA_GCMD_CFI;
+               writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
+               IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+                             readl, !(sts & DMA_GSTS_CFIS), sts);
+       }
+
        /*
         * With CFI clear in the Global Command register, we should be
         * protected from dangerous (i.e. compatibility) interrupts
@@ -996,7 +1007,7 @@ static int __init parse_ioapics_under_ir(void)
 
        for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) {
                int ioapic_id = mpc_ioapic_id(ioapic_idx);
-               if (!map_ioapic_to_ir(ioapic_id)) {
+               if (!map_ioapic_to_iommu(ioapic_id)) {
                        pr_err(FW_BUG "ioapic %d has no mapping iommu, "
                               "interrupt remapping will be disabled\n",
                               ioapic_id);
@@ -1081,6 +1092,22 @@ error:
        return -1;
 }
 
+/*
+ * Store the MSI remapping domain pointer in the device if enabled.
+ *
+ * This is called from dmar_pci_bus_add_dev() so it works even when DMA
+ * remapping is disabled. Only update the pointer if the device is not
+ * already handled by a non default PCI/MSI interrupt domain. This protects
+ * e.g. VMD devices.
+ */
+void intel_irq_remap_add_device(struct dmar_pci_notify_info *info)
+{
+       if (!irq_remapping_enabled || pci_dev_has_special_msi_domain(info->dev))
+               return;
+
+       dev_set_msi_domain(&info->dev->dev, map_dev_to_ir(info->dev));
+}
+
 static void prepare_irte(struct irte *irte, int vector, unsigned int dest)
 {
        memset(irte, 0, sizeof(*irte));
@@ -1101,51 +1128,20 @@ static void prepare_irte(struct irte *irte, int vector, unsigned int dest)
        irte->redir_hint = 1;
 }
 
-static struct irq_domain *intel_get_ir_irq_domain(struct irq_alloc_info *info)
-{
-       struct intel_iommu *iommu = NULL;
-
-       if (!info)
-               return NULL;
-
-       switch (info->type) {
-       case X86_IRQ_ALLOC_TYPE_IOAPIC:
-               iommu = map_ioapic_to_ir(info->ioapic_id);
-               break;
-       case X86_IRQ_ALLOC_TYPE_HPET:
-               iommu = map_hpet_to_ir(info->hpet_id);
-               break;
-       case X86_IRQ_ALLOC_TYPE_MSI:
-       case X86_IRQ_ALLOC_TYPE_MSIX:
-               iommu = map_dev_to_ir(info->msi_dev);
-               break;
-       default:
-               BUG_ON(1);
-               break;
-       }
-
-       return iommu ? iommu->ir_domain : NULL;
-}
-
 static struct irq_domain *intel_get_irq_domain(struct irq_alloc_info *info)
 {
-       struct intel_iommu *iommu;
-
        if (!info)
                return NULL;
 
        switch (info->type) {
-       case X86_IRQ_ALLOC_TYPE_MSI:
-       case X86_IRQ_ALLOC_TYPE_MSIX:
-               iommu = map_dev_to_ir(info->msi_dev);
-               if (iommu)
-                       return iommu->ir_msi_domain;
-               break;
+       case X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT:
+               return map_ioapic_to_ir(info->devid);
+       case X86_IRQ_ALLOC_TYPE_HPET_GET_PARENT:
+               return map_hpet_to_ir(info->devid);
        default:
-               break;
+               WARN_ON_ONCE(1);
+               return NULL;
        }
-
-       return NULL;
 }
 
 struct irq_remap_ops intel_irq_remap_ops = {
@@ -1154,7 +1150,6 @@ struct irq_remap_ops intel_irq_remap_ops = {
        .disable                = disable_irq_remapping,
        .reenable               = reenable_irq_remapping,
        .enable_faulting        = enable_drhd_fault_handling,
-       .get_ir_irq_domain      = intel_get_ir_irq_domain,
        .get_irq_domain         = intel_get_irq_domain,
 };
 
@@ -1278,16 +1273,16 @@ static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data,
        switch (info->type) {
        case X86_IRQ_ALLOC_TYPE_IOAPIC:
                /* Set source-id of interrupt request */
-               set_ioapic_sid(irte, info->ioapic_id);
+               set_ioapic_sid(irte, info->devid);
                apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: Set IRTE entry (P:%d FPD:%d Dst_Mode:%d Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X Avail:%X Vector:%02X Dest:%08X SID:%04X SQ:%X SVT:%X)\n",
-                       info->ioapic_id, irte->present, irte->fpd,
+                       info->devid, irte->present, irte->fpd,
                        irte->dst_mode, irte->redir_hint,
                        irte->trigger_mode, irte->dlvry_mode,
                        irte->avail, irte->vector, irte->dest_id,
                        irte->sid, irte->sq, irte->svt);
 
-               entry = (struct IR_IO_APIC_route_entry *)info->ioapic_entry;
-               info->ioapic_entry = NULL;
+               entry = (struct IR_IO_APIC_route_entry *)info->ioapic.entry;
+               info->ioapic.entry = NULL;
                memset(entry, 0, sizeof(*entry));
                entry->index2   = (index >> 15) & 0x1;
                entry->zero     = 0;
@@ -1297,21 +1292,21 @@ static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data,
                 * IO-APIC RTE will be configured with virtual vector.
                 * irq handler will do the explicit EOI to the io-apic.
                 */
-               entry->vector   = info->ioapic_pin;
+               entry->vector   = info->ioapic.pin;
                entry->mask     = 0;                    /* enable IRQ */
-               entry->trigger  = info->ioapic_trigger;
-               entry->polarity = info->ioapic_polarity;
-               if (info->ioapic_trigger)
+               entry->trigger  = info->ioapic.trigger;
+               entry->polarity = info->ioapic.polarity;
+               if (info->ioapic.trigger)
                        entry->mask = 1; /* Mask level triggered irqs. */
                break;
 
        case X86_IRQ_ALLOC_TYPE_HPET:
-       case X86_IRQ_ALLOC_TYPE_MSI:
-       case X86_IRQ_ALLOC_TYPE_MSIX:
+       case X86_IRQ_ALLOC_TYPE_PCI_MSI:
+       case X86_IRQ_ALLOC_TYPE_PCI_MSIX:
                if (info->type == X86_IRQ_ALLOC_TYPE_HPET)
-                       set_hpet_sid(irte, info->hpet_id);
+                       set_hpet_sid(irte, info->devid);
                else
-                       set_msi_sid(irte, info->msi_dev);
+                       set_msi_sid(irte, msi_desc_to_pci_dev(info->desc));
 
                msg->address_hi = MSI_ADDR_BASE_HI;
                msg->data = sub_handle;
@@ -1362,15 +1357,15 @@ static int intel_irq_remapping_alloc(struct irq_domain *domain,
 
        if (!info || !iommu)
                return -EINVAL;
-       if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_MSI &&
-           info->type != X86_IRQ_ALLOC_TYPE_MSIX)
+       if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_PCI_MSI &&
+           info->type != X86_IRQ_ALLOC_TYPE_PCI_MSIX)
                return -EINVAL;
 
        /*
         * With IRQ remapping enabled, don't need contiguous CPU vectors
         * to support multiple MSI interrupts.
         */
-       if (info->type == X86_IRQ_ALLOC_TYPE_MSI)
+       if (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI)
                info->flags &= ~X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
 
        ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
index e6faedf..b92af83 100644 (file)
@@ -27,7 +27,7 @@
 static DEFINE_SPINLOCK(pasid_lock);
 u32 intel_pasid_max_id = PASID_MAX;
 
-int vcmd_alloc_pasid(struct intel_iommu *iommu, unsigned int *pasid)
+int vcmd_alloc_pasid(struct intel_iommu *iommu, u32 *pasid)
 {
        unsigned long flags;
        u8 status_code;
@@ -58,7 +58,7 @@ int vcmd_alloc_pasid(struct intel_iommu *iommu, unsigned int *pasid)
        return ret;
 }
 
-void vcmd_free_pasid(struct intel_iommu *iommu, unsigned int pasid)
+void vcmd_free_pasid(struct intel_iommu *iommu, u32 pasid)
 {
        unsigned long flags;
        u8 status_code;
@@ -146,7 +146,7 @@ int intel_pasid_alloc_table(struct device *dev)
        struct pasid_table *pasid_table;
        struct pasid_table_opaque data;
        struct page *pages;
-       int max_pasid = 0;
+       u32 max_pasid = 0;
        int ret, order;
        int size;
 
@@ -168,7 +168,7 @@ int intel_pasid_alloc_table(struct device *dev)
        INIT_LIST_HEAD(&pasid_table->dev);
 
        if (info->pasid_supported)
-               max_pasid = min_t(int, pci_max_pasids(to_pci_dev(dev)),
+               max_pasid = min_t(u32, pci_max_pasids(to_pci_dev(dev)),
                                  intel_pasid_max_id);
 
        size = max_pasid >> (PASID_PDE_SHIFT - 3);
@@ -242,7 +242,7 @@ int intel_pasid_get_dev_max_id(struct device *dev)
        return info->pasid_table->max_pasid;
 }
 
-struct pasid_entry *intel_pasid_get_entry(struct device *dev, int pasid)
+struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid)
 {
        struct device_domain_info *info;
        struct pasid_table *pasid_table;
@@ -251,8 +251,7 @@ struct pasid_entry *intel_pasid_get_entry(struct device *dev, int pasid)
        int dir_index, index;
 
        pasid_table = intel_pasid_get_table(dev);
-       if (WARN_ON(!pasid_table || pasid < 0 ||
-                   pasid >= intel_pasid_get_dev_max_id(dev)))
+       if (WARN_ON(!pasid_table || pasid >= intel_pasid_get_dev_max_id(dev)))
                return NULL;
 
        dir = pasid_table->table;
@@ -305,7 +304,7 @@ static inline void pasid_clear_entry_with_fpd(struct pasid_entry *pe)
 }
 
 static void
-intel_pasid_clear_entry(struct device *dev, int pasid, bool fault_ignore)
+intel_pasid_clear_entry(struct device *dev, u32 pasid, bool fault_ignore)
 {
        struct pasid_entry *pe;
 
@@ -444,7 +443,7 @@ pasid_set_eafe(struct pasid_entry *pe)
 
 static void
 pasid_cache_invalidation_with_pasid(struct intel_iommu *iommu,
-                                   u16 did, int pasid)
+                                   u16 did, u32 pasid)
 {
        struct qi_desc desc;
 
@@ -473,7 +472,7 @@ iotlb_invalidation_with_pasid(struct intel_iommu *iommu, u16 did, u32 pasid)
 
 static void
 devtlb_invalidation_with_pasid(struct intel_iommu *iommu,
-                              struct device *dev, int pasid)
+                              struct device *dev, u32 pasid)
 {
        struct device_domain_info *info;
        u16 sid, qdep, pfsid;
@@ -499,7 +498,7 @@ devtlb_invalidation_with_pasid(struct intel_iommu *iommu,
 }
 
 void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
-                                int pasid, bool fault_ignore)
+                                u32 pasid, bool fault_ignore)
 {
        struct pasid_entry *pte;
        u16 did;
@@ -524,7 +523,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
 
 static void pasid_flush_caches(struct intel_iommu *iommu,
                                struct pasid_entry *pte,
-                               int pasid, u16 did)
+                              u32 pasid, u16 did)
 {
        if (!ecap_coherent(iommu->ecap))
                clflush_cache_range(pte, sizeof(*pte));
@@ -543,7 +542,7 @@ static void pasid_flush_caches(struct intel_iommu *iommu,
  */
 int intel_pasid_setup_first_level(struct intel_iommu *iommu,
                                  struct device *dev, pgd_t *pgd,
-                                 int pasid, u16 did, int flags)
+                                 u32 pasid, u16 did, int flags)
 {
        struct pasid_entry *pte;
 
@@ -616,7 +615,7 @@ static inline int iommu_skip_agaw(struct dmar_domain *domain,
  */
 int intel_pasid_setup_second_level(struct intel_iommu *iommu,
                                   struct dmar_domain *domain,
-                                  struct device *dev, int pasid)
+                                  struct device *dev, u32 pasid)
 {
        struct pasid_entry *pte;
        struct dma_pte *pgd;
@@ -674,7 +673,7 @@ int intel_pasid_setup_second_level(struct intel_iommu *iommu,
  */
 int intel_pasid_setup_pass_through(struct intel_iommu *iommu,
                                   struct dmar_domain *domain,
-                                  struct device *dev, int pasid)
+                                  struct device *dev, u32 pasid)
 {
        u16 did = FLPT_DEFAULT_DID;
        struct pasid_entry *pte;
@@ -760,7 +759,7 @@ intel_pasid_setup_bind_data(struct intel_iommu *iommu, struct pasid_entry *pte,
  * @addr_width: Address width of the first level (guest)
  */
 int intel_pasid_setup_nested(struct intel_iommu *iommu, struct device *dev,
-                            pgd_t *gpgd, int pasid,
+                            pgd_t *gpgd, u32 pasid,
                             struct iommu_gpasid_bind_data_vtd *pasid_data,
                             struct dmar_domain *domain, int addr_width)
 {
index c985076..97dfcff 100644 (file)
@@ -72,7 +72,7 @@ struct pasid_entry {
 struct pasid_table {
        void                    *table;         /* pasid table pointer */
        int                     order;          /* page order of pasid table */
-       int                     max_pasid;      /* max pasid */
+       u32                     max_pasid;      /* max pasid */
        struct list_head        dev;            /* device list */
 };
 
@@ -98,31 +98,31 @@ static inline bool pasid_pte_is_present(struct pasid_entry *pte)
        return READ_ONCE(pte->val[0]) & PASID_PTE_PRESENT;
 }
 
-extern u32 intel_pasid_max_id;
+extern unsigned int intel_pasid_max_id;
 int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp);
-void intel_pasid_free_id(int pasid);
-void *intel_pasid_lookup_id(int pasid);
+void intel_pasid_free_id(u32 pasid);
+void *intel_pasid_lookup_id(u32 pasid);
 int intel_pasid_alloc_table(struct device *dev);
 void intel_pasid_free_table(struct device *dev);
 struct pasid_table *intel_pasid_get_table(struct device *dev);
 int intel_pasid_get_dev_max_id(struct device *dev);
-struct pasid_entry *intel_pasid_get_entry(struct device *dev, int pasid);
+struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid);
 int intel_pasid_setup_first_level(struct intel_iommu *iommu,
                                  struct device *dev, pgd_t *pgd,
-                                 int pasid, u16 did, int flags);
+                                 u32 pasid, u16 did, int flags);
 int intel_pasid_setup_second_level(struct intel_iommu *iommu,
                                   struct dmar_domain *domain,
-                                  struct device *dev, int pasid);
+                                  struct device *dev, u32 pasid);
 int intel_pasid_setup_pass_through(struct intel_iommu *iommu,
                                   struct dmar_domain *domain,
-                                  struct device *dev, int pasid);
+                                  struct device *dev, u32 pasid);
 int intel_pasid_setup_nested(struct intel_iommu *iommu,
-                            struct device *dev, pgd_t *pgd, int pasid,
+                            struct device *dev, pgd_t *pgd, u32 pasid,
                             struct iommu_gpasid_bind_data_vtd *pasid_data,
                             struct dmar_domain *domain, int addr_width);
 void intel_pasid_tear_down_entry(struct intel_iommu *iommu,
-                                struct device *dev, int pasid,
+                                struct device *dev, u32 pasid,
                                 bool fault_ignore);
-int vcmd_alloc_pasid(struct intel_iommu *iommu, unsigned int *pasid);
-void vcmd_free_pasid(struct intel_iommu *iommu, unsigned int pasid);
+int vcmd_alloc_pasid(struct intel_iommu *iommu, u32 *pasid);
+void vcmd_free_pasid(struct intel_iommu *iommu, u32 pasid);
 #endif /* __INTEL_PASID_H */
index 95c3164..60ffe08 100644 (file)
 #include <linux/mm_types.h>
 #include <linux/ioasid.h>
 #include <asm/page.h>
+#include <asm/fpu/api.h>
 
 #include "pasid.h"
 
 static irqreturn_t prq_event_thread(int irq, void *d);
-static void intel_svm_drain_prq(struct device *dev, int pasid);
+static void intel_svm_drain_prq(struct device *dev, u32 pasid);
 
 #define PRQ_ORDER 0
 
@@ -399,7 +400,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
        return ret;
 }
 
-int intel_svm_unbind_gpasid(struct device *dev, int pasid)
+int intel_svm_unbind_gpasid(struct device *dev, u32 pasid)
 {
        struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
        struct intel_svm_dev *sdev;
@@ -444,9 +445,28 @@ out:
        return ret;
 }
 
+static void _load_pasid(void *unused)
+{
+       update_pasid();
+}
+
+static void load_pasid(struct mm_struct *mm, u32 pasid)
+{
+       mutex_lock(&mm->context.lock);
+
+       /* Synchronize with READ_ONCE in update_pasid(). */
+       smp_store_release(&mm->pasid, pasid);
+
+       /* Update PASID MSR on all CPUs running the mm's tasks. */
+       on_each_cpu_mask(mm_cpumask(mm), _load_pasid, NULL, true);
+
+       mutex_unlock(&mm->context.lock);
+}
+
 /* Caller must hold pasid_mutex, mm reference */
 static int
-intel_svm_bind_mm(struct device *dev, int flags, struct svm_dev_ops *ops,
+intel_svm_bind_mm(struct device *dev, unsigned int flags,
+                 struct svm_dev_ops *ops,
                  struct mm_struct *mm, struct intel_svm_dev **sd)
 {
        struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
@@ -590,6 +610,10 @@ intel_svm_bind_mm(struct device *dev, int flags, struct svm_dev_ops *ops,
                }
 
                list_add_tail(&svm->list, &global_svm_list);
+               if (mm) {
+                       /* The newly allocated pasid is loaded to the mm. */
+                       load_pasid(mm, svm->pasid);
+               }
        } else {
                /*
                 * Binding a new device with existing PASID, need to setup
@@ -620,7 +644,7 @@ out:
 }
 
 /* Caller must hold pasid_mutex */
-static int intel_svm_unbind_mm(struct device *dev, int pasid)
+static int intel_svm_unbind_mm(struct device *dev, u32 pasid)
 {
        struct intel_svm_dev *sdev;
        struct intel_iommu *iommu;
@@ -653,8 +677,11 @@ static int intel_svm_unbind_mm(struct device *dev, int pasid)
 
                        if (list_empty(&svm->devs)) {
                                ioasid_free(svm->pasid);
-                               if (svm->mm)
+                               if (svm->mm) {
                                        mmu_notifier_unregister(&svm->notifier, svm->mm);
+                                       /* Clear mm's pasid. */
+                                       load_pasid(svm->mm, PASID_DISABLED);
+                               }
                                list_del(&svm->list);
                                /* We mandate that no page faults may be outstanding
                                 * for the PASID when intel_svm_unbind_mm() is called.
@@ -739,7 +766,7 @@ static bool is_canonical_address(u64 addr)
  * described in VT-d spec CH7.10 to drain all page requests and page
  * responses pending in the hardware.
  */
-static void intel_svm_drain_prq(struct device *dev, int pasid)
+static void intel_svm_drain_prq(struct device *dev, u32 pasid)
 {
        struct device_domain_info *info;
        struct dmar_domain *domain;
@@ -1033,7 +1060,7 @@ intel_svm_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
 {
        struct iommu_sva *sva = ERR_PTR(-EINVAL);
        struct intel_svm_dev *sdev = NULL;
-       int flags = 0;
+       unsigned int flags = 0;
        int ret;
 
        /*
@@ -1042,7 +1069,7 @@ intel_svm_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
         * and intel_svm etc.
         */
        if (drvdata)
-               flags = *(int *)drvdata;
+               flags = *(unsigned int *)drvdata;
        mutex_lock(&pasid_mutex);
        ret = intel_svm_bind_mm(dev, flags, NULL, mm, &sdev);
        if (ret)
@@ -1067,10 +1094,10 @@ void intel_svm_unbind(struct iommu_sva *sva)
        mutex_unlock(&pasid_mutex);
 }
 
-int intel_svm_get_pasid(struct iommu_sva *sva)
+u32 intel_svm_get_pasid(struct iommu_sva *sva)
 {
        struct intel_svm_dev *sdev;
-       int pasid;
+       u32 pasid;
 
        mutex_lock(&pasid_mutex);
        sdev = to_intel_svm_dev(sva);
index 609bd25..0e4fbdc 100644 (file)
@@ -2839,7 +2839,7 @@ void iommu_sva_unbind_device(struct iommu_sva *handle)
 }
 EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
 
-int iommu_sva_get_pasid(struct iommu_sva *handle)
+u32 iommu_sva_get_pasid(struct iommu_sva *handle)
 {
        const struct iommu_ops *ops = handle->dev->bus->iommu_ops;
 
index 83f36f6..2d84b1e 100644 (file)
@@ -160,33 +160,12 @@ void panic_if_irq_remap(const char *msg)
 }
 
 /**
- * irq_remapping_get_ir_irq_domain - Get the irqdomain associated with the IOMMU
- *                                  device serving request @info
- * @info: interrupt allocation information, used to identify the IOMMU device
- *
- * It's used to get parent irqdomain for HPET and IOAPIC irqdomains.
- * Returns pointer to IRQ domain, or NULL on failure.
- */
-struct irq_domain *
-irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info)
-{
-       if (!remap_ops || !remap_ops->get_ir_irq_domain)
-               return NULL;
-
-       return remap_ops->get_ir_irq_domain(info);
-}
-
-/**
  * irq_remapping_get_irq_domain - Get the irqdomain serving the request @info
  * @info: interrupt allocation information, used to identify the IOMMU device
  *
- * There will be one PCI MSI/MSIX irqdomain associated with each interrupt
- * remapping device, so this interface is used to retrieve the PCI MSI/MSIX
- * irqdomain serving request @info.
  * Returns pointer to IRQ domain, or NULL on failure.
  */
-struct irq_domain *
-irq_remapping_get_irq_domain(struct irq_alloc_info *info)
+struct irq_domain *irq_remapping_get_irq_domain(struct irq_alloc_info *info)
 {
        if (!remap_ops || !remap_ops->get_irq_domain)
                return NULL;
index 6a190d5..1661b3d 100644 (file)
@@ -43,10 +43,7 @@ struct irq_remap_ops {
        /* Enable fault handling */
        int  (*enable_faulting)(void);
 
-       /* Get the irqdomain associated the IOMMU device */
-       struct irq_domain *(*get_ir_irq_domain)(struct irq_alloc_info *);
-
-       /* Get the MSI irqdomain associated with the IOMMU device */
+       /* Get the irqdomain associated to IOMMU device */
        struct irq_domain *(*get_irq_domain)(struct irq_alloc_info *);
 };
 
index b4da396..2bfdd57 100644 (file)
@@ -440,7 +440,7 @@ static int viommu_add_resv_mem(struct viommu_endpoint *vdev,
        default:
                dev_warn(vdev->dev, "unknown resv mem subtype 0x%x\n",
                         mem->subtype);
-               /* Fall-through */
+               fallthrough;
        case VIRTIO_IOMMU_RESV_MEM_T_RESERVED:
                region = iommu_alloc_resv_region(start, size, 0,
                                                 IOMMU_RESV_RESERVED);
index bb70b71..570a770 100644 (file)
@@ -148,7 +148,7 @@ config DAVINCI_CP_INTC
 config DW_APB_ICTL
        bool
        select GENERIC_IRQ_CHIP
-       select IRQ_DOMAIN
+       select IRQ_DOMAIN_HIERARCHY
 
 config FARADAY_FTINTC010
        bool
@@ -232,12 +232,12 @@ config RENESAS_INTC_IRQPIN
          interrupt pins, as found on SH/R-Mobile and R-Car Gen1 SoCs.
 
 config RENESAS_IRQC
-       bool "Renesas R-Mobile APE6 and R-Car IRQC support" if COMPILE_TEST
+       bool "Renesas R-Mobile APE6, R-Car Gen{2,3} and RZ/G{1,2} IRQC support" if COMPILE_TEST
        select GENERIC_IRQ_CHIP
        select IRQ_DOMAIN
        help
          Enable support for the Renesas Interrupt Controller for external
-         devices, as found on R-Mobile APE6, R-Car Gen2, and R-Car Gen3 SoCs.
+         devices, as found on R-Mobile APE6, R-Car Gen{2,3} and RZ/G{1,2} SoCs.
 
 config RENESAS_RZA1_IRQC
        bool "Renesas RZ/A1 IRQC support" if COMPILE_TEST
@@ -425,7 +425,7 @@ config GOLDFISH_PIC
          for Goldfish based virtual platforms.
 
 config QCOM_PDC
-       tristate "QCOM PDC"
+       bool "QCOM PDC"
        depends on ARCH_QCOM
        select IRQ_DOMAIN_HIERARCHY
        help
@@ -493,6 +493,16 @@ config TI_SCI_INTA_IRQCHIP
          If you wish to use interrupt aggregator irq resources managed by the
          TI System Controller, say Y here. Otherwise, say N.
 
+config TI_PRUSS_INTC
+       tristate "TI PRU-ICSS Interrupt Controller"
+       depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3
+       select IRQ_DOMAIN
+       help
+         This enables support for the PRU-ICSS Local Interrupt Controller
+         present within a PRU-ICSS subsystem present on various TI SoCs.
+         The PRUSS INTC enables various interrupts to be routed to multiple
+         different processors within the SoC.
+
 config RISCV_INTC
        bool "RISC-V Local Interrupt Controller"
        depends on RISCV
@@ -571,4 +581,12 @@ config LOONGSON_PCH_MSI
        help
          Support for the Loongson PCH MSI Controller.
 
+config MST_IRQ
+       bool "MStar Interrupt Controller"
+       default ARCH_MEDIATEK
+       select IRQ_DOMAIN
+       select IRQ_DOMAIN_HIERARCHY
+       help
+         Support MStar Interrupt Controller.
+
 endmenu
index 133f9c4..f152514 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_ATH79)                     += irq-ath79-cpu.o
 obj-$(CONFIG_ATH79)                    += irq-ath79-misc.o
 obj-$(CONFIG_ARCH_BCM2835)             += irq-bcm2835.o
 obj-$(CONFIG_ARCH_BCM2835)             += irq-bcm2836.o
+obj-$(CONFIG_ARCH_ACTIONS)             += irq-owl-sirq.o
 obj-$(CONFIG_DAVINCI_AINTC)            += irq-davinci-aintc.o
 obj-$(CONFIG_DAVINCI_CP_INTC)          += irq-davinci-cp-intc.o
 obj-$(CONFIG_EXYNOS_IRQ_COMBINER)      += exynos-combiner.o
@@ -106,8 +107,10 @@ obj-$(CONFIG_MADERA_IRQ)           += irq-madera.o
 obj-$(CONFIG_LS1X_IRQ)                 += irq-ls1x.o
 obj-$(CONFIG_TI_SCI_INTR_IRQCHIP)      += irq-ti-sci-intr.o
 obj-$(CONFIG_TI_SCI_INTA_IRQCHIP)      += irq-ti-sci-inta.o
+obj-$(CONFIG_TI_PRUSS_INTC)            += irq-pruss-intc.o
 obj-$(CONFIG_LOONGSON_LIOINTC)         += irq-loongson-liointc.o
 obj-$(CONFIG_LOONGSON_HTPIC)           += irq-loongson-htpic.o
 obj-$(CONFIG_LOONGSON_HTVEC)           += irq-loongson-htvec.o
 obj-$(CONFIG_LOONGSON_PCH_PIC)         += irq-loongson-pch-pic.o
 obj-$(CONFIG_LOONGSON_PCH_MSI)         += irq-loongson-pch-msi.o
+obj-$(CONFIG_MST_IRQ)                  += irq-mst-intc.o
index c9bdc52..d7eb2e9 100644 (file)
@@ -310,7 +310,134 @@ static inline int armada_370_xp_msi_init(struct device_node *node,
 }
 #endif
 
+static void armada_xp_mpic_perf_init(void)
+{
+       unsigned long cpuid = cpu_logical_map(smp_processor_id());
+
+       /* Enable Performance Counter Overflow interrupts */
+       writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid),
+              per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS);
+}
+
 #ifdef CONFIG_SMP
+static struct irq_domain *ipi_domain;
+
+static void armada_370_xp_ipi_mask(struct irq_data *d)
+{
+       u32 reg;
+       reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
+       reg &= ~BIT(d->hwirq);
+       writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
+}
+
+static void armada_370_xp_ipi_unmask(struct irq_data *d)
+{
+       u32 reg;
+       reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
+       reg |= BIT(d->hwirq);
+       writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
+}
+
+static void armada_370_xp_ipi_send_mask(struct irq_data *d,
+                                       const struct cpumask *mask)
+{
+       unsigned long map = 0;
+       int cpu;
+
+       /* Convert our logical CPU mask into a physical one. */
+       for_each_cpu(cpu, mask)
+               map |= 1 << cpu_logical_map(cpu);
+
+       /*
+        * Ensure that stores to Normal memory are visible to the
+        * other CPUs before issuing the IPI.
+        */
+       dsb();
+
+       /* submit softirq */
+       writel((map << 8) | d->hwirq, main_int_base +
+               ARMADA_370_XP_SW_TRIG_INT_OFFS);
+}
+
+static void armada_370_xp_ipi_eoi(struct irq_data *d)
+{
+       writel(~BIT(d->hwirq), per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
+}
+
+static struct irq_chip ipi_irqchip = {
+       .name           = "IPI",
+       .irq_mask       = armada_370_xp_ipi_mask,
+       .irq_unmask     = armada_370_xp_ipi_unmask,
+       .irq_eoi        = armada_370_xp_ipi_eoi,
+       .ipi_send_mask  = armada_370_xp_ipi_send_mask,
+};
+
+static int armada_370_xp_ipi_alloc(struct irq_domain *d,
+                                        unsigned int virq,
+                                        unsigned int nr_irqs, void *args)
+{
+       int i;
+
+       for (i = 0; i < nr_irqs; i++) {
+               irq_set_percpu_devid(virq + i);
+               irq_domain_set_info(d, virq + i, i, &ipi_irqchip,
+                                   d->host_data,
+                                   handle_percpu_devid_fasteoi_ipi,
+                                   NULL, NULL);
+       }
+
+       return 0;
+}
+
+static void armada_370_xp_ipi_free(struct irq_domain *d,
+                                        unsigned int virq,
+                                        unsigned int nr_irqs)
+{
+       /* Not freeing IPIs */
+}
+
+static const struct irq_domain_ops ipi_domain_ops = {
+       .alloc  = armada_370_xp_ipi_alloc,
+       .free   = armada_370_xp_ipi_free,
+};
+
+static void ipi_resume(void)
+{
+       int i;
+
+       for (i = 0; i < IPI_DOORBELL_END; i++) {
+               int irq;
+
+               irq = irq_find_mapping(ipi_domain, i);
+               if (irq <= 0)
+                       continue;
+               if (irq_percpu_is_enabled(irq)) {
+                       struct irq_data *d;
+                       d = irq_domain_get_irq_data(ipi_domain, irq);
+                       armada_370_xp_ipi_unmask(d);
+               }
+       }
+}
+
+static __init void armada_xp_ipi_init(struct device_node *node)
+{
+       int base_ipi;
+
+       ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node),
+                                             IPI_DOORBELL_END,
+                                             &ipi_domain_ops, NULL);
+       if (WARN_ON(!ipi_domain))
+               return;
+
+       irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI);
+       base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, IPI_DOORBELL_END,
+                                          NUMA_NO_NODE, NULL, false, NULL);
+       if (WARN_ON(!base_ipi))
+               return;
+
+       set_smp_ipi_range(base_ipi, IPI_DOORBELL_END);
+}
+
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 
 static int armada_xp_set_affinity(struct irq_data *d,
@@ -334,43 +461,6 @@ static int armada_xp_set_affinity(struct irq_data *d,
 
        return IRQ_SET_MASK_OK;
 }
-#endif
-
-static struct irq_chip armada_370_xp_irq_chip = {
-       .name           = "MPIC",
-       .irq_mask       = armada_370_xp_irq_mask,
-       .irq_mask_ack   = armada_370_xp_irq_mask,
-       .irq_unmask     = armada_370_xp_irq_unmask,
-#ifdef CONFIG_SMP
-       .irq_set_affinity = armada_xp_set_affinity,
-#endif
-       .flags          = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
-};
-
-static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
-                                     unsigned int virq, irq_hw_number_t hw)
-{
-       armada_370_xp_irq_mask(irq_get_irq_data(virq));
-       if (!is_percpu_irq(hw))
-               writel(hw, per_cpu_int_base +
-                       ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
-       else
-               writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
-       irq_set_status_flags(virq, IRQ_LEVEL);
-
-       if (is_percpu_irq(hw)) {
-               irq_set_percpu_devid(virq);
-               irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
-                                       handle_percpu_devid_irq);
-       } else {
-               irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
-                                       handle_level_irq);
-               irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq)));
-       }
-       irq_set_probe(virq);
-
-       return 0;
-}
 
 static void armada_xp_mpic_smp_cpu_init(void)
 {
@@ -383,48 +473,16 @@ static void armada_xp_mpic_smp_cpu_init(void)
        for (i = 0; i < nr_irqs; i++)
                writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
 
+       /* Disable all IPIs */
+       writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
+
        /* Clear pending IPIs */
        writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
 
-       /* Enable first 8 IPIs */
-       writel(IPI_DOORBELL_MASK, per_cpu_int_base +
-               ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
-
        /* Unmask IPI interrupt */
        writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 }
 
-static void armada_xp_mpic_perf_init(void)
-{
-       unsigned long cpuid = cpu_logical_map(smp_processor_id());
-
-       /* Enable Performance Counter Overflow interrupts */
-       writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid),
-              per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS);
-}
-
-#ifdef CONFIG_SMP
-static void armada_mpic_send_doorbell(const struct cpumask *mask,
-                                     unsigned int irq)
-{
-       int cpu;
-       unsigned long map = 0;
-
-       /* Convert our logical CPU mask into a physical one. */
-       for_each_cpu(cpu, mask)
-               map |= 1 << cpu_logical_map(cpu);
-
-       /*
-        * Ensure that stores to Normal memory are visible to the
-        * other CPUs before issuing the IPI.
-        */
-       dsb();
-
-       /* submit softirq */
-       writel((map << 8) | irq, main_int_base +
-               ARMADA_370_XP_SW_TRIG_INT_OFFS);
-}
-
 static void armada_xp_mpic_reenable_percpu(void)
 {
        unsigned int irq;
@@ -445,6 +503,8 @@ static void armada_xp_mpic_reenable_percpu(void)
 
                armada_370_xp_irq_unmask(data);
        }
+
+       ipi_resume();
 }
 
 static int armada_xp_mpic_starting_cpu(unsigned int cpu)
@@ -462,7 +522,46 @@ static int mpic_cascaded_starting_cpu(unsigned int cpu)
        enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
        return 0;
 }
+#else
+static void armada_xp_mpic_smp_cpu_init(void) {}
+static void ipi_resume(void) {}
+#endif
+
+static struct irq_chip armada_370_xp_irq_chip = {
+       .name           = "MPIC",
+       .irq_mask       = armada_370_xp_irq_mask,
+       .irq_mask_ack   = armada_370_xp_irq_mask,
+       .irq_unmask     = armada_370_xp_irq_unmask,
+#ifdef CONFIG_SMP
+       .irq_set_affinity = armada_xp_set_affinity,
 #endif
+       .flags          = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
+};
+
+static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
+                                     unsigned int virq, irq_hw_number_t hw)
+{
+       armada_370_xp_irq_mask(irq_get_irq_data(virq));
+       if (!is_percpu_irq(hw))
+               writel(hw, per_cpu_int_base +
+                       ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
+       else
+               writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
+       irq_set_status_flags(virq, IRQ_LEVEL);
+
+       if (is_percpu_irq(hw)) {
+               irq_set_percpu_devid(virq);
+               irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
+                                       handle_percpu_devid_irq);
+       } else {
+               irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
+                                       handle_level_irq);
+               irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq)));
+       }
+       irq_set_probe(virq);
+
+       return 0;
+}
 
 static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
        .map = armada_370_xp_mpic_irq_map,
@@ -562,22 +661,15 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
 #ifdef CONFIG_SMP
                /* IPI Handling */
                if (irqnr == 0) {
-                       u32 ipimask, ipinr;
+                       unsigned long ipimask;
+                       int ipi;
 
                        ipimask = readl_relaxed(per_cpu_int_base +
                                                ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
                                & IPI_DOORBELL_MASK;
 
-                       writel(~ipimask, per_cpu_int_base +
-                               ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
-
-                       /* Handle all pending doorbells */
-                       for (ipinr = IPI_DOORBELL_START;
-                            ipinr < IPI_DOORBELL_END; ipinr++) {
-                               if (ipimask & (0x1 << ipinr))
-                                       handle_IPI(ipinr, regs);
-                       }
-                       continue;
+                       for_each_set_bit(ipi, &ipimask, IPI_DOORBELL_END)
+                               handle_domain_irq(ipi_domain, ipi, regs);
                }
 #endif
 
@@ -636,6 +728,8 @@ static void armada_370_xp_mpic_resume(void)
                writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
        if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
                writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
+
+       ipi_resume();
 }
 
 static struct syscore_ops armada_370_xp_mpic_syscore_ops = {
@@ -691,7 +785,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
                irq_set_default_host(armada_370_xp_mpic_domain);
                set_handle_irq(armada_370_xp_handle_irq);
 #ifdef CONFIG_SMP
-               set_smp_cross_call(armada_mpic_send_doorbell);
+               armada_xp_ipi_init(node);
                cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING,
                                          "irqchip/armada/ipi:starting",
                                          armada_xp_mpic_starting_cpu, NULL);
index 2038693..97838eb 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/of_irq.h>
 #include <linux/irqchip.h>
 #include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/irq-bcm2836.h>
 
 #include <asm/exception.h>
@@ -89,12 +90,24 @@ static struct irq_chip bcm2836_arm_irqchip_gpu = {
        .irq_unmask     = bcm2836_arm_irqchip_unmask_gpu_irq,
 };
 
+static void bcm2836_arm_irqchip_dummy_op(struct irq_data *d)
+{
+}
+
+static struct irq_chip bcm2836_arm_irqchip_dummy = {
+       .name           = "bcm2836-dummy",
+       .irq_eoi        = bcm2836_arm_irqchip_dummy_op,
+};
+
 static int bcm2836_map(struct irq_domain *d, unsigned int irq,
                       irq_hw_number_t hw)
 {
        struct irq_chip *chip;
 
        switch (hw) {
+       case LOCAL_IRQ_MAILBOX0:
+               chip = &bcm2836_arm_irqchip_dummy;
+               break;
        case LOCAL_IRQ_CNTPSIRQ:
        case LOCAL_IRQ_CNTPNSIRQ:
        case LOCAL_IRQ_CNTHPIRQ:
@@ -127,17 +140,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
        u32 stat;
 
        stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu);
-       if (stat & BIT(LOCAL_IRQ_MAILBOX0)) {
-#ifdef CONFIG_SMP
-               void __iomem *mailbox0 = (intc.base +
-                                         LOCAL_MAILBOX0_CLR0 + 16 * cpu);
-               u32 mbox_val = readl(mailbox0);
-               u32 ipi = ffs(mbox_val) - 1;
-
-               writel(1 << ipi, mailbox0);
-               handle_IPI(ipi, regs);
-#endif
-       } else if (stat) {
+       if (stat) {
                u32 hwirq = ffs(stat) - 1;
 
                handle_domain_irq(intc.domain, hwirq, regs);
@@ -145,8 +148,35 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
 }
 
 #ifdef CONFIG_SMP
-static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask,
-                                        unsigned int ipi)
+static struct irq_domain *ipi_domain;
+
+static void bcm2836_arm_irqchip_handle_ipi(struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       int cpu = smp_processor_id();
+       u32 mbox_val;
+
+       chained_irq_enter(chip, desc);
+
+       mbox_val = readl_relaxed(intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu);
+       if (mbox_val) {
+               int hwirq = ffs(mbox_val) - 1;
+               generic_handle_irq(irq_find_mapping(ipi_domain, hwirq));
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static void bcm2836_arm_irqchip_ipi_eoi(struct irq_data *d)
+{
+       int cpu = smp_processor_id();
+
+       writel_relaxed(BIT(d->hwirq),
+                      intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu);
+}
+
+static void bcm2836_arm_irqchip_ipi_send_mask(struct irq_data *d,
+                                             const struct cpumask *mask)
 {
        int cpu;
        void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0;
@@ -157,11 +187,47 @@ static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask,
         */
        smp_wmb();
 
-       for_each_cpu(cpu, mask) {
-               writel(1 << ipi, mailbox0_base + 16 * cpu);
+       for_each_cpu(cpu, mask)
+               writel_relaxed(BIT(d->hwirq), mailbox0_base + 16 * cpu);
+}
+
+static struct irq_chip bcm2836_arm_irqchip_ipi = {
+       .name           = "IPI",
+       .irq_mask       = bcm2836_arm_irqchip_dummy_op,
+       .irq_unmask     = bcm2836_arm_irqchip_dummy_op,
+       .irq_eoi        = bcm2836_arm_irqchip_ipi_eoi,
+       .ipi_send_mask  = bcm2836_arm_irqchip_ipi_send_mask,
+};
+
+static int bcm2836_arm_irqchip_ipi_alloc(struct irq_domain *d,
+                                        unsigned int virq,
+                                        unsigned int nr_irqs, void *args)
+{
+       int i;
+
+       for (i = 0; i < nr_irqs; i++) {
+               irq_set_percpu_devid(virq + i);
+               irq_domain_set_info(d, virq + i, i, &bcm2836_arm_irqchip_ipi,
+                                   d->host_data,
+                                   handle_percpu_devid_fasteoi_ipi,
+                                   NULL, NULL);
        }
+
+       return 0;
 }
 
+static void bcm2836_arm_irqchip_ipi_free(struct irq_domain *d,
+                                        unsigned int virq,
+                                        unsigned int nr_irqs)
+{
+       /* Not freeing IPIs */
+}
+
+static const struct irq_domain_ops ipi_domain_ops = {
+       .alloc  = bcm2836_arm_irqchip_ipi_alloc,
+       .free   = bcm2836_arm_irqchip_ipi_free,
+};
+
 static int bcm2836_cpu_starting(unsigned int cpu)
 {
        bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_MAILBOX_INT_CONTROL0, 0,
@@ -175,25 +241,58 @@ static int bcm2836_cpu_dying(unsigned int cpu)
                                             cpu);
        return 0;
 }
-#endif
 
-static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
-       .xlate = irq_domain_xlate_onetwocell,
-       .map = bcm2836_map,
-};
+#define BITS_PER_MBOX  32
 
-static void
-bcm2836_arm_irqchip_smp_init(void)
+static void bcm2836_arm_irqchip_smp_init(void)
 {
-#ifdef CONFIG_SMP
+       struct irq_fwspec ipi_fwspec = {
+               .fwnode         = intc.domain->fwnode,
+               .param_count    = 1,
+               .param          = {
+                       [0]     = LOCAL_IRQ_MAILBOX0,
+               },
+       };
+       int base_ipi, mux_irq;
+
+       mux_irq = irq_create_fwspec_mapping(&ipi_fwspec);
+       if (WARN_ON(mux_irq <= 0))
+               return;
+
+       ipi_domain = irq_domain_create_linear(intc.domain->fwnode,
+                                             BITS_PER_MBOX, &ipi_domain_ops,
+                                             NULL);
+       if (WARN_ON(!ipi_domain))
+               return;
+
+       ipi_domain->flags |= IRQ_DOMAIN_FLAG_IPI_SINGLE;
+       irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI);
+
+       base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, BITS_PER_MBOX,
+                                          NUMA_NO_NODE, NULL,
+                                          false, NULL);
+
+       if (WARN_ON(!base_ipi))
+               return;
+
+       set_smp_ipi_range(base_ipi, BITS_PER_MBOX);
+
+       irq_set_chained_handler_and_data(mux_irq,
+                                        bcm2836_arm_irqchip_handle_ipi, NULL);
+
        /* Unmask IPIs to the boot CPU. */
        cpuhp_setup_state(CPUHP_AP_IRQ_BCM2836_STARTING,
                          "irqchip/bcm2836:starting", bcm2836_cpu_starting,
                          bcm2836_cpu_dying);
-
-       set_smp_cross_call(bcm2836_arm_irqchip_send_ipi);
-#endif
 }
+#else
+#define bcm2836_arm_irqchip_smp_init() do { } while(0)
+#endif
+
+static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
+       .xlate = irq_domain_xlate_onetwocell,
+       .map = bcm2836_map,
+};
 
 /*
  * The LOCAL_IRQ_CNT* timer firings are based off of the external
@@ -232,6 +331,8 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
        if (!intc.domain)
                panic("%pOF: unable to create IRQ domain\n", node);
 
+       irq_domain_update_bus_token(intc.domain, DOMAIN_BUS_WIRED);
+
        bcm2836_arm_irqchip_smp_init();
 
        set_handle_irq(bcm2836_arm_irqchip_handle_irq);
index e4550e9..54b09d6 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/interrupt.h>
 
 #define APB_INT_ENABLE_L       0x00
 #define APB_INT_ENABLE_H       0x04
 #define APB_INT_FINALSTATUS_H  0x34
 #define APB_INT_BASE_OFFSET    0x04
 
-static void dw_apb_ictl_handler(struct irq_desc *desc)
+/* irq domain of the primary interrupt controller. */
+static struct irq_domain *dw_apb_ictl_irq_domain;
+
+static void __irq_entry dw_apb_ictl_handle_irq(struct pt_regs *regs)
+{
+       struct irq_domain *d = dw_apb_ictl_irq_domain;
+       int n;
+
+       for (n = 0; n < d->revmap_size; n += 32) {
+               struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, n);
+               u32 stat = readl_relaxed(gc->reg_base + APB_INT_FINALSTATUS_L);
+
+               while (stat) {
+                       u32 hwirq = ffs(stat) - 1;
+
+                       handle_domain_irq(d, hwirq, regs);
+                       stat &= ~BIT(hwirq);
+               }
+       }
+}
+
+static void dw_apb_ictl_handle_irq_cascaded(struct irq_desc *desc)
 {
        struct irq_domain *d = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -43,13 +65,37 @@ static void dw_apb_ictl_handler(struct irq_desc *desc)
                        u32 virq = irq_find_mapping(d, gc->irq_base + hwirq);
 
                        generic_handle_irq(virq);
-                       stat &= ~(1 << hwirq);
+                       stat &= ~BIT(hwirq);
                }
        }
 
        chained_irq_exit(chip, desc);
 }
 
+static int dw_apb_ictl_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                               unsigned int nr_irqs, void *arg)
+{
+       int i, ret;
+       irq_hw_number_t hwirq;
+       unsigned int type = IRQ_TYPE_NONE;
+       struct irq_fwspec *fwspec = arg;
+
+       ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < nr_irqs; i++)
+               irq_map_generic_chip(domain, virq + i, hwirq + i);
+
+       return 0;
+}
+
+static const struct irq_domain_ops dw_apb_ictl_irq_domain_ops = {
+       .translate = irq_domain_translate_onecell,
+       .alloc = dw_apb_ictl_irq_domain_alloc,
+       .free = irq_domain_free_irqs_top,
+};
+
 #ifdef CONFIG_PM
 static void dw_apb_ictl_resume(struct irq_data *d)
 {
@@ -68,19 +114,27 @@ static void dw_apb_ictl_resume(struct irq_data *d)
 static int __init dw_apb_ictl_init(struct device_node *np,
                                   struct device_node *parent)
 {
+       const struct irq_domain_ops *domain_ops;
        unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
        struct resource r;
        struct irq_domain *domain;
        struct irq_chip_generic *gc;
        void __iomem *iobase;
-       int ret, nrirqs, irq, i;
+       int ret, nrirqs, parent_irq, i;
        u32 reg;
 
-       /* Map the parent interrupt for the chained handler */
-       irq = irq_of_parse_and_map(np, 0);
-       if (irq <= 0) {
-               pr_err("%pOF: unable to parse irq\n", np);
-               return -EINVAL;
+       if (!parent) {
+               /* Used as the primary interrupt controller */
+               parent_irq = 0;
+               domain_ops = &dw_apb_ictl_irq_domain_ops;
+       } else {
+               /* Map the parent interrupt for the chained handler */
+               parent_irq = irq_of_parse_and_map(np, 0);
+               if (parent_irq <= 0) {
+                       pr_err("%pOF: unable to parse irq\n", np);
+                       return -EINVAL;
+               }
+               domain_ops = &irq_generic_chip_ops;
        }
 
        ret = of_address_to_resource(np, 0, &r);
@@ -120,8 +174,7 @@ static int __init dw_apb_ictl_init(struct device_node *np,
        else
                nrirqs = fls(readl_relaxed(iobase + APB_INT_ENABLE_L));
 
-       domain = irq_domain_add_linear(np, nrirqs,
-                                      &irq_generic_chip_ops, NULL);
+       domain = irq_domain_add_linear(np, nrirqs, domain_ops, NULL);
        if (!domain) {
                pr_err("%pOF: unable to add irq domain\n", np);
                ret = -ENOMEM;
@@ -146,7 +199,13 @@ static int __init dw_apb_ictl_init(struct device_node *np,
                gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume;
        }
 
-       irq_set_chained_handler_and_data(irq, dw_apb_ictl_handler, domain);
+       if (parent_irq) {
+               irq_set_chained_handler_and_data(parent_irq,
+                               dw_apb_ictl_handle_irq_cascaded, domain);
+       } else {
+               dw_apb_ictl_irq_domain = domain;
+               set_handle_irq(dw_apb_ictl_handle_irq);
+       }
 
        return 0;
 
index 8252000..f47b41d 100644 (file)
@@ -152,9 +152,6 @@ void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void))
                writel_relaxed(GICD_INT_DEF_PRI_X4,
                                        base + GIC_DIST_PRI + i * 4 / 4);
 
-       /* Ensure all SGI interrupts are now enabled */
-       writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET);
-
        if (sync_access)
                sync_access();
 }
index 95f0974..0418071 100644 (file)
@@ -1720,6 +1720,11 @@ static int its_irq_set_irqchip_state(struct irq_data *d,
        return 0;
 }
 
+static int its_irq_retrigger(struct irq_data *d)
+{
+       return !its_irq_set_irqchip_state(d, IRQCHIP_STATE_PENDING, true);
+}
+
 /*
  * Two favourable cases:
  *
@@ -1971,6 +1976,7 @@ static struct irq_chip its_irq_chip = {
        .irq_set_affinity       = its_set_affinity,
        .irq_compose_msi_msg    = its_irq_compose_msi_msg,
        .irq_set_irqchip_state  = its_irq_set_irqchip_state,
+       .irq_retrigger          = its_irq_retrigger,
        .irq_set_vcpu_affinity  = its_irq_set_vcpu_affinity,
 };
 
@@ -2737,7 +2743,7 @@ static bool allocate_vpe_l2_table(int cpu, u32 id)
        switch (gpsz) {
        default:
                WARN_ON(1);
-               /* fall through */
+               fallthrough;
        case GIC_PAGE_SIZE_4K:
                psz = SZ_4K;
                break;
@@ -2832,7 +2838,7 @@ static int allocate_vpe_l1_table(void)
        switch (gpsz) {
        default:
                gpsz = GIC_PAGE_SIZE_4K;
-               /* fall through */
+               fallthrough;
        case GIC_PAGE_SIZE_4K:
                psz = SZ_4K;
                break;
index 324f280..16fecc0 100644 (file)
@@ -36,6 +36,8 @@
 #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996    (1ULL << 0)
 #define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539  (1ULL << 1)
 
+#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1)
+
 struct redist_region {
        void __iomem            *redist_base;
        phys_addr_t             phys_base;
@@ -75,16 +77,14 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
  *
  * If SCR_EL3.FIQ == 1, the values writen to/read from PMR and RPR at non-secure
  * EL1 are subject to a similar operation thus matching the priorities presented
- * from the (re)distributor when security is enabled.
+ * from the (re)distributor when security is enabled. When SCR_EL3.FIQ == 0,
+ * these values are unchanched by the GIC.
  *
  * see GICv3/GICv4 Architecture Specification (IHI0069D):
  * - section 4.8.1 Non-secure accesses to register fields for Secure interrupt
  *   priorities.
  * - Figure 4-7 Secure read of the priority field for a Non-secure Group 1
  *   interrupt.
- *
- * For now, we only support pseudo-NMIs if we have non-secure view of
- * priorities.
  */
 static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
 
@@ -97,6 +97,9 @@ static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
 DEFINE_STATIC_KEY_FALSE(gic_pmr_sync);
 EXPORT_SYMBOL(gic_pmr_sync);
 
+DEFINE_STATIC_KEY_FALSE(gic_nonsecure_priorities);
+EXPORT_SYMBOL(gic_nonsecure_priorities);
+
 /* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
 static refcount_t *ppi_nmi_refs;
 
@@ -112,6 +115,7 @@ static DEFINE_PER_CPU(bool, has_rss);
 #define DEFAULT_PMR_VALUE      0xf0
 
 enum gic_intid_range {
+       SGI_RANGE,
        PPI_RANGE,
        SPI_RANGE,
        EPPI_RANGE,
@@ -123,6 +127,8 @@ enum gic_intid_range {
 static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq)
 {
        switch (hwirq) {
+       case 0 ... 15:
+               return SGI_RANGE;
        case 16 ... 31:
                return PPI_RANGE;
        case 32 ... 1019:
@@ -148,15 +154,22 @@ static inline unsigned int gic_irq(struct irq_data *d)
        return d->hwirq;
 }
 
-static inline int gic_irq_in_rdist(struct irq_data *d)
+static inline bool gic_irq_in_rdist(struct irq_data *d)
 {
-       enum gic_intid_range range = get_intid_range(d);
-       return range == PPI_RANGE || range == EPPI_RANGE;
+       switch (get_intid_range(d)) {
+       case SGI_RANGE:
+       case PPI_RANGE:
+       case EPPI_RANGE:
+               return true;
+       default:
+               return false;
+       }
 }
 
 static inline void __iomem *gic_dist_base(struct irq_data *d)
 {
        switch (get_intid_range(d)) {
+       case SGI_RANGE:
        case PPI_RANGE:
        case EPPI_RANGE:
                /* SGI+PPI -> SGI_base for this CPU */
@@ -253,6 +266,7 @@ static void gic_enable_redist(bool enable)
 static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index)
 {
        switch (get_intid_range(d)) {
+       case SGI_RANGE:
        case PPI_RANGE:
        case SPI_RANGE:
                *index = d->hwirq;
@@ -372,7 +386,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d,
 {
        u32 reg;
 
-       if (d->hwirq >= 8192) /* PPI/SPI only */
+       if (d->hwirq >= 8192) /* SGI/PPI/SPI only */
                return -EINVAL;
 
        switch (which) {
@@ -539,12 +553,12 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
        u32 offset, index;
        int ret;
 
-       /* Interrupt configuration for SGIs can't be changed */
-       if (irq < 16)
-               return -EINVAL;
-
        range = get_intid_range(d);
 
+       /* Interrupt configuration for SGIs can't be changed */
+       if (range == SGI_RANGE)
+               return type != IRQ_TYPE_EDGE_RISING ? -EINVAL : 0;
+
        /* SPIs have restrictions on the supported types */
        if ((range == SPI_RANGE || range == ESPI_RANGE) &&
            type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
@@ -572,6 +586,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 
 static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
 {
+       if (get_intid_range(d) == SGI_RANGE)
+               return -EINVAL;
+
        if (vcpu)
                irqd_set_forwarded_to_vcpu(d);
        else
@@ -646,38 +663,14 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
        if ((irqnr >= 1020 && irqnr <= 1023))
                return;
 
-       /* Treat anything but SGIs in a uniform way */
-       if (likely(irqnr > 15)) {
-               int err;
-
-               if (static_branch_likely(&supports_deactivate_key))
-                       gic_write_eoir(irqnr);
-               else
-                       isb();
-
-               err = handle_domain_irq(gic_data.domain, irqnr, regs);
-               if (err) {
-                       WARN_ONCE(true, "Unexpected interrupt received!\n");
-                       gic_deactivate_unhandled(irqnr);
-               }
-               return;
-       }
-       if (irqnr < 16) {
+       if (static_branch_likely(&supports_deactivate_key))
                gic_write_eoir(irqnr);
-               if (static_branch_likely(&supports_deactivate_key))
-                       gic_write_dir(irqnr);
-#ifdef CONFIG_SMP
-               /*
-                * Unlike GICv2, we don't need an smp_rmb() here.
-                * The control dependency from gic_read_iar to
-                * the ISB in gic_write_eoir is enough to ensure
-                * that any shared data read by handle_IPI will
-                * be read after the ACK.
-                */
-               handle_IPI(irqnr, regs);
-#else
-               WARN_ONCE(true, "Unexpected SGI received!\n");
-#endif
+       else
+               isb();
+
+       if (handle_domain_irq(gic_data.domain, irqnr, regs)) {
+               WARN_ONCE(true, "Unexpected interrupt received!\n");
+               gic_deactivate_unhandled(irqnr);
        }
 }
 
@@ -932,14 +925,20 @@ static void gic_cpu_sys_reg_init(void)
        /* Set priority mask register */
        if (!gic_prio_masking_enabled()) {
                write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
-       } else {
+       } else if (gic_supports_nmi()) {
                /*
                 * Mismatch configuration with boot CPU, the system is likely
                 * to die as interrupt masking will not work properly on all
                 * CPUs
+                *
+                * The boot CPU calls this function before enabling NMI support,
+                * and as a result we'll never see this warning in the boot path
+                * for that CPU.
                 */
-               WARN_ON(gic_supports_nmi() && group0 &&
-                       !gic_dist_security_disabled());
+               if (static_branch_unlikely(&gic_nonsecure_priorities))
+                       WARN_ON(!group0 || gic_dist_security_disabled());
+               else
+                       WARN_ON(group0 && !gic_dist_security_disabled());
        }
 
        /*
@@ -965,10 +964,10 @@ static void gic_cpu_sys_reg_init(void)
                case 7:
                        write_gicreg(0, ICC_AP0R3_EL1);
                        write_gicreg(0, ICC_AP0R2_EL1);
-               /* Fall through */
+                       fallthrough;
                case 6:
                        write_gicreg(0, ICC_AP0R1_EL1);
-               /* Fall through */
+                       fallthrough;
                case 5:
                case 4:
                        write_gicreg(0, ICC_AP0R0_EL1);
@@ -982,10 +981,10 @@ static void gic_cpu_sys_reg_init(void)
        case 7:
                write_gicreg(0, ICC_AP1R3_EL1);
                write_gicreg(0, ICC_AP1R2_EL1);
-               /* Fall through */
+               fallthrough;
        case 6:
                write_gicreg(0, ICC_AP1R1_EL1);
-               /* Fall through */
+               fallthrough;
        case 5:
        case 4:
                write_gicreg(0, ICC_AP1R0_EL1);
@@ -1125,11 +1124,11 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
        gic_write_sgi1r(val);
 }
 
-static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
+static void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
 {
        int cpu;
 
-       if (WARN_ON(irq >= 16))
+       if (WARN_ON(d->hwirq >= 16))
                return;
 
        /*
@@ -1143,7 +1142,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
                u16 tlist;
 
                tlist = gic_compute_target_list(&cpu, mask, cluster_id);
-               gic_send_sgi(cluster_id, tlist, irq);
+               gic_send_sgi(cluster_id, tlist, d->hwirq);
        }
 
        /* Force the above writes to ICC_SGI1R_EL1 to be executed */
@@ -1152,10 +1151,24 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 
 static void __init gic_smp_init(void)
 {
-       set_smp_cross_call(gic_raise_softirq);
+       struct irq_fwspec sgi_fwspec = {
+               .fwnode         = gic_data.fwnode,
+               .param_count    = 1,
+       };
+       int base_sgi;
+
        cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
                                  "irqchip/arm/gicv3:starting",
                                  gic_starting_cpu, NULL);
+
+       /* Register all 8 non-secure SGIs */
+       base_sgi = __irq_domain_alloc_irqs(gic_data.domain, -1, 8,
+                                          NUMA_NO_NODE, &sgi_fwspec,
+                                          false, NULL);
+       if (WARN_ON(base_sgi <= 0))
+               return;
+
+       set_smp_ipi_range(base_sgi, 8);
 }
 
 static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
@@ -1204,9 +1217,15 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
 }
 #else
 #define gic_set_affinity       NULL
+#define gic_ipi_send_mask      NULL
 #define gic_smp_init()         do { } while(0)
 #endif
 
+static int gic_retrigger(struct irq_data *data)
+{
+       return !gic_irq_set_irqchip_state(data, IRQCHIP_STATE_PENDING, true);
+}
+
 #ifdef CONFIG_CPU_PM
 static int gic_cpu_pm_notifier(struct notifier_block *self,
                               unsigned long cmd, void *v)
@@ -1242,10 +1261,12 @@ static struct irq_chip gic_chip = {
        .irq_eoi                = gic_eoi_irq,
        .irq_set_type           = gic_set_type,
        .irq_set_affinity       = gic_set_affinity,
+       .irq_retrigger          = gic_retrigger,
        .irq_get_irqchip_state  = gic_irq_get_irqchip_state,
        .irq_set_irqchip_state  = gic_irq_set_irqchip_state,
        .irq_nmi_setup          = gic_irq_nmi_setup,
        .irq_nmi_teardown       = gic_irq_nmi_teardown,
+       .ipi_send_mask          = gic_ipi_send_mask,
        .flags                  = IRQCHIP_SET_TYPE_MASKED |
                                  IRQCHIP_SKIP_SET_WAKE |
                                  IRQCHIP_MASK_ON_SUSPEND,
@@ -1258,11 +1279,13 @@ static struct irq_chip gic_eoimode1_chip = {
        .irq_eoi                = gic_eoimode1_eoi_irq,
        .irq_set_type           = gic_set_type,
        .irq_set_affinity       = gic_set_affinity,
+       .irq_retrigger          = gic_retrigger,
        .irq_get_irqchip_state  = gic_irq_get_irqchip_state,
        .irq_set_irqchip_state  = gic_irq_set_irqchip_state,
        .irq_set_vcpu_affinity  = gic_irq_set_vcpu_affinity,
        .irq_nmi_setup          = gic_irq_nmi_setup,
        .irq_nmi_teardown       = gic_irq_nmi_teardown,
+       .ipi_send_mask          = gic_ipi_send_mask,
        .flags                  = IRQCHIP_SET_TYPE_MASKED |
                                  IRQCHIP_SKIP_SET_WAKE |
                                  IRQCHIP_MASK_ON_SUSPEND,
@@ -1272,11 +1295,19 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
                              irq_hw_number_t hw)
 {
        struct irq_chip *chip = &gic_chip;
+       struct irq_data *irqd = irq_desc_get_irq_data(irq_to_desc(irq));
 
        if (static_branch_likely(&supports_deactivate_key))
                chip = &gic_eoimode1_chip;
 
        switch (__get_intid_range(hw)) {
+       case SGI_RANGE:
+               irq_set_percpu_devid(irq);
+               irq_domain_set_info(d, irq, hw, chip, d->host_data,
+                                   handle_percpu_devid_fasteoi_ipi,
+                                   NULL, NULL);
+               break;
+
        case PPI_RANGE:
        case EPPI_RANGE:
                irq_set_percpu_devid(irq);
@@ -1289,7 +1320,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
                irq_domain_set_info(d, irq, hw, chip, d->host_data,
                                    handle_fasteoi_irq, NULL, NULL);
                irq_set_probe(irq);
-               irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));
+               irqd_set_single_target(irqd);
                break;
 
        case LPI_RANGE:
@@ -1303,16 +1334,22 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
                return -EPERM;
        }
 
+       /* Prevents SW retriggers which mess up the ACK/EOI ordering */
+       irqd_set_handle_enforce_irqctx(irqd);
        return 0;
 }
 
-#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1)
-
 static int gic_irq_domain_translate(struct irq_domain *d,
                                    struct irq_fwspec *fwspec,
                                    unsigned long *hwirq,
                                    unsigned int *type)
 {
+       if (fwspec->param_count == 1 && fwspec->param[0] < 16) {
+               *hwirq = fwspec->param[0];
+               *type = IRQ_TYPE_EDGE_RISING;
+               return 0;
+       }
+
        if (is_of_node(fwspec->fwnode)) {
                if (fwspec->param_count < 3)
                        return -EINVAL;
@@ -1544,11 +1581,6 @@ static void gic_enable_nmi_support(void)
        if (!gic_prio_masking_enabled())
                return;
 
-       if (gic_has_group0() && !gic_dist_security_disabled()) {
-               pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
-               return;
-       }
-
        ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL);
        if (!ppi_nmi_refs)
                return;
@@ -1564,8 +1596,38 @@ static void gic_enable_nmi_support(void)
        if (gic_read_ctlr() & ICC_CTLR_EL1_PMHE_MASK)
                static_branch_enable(&gic_pmr_sync);
 
-       pr_info("%s ICC_PMR_EL1 synchronisation\n",
-               static_branch_unlikely(&gic_pmr_sync) ? "Forcing" : "Relaxing");
+       pr_info("Pseudo-NMIs enabled using %s ICC_PMR_EL1 synchronisation\n",
+               static_branch_unlikely(&gic_pmr_sync) ? "forced" : "relaxed");
+
+       /*
+        * How priority values are used by the GIC depends on two things:
+        * the security state of the GIC (controlled by the GICD_CTRL.DS bit)
+        * and if Group 0 interrupts can be delivered to Linux in the non-secure
+        * world as FIQs (controlled by the SCR_EL3.FIQ bit). These affect the
+        * the ICC_PMR_EL1 register and the priority that software assigns to
+        * interrupts:
+        *
+        * GICD_CTRL.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Group 1 priority
+        * -----------------------------------------------------------
+        *      1       |      -      |  unchanged  |    unchanged
+        * -----------------------------------------------------------
+        *      0       |      1      |  non-secure |    non-secure
+        * -----------------------------------------------------------
+        *      0       |      0      |  unchanged  |    non-secure
+        *
+        * where non-secure means that the value is right-shifted by one and the
+        * MSB bit set, to make it fit in the non-secure priority range.
+        *
+        * In the first two cases, where ICC_PMR_EL1 and the interrupt priority
+        * are both either modified or unchanged, we can use the same set of
+        * priorities.
+        *
+        * In the last case, where only the interrupt priorities are modified to
+        * be in the non-secure range, we use a different PMR value to mask IRQs
+        * and the rest of the values that we use remain unchanged.
+        */
+       if (gic_has_group0() && !gic_dist_security_disabled())
+               static_branch_enable(&gic_nonsecure_priorities);
 
        static_branch_enable(&supports_pseudo_nmis);
 
@@ -1644,9 +1706,9 @@ static int __init gic_init_bases(void __iomem *dist_base,
 
        gic_update_rdist_properties();
 
-       gic_smp_init();
        gic_dist_init();
        gic_cpu_init();
+       gic_smp_init();
        gic_cpu_pm_init();
 
        if (gic_dist_supports_lpis()) {
index a27ba2c..6053245 100644 (file)
@@ -83,9 +83,6 @@ struct gic_chip_data {
 #endif
        struct irq_domain *domain;
        unsigned int gic_irqs;
-#ifdef CONFIG_GIC_NON_BANKED
-       void __iomem *(*get_base)(union gic_base *);
-#endif
 };
 
 #ifdef CONFIG_BL_SWITCHER
@@ -124,36 +121,30 @@ static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
 
 static struct gic_kvm_info gic_v2_kvm_info;
 
+static DEFINE_PER_CPU(u32, sgi_intid);
+
 #ifdef CONFIG_GIC_NON_BANKED
-static void __iomem *gic_get_percpu_base(union gic_base *base)
-{
-       return raw_cpu_read(*base->percpu_base);
-}
+static DEFINE_STATIC_KEY_FALSE(frankengic_key);
 
-static void __iomem *gic_get_common_base(union gic_base *base)
+static void enable_frankengic(void)
 {
-       return base->common_base;
+       static_branch_enable(&frankengic_key);
 }
 
-static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
+static inline void __iomem *__get_base(union gic_base *base)
 {
-       return data->get_base(&data->dist_base);
-}
+       if (static_branch_unlikely(&frankengic_key))
+               return raw_cpu_read(*base->percpu_base);
 
-static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
-{
-       return data->get_base(&data->cpu_base);
+       return base->common_base;
 }
 
-static inline void gic_set_base_accessor(struct gic_chip_data *data,
-                                        void __iomem *(*f)(union gic_base *))
-{
-       data->get_base = f;
-}
+#define gic_data_dist_base(d)  __get_base(&(d)->dist_base)
+#define gic_data_cpu_base(d)   __get_base(&(d)->cpu_base)
 #else
 #define gic_data_dist_base(d)  ((d)->dist_base.common_base)
 #define gic_data_cpu_base(d)   ((d)->cpu_base.common_base)
-#define gic_set_base_accessor(d, f)
+#define enable_frankengic()    do { } while(0)
 #endif
 
 static inline void __iomem *gic_dist_base(struct irq_data *d)
@@ -226,16 +217,26 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-       writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
+       u32 hwirq = gic_irq(d);
+
+       if (hwirq < 16)
+               hwirq = this_cpu_read(sgi_intid);
+
+       writel_relaxed(hwirq, gic_cpu_base(d) + GIC_CPU_EOI);
 }
 
 static void gic_eoimode1_eoi_irq(struct irq_data *d)
 {
+       u32 hwirq = gic_irq(d);
+
        /* Do not deactivate an IRQ forwarded to a vcpu. */
        if (irqd_is_forwarded_to_vcpu(d))
                return;
 
-       writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_DEACTIVATE);
+       if (hwirq < 16)
+               hwirq = this_cpu_read(sgi_intid);
+
+       writel_relaxed(hwirq, gic_cpu_base(d) + GIC_CPU_DEACTIVATE);
 }
 
 static int gic_irq_set_irqchip_state(struct irq_data *d,
@@ -295,7 +296,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 
        /* Interrupt configuration for SGIs can't be changed */
        if (gicirq < 16)
-               return -EINVAL;
+               return type != IRQ_TYPE_EDGE_RISING ? -EINVAL : 0;
 
        /* SPIs have restrictions on the supported types */
        if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
@@ -315,7 +316,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
 {
        /* Only interrupts on the primary GIC can be forwarded to a vcpu. */
-       if (cascading_gic_irq(d))
+       if (cascading_gic_irq(d) || gic_irq(d) < 16)
                return -EINVAL;
 
        if (vcpu)
@@ -325,27 +326,10 @@ static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
        return 0;
 }
 
-#ifdef CONFIG_SMP
-static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
-                           bool force)
+static int gic_retrigger(struct irq_data *data)
 {
-       void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d);
-       unsigned int cpu;
-
-       if (!force)
-               cpu = cpumask_any_and(mask_val, cpu_online_mask);
-       else
-               cpu = cpumask_first(mask_val);
-
-       if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
-               return -EINVAL;
-
-       writeb_relaxed(gic_cpu_map[cpu], reg);
-       irq_data_update_effective_affinity(d, cpumask_of(cpu));
-
-       return IRQ_SET_MASK_OK_DONE;
+       return !gic_irq_set_irqchip_state(data, IRQCHIP_STATE_PENDING, true);
 }
-#endif
 
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
@@ -357,31 +341,33 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
                irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
                irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
-               if (likely(irqnr > 15 && irqnr < 1020)) {
-                       if (static_branch_likely(&supports_deactivate_key))
-                               writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
-                       isb();
-                       handle_domain_irq(gic->domain, irqnr, regs);
-                       continue;
-               }
-               if (irqnr < 16) {
+               if (unlikely(irqnr >= 1020))
+                       break;
+
+               if (static_branch_likely(&supports_deactivate_key))
                        writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
-                       if (static_branch_likely(&supports_deactivate_key))
-                               writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE);
-#ifdef CONFIG_SMP
+               isb();
+
+               /*
+                * Ensure any shared data written by the CPU sending the IPI
+                * is read after we've read the ACK register on the GIC.
+                *
+                * Pairs with the write barrier in gic_ipi_send_mask
+                */
+               if (irqnr <= 15) {
+                       smp_rmb();
+
                        /*
-                        * Ensure any shared data written by the CPU sending
-                        * the IPI is read after we've read the ACK register
-                        * on the GIC.
-                        *
-                        * Pairs with the write barrier in gic_raise_softirq
+                        * The GIC encodes the source CPU in GICC_IAR,
+                        * leading to the deactivation to fail if not
+                        * written back as is to GICC_EOI.  Stash the INTID
+                        * away for gic_eoi_irq() to write back.  This only
+                        * works because we don't nest SGIs...
                         */
-                       smp_rmb();
-                       handle_IPI(irqnr, regs);
-#endif
-                       continue;
+                       this_cpu_write(sgi_intid, irqstat);
                }
-               break;
+
+               handle_domain_irq(gic->domain, irqnr, regs);
        } while (1);
 }
 
@@ -417,6 +403,7 @@ static const struct irq_chip gic_chip = {
        .irq_unmask             = gic_unmask_irq,
        .irq_eoi                = gic_eoi_irq,
        .irq_set_type           = gic_set_type,
+       .irq_retrigger          = gic_retrigger,
        .irq_get_irqchip_state  = gic_irq_get_irqchip_state,
        .irq_set_irqchip_state  = gic_irq_set_irqchip_state,
        .flags                  = IRQCHIP_SET_TYPE_MASKED |
@@ -728,11 +715,6 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd,    void *v)
        int i;
 
        for (i = 0; i < CONFIG_ARM_GIC_MAX_NR; i++) {
-#ifdef CONFIG_GIC_NON_BANKED
-               /* Skip over unused GICs */
-               if (!gic_data[i].get_base)
-                       continue;
-#endif
                switch (cmd) {
                case CPU_PM_ENTER:
                        gic_cpu_save(&gic_data[i]);
@@ -795,14 +777,34 @@ static int gic_pm_init(struct gic_chip_data *gic)
 #endif
 
 #ifdef CONFIG_SMP
-static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
+static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
+                           bool force)
+{
+       void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d);
+       unsigned int cpu;
+
+       if (!force)
+               cpu = cpumask_any_and(mask_val, cpu_online_mask);
+       else
+               cpu = cpumask_first(mask_val);
+
+       if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
+               return -EINVAL;
+
+       writeb_relaxed(gic_cpu_map[cpu], reg);
+       irq_data_update_effective_affinity(d, cpumask_of(cpu));
+
+       return IRQ_SET_MASK_OK_DONE;
+}
+
+static void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
 {
        int cpu;
        unsigned long flags, map = 0;
 
        if (unlikely(nr_cpu_ids == 1)) {
                /* Only one CPU? let's do a self-IPI... */
-               writel_relaxed(2 << 24 | irq,
+               writel_relaxed(2 << 24 | d->hwirq,
                               gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
                return;
        }
@@ -820,10 +822,41 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
        dmb(ishst);
 
        /* this always happens on GIC0 */
-       writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+       writel_relaxed(map << 16 | d->hwirq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 
        gic_unlock_irqrestore(flags);
 }
+
+static int gic_starting_cpu(unsigned int cpu)
+{
+       gic_cpu_init(&gic_data[0]);
+       return 0;
+}
+
+static __init void gic_smp_init(void)
+{
+       struct irq_fwspec sgi_fwspec = {
+               .fwnode         = gic_data[0].domain->fwnode,
+               .param_count    = 1,
+       };
+       int base_sgi;
+
+       cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
+                                 "irqchip/arm/gic:starting",
+                                 gic_starting_cpu, NULL);
+
+       base_sgi = __irq_domain_alloc_irqs(gic_data[0].domain, -1, 8,
+                                          NUMA_NO_NODE, &sgi_fwspec,
+                                          false, NULL);
+       if (WARN_ON(base_sgi <= 0))
+               return;
+
+       set_smp_ipi_range(base_sgi, 8);
+}
+#else
+#define gic_smp_init()         do { } while(0)
+#define gic_set_affinity       NULL
+#define gic_ipi_send_mask      NULL
 #endif
 
 #ifdef CONFIG_BL_SWITCHER
@@ -969,17 +1002,30 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
                                irq_hw_number_t hw)
 {
        struct gic_chip_data *gic = d->host_data;
+       struct irq_data *irqd = irq_desc_get_irq_data(irq_to_desc(irq));
 
-       if (hw < 32) {
+       switch (hw) {
+       case 0 ... 15:
+               irq_set_percpu_devid(irq);
+               irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
+                                   handle_percpu_devid_fasteoi_ipi,
+                                   NULL, NULL);
+               break;
+       case 16 ... 31:
                irq_set_percpu_devid(irq);
                irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
                                    handle_percpu_devid_irq, NULL, NULL);
-       } else {
+               break;
+       default:
                irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
                                    handle_fasteoi_irq, NULL, NULL);
                irq_set_probe(irq);
-               irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));
+               irqd_set_single_target(irqd);
+               break;
        }
+
+       /* Prevents SW retriggers which mess up the ACK/EOI ordering */
+       irqd_set_handle_enforce_irqctx(irqd);
        return 0;
 }
 
@@ -992,19 +1038,26 @@ static int gic_irq_domain_translate(struct irq_domain *d,
                                    unsigned long *hwirq,
                                    unsigned int *type)
 {
+       if (fwspec->param_count == 1 && fwspec->param[0] < 16) {
+               *hwirq = fwspec->param[0];
+               *type = IRQ_TYPE_EDGE_RISING;
+               return 0;
+       }
+
        if (is_of_node(fwspec->fwnode)) {
                if (fwspec->param_count < 3)
                        return -EINVAL;
 
-               /* Get the interrupt number and add 16 to skip over SGIs */
-               *hwirq = fwspec->param[1] + 16;
-
-               /*
-                * For SPIs, we need to add 16 more to get the GIC irq
-                * ID number
-                */
-               if (!fwspec->param[0])
-                       *hwirq += 16;
+               switch (fwspec->param[0]) {
+               case 0:                 /* SPI */
+                       *hwirq = fwspec->param[1] + 32;
+                       break;
+               case 1:                 /* PPI */
+                       *hwirq = fwspec->param[1] + 16;
+                       break;
+               default:
+                       return -EINVAL;
+               }
 
                *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
 
@@ -1027,12 +1080,6 @@ static int gic_irq_domain_translate(struct irq_domain *d,
        return -EINVAL;
 }
 
-static int gic_starting_cpu(unsigned int cpu)
-{
-       gic_cpu_init(&gic_data[0]);
-       return 0;
-}
-
 static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
                                unsigned int nr_irqs, void *arg)
 {
@@ -1079,10 +1126,10 @@ static void gic_init_chip(struct gic_chip_data *gic, struct device *dev,
                gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity;
        }
 
-#ifdef CONFIG_SMP
-       if (gic == &gic_data[0])
+       if (gic == &gic_data[0]) {
                gic->chip.irq_set_affinity = gic_set_affinity;
-#endif
+               gic->chip.ipi_send_mask = gic_ipi_send_mask;
+       }
 }
 
 static int gic_init_bases(struct gic_chip_data *gic,
@@ -1112,7 +1159,7 @@ static int gic_init_bases(struct gic_chip_data *gic,
                                gic->raw_cpu_base + offset;
                }
 
-               gic_set_base_accessor(gic, gic_get_percpu_base);
+               enable_frankengic();
        } else {
                /* Normal, sane GIC... */
                WARN(gic->percpu_offset,
@@ -1120,7 +1167,6 @@ static int gic_init_bases(struct gic_chip_data *gic,
                     gic->percpu_offset);
                gic->dist_base.common_base = gic->raw_dist_base;
                gic->cpu_base.common_base = gic->raw_cpu_base;
-               gic_set_base_accessor(gic, gic_get_common_base);
        }
 
        /*
@@ -1199,12 +1245,7 @@ static int __init __gic_init_bases(struct gic_chip_data *gic,
                 */
                for (i = 0; i < NR_GIC_CPU_IF; i++)
                        gic_cpu_map[i] = 0xff;
-#ifdef CONFIG_SMP
-               set_smp_cross_call(gic_raise_softirq);
-#endif
-               cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
-                                         "irqchip/arm/gic:starting",
-                                         gic_starting_cpu, NULL);
+
                set_handle_irq(gic_handle_irq);
                if (static_branch_likely(&supports_deactivate_key))
                        pr_info("GIC: Using split EOI/Deactivate mode\n");
@@ -1221,6 +1262,8 @@ static int __init __gic_init_bases(struct gic_chip_data *gic,
        ret = gic_init_bases(gic, handle);
        if (ret)
                kfree(name);
+       else if (gic == &gic_data[0])
+               gic_smp_init();
 
        return ret;
 }
index 130caa1..9b73dcf 100644 (file)
@@ -171,6 +171,29 @@ static int hip04_irq_set_affinity(struct irq_data *d,
 
        return IRQ_SET_MASK_OK;
 }
+
+static void hip04_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
+{
+       int cpu;
+       unsigned long flags, map = 0;
+
+       raw_spin_lock_irqsave(&irq_controller_lock, flags);
+
+       /* Convert our logical CPU mask into a physical one. */
+       for_each_cpu(cpu, mask)
+               map |= hip04_cpu_map[cpu];
+
+       /*
+        * Ensure that stores to Normal memory are visible to the
+        * other CPUs before they observe us issuing the IPI.
+        */
+       dmb(ishst);
+
+       /* this always happens on GIC0 */
+       writel_relaxed(map << 8 | d->hwirq, hip04_data.dist_base + GIC_DIST_SOFTINT);
+
+       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
 #endif
 
 static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs)
@@ -182,19 +205,9 @@ static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs)
                irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
                irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
-               if (likely(irqnr > 15 && irqnr <= HIP04_MAX_IRQS)) {
+               if (irqnr <= HIP04_MAX_IRQS)
                        handle_domain_irq(hip04_data.domain, irqnr, regs);
-                       continue;
-               }
-               if (irqnr < 16) {
-                       writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
-#ifdef CONFIG_SMP
-                       handle_IPI(irqnr, regs);
-#endif
-                       continue;
-               }
-               break;
-       } while (1);
+       } while (irqnr > HIP04_MAX_IRQS);
 }
 
 static struct irq_chip hip04_irq_chip = {
@@ -205,6 +218,7 @@ static struct irq_chip hip04_irq_chip = {
        .irq_set_type           = hip04_irq_set_type,
 #ifdef CONFIG_SMP
        .irq_set_affinity       = hip04_irq_set_affinity,
+       .ipi_send_mask          = hip04_ipi_send_mask,
 #endif
        .flags                  = IRQCHIP_SET_TYPE_MASKED |
                                  IRQCHIP_SKIP_SET_WAKE |
@@ -279,39 +293,17 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc)
        writel_relaxed(1, base + GIC_CPU_CTRL);
 }
 
-#ifdef CONFIG_SMP
-static void hip04_raise_softirq(const struct cpumask *mask, unsigned int irq)
-{
-       int cpu;
-       unsigned long flags, map = 0;
-
-       raw_spin_lock_irqsave(&irq_controller_lock, flags);
-
-       /* Convert our logical CPU mask into a physical one. */
-       for_each_cpu(cpu, mask)
-               map |= hip04_cpu_map[cpu];
-
-       /*
-        * Ensure that stores to Normal memory are visible to the
-        * other CPUs before they observe us issuing the IPI.
-        */
-       dmb(ishst);
-
-       /* this always happens on GIC0 */
-       writel_relaxed(map << 8 | irq, hip04_data.dist_base + GIC_DIST_SOFTINT);
-
-       raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
-}
-#endif
-
 static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq,
                                irq_hw_number_t hw)
 {
-       if (hw < 32) {
+       if (hw < 16) {
+               irq_set_percpu_devid(irq);
+               irq_set_chip_and_handler(irq, &hip04_irq_chip,
+                                        handle_percpu_devid_fasteoi_ipi);
+       } else if (hw < 32) {
                irq_set_percpu_devid(irq);
                irq_set_chip_and_handler(irq, &hip04_irq_chip,
                                         handle_percpu_devid_irq);
-               irq_set_status_flags(irq, IRQ_NOAUTOEN);
        } else {
                irq_set_chip_and_handler(irq, &hip04_irq_chip,
                                         handle_fasteoi_irq);
@@ -328,10 +320,13 @@ static int hip04_irq_domain_xlate(struct irq_domain *d,
                                  unsigned long *out_hwirq,
                                  unsigned int *out_type)
 {
-       unsigned long ret = 0;
-
        if (irq_domain_get_of_node(d) != controller)
                return -EINVAL;
+       if (intsize == 1 && intspec[0] < 16) {
+               *out_hwirq = intspec[0];
+               *out_type = IRQ_TYPE_EDGE_RISING;
+               return 0;
+       }
        if (intsize < 3)
                return -EINVAL;
 
@@ -344,7 +339,7 @@ static int hip04_irq_domain_xlate(struct irq_domain *d,
 
        *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
 
-       return ret;
+       return 0;
 }
 
 static int hip04_irq_starting_cpu(unsigned int cpu)
@@ -361,7 +356,6 @@ static const struct irq_domain_ops hip04_irq_domain_ops = {
 static int __init
 hip04_of_init(struct device_node *node, struct device_node *parent)
 {
-       irq_hw_number_t hwirq_base = 16;
        int nr_irqs, irq_base, i;
 
        if (WARN_ON(!node))
@@ -390,24 +384,21 @@ hip04_of_init(struct device_node *node, struct device_node *parent)
                nr_irqs = HIP04_MAX_IRQS;
        hip04_data.nr_irqs = nr_irqs;
 
-       nr_irqs -= hwirq_base; /* calculate # of irqs to allocate */
-
-       irq_base = irq_alloc_descs(-1, hwirq_base, nr_irqs, numa_node_id());
+       irq_base = irq_alloc_descs(-1, 0, nr_irqs, numa_node_id());
        if (irq_base < 0) {
                pr_err("failed to allocate IRQ numbers\n");
                return -EINVAL;
        }
 
        hip04_data.domain = irq_domain_add_legacy(node, nr_irqs, irq_base,
-                                                 hwirq_base,
+                                                 0,
                                                  &hip04_irq_domain_ops,
                                                  &hip04_data);
-
        if (WARN_ON(!hip04_data.domain))
                return -EINVAL;
 
 #ifdef CONFIG_SMP
-       set_smp_cross_call(hip04_raise_softirq);
+       set_smp_ipi_range(irq_base, 16);
 #endif
        set_handle_irq(hip04_handle_irq);
 
index 4f74c15..7031ef4 100644 (file)
@@ -259,7 +259,7 @@ static int __init imx_gpcv2_irqchip_init(struct device_node *node,
                case 4:
                        writel_relaxed(~0, reg + GPC_IMR1_CORE2);
                        writel_relaxed(~0, reg + GPC_IMR1_CORE3);
-                       /* fall through */
+                       fallthrough;
                case 2:
                        writel_relaxed(~0, reg + GPC_IMR1_CORE0);
                        writel_relaxed(~0, reg + GPC_IMR1_CORE1);
index e35b7b0..7709f97 100644 (file)
@@ -226,12 +226,9 @@ static int imx_intmux_probe(struct platform_device *pdev)
        }
 
        data->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
-       if (IS_ERR(data->ipg_clk)) {
-               ret = PTR_ERR(data->ipg_clk);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
-               return ret;
-       }
+       if (IS_ERR(data->ipg_clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(data->ipg_clk),
+                                    "failed to get ipg clk\n");
 
        data->channum = channum;
        raw_spin_lock_init(&data->lock);
index 290531e..1edf769 100644 (file)
@@ -158,12 +158,9 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
        }
 
        data->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
-       if (IS_ERR(data->ipg_clk)) {
-               ret = PTR_ERR(data->ipg_clk);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
-               return ret;
-       }
+       if (IS_ERR(data->ipg_clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(data->ipg_clk),
+                                    "failed to get ipg clk\n");
 
        raw_spin_lock_init(&data->lock);
 
index 9f3da42..b61a890 100644 (file)
@@ -125,7 +125,7 @@ static int __init ingenic_intc_of_init(struct device_node *node,
                irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK);
        }
 
-       if (request_irq(parent_irq, intc_cascade, 0,
+       if (request_irq(parent_irq, intc_cascade, IRQF_NO_SUSPEND,
                        "SoC intc cascade interrupt", NULL))
                pr_err("Failed to register SoC intc cascade interrupt\n");
        return 0;
index 13e6016..6392aaf 100644 (file)
@@ -151,7 +151,7 @@ static void htvec_reset(struct htvec *priv)
        /* Clear IRQ cause registers, mask all interrupts */
        for (idx = 0; idx < priv->num_parents; idx++) {
                writel_relaxed(0x0, priv->base + HTVEC_EN_OFF + 4 * idx);
-               writel_relaxed(0xFFFFFFFF, priv->base);
+               writel_relaxed(0xFFFFFFFF, priv->base + 4 * idx);
        }
 }
 
@@ -172,7 +172,7 @@ static int htvec_of_init(struct device_node *node,
                goto free_priv;
        }
 
-       /* Interrupt may come from any of the 4 interrupt line */
+       /* Interrupt may come from any of the 8 interrupt lines */
        for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) {
                parent_irq[i] = irq_of_parse_and_map(node, i);
                if (parent_irq[i] <= 0)
index aacfa01..2158859 100644 (file)
@@ -480,7 +480,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
        case GIC_LOCAL_INT_TIMER:
                /* CONFIG_MIPS_CMP workaround (see __gic_init) */
                map = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin;
-               /* fall-through */
+               fallthrough;
        case GIC_LOCAL_INT_PERFCTR:
        case GIC_LOCAL_INT_FDC:
                /*
diff --git a/drivers/irqchip/irq-mst-intc.c b/drivers/irqchip/irq-mst-intc.c
new file mode 100644 (file)
index 0000000..4be0775
--- /dev/null
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author Mark-PK Tsai <mark-pk.tsai@mediatek.com>
+ */
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define INTC_MASK      0x0
+#define INTC_EOI       0x20
+
+struct mst_intc_chip_data {
+       raw_spinlock_t  lock;
+       unsigned int    irq_start, nr_irqs;
+       void __iomem    *base;
+       bool            no_eoi;
+};
+
+static void mst_set_irq(struct irq_data *d, u32 offset)
+{
+       irq_hw_number_t hwirq = irqd_to_hwirq(d);
+       struct mst_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
+       u16 val, mask;
+       unsigned long flags;
+
+       mask = 1 << (hwirq % 16);
+       offset += (hwirq / 16) * 4;
+
+       raw_spin_lock_irqsave(&cd->lock, flags);
+       val = readw_relaxed(cd->base + offset) | mask;
+       writew_relaxed(val, cd->base + offset);
+       raw_spin_unlock_irqrestore(&cd->lock, flags);
+}
+
+static void mst_clear_irq(struct irq_data *d, u32 offset)
+{
+       irq_hw_number_t hwirq = irqd_to_hwirq(d);
+       struct mst_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
+       u16 val, mask;
+       unsigned long flags;
+
+       mask = 1 << (hwirq % 16);
+       offset += (hwirq / 16) * 4;
+
+       raw_spin_lock_irqsave(&cd->lock, flags);
+       val = readw_relaxed(cd->base + offset) & ~mask;
+       writew_relaxed(val, cd->base + offset);
+       raw_spin_unlock_irqrestore(&cd->lock, flags);
+}
+
+static void mst_intc_mask_irq(struct irq_data *d)
+{
+       mst_set_irq(d, INTC_MASK);
+       irq_chip_mask_parent(d);
+}
+
+static void mst_intc_unmask_irq(struct irq_data *d)
+{
+       mst_clear_irq(d, INTC_MASK);
+       irq_chip_unmask_parent(d);
+}
+
+static void mst_intc_eoi_irq(struct irq_data *d)
+{
+       struct mst_intc_chip_data *cd = irq_data_get_irq_chip_data(d);
+
+       if (!cd->no_eoi)
+               mst_set_irq(d, INTC_EOI);
+
+       irq_chip_eoi_parent(d);
+}
+
+static struct irq_chip mst_intc_chip = {
+       .name                   = "mst-intc",
+       .irq_mask               = mst_intc_mask_irq,
+       .irq_unmask             = mst_intc_unmask_irq,
+       .irq_eoi                = mst_intc_eoi_irq,
+       .irq_get_irqchip_state  = irq_chip_get_parent_state,
+       .irq_set_irqchip_state  = irq_chip_set_parent_state,
+       .irq_set_affinity       = irq_chip_set_affinity_parent,
+       .irq_set_vcpu_affinity  = irq_chip_set_vcpu_affinity_parent,
+       .irq_set_type           = irq_chip_set_type_parent,
+       .irq_retrigger          = irq_chip_retrigger_hierarchy,
+       .flags                  = IRQCHIP_SET_TYPE_MASKED |
+                                 IRQCHIP_SKIP_SET_WAKE |
+                                 IRQCHIP_MASK_ON_SUSPEND,
+};
+
+static int mst_intc_domain_translate(struct irq_domain *d,
+                                    struct irq_fwspec *fwspec,
+                                    unsigned long *hwirq,
+                                    unsigned int *type)
+{
+       struct mst_intc_chip_data *cd = d->host_data;
+
+       if (is_of_node(fwspec->fwnode)) {
+               if (fwspec->param_count != 3)
+                       return -EINVAL;
+
+               /* No PPI should point to this domain */
+               if (fwspec->param[0] != 0)
+                       return -EINVAL;
+
+               if (fwspec->param[1] >= cd->nr_irqs)
+                       return -EINVAL;
+
+               *hwirq = fwspec->param[1];
+               *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int mst_intc_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                                unsigned int nr_irqs, void *data)
+{
+       int i;
+       irq_hw_number_t hwirq;
+       struct irq_fwspec parent_fwspec, *fwspec = data;
+       struct mst_intc_chip_data *cd = domain->host_data;
+
+       /* Not GIC compliant */
+       if (fwspec->param_count != 3)
+               return -EINVAL;
+
+       /* No PPI should point to this domain */
+       if (fwspec->param[0])
+               return -EINVAL;
+
+       hwirq = fwspec->param[1];
+       for (i = 0; i < nr_irqs; i++)
+               irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+                                             &mst_intc_chip,
+                                             domain->host_data);
+
+       parent_fwspec = *fwspec;
+       parent_fwspec.fwnode = domain->parent->fwnode;
+       parent_fwspec.param[1] = cd->irq_start + hwirq;
+       return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec);
+}
+
+static const struct irq_domain_ops mst_intc_domain_ops = {
+       .translate      = mst_intc_domain_translate,
+       .alloc          = mst_intc_domain_alloc,
+       .free           = irq_domain_free_irqs_common,
+};
+
+int __init
+mst_intc_of_init(struct device_node *dn, struct device_node *parent)
+{
+       struct irq_domain *domain, *domain_parent;
+       struct mst_intc_chip_data *cd;
+       u32 irq_start, irq_end;
+
+       domain_parent = irq_find_host(parent);
+       if (!domain_parent) {
+               pr_err("mst-intc: interrupt-parent not found\n");
+               return -EINVAL;
+       }
+
+       if (of_property_read_u32_index(dn, "mstar,irqs-map-range", 0, &irq_start) ||
+           of_property_read_u32_index(dn, "mstar,irqs-map-range", 1, &irq_end))
+               return -EINVAL;
+
+       cd = kzalloc(sizeof(*cd), GFP_KERNEL);
+       if (!cd)
+               return -ENOMEM;
+
+       cd->base = of_iomap(dn, 0);
+       if (!cd->base) {
+               kfree(cd);
+               return -ENOMEM;
+       }
+
+       cd->no_eoi = of_property_read_bool(dn, "mstar,intc-no-eoi");
+       raw_spin_lock_init(&cd->lock);
+       cd->irq_start = irq_start;
+       cd->nr_irqs = irq_end - irq_start + 1;
+       domain = irq_domain_add_hierarchy(domain_parent, 0, cd->nr_irqs, dn,
+                                         &mst_intc_domain_ops, cd);
+       if (!domain) {
+               iounmap(cd->base);
+               kfree(cd);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+IRQCHIP_DECLARE(mst_intc, "mstar,mst-intc", mst_intc_of_init);
index 62a6127..69ba8ce 100644 (file)
@@ -295,6 +295,4 @@ out_free:
        return ret;
 }
 
-IRQCHIP_PLATFORM_DRIVER_BEGIN(mtk_cirq)
-IRQCHIP_MATCH("mediatek,mtk-cirq", mtk_cirq_of_init)
-IRQCHIP_PLATFORM_DRIVER_END(mtk_cirq)
+IRQCHIP_DECLARE(mtk_cirq, "mediatek,mtk-cirq", mtk_cirq_of_init);
index 7299c5a..6ff98b8 100644 (file)
@@ -231,6 +231,4 @@ out_free_chip:
        kfree(chip_data);
        return ret;
 }
-IRQCHIP_PLATFORM_DRIVER_BEGIN(mtk_sysirq)
-IRQCHIP_MATCH("mediatek,mt6577-sysirq", mtk_sysirq_of_init)
-IRQCHIP_PLATFORM_DRIVER_END(mtk_sysirq)
+IRQCHIP_DECLARE(mtk_sysirq, "mediatek,mt6577-sysirq", mtk_sysirq_of_init);
diff --git a/drivers/irqchip/irq-owl-sirq.c b/drivers/irqchip/irq-owl-sirq.c
new file mode 100644 (file)
index 0000000..6e41274
--- /dev/null
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Actions Semi Owl SoCs SIRQ interrupt controller driver
+ *
+ * Copyright (C) 2014 Actions Semi Inc.
+ * David Liu <liuwei@actions-semi.com>
+ *
+ * Author: Parthiban Nallathambi <pn@denx.de>
+ * Author: Saravanan Sekar <sravanhome@gmail.com>
+ * Author: Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/interrupt.h>
+#include <linux/irqchip.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#define NUM_SIRQ                       3
+
+#define INTC_EXTCTL_PENDING            BIT(0)
+#define INTC_EXTCTL_CLK_SEL            BIT(4)
+#define INTC_EXTCTL_EN                 BIT(5)
+#define INTC_EXTCTL_TYPE_MASK          GENMASK(7, 6)
+#define INTC_EXTCTL_TYPE_HIGH          0
+#define INTC_EXTCTL_TYPE_LOW           BIT(6)
+#define INTC_EXTCTL_TYPE_RISING                BIT(7)
+#define INTC_EXTCTL_TYPE_FALLING       (BIT(6) | BIT(7))
+
+/* S500 & S700 SIRQ control register masks */
+#define INTC_EXTCTL_SIRQ0_MASK         GENMASK(23, 16)
+#define INTC_EXTCTL_SIRQ1_MASK         GENMASK(15, 8)
+#define INTC_EXTCTL_SIRQ2_MASK         GENMASK(7, 0)
+
+/* S900 SIRQ control register offsets, relative to controller base address */
+#define INTC_EXTCTL0                   0x0000
+#define INTC_EXTCTL1                   0x0328
+#define INTC_EXTCTL2                   0x032c
+
+struct owl_sirq_params {
+       /* INTC_EXTCTL reg shared for all three SIRQ lines */
+       bool reg_shared;
+       /* INTC_EXTCTL reg offsets relative to controller base address */
+       u16 reg_offset[NUM_SIRQ];
+};
+
+struct owl_sirq_chip_data {
+       const struct owl_sirq_params    *params;
+       void __iomem                    *base;
+       raw_spinlock_t                  lock;
+       u32                             ext_irqs[NUM_SIRQ];
+};
+
+/* S500 & S700 SoCs */
+static const struct owl_sirq_params owl_sirq_s500_params = {
+       .reg_shared = true,
+       .reg_offset = { 0, 0, 0 },
+};
+
+/* S900 SoC */
+static const struct owl_sirq_params owl_sirq_s900_params = {
+       .reg_shared = false,
+       .reg_offset = { INTC_EXTCTL0, INTC_EXTCTL1, INTC_EXTCTL2 },
+};
+
+static u32 owl_field_get(u32 val, u32 index)
+{
+       switch (index) {
+       case 0:
+               return FIELD_GET(INTC_EXTCTL_SIRQ0_MASK, val);
+       case 1:
+               return FIELD_GET(INTC_EXTCTL_SIRQ1_MASK, val);
+       case 2:
+       default:
+               return FIELD_GET(INTC_EXTCTL_SIRQ2_MASK, val);
+       }
+}
+
+static u32 owl_field_prep(u32 val, u32 index)
+{
+       switch (index) {
+       case 0:
+               return FIELD_PREP(INTC_EXTCTL_SIRQ0_MASK, val);
+       case 1:
+               return FIELD_PREP(INTC_EXTCTL_SIRQ1_MASK, val);
+       case 2:
+       default:
+               return FIELD_PREP(INTC_EXTCTL_SIRQ2_MASK, val);
+       }
+}
+
+static u32 owl_sirq_read_extctl(struct owl_sirq_chip_data *data, u32 index)
+{
+       u32 val;
+
+       val = readl_relaxed(data->base + data->params->reg_offset[index]);
+       if (data->params->reg_shared)
+               val = owl_field_get(val, index);
+
+       return val;
+}
+
+static void owl_sirq_write_extctl(struct owl_sirq_chip_data *data,
+                                 u32 extctl, u32 index)
+{
+       u32 val;
+
+       if (data->params->reg_shared) {
+               val = readl_relaxed(data->base + data->params->reg_offset[index]);
+               val &= ~owl_field_prep(0xff, index);
+               extctl = owl_field_prep(extctl, index) | val;
+       }
+
+       writel_relaxed(extctl, data->base + data->params->reg_offset[index]);
+}
+
+static void owl_sirq_clear_set_extctl(struct owl_sirq_chip_data *d,
+                                     u32 clear, u32 set, u32 index)
+{
+       unsigned long flags;
+       u32 val;
+
+       raw_spin_lock_irqsave(&d->lock, flags);
+       val = owl_sirq_read_extctl(d, index);
+       val &= ~clear;
+       val |= set;
+       owl_sirq_write_extctl(d, val, index);
+       raw_spin_unlock_irqrestore(&d->lock, flags);
+}
+
+static void owl_sirq_eoi(struct irq_data *data)
+{
+       struct owl_sirq_chip_data *chip_data = irq_data_get_irq_chip_data(data);
+
+       /*
+        * Software must clear external interrupt pending, when interrupt type
+        * is edge triggered, so we need per SIRQ based clearing.
+        */
+       if (!irqd_is_level_type(data))
+               owl_sirq_clear_set_extctl(chip_data, 0, INTC_EXTCTL_PENDING,
+                                         data->hwirq);
+
+       irq_chip_eoi_parent(data);
+}
+
+static void owl_sirq_mask(struct irq_data *data)
+{
+       struct owl_sirq_chip_data *chip_data = irq_data_get_irq_chip_data(data);
+
+       owl_sirq_clear_set_extctl(chip_data, INTC_EXTCTL_EN, 0, data->hwirq);
+       irq_chip_mask_parent(data);
+}
+
+static void owl_sirq_unmask(struct irq_data *data)
+{
+       struct owl_sirq_chip_data *chip_data = irq_data_get_irq_chip_data(data);
+
+       owl_sirq_clear_set_extctl(chip_data, 0, INTC_EXTCTL_EN, data->hwirq);
+       irq_chip_unmask_parent(data);
+}
+
+/*
+ * GIC does not handle falling edge or active low, hence SIRQ shall be
+ * programmed to convert falling edge to rising edge signal and active
+ * low to active high signal.
+ */
+static int owl_sirq_set_type(struct irq_data *data, unsigned int type)
+{
+       struct owl_sirq_chip_data *chip_data = irq_data_get_irq_chip_data(data);
+       u32 sirq_type;
+
+       switch (type) {
+       case IRQ_TYPE_LEVEL_LOW:
+               sirq_type = INTC_EXTCTL_TYPE_LOW;
+               type = IRQ_TYPE_LEVEL_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               sirq_type = INTC_EXTCTL_TYPE_HIGH;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               sirq_type = INTC_EXTCTL_TYPE_FALLING;
+               type = IRQ_TYPE_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               sirq_type = INTC_EXTCTL_TYPE_RISING;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       owl_sirq_clear_set_extctl(chip_data, INTC_EXTCTL_TYPE_MASK, sirq_type,
+                                 data->hwirq);
+
+       return irq_chip_set_type_parent(data, type);
+}
+
+static struct irq_chip owl_sirq_chip = {
+       .name           = "owl-sirq",
+       .irq_mask       = owl_sirq_mask,
+       .irq_unmask     = owl_sirq_unmask,
+       .irq_eoi        = owl_sirq_eoi,
+       .irq_set_type   = owl_sirq_set_type,
+       .irq_retrigger  = irq_chip_retrigger_hierarchy,
+#ifdef CONFIG_SMP
+       .irq_set_affinity = irq_chip_set_affinity_parent,
+#endif
+};
+
+static int owl_sirq_domain_translate(struct irq_domain *d,
+                                    struct irq_fwspec *fwspec,
+                                    unsigned long *hwirq,
+                                    unsigned int *type)
+{
+       if (!is_of_node(fwspec->fwnode))
+               return -EINVAL;
+
+       if (fwspec->param_count != 2 || fwspec->param[0] >= NUM_SIRQ)
+               return -EINVAL;
+
+       *hwirq = fwspec->param[0];
+       *type = fwspec->param[1];
+
+       return 0;
+}
+
+static int owl_sirq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                                unsigned int nr_irqs, void *data)
+{
+       struct owl_sirq_chip_data *chip_data = domain->host_data;
+       struct irq_fwspec *fwspec = data;
+       struct irq_fwspec parent_fwspec;
+       irq_hw_number_t hwirq;
+       unsigned int type;
+       int ret;
+
+       if (WARN_ON(nr_irqs != 1))
+               return -EINVAL;
+
+       ret = owl_sirq_domain_translate(domain, fwspec, &hwirq, &type);
+       if (ret)
+               return ret;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+       case IRQ_TYPE_LEVEL_HIGH:
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               type = IRQ_TYPE_EDGE_RISING;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               type = IRQ_TYPE_LEVEL_HIGH;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &owl_sirq_chip,
+                                     chip_data);
+
+       parent_fwspec.fwnode = domain->parent->fwnode;
+       parent_fwspec.param_count = 3;
+       parent_fwspec.param[0] = GIC_SPI;
+       parent_fwspec.param[1] = chip_data->ext_irqs[hwirq];
+       parent_fwspec.param[2] = type;
+
+       return irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
+}
+
+static const struct irq_domain_ops owl_sirq_domain_ops = {
+       .translate      = owl_sirq_domain_translate,
+       .alloc          = owl_sirq_domain_alloc,
+       .free           = irq_domain_free_irqs_common,
+};
+
+static int __init owl_sirq_init(const struct owl_sirq_params *params,
+                               struct device_node *node,
+                               struct device_node *parent)
+{
+       struct irq_domain *domain, *parent_domain;
+       struct owl_sirq_chip_data *chip_data;
+       int ret, i;
+
+       parent_domain = irq_find_host(parent);
+       if (!parent_domain) {
+               pr_err("%pOF: failed to find sirq parent domain\n", node);
+               return -ENXIO;
+       }
+
+       chip_data = kzalloc(sizeof(*chip_data), GFP_KERNEL);
+       if (!chip_data)
+               return -ENOMEM;
+
+       raw_spin_lock_init(&chip_data->lock);
+
+       chip_data->params = params;
+
+       chip_data->base = of_iomap(node, 0);
+       if (!chip_data->base) {
+               pr_err("%pOF: failed to map sirq registers\n", node);
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       for (i = 0; i < NUM_SIRQ; i++) {
+               struct of_phandle_args irq;
+
+               ret = of_irq_parse_one(node, i, &irq);
+               if (ret) {
+                       pr_err("%pOF: failed to parse interrupt %d\n", node, i);
+                       goto out_unmap;
+               }
+
+               if (WARN_ON(irq.args_count != 3)) {
+                       ret = -EINVAL;
+                       goto out_unmap;
+               }
+
+               chip_data->ext_irqs[i] = irq.args[1];
+
+               /* Set 24MHz external interrupt clock freq */
+               owl_sirq_clear_set_extctl(chip_data, 0, INTC_EXTCTL_CLK_SEL, i);
+       }
+
+       domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_SIRQ, node,
+                                         &owl_sirq_domain_ops, chip_data);
+       if (!domain) {
+               pr_err("%pOF: failed to add domain\n", node);
+               ret = -ENOMEM;
+               goto out_unmap;
+       }
+
+       return 0;
+
+out_unmap:
+       iounmap(chip_data->base);
+out_free:
+       kfree(chip_data);
+
+       return ret;
+}
+
+static int __init owl_sirq_s500_of_init(struct device_node *node,
+                                       struct device_node *parent)
+{
+       return owl_sirq_init(&owl_sirq_s500_params, node, parent);
+}
+
+IRQCHIP_DECLARE(owl_sirq_s500, "actions,s500-sirq", owl_sirq_s500_of_init);
+IRQCHIP_DECLARE(owl_sirq_s700, "actions,s700-sirq", owl_sirq_s500_of_init);
+
+static int __init owl_sirq_s900_of_init(struct device_node *node,
+                                       struct device_node *parent)
+{
+       return owl_sirq_init(&owl_sirq_s900_params, node, parent);
+}
+
+IRQCHIP_DECLARE(owl_sirq_s900, "actions,s900-sirq", owl_sirq_s900_of_init);
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
new file mode 100644 (file)
index 0000000..92fb578
--- /dev/null
@@ -0,0 +1,664 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PRU-ICSS INTC IRQChip driver for various TI SoCs
+ *
+ * Copyright (C) 2016-2020 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Author(s):
+ *     Andrew F. Davis <afd@ti.com>
+ *     Suman Anna <s-anna@ti.com>
+ *     Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org> for Texas Instruments
+ *
+ * Copyright (C) 2019 David Lechner <david@lechnology.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+/*
+ * Number of host interrupts reaching the main MPU sub-system. Note that this
+ * is not the same as the total number of host interrupts supported by the PRUSS
+ * INTC instance
+ */
+#define MAX_NUM_HOST_IRQS      8
+
+/* minimum starting host interrupt number for MPU */
+#define FIRST_PRU_HOST_INT     2
+
+/* PRU_ICSS_INTC registers */
+#define PRU_INTC_REVID         0x0000
+#define PRU_INTC_CR            0x0004
+#define PRU_INTC_GER           0x0010
+#define PRU_INTC_GNLR          0x001c
+#define PRU_INTC_SISR          0x0020
+#define PRU_INTC_SICR          0x0024
+#define PRU_INTC_EISR          0x0028
+#define PRU_INTC_EICR          0x002c
+#define PRU_INTC_HIEISR                0x0034
+#define PRU_INTC_HIDISR                0x0038
+#define PRU_INTC_GPIR          0x0080
+#define PRU_INTC_SRSR(x)       (0x0200 + (x) * 4)
+#define PRU_INTC_SECR(x)       (0x0280 + (x) * 4)
+#define PRU_INTC_ESR(x)                (0x0300 + (x) * 4)
+#define PRU_INTC_ECR(x)                (0x0380 + (x) * 4)
+#define PRU_INTC_CMR(x)                (0x0400 + (x) * 4)
+#define PRU_INTC_HMR(x)                (0x0800 + (x) * 4)
+#define PRU_INTC_HIPIR(x)      (0x0900 + (x) * 4)
+#define PRU_INTC_SIPR(x)       (0x0d00 + (x) * 4)
+#define PRU_INTC_SITR(x)       (0x0d80 + (x) * 4)
+#define PRU_INTC_HINLR(x)      (0x1100 + (x) * 4)
+#define PRU_INTC_HIER          0x1500
+
+/* CMR register bit-field macros */
+#define CMR_EVT_MAP_MASK       0xf
+#define CMR_EVT_MAP_BITS       8
+#define CMR_EVT_PER_REG                4
+
+/* HMR register bit-field macros */
+#define HMR_CH_MAP_MASK                0xf
+#define HMR_CH_MAP_BITS                8
+#define HMR_CH_PER_REG         4
+
+/* HIPIR register bit-fields */
+#define INTC_HIPIR_NONE_HINT   0x80000000
+
+#define MAX_PRU_SYS_EVENTS 160
+#define MAX_PRU_CHANNELS 20
+
+/**
+ * struct pruss_intc_map_record - keeps track of actual mapping state
+ * @value: The currently mapped value (channel or host)
+ * @ref_count: Keeps track of number of current users of this resource
+ */
+struct pruss_intc_map_record {
+       u8 value;
+       u8 ref_count;
+};
+
+/**
+ * struct pruss_intc_match_data - match data to handle SoC variations
+ * @num_system_events: number of input system events handled by the PRUSS INTC
+ * @num_host_events: number of host events (which is equal to number of
+ *                  channels) supported by the PRUSS INTC
+ */
+struct pruss_intc_match_data {
+       u8 num_system_events;
+       u8 num_host_events;
+};
+
+/**
+ * struct pruss_intc - PRUSS interrupt controller structure
+ * @event_channel: current state of system event to channel mappings
+ * @channel_host: current state of channel to host mappings
+ * @irqs: kernel irq numbers corresponding to PRUSS host interrupts
+ * @base: base virtual address of INTC register space
+ * @domain: irq domain for this interrupt controller
+ * @soc_config: cached PRUSS INTC IP configuration data
+ * @dev: PRUSS INTC device pointer
+ * @lock: mutex to serialize interrupts mapping
+ */
+struct pruss_intc {
+       struct pruss_intc_map_record event_channel[MAX_PRU_SYS_EVENTS];
+       struct pruss_intc_map_record channel_host[MAX_PRU_CHANNELS];
+       unsigned int irqs[MAX_NUM_HOST_IRQS];
+       void __iomem *base;
+       struct irq_domain *domain;
+       const struct pruss_intc_match_data *soc_config;
+       struct device *dev;
+       struct mutex lock; /* PRUSS INTC lock */
+};
+
+/**
+ * struct pruss_host_irq_data - PRUSS host irq data structure
+ * @intc: PRUSS interrupt controller pointer
+ * @host_irq: host irq number
+ */
+struct pruss_host_irq_data {
+       struct pruss_intc *intc;
+       u8 host_irq;
+};
+
+static inline u32 pruss_intc_read_reg(struct pruss_intc *intc, unsigned int reg)
+{
+       return readl_relaxed(intc->base + reg);
+}
+
+static inline void pruss_intc_write_reg(struct pruss_intc *intc,
+                                       unsigned int reg, u32 val)
+{
+       writel_relaxed(val, intc->base + reg);
+}
+
+static void pruss_intc_update_cmr(struct pruss_intc *intc, unsigned int evt,
+                                 u8 ch)
+{
+       u32 idx, offset, val;
+
+       idx = evt / CMR_EVT_PER_REG;
+       offset = (evt % CMR_EVT_PER_REG) * CMR_EVT_MAP_BITS;
+
+       val = pruss_intc_read_reg(intc, PRU_INTC_CMR(idx));
+       val &= ~(CMR_EVT_MAP_MASK << offset);
+       val |= ch << offset;
+       pruss_intc_write_reg(intc, PRU_INTC_CMR(idx), val);
+
+       dev_dbg(intc->dev, "SYSEV%u -> CH%d (CMR%d 0x%08x)\n", evt, ch,
+               idx, pruss_intc_read_reg(intc, PRU_INTC_CMR(idx)));
+}
+
+static void pruss_intc_update_hmr(struct pruss_intc *intc, u8 ch, u8 host)
+{
+       u32 idx, offset, val;
+
+       idx = ch / HMR_CH_PER_REG;
+       offset = (ch % HMR_CH_PER_REG) * HMR_CH_MAP_BITS;
+
+       val = pruss_intc_read_reg(intc, PRU_INTC_HMR(idx));
+       val &= ~(HMR_CH_MAP_MASK << offset);
+       val |= host << offset;
+       pruss_intc_write_reg(intc, PRU_INTC_HMR(idx), val);
+
+       dev_dbg(intc->dev, "CH%d -> HOST%d (HMR%d 0x%08x)\n", ch, host, idx,
+               pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)));
+}
+
+/**
+ * pruss_intc_map() - configure the PRUSS INTC
+ * @intc: PRUSS interrupt controller pointer
+ * @hwirq: the system event number
+ *
+ * Configures the PRUSS INTC with the provided configuration from the one parsed
+ * in the xlate function.
+ */
+static void pruss_intc_map(struct pruss_intc *intc, unsigned long hwirq)
+{
+       struct device *dev = intc->dev;
+       u8 ch, host, reg_idx;
+       u32 val;
+
+       mutex_lock(&intc->lock);
+
+       intc->event_channel[hwirq].ref_count++;
+
+       ch = intc->event_channel[hwirq].value;
+       host = intc->channel_host[ch].value;
+
+       pruss_intc_update_cmr(intc, hwirq, ch);
+
+       reg_idx = hwirq / 32;
+       val = BIT(hwirq  % 32);
+
+       /* clear and enable system event */
+       pruss_intc_write_reg(intc, PRU_INTC_ESR(reg_idx), val);
+       pruss_intc_write_reg(intc, PRU_INTC_SECR(reg_idx), val);
+
+       if (++intc->channel_host[ch].ref_count == 1) {
+               pruss_intc_update_hmr(intc, ch, host);
+
+               /* enable host interrupts */
+               pruss_intc_write_reg(intc, PRU_INTC_HIEISR, host);
+       }
+
+       dev_dbg(dev, "mapped system_event = %lu channel = %d host = %d",
+               hwirq, ch, host);
+
+       mutex_unlock(&intc->lock);
+}
+
+/**
+ * pruss_intc_unmap() - unconfigure the PRUSS INTC
+ * @intc: PRUSS interrupt controller pointer
+ * @hwirq: the system event number
+ *
+ * Undo whatever was done in pruss_intc_map() for a PRU core.
+ * Mappings are reference counted, so resources are only disabled when there
+ * are no longer any users.
+ */
+static void pruss_intc_unmap(struct pruss_intc *intc, unsigned long hwirq)
+{
+       u8 ch, host, reg_idx;
+       u32 val;
+
+       mutex_lock(&intc->lock);
+
+       ch = intc->event_channel[hwirq].value;
+       host = intc->channel_host[ch].value;
+
+       if (--intc->channel_host[ch].ref_count == 0) {
+               /* disable host interrupts */
+               pruss_intc_write_reg(intc, PRU_INTC_HIDISR, host);
+
+               /* clear the map using reset value 0 */
+               pruss_intc_update_hmr(intc, ch, 0);
+       }
+
+       intc->event_channel[hwirq].ref_count--;
+       reg_idx = hwirq / 32;
+       val = BIT(hwirq  % 32);
+
+       /* disable system events */
+       pruss_intc_write_reg(intc, PRU_INTC_ECR(reg_idx), val);
+       /* clear any pending status */
+       pruss_intc_write_reg(intc, PRU_INTC_SECR(reg_idx), val);
+
+       /* clear the map using reset value 0 */
+       pruss_intc_update_cmr(intc, hwirq, 0);
+
+       dev_dbg(intc->dev, "unmapped system_event = %lu channel = %d host = %d\n",
+               hwirq, ch, host);
+
+       mutex_unlock(&intc->lock);
+}
+
+static void pruss_intc_init(struct pruss_intc *intc)
+{
+       const struct pruss_intc_match_data *soc_config = intc->soc_config;
+       int num_chnl_map_regs, num_host_intr_regs, num_event_type_regs, i;
+
+       num_chnl_map_regs = DIV_ROUND_UP(soc_config->num_system_events,
+                                        CMR_EVT_PER_REG);
+       num_host_intr_regs = DIV_ROUND_UP(soc_config->num_host_events,
+                                         HMR_CH_PER_REG);
+       num_event_type_regs = DIV_ROUND_UP(soc_config->num_system_events, 32);
+
+       /*
+        * configure polarity (SIPR register) to active high and
+        * type (SITR register) to level interrupt for all system events
+        */
+       for (i = 0; i < num_event_type_regs; i++) {
+               pruss_intc_write_reg(intc, PRU_INTC_SIPR(i), 0xffffffff);
+               pruss_intc_write_reg(intc, PRU_INTC_SITR(i), 0);
+       }
+
+       /* clear all interrupt channel map registers, 4 events per register */
+       for (i = 0; i < num_chnl_map_regs; i++)
+               pruss_intc_write_reg(intc, PRU_INTC_CMR(i), 0);
+
+       /* clear all host interrupt map registers, 4 channels per register */
+       for (i = 0; i < num_host_intr_regs; i++)
+               pruss_intc_write_reg(intc, PRU_INTC_HMR(i), 0);
+
+       /* global interrupt enable */
+       pruss_intc_write_reg(intc, PRU_INTC_GER, 1);
+}
+
+static void pruss_intc_irq_ack(struct irq_data *data)
+{
+       struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+       unsigned int hwirq = data->hwirq;
+
+       pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq);
+}
+
+static void pruss_intc_irq_mask(struct irq_data *data)
+{
+       struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+       unsigned int hwirq = data->hwirq;
+
+       pruss_intc_write_reg(intc, PRU_INTC_EICR, hwirq);
+}
+
+static void pruss_intc_irq_unmask(struct irq_data *data)
+{
+       struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+       unsigned int hwirq = data->hwirq;
+
+       pruss_intc_write_reg(intc, PRU_INTC_EISR, hwirq);
+}
+
+static int pruss_intc_irq_reqres(struct irq_data *data)
+{
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
+       return 0;
+}
+
+static void pruss_intc_irq_relres(struct irq_data *data)
+{
+       module_put(THIS_MODULE);
+}
+
+static int pruss_intc_irq_get_irqchip_state(struct irq_data *data,
+                                           enum irqchip_irq_state which,
+                                           bool *state)
+{
+       struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+       u32 reg, mask, srsr;
+
+       if (which != IRQCHIP_STATE_PENDING)
+               return -EINVAL;
+
+       reg = PRU_INTC_SRSR(data->hwirq / 32);
+       mask = BIT(data->hwirq % 32);
+
+       srsr = pruss_intc_read_reg(intc, reg);
+
+       *state = !!(srsr & mask);
+
+       return 0;
+}
+
+static int pruss_intc_irq_set_irqchip_state(struct irq_data *data,
+                                           enum irqchip_irq_state which,
+                                           bool state)
+{
+       struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+
+       if (which != IRQCHIP_STATE_PENDING)
+               return -EINVAL;
+
+       if (state)
+               pruss_intc_write_reg(intc, PRU_INTC_SISR, data->hwirq);
+       else
+               pruss_intc_write_reg(intc, PRU_INTC_SICR, data->hwirq);
+
+       return 0;
+}
+
+static struct irq_chip pruss_irqchip = {
+       .name                   = "pruss-intc",
+       .irq_ack                = pruss_intc_irq_ack,
+       .irq_mask               = pruss_intc_irq_mask,
+       .irq_unmask             = pruss_intc_irq_unmask,
+       .irq_request_resources  = pruss_intc_irq_reqres,
+       .irq_release_resources  = pruss_intc_irq_relres,
+       .irq_get_irqchip_state  = pruss_intc_irq_get_irqchip_state,
+       .irq_set_irqchip_state  = pruss_intc_irq_set_irqchip_state,
+};
+
+static int pruss_intc_validate_mapping(struct pruss_intc *intc, int event,
+                                      int channel, int host)
+{
+       struct device *dev = intc->dev;
+       int ret = 0;
+
+       mutex_lock(&intc->lock);
+
+       /* check if sysevent already assigned */
+       if (intc->event_channel[event].ref_count > 0 &&
+           intc->event_channel[event].value != channel) {
+               dev_err(dev, "event %d (req. ch %d) already assigned to channel %d\n",
+                       event, channel, intc->event_channel[event].value);
+               ret = -EBUSY;
+               goto unlock;
+       }
+
+       /* check if channel already assigned */
+       if (intc->channel_host[channel].ref_count > 0 &&
+           intc->channel_host[channel].value != host) {
+               dev_err(dev, "channel %d (req. host %d) already assigned to host %d\n",
+                       channel, host, intc->channel_host[channel].value);
+               ret = -EBUSY;
+               goto unlock;
+       }
+
+       intc->event_channel[event].value = channel;
+       intc->channel_host[channel].value = host;
+
+unlock:
+       mutex_unlock(&intc->lock);
+       return ret;
+}
+
+static int
+pruss_intc_irq_domain_xlate(struct irq_domain *d, struct device_node *node,
+                           const u32 *intspec, unsigned int intsize,
+                           unsigned long *out_hwirq, unsigned int *out_type)
+{
+       struct pruss_intc *intc = d->host_data;
+       struct device *dev = intc->dev;
+       int ret, sys_event, channel, host;
+
+       if (intsize < 3)
+               return -EINVAL;
+
+       sys_event = intspec[0];
+       if (sys_event < 0 || sys_event >= intc->soc_config->num_system_events) {
+               dev_err(dev, "%d is not valid event number\n", sys_event);
+               return -EINVAL;
+       }
+
+       channel = intspec[1];
+       if (channel < 0 || channel >= intc->soc_config->num_host_events) {
+               dev_err(dev, "%d is not valid channel number", channel);
+               return -EINVAL;
+       }
+
+       host = intspec[2];
+       if (host < 0 || host >= intc->soc_config->num_host_events) {
+               dev_err(dev, "%d is not valid host irq number\n", host);
+               return -EINVAL;
+       }
+
+       /* check if requested sys_event was already mapped, if so validate it */
+       ret = pruss_intc_validate_mapping(intc, sys_event, channel, host);
+       if (ret)
+               return ret;
+
+       *out_hwirq = sys_event;
+       *out_type = IRQ_TYPE_LEVEL_HIGH;
+
+       return 0;
+}
+
+static int pruss_intc_irq_domain_map(struct irq_domain *d, unsigned int virq,
+                                    irq_hw_number_t hw)
+{
+       struct pruss_intc *intc = d->host_data;
+
+       pruss_intc_map(intc, hw);
+
+       irq_set_chip_data(virq, intc);
+       irq_set_chip_and_handler(virq, &pruss_irqchip, handle_level_irq);
+
+       return 0;
+}
+
+static void pruss_intc_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
+{
+       struct pruss_intc *intc = d->host_data;
+       unsigned long hwirq = irqd_to_hwirq(irq_get_irq_data(virq));
+
+       irq_set_chip_and_handler(virq, NULL, NULL);
+       irq_set_chip_data(virq, NULL);
+       pruss_intc_unmap(intc, hwirq);
+}
+
+static const struct irq_domain_ops pruss_intc_irq_domain_ops = {
+       .xlate  = pruss_intc_irq_domain_xlate,
+       .map    = pruss_intc_irq_domain_map,
+       .unmap  = pruss_intc_irq_domain_unmap,
+};
+
+static void pruss_intc_irq_handler(struct irq_desc *desc)
+{
+       unsigned int irq = irq_desc_get_irq(desc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct pruss_host_irq_data *host_irq_data = irq_get_handler_data(irq);
+       struct pruss_intc *intc = host_irq_data->intc;
+       u8 host_irq = host_irq_data->host_irq + FIRST_PRU_HOST_INT;
+
+       chained_irq_enter(chip, desc);
+
+       while (true) {
+               u32 hipir;
+               unsigned int virq;
+               int hwirq;
+
+               /* get highest priority pending PRUSS system event */
+               hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(host_irq));
+               if (hipir & INTC_HIPIR_NONE_HINT)
+                       break;
+
+               hwirq = hipir & GENMASK(9, 0);
+               virq = irq_find_mapping(intc->domain, hwirq);
+
+               /*
+                * NOTE: manually ACK any system events that do not have a
+                * handler mapped yet
+                */
+               if (WARN_ON_ONCE(!virq))
+                       pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq);
+               else
+                       generic_handle_irq(virq);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static const char * const irq_names[MAX_NUM_HOST_IRQS] = {
+       "host_intr0", "host_intr1", "host_intr2", "host_intr3",
+       "host_intr4", "host_intr5", "host_intr6", "host_intr7",
+};
+
+static int pruss_intc_probe(struct platform_device *pdev)
+{
+       const struct pruss_intc_match_data *data;
+       struct device *dev = &pdev->dev;
+       struct pruss_intc *intc;
+       struct pruss_host_irq_data *host_data;
+       int i, irq, ret;
+       u8 max_system_events, irqs_reserved = 0;
+
+       data = of_device_get_match_data(dev);
+       if (!data)
+               return -ENODEV;
+
+       max_system_events = data->num_system_events;
+
+       intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL);
+       if (!intc)
+               return -ENOMEM;
+
+       intc->soc_config = data;
+       intc->dev = dev;
+       platform_set_drvdata(pdev, intc);
+
+       intc->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(intc->base))
+               return PTR_ERR(intc->base);
+
+       ret = of_property_read_u8(dev->of_node, "ti,irqs-reserved",
+                                 &irqs_reserved);
+
+       /*
+        * The irqs-reserved is used only for some SoC's therefore not having
+        * this property is still valid
+        */
+       if (ret < 0 && ret != -EINVAL)
+               return ret;
+
+       pruss_intc_init(intc);
+
+       mutex_init(&intc->lock);
+
+       intc->domain = irq_domain_add_linear(dev->of_node, max_system_events,
+                                            &pruss_intc_irq_domain_ops, intc);
+       if (!intc->domain)
+               return -ENOMEM;
+
+       for (i = 0; i < MAX_NUM_HOST_IRQS; i++) {
+               if (irqs_reserved & BIT(i))
+                       continue;
+
+               irq = platform_get_irq_byname(pdev, irq_names[i]);
+               if (irq <= 0) {
+                       ret = (irq == 0) ? -EINVAL : irq;
+                       goto fail_irq;
+               }
+
+               intc->irqs[i] = irq;
+
+               host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL);
+               if (!host_data) {
+                       ret = -ENOMEM;
+                       goto fail_irq;
+               }
+
+               host_data->intc = intc;
+               host_data->host_irq = i;
+
+               irq_set_handler_data(irq, host_data);
+               irq_set_chained_handler(irq, pruss_intc_irq_handler);
+       }
+
+       return 0;
+
+fail_irq:
+       while (--i >= 0) {
+               if (intc->irqs[i])
+                       irq_set_chained_handler_and_data(intc->irqs[i], NULL,
+                                                        NULL);
+       }
+
+       irq_domain_remove(intc->domain);
+
+       return ret;
+}
+
+static int pruss_intc_remove(struct platform_device *pdev)
+{
+       struct pruss_intc *intc = platform_get_drvdata(pdev);
+       u8 max_system_events = intc->soc_config->num_system_events;
+       unsigned int hwirq;
+       int i;
+
+       for (i = 0; i < MAX_NUM_HOST_IRQS; i++) {
+               if (intc->irqs[i])
+                       irq_set_chained_handler_and_data(intc->irqs[i], NULL,
+                                                        NULL);
+       }
+
+       for (hwirq = 0; hwirq < max_system_events; hwirq++)
+               irq_dispose_mapping(irq_find_mapping(intc->domain, hwirq));
+
+       irq_domain_remove(intc->domain);
+
+       return 0;
+}
+
+static const struct pruss_intc_match_data pruss_intc_data = {
+       .num_system_events = 64,
+       .num_host_events = 10,
+};
+
+static const struct pruss_intc_match_data icssg_intc_data = {
+       .num_system_events = 160,
+       .num_host_events = 20,
+};
+
+static const struct of_device_id pruss_intc_of_match[] = {
+       {
+               .compatible = "ti,pruss-intc",
+               .data = &pruss_intc_data,
+       },
+       {
+               .compatible = "ti,icssg-intc",
+               .data = &icssg_intc_data,
+       },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, pruss_intc_of_match);
+
+static struct platform_driver pruss_intc_driver = {
+       .driver = {
+               .name = "pruss-intc",
+               .of_match_table = pruss_intc_of_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe  = pruss_intc_probe,
+       .remove = pruss_intc_remove,
+};
+module_platform_driver(pruss_intc_driver);
+
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
+MODULE_AUTHOR("Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>");
+MODULE_DESCRIPTION("TI PRU-ICSS INTC Driver");
+MODULE_LICENSE("GPL v2");
index 03a36be..0c2c61d 100644 (file)
@@ -416,6 +416,16 @@ static void stm32_irq_ack(struct irq_data *d)
        irq_gc_unlock(gc);
 }
 
+/* directly set the target bit without reading first. */
+static inline void stm32_exti_write_bit(struct irq_data *d, u32 reg)
+{
+       struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
+       void __iomem *base = chip_data->host_data->base;
+       u32 val = BIT(d->hwirq % IRQS_PER_BANK);
+
+       writel_relaxed(val, base + reg);
+}
+
 static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg)
 {
        struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
@@ -449,9 +459,9 @@ static void stm32_exti_h_eoi(struct irq_data *d)
 
        raw_spin_lock(&chip_data->rlock);
 
-       stm32_exti_set_bit(d, stm32_bank->rpr_ofst);
+       stm32_exti_write_bit(d, stm32_bank->rpr_ofst);
        if (stm32_bank->fpr_ofst != UNDEF_REG)
-               stm32_exti_set_bit(d, stm32_bank->fpr_ofst);
+               stm32_exti_write_bit(d, stm32_bank->fpr_ofst);
 
        raw_spin_unlock(&chip_data->rlock);
 
index b7cc5d6..e0cceb8 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/irq.h>
 #include <linux/irqchip.h>
 #include <linux/irqdomain.h>
 #include <linux/interrupt.h>
@@ -83,6 +84,7 @@ struct ti_sci_inta_vint_desc {
  * @vint_mutex:                Mutex to protect vint_list
  * @base:              Base address of the memory mapped IO registers
  * @pdev:              Pointer to platform device.
+ * @ti_sci_id:         TI-SCI device identifier
  */
 struct ti_sci_inta_irq_domain {
        const struct ti_sci_handle *sci;
@@ -93,6 +95,7 @@ struct ti_sci_inta_irq_domain {
        struct mutex vint_mutex;
        void __iomem *base;
        struct platform_device *pdev;
+       u32 ti_sci_id;
 };
 
 #define to_vint_desc(e, i) container_of(e, struct ti_sci_inta_vint_desc, \
@@ -129,6 +132,37 @@ static void ti_sci_inta_irq_handler(struct irq_desc *desc)
 }
 
 /**
+ * ti_sci_inta_xlate_irq() - Translate hwirq to parent's hwirq.
+ * @inta:      IRQ domain corresponding to Interrupt Aggregator
+ * @irq:       Hardware irq corresponding to the above irq domain
+ *
+ * Return parent irq number if translation is available else -ENOENT.
+ */
+static int ti_sci_inta_xlate_irq(struct ti_sci_inta_irq_domain *inta,
+                                u16 vint_id)
+{
+       struct device_node *np = dev_of_node(&inta->pdev->dev);
+       u32 base, parent_base, size;
+       const __be32 *range;
+       int len;
+
+       range = of_get_property(np, "ti,interrupt-ranges", &len);
+       if (!range)
+               return vint_id;
+
+       for (len /= sizeof(*range); len >= 3; len -= 3) {
+               base = be32_to_cpu(*range++);
+               parent_base = be32_to_cpu(*range++);
+               size = be32_to_cpu(*range++);
+
+               if (base <= vint_id && vint_id < base + size)
+                       return vint_id - base + parent_base;
+       }
+
+       return -ENOENT;
+}
+
+/**
  * ti_sci_inta_alloc_parent_irq() - Allocate parent irq to Interrupt aggregator
  * @domain:    IRQ domain corresponding to Interrupt Aggregator
  *
@@ -139,30 +173,52 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
        struct ti_sci_inta_irq_domain *inta = domain->host_data;
        struct ti_sci_inta_vint_desc *vint_desc;
        struct irq_fwspec parent_fwspec;
+       struct device_node *parent_node;
        unsigned int parent_virq;
+       int p_hwirq, ret;
        u16 vint_id;
 
        vint_id = ti_sci_get_free_resource(inta->vint);
        if (vint_id == TI_SCI_RESOURCE_NULL)
                return ERR_PTR(-EINVAL);
 
+       p_hwirq = ti_sci_inta_xlate_irq(inta, vint_id);
+       if (p_hwirq < 0) {
+               ret = p_hwirq;
+               goto free_vint;
+       }
+
        vint_desc = kzalloc(sizeof(*vint_desc), GFP_KERNEL);
-       if (!vint_desc)
-               return ERR_PTR(-ENOMEM);
+       if (!vint_desc) {
+               ret = -ENOMEM;
+               goto free_vint;
+       }
 
        vint_desc->domain = domain;
        vint_desc->vint_id = vint_id;
        INIT_LIST_HEAD(&vint_desc->list);
 
-       parent_fwspec.fwnode = of_node_to_fwnode(of_irq_find_parent(dev_of_node(&inta->pdev->dev)));
-       parent_fwspec.param_count = 2;
-       parent_fwspec.param[0] = inta->pdev->id;
-       parent_fwspec.param[1] = vint_desc->vint_id;
+       parent_node = of_irq_find_parent(dev_of_node(&inta->pdev->dev));
+       parent_fwspec.fwnode = of_node_to_fwnode(parent_node);
+
+       if (of_device_is_compatible(parent_node, "arm,gic-v3")) {
+               /* Parent is GIC */
+               parent_fwspec.param_count = 3;
+               parent_fwspec.param[0] = 0;
+               parent_fwspec.param[1] = p_hwirq - 32;
+               parent_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
+       } else {
+               /* Parent is Interrupt Router */
+               parent_fwspec.param_count = 1;
+               parent_fwspec.param[0] = p_hwirq;
+       }
 
        parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
        if (parent_virq == 0) {
-               kfree(vint_desc);
-               return ERR_PTR(-EINVAL);
+               dev_err(&inta->pdev->dev, "Parent IRQ allocation failed\n");
+               ret = -EINVAL;
+               goto free_vint_desc;
+
        }
        vint_desc->parent_virq = parent_virq;
 
@@ -171,6 +227,11 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
                                         ti_sci_inta_irq_handler, vint_desc);
 
        return vint_desc;
+free_vint_desc:
+       kfree(vint_desc);
+free_vint:
+       ti_sci_release_resource(inta->vint, vint_id);
+       return ERR_PTR(ret);
 }
 
 /**
@@ -202,7 +263,7 @@ static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_event(struct ti_sci_inta
 
        err = inta->sci->ops.rm_irq_ops.set_event_map(inta->sci,
                                                      dev_id, dev_index,
-                                                     inta->pdev->id,
+                                                     inta->ti_sci_id,
                                                      vint_desc->vint_id,
                                                      event_desc->global_event,
                                                      free_bit);
@@ -299,7 +360,7 @@ static void ti_sci_inta_free_irq(struct ti_sci_inta_event_desc *event_desc,
        inta->sci->ops.rm_irq_ops.free_event_map(inta->sci,
                                                 HWIRQ_TO_DEVID(hwirq),
                                                 HWIRQ_TO_IRQID(hwirq),
-                                                inta->pdev->id,
+                                                inta->ti_sci_id,
                                                 vint_desc->vint_id,
                                                 event_desc->global_event,
                                                 event_desc->vint_bit);
@@ -539,29 +600,25 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
 
        inta->pdev = pdev;
        inta->sci = devm_ti_sci_get_by_phandle(dev, "ti,sci");
-       if (IS_ERR(inta->sci)) {
-               ret = PTR_ERR(inta->sci);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "ti,sci read fail %d\n", ret);
-               inta->sci = NULL;
-               return ret;
-       }
+       if (IS_ERR(inta->sci))
+               return dev_err_probe(dev, PTR_ERR(inta->sci),
+                                    "ti,sci read fail\n");
 
-       ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id", &pdev->id);
+       ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id", &inta->ti_sci_id);
        if (ret) {
                dev_err(dev, "missing 'ti,sci-dev-id' property\n");
                return -EINVAL;
        }
 
-       inta->vint = devm_ti_sci_get_of_resource(inta->sci, dev, pdev->id,
-                                                "ti,sci-rm-range-vint");
+       inta->vint = devm_ti_sci_get_resource(inta->sci, dev, inta->ti_sci_id,
+                                             TI_SCI_RESASG_SUBTYPE_IA_VINT);
        if (IS_ERR(inta->vint)) {
                dev_err(dev, "VINT resource allocation failed\n");
                return PTR_ERR(inta->vint);
        }
 
-       inta->global_event = devm_ti_sci_get_of_resource(inta->sci, dev, pdev->id,
-                                               "ti,sci-rm-range-global-event");
+       inta->global_event = devm_ti_sci_get_resource(inta->sci, dev, inta->ti_sci_id,
+                                                     TI_SCI_RESASG_SUBTYPE_GLOBAL_EVENT_SEVT);
        if (IS_ERR(inta->global_event)) {
                dev_err(dev, "Global event resource allocation failed\n");
                return PTR_ERR(inta->global_event);
@@ -592,6 +649,8 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&inta->vint_list);
        mutex_init(&inta->vint_mutex);
 
+       dev_info(dev, "Interrupt Aggregator domain %d created\n", pdev->id);
+
        return 0;
 }
 
index 5ea148f..ac9d6d6 100644 (file)
 #include <linux/of_irq.h>
 #include <linux/soc/ti/ti_sci_protocol.h>
 
-#define TI_SCI_DEV_ID_MASK     0xffff
-#define TI_SCI_DEV_ID_SHIFT    16
-#define TI_SCI_IRQ_ID_MASK     0xffff
-#define TI_SCI_IRQ_ID_SHIFT    0
-#define HWIRQ_TO_DEVID(hwirq)  (((hwirq) >> (TI_SCI_DEV_ID_SHIFT)) & \
-                                (TI_SCI_DEV_ID_MASK))
-#define HWIRQ_TO_IRQID(hwirq)  ((hwirq) & (TI_SCI_IRQ_ID_MASK))
-#define TO_HWIRQ(dev, index)   ((((dev) & TI_SCI_DEV_ID_MASK) << \
-                                TI_SCI_DEV_ID_SHIFT) | \
-                               ((index) & TI_SCI_IRQ_ID_MASK))
-
 /**
  * struct ti_sci_intr_irq_domain - Structure representing a TISCI based
  *                                Interrupt Router IRQ domain.
  * @sci:       Pointer to TISCI handle
- * @dst_irq:   TISCI resource pointer representing GIC irq controller.
- * @dst_id:    TISCI device ID of the GIC irq controller.
+ * @out_irqs:  TISCI resource pointer representing INTR irqs.
+ * @dev:       Struct device pointer.
+ * @ti_sci_id: TI-SCI device identifier
  * @type:      Specifies the trigger type supported by this Interrupt Router
  */
 struct ti_sci_intr_irq_domain {
        const struct ti_sci_handle *sci;
-       struct ti_sci_resource *dst_irq;
-       u32 dst_id;
+       struct ti_sci_resource *out_irqs;
+       struct device *dev;
+       u32 ti_sci_id;
        u32 type;
 };
 
@@ -70,16 +61,45 @@ static int ti_sci_intr_irq_domain_translate(struct irq_domain *domain,
 {
        struct ti_sci_intr_irq_domain *intr = domain->host_data;
 
-       if (fwspec->param_count != 2)
+       if (fwspec->param_count != 1)
                return -EINVAL;
 
-       *hwirq = TO_HWIRQ(fwspec->param[0], fwspec->param[1]);
+       *hwirq = fwspec->param[0];
        *type = intr->type;
 
        return 0;
 }
 
 /**
+ * ti_sci_intr_xlate_irq() - Translate hwirq to parent's hwirq.
+ * @intr:      IRQ domain corresponding to Interrupt Router
+ * @irq:       Hardware irq corresponding to the above irq domain
+ *
+ * Return parent irq number if translation is available else -ENOENT.
+ */
+static int ti_sci_intr_xlate_irq(struct ti_sci_intr_irq_domain *intr, u32 irq)
+{
+       struct device_node *np = dev_of_node(intr->dev);
+       u32 base, pbase, size, len;
+       const __be32 *range;
+
+       range = of_get_property(np, "ti,interrupt-ranges", &len);
+       if (!range)
+               return irq;
+
+       for (len /= sizeof(*range); len >= 3; len -= 3) {
+               base = be32_to_cpu(*range++);
+               pbase = be32_to_cpu(*range++);
+               size = be32_to_cpu(*range++);
+
+               if (base <= irq && irq < base + size)
+                       return irq - base + pbase;
+       }
+
+       return -ENOENT;
+}
+
+/**
  * ti_sci_intr_irq_domain_free() - Free the specified IRQs from the domain.
  * @domain:    Domain to which the irqs belong
  * @virq:      Linux virtual IRQ to be freed.
@@ -89,66 +109,76 @@ static void ti_sci_intr_irq_domain_free(struct irq_domain *domain,
                                        unsigned int virq, unsigned int nr_irqs)
 {
        struct ti_sci_intr_irq_domain *intr = domain->host_data;
-       struct irq_data *data, *parent_data;
-       u16 dev_id, irq_index;
+       struct irq_data *data;
+       int out_irq;
 
-       parent_data = irq_domain_get_irq_data(domain->parent, virq);
        data = irq_domain_get_irq_data(domain, virq);
-       irq_index = HWIRQ_TO_IRQID(data->hwirq);
-       dev_id = HWIRQ_TO_DEVID(data->hwirq);
+       out_irq = (uintptr_t)data->chip_data;
 
-       intr->sci->ops.rm_irq_ops.free_irq(intr->sci, dev_id, irq_index,
-                                          intr->dst_id, parent_data->hwirq);
-       ti_sci_release_resource(intr->dst_irq, parent_data->hwirq);
+       intr->sci->ops.rm_irq_ops.free_irq(intr->sci,
+                                          intr->ti_sci_id, data->hwirq,
+                                          intr->ti_sci_id, out_irq);
+       ti_sci_release_resource(intr->out_irqs, out_irq);
        irq_domain_free_irqs_parent(domain, virq, 1);
        irq_domain_reset_irq_data(data);
 }
 
 /**
- * ti_sci_intr_alloc_gic_irq() - Allocate GIC specific IRQ
+ * ti_sci_intr_alloc_parent_irq() - Allocate parent IRQ
  * @domain:    Pointer to the interrupt router IRQ domain
  * @virq:      Corresponding Linux virtual IRQ number
  * @hwirq:     Corresponding hwirq for the IRQ within this IRQ domain
  *
- * Returns 0 if all went well else appropriate error pointer.
+ * Returns parent irq if all went well else appropriate error pointer.
  */
-static int ti_sci_intr_alloc_gic_irq(struct irq_domain *domain,
-                                    unsigned int virq, u32 hwirq)
+static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain,
+                                       unsigned int virq, u32 hwirq)
 {
        struct ti_sci_intr_irq_domain *intr = domain->host_data;
+       struct device_node *parent_node;
        struct irq_fwspec fwspec;
-       u16 dev_id, irq_index;
-       u16 dst_irq;
-       int err;
-
-       dev_id = HWIRQ_TO_DEVID(hwirq);
-       irq_index = HWIRQ_TO_IRQID(hwirq);
+       int p_hwirq, err = 0;
+       u16 out_irq;
 
-       dst_irq = ti_sci_get_free_resource(intr->dst_irq);
-       if (dst_irq == TI_SCI_RESOURCE_NULL)
+       out_irq = ti_sci_get_free_resource(intr->out_irqs);
+       if (out_irq == TI_SCI_RESOURCE_NULL)
                return -EINVAL;
 
-       fwspec.fwnode = domain->parent->fwnode;
-       fwspec.param_count = 3;
-       fwspec.param[0] = 0;    /* SPI */
-       fwspec.param[1] = dst_irq - 32; /* SPI offset */
-       fwspec.param[2] = intr->type;
+       p_hwirq = ti_sci_intr_xlate_irq(intr, out_irq);
+       if (p_hwirq < 0)
+               goto err_irqs;
+
+       parent_node = of_irq_find_parent(dev_of_node(intr->dev));
+       fwspec.fwnode = of_node_to_fwnode(parent_node);
+
+       if (of_device_is_compatible(parent_node, "arm,gic-v3")) {
+               /* Parent is GIC */
+               fwspec.param_count = 3;
+               fwspec.param[0] = 0;    /* SPI */
+               fwspec.param[1] = p_hwirq - 32; /* SPI offset */
+               fwspec.param[2] = intr->type;
+       } else {
+               /* Parent is Interrupt Router */
+               fwspec.param_count = 1;
+               fwspec.param[0] = p_hwirq;
+       }
 
        err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
        if (err)
                goto err_irqs;
 
-       err = intr->sci->ops.rm_irq_ops.set_irq(intr->sci, dev_id, irq_index,
-                                               intr->dst_id, dst_irq);
+       err = intr->sci->ops.rm_irq_ops.set_irq(intr->sci,
+                                               intr->ti_sci_id, hwirq,
+                                               intr->ti_sci_id, out_irq);
        if (err)
                goto err_msg;
 
-       return 0;
+       return p_hwirq;
 
 err_msg:
        irq_domain_free_irqs_parent(domain, virq, 1);
 err_irqs:
-       ti_sci_release_resource(intr->dst_irq, dst_irq);
+       ti_sci_release_resource(intr->out_irqs, out_irq);
        return err;
 }
 
@@ -168,18 +198,19 @@ static int ti_sci_intr_irq_domain_alloc(struct irq_domain *domain,
        struct irq_fwspec *fwspec = data;
        unsigned long hwirq;
        unsigned int flags;
-       int err;
+       int err, p_hwirq;
 
        err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &flags);
        if (err)
                return err;
 
-       err = ti_sci_intr_alloc_gic_irq(domain, virq, hwirq);
-       if (err)
-               return err;
+       p_hwirq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq);
+       if (p_hwirq < 0)
+               return p_hwirq;
 
        irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
-                                     &ti_sci_intr_irq_chip, NULL);
+                                     &ti_sci_intr_irq_chip,
+                                     (void *)(uintptr_t)p_hwirq);
 
        return 0;
 }
@@ -214,6 +245,7 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
        if (!intr)
                return -ENOMEM;
 
+       intr->dev = dev;
        ret = of_property_read_u32(dev_of_node(dev), "ti,intr-trigger-type",
                                   &intr->type);
        if (ret) {
@@ -222,27 +254,23 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
        }
 
        intr->sci = devm_ti_sci_get_by_phandle(dev, "ti,sci");
-       if (IS_ERR(intr->sci)) {
-               ret = PTR_ERR(intr->sci);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "ti,sci read fail %d\n", ret);
-               intr->sci = NULL;
-               return ret;
-       }
+       if (IS_ERR(intr->sci))
+               return dev_err_probe(dev, PTR_ERR(intr->sci),
+                                    "ti,sci read fail\n");
 
-       ret = of_property_read_u32(dev_of_node(dev), "ti,sci-dst-id",
-                                  &intr->dst_id);
+       ret = of_property_read_u32(dev_of_node(dev), "ti,sci-dev-id",
+                                  &intr->ti_sci_id);
        if (ret) {
-               dev_err(dev, "missing 'ti,sci-dst-id' property\n");
+               dev_err(dev, "missing 'ti,sci-dev-id' property\n");
                return -EINVAL;
        }
 
-       intr->dst_irq = devm_ti_sci_get_of_resource(intr->sci, dev,
-                                                   intr->dst_id,
-                                                   "ti,sci-rm-range-girq");
-       if (IS_ERR(intr->dst_irq)) {
+       intr->out_irqs = devm_ti_sci_get_resource(intr->sci, dev,
+                                                 intr->ti_sci_id,
+                                                 TI_SCI_RESASG_SUBTYPE_IR_OUTPUT);
+       if (IS_ERR(intr->out_irqs)) {
                dev_err(dev, "Destination irq resource allocation failed\n");
-               return PTR_ERR(intr->dst_irq);
+               return PTR_ERR(intr->out_irqs);
        }
 
        domain = irq_domain_add_hierarchy(parent_domain, 0, 0, dev_of_node(dev),
@@ -252,6 +280,8 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       dev_info(dev, "Interrupt Router %d domain created\n", intr->ti_sci_id);
+
        return 0;
 }
 
index bc235db..e460363 100644 (file)
@@ -455,7 +455,7 @@ static void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
                return;
        default:
                printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
-               /* fall through */
+               fallthrough;
        case AMBA_VENDOR_ARM:
                break;
        }
index 1bb0e36..d234115 100644 (file)
@@ -52,7 +52,7 @@ int platform_irqchip_probe(struct platform_device *pdev)
         * interrupt controller. The actual initialization callback of this
         * interrupt controller can check for specific domains as necessary.
         */
-       if (par_np && !irq_find_matching_host(np, DOMAIN_BUS_ANY))
+       if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY))
                return -EPROBE_DEFER;
 
        return irq_init_cb(np, par_np);
index c1c5dfa..bd39e9d 100644 (file)
 #include <linux/irqdomain.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
-#include <linux/of_irq.h>
 #include <linux/soc/qcom/irq.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
@@ -207,7 +205,8 @@ static struct irq_chip qcom_pdc_gic_chip = {
        .irq_set_type           = qcom_pdc_gic_set_type,
        .flags                  = IRQCHIP_MASK_ON_SUSPEND |
                                  IRQCHIP_SET_TYPE_MASKED |
-                                 IRQCHIP_SKIP_SET_WAKE,
+                                 IRQCHIP_SKIP_SET_WAKE |
+                                 IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,
        .irq_set_vcpu_affinity  = irq_chip_set_vcpu_affinity_parent,
        .irq_set_affinity       = irq_chip_set_affinity_parent,
 };
@@ -342,7 +341,8 @@ static const struct irq_domain_ops qcom_pdc_gpio_ops = {
 
 static int pdc_setup_pin_mapping(struct device_node *np)
 {
-       int ret, n;
+       int ret, n, i;
+       u32 irq_index, reg_index, val;
 
        n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32));
        if (n <= 0 || n % 3)
@@ -371,6 +371,14 @@ static int pdc_setup_pin_mapping(struct device_node *np)
                                                 &pdc_region[n].cnt);
                if (ret)
                        return ret;
+
+               for (i = 0; i < pdc_region[n].cnt; i++) {
+                       reg_index = (i + pdc_region[n].pin_base) >> 5;
+                       irq_index = (i + pdc_region[n].pin_base) & 0x1f;
+                       val = pdc_reg_read(IRQ_ENABLE_BANK, reg_index);
+                       val &= ~BIT(irq_index);
+                       pdc_reg_write(IRQ_ENABLE_BANK, reg_index, val);
+               }
        }
 
        return 0;
@@ -432,8 +440,4 @@ fail:
        return ret;
 }
 
-IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_pdc)
-IRQCHIP_MATCH("qcom,pdc", qcom_pdc_init)
-IRQCHIP_PLATFORM_DRIVER_END(qcom_pdc)
-MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller");
-MODULE_LICENSE("GPL v2");
+IRQCHIP_DECLARE(qcom_pdc, "qcom,pdc", qcom_pdc_init);
index ecc1ef6..f68569b 100644 (file)
@@ -348,7 +348,7 @@ modehdlc(struct bchannel *bch, int protocol)
        switch (protocol) {
        case -1: /* used for init */
                bch->state = -1;
-               /* fall through */
+               fallthrough;
        case ISDN_P_NONE:
                if (bch->state == ISDN_P_NONE)
                        break;
index b0d7723..448ded8 100644 (file)
@@ -121,7 +121,6 @@ setup_embedded(struct hfc_multi *hc, struct hm_map *m)
        case HFC_IO_MODE_EMBSD:
                test_and_set_bit(HFC_CHIP_EMBSD, &hc->chip);
                hc->slots = 128; /* required */
-               /* fall through */
                hc->HFC_outb = HFC_outb_embsd;
                hc->HFC_inb = HFC_inb_embsd;
                hc->HFC_inw = HFC_inw_embsd;
index 904a4f4..56bd2e9 100644 (file)
@@ -1280,7 +1280,7 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol)
        case (-1): /* used for init */
                bch->state = -1;
                bch->nr = bc;
-               /* fall through */
+               fallthrough;
        case (ISDN_P_NONE):
                if (bch->state == ISDN_P_NONE)
                        return 0;
index 4274906..7006199 100644 (file)
@@ -695,7 +695,7 @@ hfcsusb_setup_bch(struct bchannel *bch, int protocol)
        switch (protocol) {
        case (-1):      /* used for init */
                bch->state = -1;
-               /* fall through */
+               fallthrough;
        case (ISDN_P_NONE):
                if (bch->state == ISDN_P_NONE)
                        return 0; /* already in idle state */
index 9fea16e..985367e 100644 (file)
@@ -397,7 +397,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen,
                                dsize--;
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
                case HDLC_SENDFLAG_ONE:
                        if (hdlc->bit_shift == 8) {
                                hdlc->cbin = hdlc->ffvalue >>
index f4cb297..a16c7a2 100644 (file)
@@ -875,7 +875,7 @@ release_card(struct inf_hw *card) {
                                release_card(card->sc[i]);
                        card->sc[i] = NULL;
                }
-               /* fall through */
+               fallthrough;
        default:
                pci_disable_device(card->pdev);
                pci_set_drvdata(card->pdev, NULL);
index 11e8c7d..5694340 100644 (file)
@@ -957,7 +957,7 @@ isar_pump_statev_fax(struct isar_ch *ch, u8 devt) {
                                break;
                        case PCTRL_CMD_FTM:
                                p1 = 2;
-                               /* fall through */
+                               fallthrough;
                        case PCTRL_CMD_FTH:
                                send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
                                          PCTRL_CMD_SILON, 1, &p1);
@@ -1163,7 +1163,7 @@ setup_pump(struct isar_ch *ch) {
                        send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG,
                                  PMOD_DTMF, 1, param);
                }
-               /* fall through */
+               fallthrough;
        case ISDN_P_B_MODEM_ASYNC:
                ctrl = PMOD_DATAMODEM;
                if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) {
@@ -1255,7 +1255,7 @@ setup_iom2(struct isar_ch *ch) {
        case ISDN_P_B_MODEM_ASYNC:
        case ISDN_P_B_T30_FAX:
                cmsb |= IOM_CTRL_RCV;
-               /* fall through */
+               fallthrough;
        case ISDN_P_B_L2DTMF:
                if (test_bit(FLG_DTMFSEND, &ch->bch.Flags))
                        cmsb |= IOM_CTRL_RCV;
@@ -1548,7 +1548,7 @@ isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
                                ich->is->name, hh->id);
                        ret = -EINVAL;
                }
-               /* fall through */
+               fallthrough;
        default:
                pr_info("%s: %s unknown prim(%x,%x)\n",
                        ich->is->name, __func__, hh->prim, hh->id);
index 27aa329..c2f76f3 100644 (file)
@@ -528,7 +528,7 @@ create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch,
                rq.protocol = ISDN_P_NT_S0;
                if (dev->Dprotocols & (1 << ISDN_P_NT_E1))
                        rq.protocol = ISDN_P_NT_E1;
-               /* fall through */
+               fallthrough;
        case ISDN_P_LAPD_TE:
                ch->recv = mISDN_queue_message;
                ch->peer = &dev->D.st->own;
index b413baf..97c6873 100644 (file)
@@ -301,7 +301,7 @@ void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type)
        switch (type) {
        case PBLK_WRITE:
                kfree(((struct pblk_c_ctx *)nvm_rq_to_pdu(rqd))->lun_bitmap);
-               /* fall through */
+               fallthrough;
        case PBLK_WRITE_INT:
                pool = &pblk->w_rq_pool;
                break;
index 75482ee..994ba5c 100644 (file)
@@ -881,7 +881,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
                }
                if (hid->name[0])
                        break;
-               /* else fall through */
+               fallthrough;
 
        default:
                pr_info("Trying to register unknown ADB device to input layer.\n");
index 23f1f41..9668458 100644 (file)
@@ -852,7 +852,7 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
                break;
        case SMU_I2C_TRANSFER_COMBINED:
                cmd->info.devaddr &= 0xfe;
-               /* fall through */
+               fallthrough;
        case SMU_I2C_TRANSFER_STDSUB:
                if (cmd->info.sublen > 3)
                        return -EINVAL;
index 77fbfd5..c1227bd 100644 (file)
@@ -608,7 +608,7 @@ static void do_journal_discard(struct cache *ca)
                        ca->sb.njournal_buckets;
 
                atomic_set(&ja->discard_in_flight, DISCARD_READY);
-               /* fallthrough */
+               fallthrough;
 
        case DISCARD_READY:
                if (ja->discard_idx == ja->last_idx)
index 62fb917..ae380bc 100644 (file)
@@ -33,27 +33,27 @@ int bch_ ## name ## _h(const char *cp, type *res)           \
        case 'y':                                               \
        case 'z':                                               \
                u++;                                            \
-               /* fall through */                              \
+               fallthrough;                                    \
        case 'e':                                               \
                u++;                                            \
-               /* fall through */                              \
+               fallthrough;                                    \
        case 'p':                                               \
                u++;                                            \
-               /* fall through */                              \
+               fallthrough;                                    \
        case 't':                                               \
                u++;                                            \
-               /* fall through */                              \
+               fallthrough;                                    \
        case 'g':                                               \
                u++;                                            \
-               /* fall through */                              \
+               fallthrough;                                    \
        case 'm':                                               \
                u++;                                            \
-               /* fall through */                              \
+               fallthrough;                                    \
        case 'k':                                               \
                u++;                                            \
                if (e++ == cp)                                  \
                        return -EINVAL;                         \
-               /* fall through */                              \
+               fallthrough;                                    \
        case '\n':                                              \
        case '\0':                                              \
                if (*e == '\n')                                 \
index 151aa95..af6d4f8 100644 (file)
@@ -537,12 +537,16 @@ static int __create_persistent_data_objects(struct dm_cache_metadata *cmd,
                                          CACHE_MAX_CONCURRENT_LOCKS);
        if (IS_ERR(cmd->bm)) {
                DMERR("could not create block manager");
-               return PTR_ERR(cmd->bm);
+               r = PTR_ERR(cmd->bm);
+               cmd->bm = NULL;
+               return r;
        }
 
        r = __open_or_format_metadata(cmd, may_format_device);
-       if (r)
+       if (r) {
                dm_block_manager_destroy(cmd->bm);
+               cmd->bm = NULL;
+       }
 
        return r;
 }
index 1489607..380386c 100644 (file)
@@ -739,7 +739,7 @@ static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
        u8 buf[MAX_CIPHER_BLOCKSIZE] __aligned(__alignof__(__le64));
        struct skcipher_request *req;
        struct scatterlist src, dst;
-       struct crypto_wait wait;
+       DECLARE_CRYPTO_WAIT(wait);
        int err;
 
        req = skcipher_request_alloc(any_tfm(cc), GFP_NOIO);
@@ -936,7 +936,7 @@ static int crypt_iv_elephant(struct crypt_config *cc, struct dm_crypt_request *d
        u8 *es, *ks, *data, *data2, *data_offset;
        struct skcipher_request *req;
        struct scatterlist *sg, *sg2, src, dst;
-       struct crypto_wait wait;
+       DECLARE_CRYPTO_WAIT(wait);
        int i, r;
 
        req = skcipher_request_alloc(elephant->tfm, GFP_NOIO);
@@ -1552,7 +1552,7 @@ static blk_status_t crypt_convert(struct crypt_config *cc,
                case -EBUSY:
                        wait_for_completion(&ctx->restart);
                        reinit_completion(&ctx->restart);
-                       /* fall through */
+                       fallthrough;
                /*
                 * The request is queued and processed asynchronously,
                 * completion function kcryptd_async_done() will be called.
index 8c8d940..3fc3757 100644 (file)
@@ -2487,6 +2487,7 @@ next_chunk:
        range.logical_sector = le64_to_cpu(ic->sb->recalc_sector);
        if (unlikely(range.logical_sector >= ic->provided_data_sectors)) {
                if (ic->mode == 'B') {
+                       block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
                        DEBUG_print("queue_delayed_work: bitmap_flush_work\n");
                        queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0);
                }
@@ -2564,6 +2565,17 @@ next_chunk:
                goto err;
        }
 
+       if (ic->mode == 'B') {
+               sector_t start, end;
+               start = (range.logical_sector >>
+                        (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit)) <<
+                       (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
+               end = ((range.logical_sector + range.n_sectors) >>
+                      (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit)) <<
+                       (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
+               block_bitmap_op(ic, ic->recalc_bitmap, start, end - start, BITMAP_OP_CLEAR);
+       }
+
 advance_and_next:
        cond_resched();
 
index 53645a6..de4da82 100644 (file)
@@ -1287,17 +1287,25 @@ static void multipath_wait_for_pg_init_completion(struct multipath *m)
 static void flush_multipath_work(struct multipath *m)
 {
        if (m->hw_handler_name) {
-               set_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
-               smp_mb__after_atomic();
+               unsigned long flags;
+
+               if (!atomic_read(&m->pg_init_in_progress))
+                       goto skip;
+
+               spin_lock_irqsave(&m->lock, flags);
+               if (atomic_read(&m->pg_init_in_progress) &&
+                   !test_and_set_bit(MPATHF_PG_INIT_DISABLED, &m->flags)) {
+                       spin_unlock_irqrestore(&m->lock, flags);
 
-               if (atomic_read(&m->pg_init_in_progress))
                        flush_workqueue(kmpath_handlerd);
-               multipath_wait_for_pg_init_completion(m);
+                       multipath_wait_for_pg_init_completion(m);
 
-               clear_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
-               smp_mb__after_atomic();
+                       spin_lock_irqsave(&m->lock, flags);
+                       clear_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
+               }
+               spin_unlock_irqrestore(&m->lock, flags);
        }
-
+skip:
        if (m->queue_mode == DM_TYPE_BIO_BASED)
                flush_work(&m->process_queued_bios);
        flush_work(&m->trigger_event);
@@ -1554,7 +1562,7 @@ static void pg_init_done(void *data, int errors)
        case SCSI_DH_RETRY:
                /* Wait before retrying. */
                delay_retry = true;
-               /* fall through */
+               fallthrough;
        case SCSI_DH_IMM_RETRY:
        case SCSI_DH_RES_TEMP_UNAVAIL:
                if (pg_init_limit_reached(m, pgpath))
index 5edc307..229f461 100644 (file)
@@ -860,10 +860,14 @@ EXPORT_SYMBOL_GPL(dm_table_set_type);
 int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
                        sector_t start, sector_t len, void *data)
 {
-       int blocksize = *(int *) data;
+       int blocksize = *(int *) data, id;
+       bool rc;
 
-       return generic_fsdax_supported(dev->dax_dev, dev->bdev, blocksize,
-                                      start, len);
+       id = dax_read_lock();
+       rc = dax_supported(dev->dax_dev, dev->bdev, blocksize, start, len);
+       dax_read_unlock(id);
+
+       return rc;
 }
 
 /* Check devices support synchronous DAX */
index 76b6b32..b461836 100644 (file)
@@ -739,12 +739,16 @@ static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool f
                                          THIN_MAX_CONCURRENT_LOCKS);
        if (IS_ERR(pmd->bm)) {
                DMERR("could not create block manager");
-               return PTR_ERR(pmd->bm);
+               r = PTR_ERR(pmd->bm);
+               pmd->bm = NULL;
+               return r;
        }
 
        r = __open_or_format_metadata(pmd, format_device);
-       if (r)
+       if (r) {
                dm_block_manager_destroy(pmd->bm);
+               pmd->bm = NULL;
+       }
 
        return r;
 }
@@ -954,7 +958,7 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
        }
 
        pmd_write_lock_in_core(pmd);
-       if (!dm_bm_is_read_only(pmd->bm) && !pmd->fail_io) {
+       if (!pmd->fail_io && !dm_bm_is_read_only(pmd->bm)) {
                r = __commit_transaction(pmd);
                if (r < 0)
                        DMWARN("%s: __commit_transaction() failed, error = %d",
index 86dbe0c..9ae4ce7 100644 (file)
@@ -49,7 +49,7 @@ do {                                                          \
 #define pmem_assign(dest, src) ((dest) = (src))
 #endif
 
-#if defined(__HAVE_ARCH_MEMCPY_MCSAFE) && defined(DM_WRITECACHE_HAS_PMEM)
+#if IS_ENABLED(CONFIG_ARCH_HAS_COPY_MC) && defined(DM_WRITECACHE_HAS_PMEM)
 #define DM_WRITECACHE_HANDLE_HARDWARE_ERRORS
 #endif
 
@@ -231,6 +231,7 @@ static int persistent_memory_claim(struct dm_writecache *wc)
        pfn_t pfn;
        int id;
        struct page **pages;
+       sector_t offset;
 
        wc->memory_vmapped = false;
 
@@ -245,9 +246,16 @@ static int persistent_memory_claim(struct dm_writecache *wc)
                goto err1;
        }
 
+       offset = get_start_sect(wc->ssd_dev->bdev);
+       if (offset & (PAGE_SIZE / 512 - 1)) {
+               r = -EINVAL;
+               goto err1;
+       }
+       offset >>= PAGE_SHIFT - 9;
+
        id = dax_read_lock();
 
-       da = dax_direct_access(wc->ssd_dev->dax_dev, 0, p, &wc->memory_map, &pfn);
+       da = dax_direct_access(wc->ssd_dev->dax_dev, offset, p, &wc->memory_map, &pfn);
        if (da < 0) {
                wc->memory_map = NULL;
                r = da;
@@ -269,7 +277,7 @@ static int persistent_memory_claim(struct dm_writecache *wc)
                i = 0;
                do {
                        long daa;
-                       daa = dax_direct_access(wc->ssd_dev->dax_dev, i, p - i,
+                       daa = dax_direct_access(wc->ssd_dev->dax_dev, offset + i, p - i,
                                                NULL, &pfn);
                        if (daa <= 0) {
                                r = daa ? daa : -EINVAL;
@@ -984,7 +992,8 @@ static void writecache_resume(struct dm_target *ti)
        }
        wc->freelist_size = 0;
 
-       r = memcpy_mcsafe(&sb_seq_count, &sb(wc)->seq_count, sizeof(uint64_t));
+       r = copy_mc_to_kernel(&sb_seq_count, &sb(wc)->seq_count,
+                             sizeof(uint64_t));
        if (r) {
                writecache_error(wc, r, "hardware memory error when reading superblock: %d", r);
                sb_seq_count = cpu_to_le64(0);
@@ -1000,7 +1009,8 @@ static void writecache_resume(struct dm_target *ti)
                        e->seq_count = -1;
                        continue;
                }
-               r = memcpy_mcsafe(&wme, memory_entry(wc, e), sizeof(struct wc_memory_entry));
+               r = copy_mc_to_kernel(&wme, memory_entry(wc, e),
+                                     sizeof(struct wc_memory_entry));
                if (r) {
                        writecache_error(wc, r, "hardware memory error when reading metadata entry %lu: %d",
                                         (unsigned long)b, r);
@@ -1198,7 +1208,7 @@ static void bio_copy_block(struct dm_writecache *wc, struct bio *bio, void *data
 
                if (rw == READ) {
                        int r;
-                       r = memcpy_mcsafe(buf, data, size);
+                       r = copy_mc_to_kernel(buf, data, size);
                        flush_dcache_page(bio_page(bio));
                        if (unlikely(r)) {
                                writecache_error(wc, r, "hardware memory error when reading data: %d", r);
@@ -2341,7 +2351,7 @@ invalid_optional:
                }
        }
 
-       r = memcpy_mcsafe(&s, sb(wc), sizeof(struct wc_memory_superblock));
+       r = copy_mc_to_kernel(&s, sb(wc), sizeof(struct wc_memory_superblock));
        if (r) {
                ti->error = "Hardware memory error when reading superblock";
                goto bad;
@@ -2352,7 +2362,8 @@ invalid_optional:
                        ti->error = "Unable to initialize device";
                        goto bad;
                }
-               r = memcpy_mcsafe(&s, sb(wc), sizeof(struct wc_memory_superblock));
+               r = copy_mc_to_kernel(&s, sb(wc),
+                                     sizeof(struct wc_memory_superblock));
                if (r) {
                        ti->error = "Hardware memory error when reading superblock";
                        goto bad;
index 32fa649..6ed05ca 100644 (file)
@@ -1021,7 +1021,7 @@ static void clone_endio(struct bio *bio)
                switch (r) {
                case DM_ENDIO_REQUEUE:
                        error = BLK_STS_DM_REQUEUE;
-                       /*FALLTHRU*/
+                       fallthrough;
                case DM_ENDIO_DONE:
                        break;
                case DM_ENDIO_INCOMPLETE:
@@ -1136,15 +1136,16 @@ static bool dm_dax_supported(struct dax_device *dax_dev, struct block_device *bd
 {
        struct mapped_device *md = dax_get_private(dax_dev);
        struct dm_table *map;
+       bool ret = false;
        int srcu_idx;
-       bool ret;
 
        map = dm_get_live_table(md, &srcu_idx);
        if (!map)
-               return false;
+               goto out;
 
        ret = dm_table_supports_dax(map, device_supports_dax, &blocksize);
 
+out:
        dm_put_live_table(md, srcu_idx);
 
        return ret;
@@ -1723,23 +1724,6 @@ out:
        return ret;
 }
 
-static void dm_queue_split(struct mapped_device *md, struct dm_target *ti, struct bio **bio)
-{
-       unsigned len, sector_count;
-
-       sector_count = bio_sectors(*bio);
-       len = min_t(sector_t, max_io_len((*bio)->bi_iter.bi_sector, ti), sector_count);
-
-       if (sector_count > len) {
-               struct bio *split = bio_split(*bio, len, GFP_NOIO, &md->queue->bio_split);
-
-               bio_chain(split, *bio);
-               trace_block_split(md->queue, split, (*bio)->bi_iter.bi_sector);
-               submit_bio_noacct(*bio);
-               *bio = split;
-       }
-}
-
 static blk_qc_t dm_process_bio(struct mapped_device *md,
                               struct dm_table *map, struct bio *bio)
 {
@@ -1760,21 +1744,21 @@ static blk_qc_t dm_process_bio(struct mapped_device *md,
        }
 
        /*
-        * If in ->queue_bio we need to use blk_queue_split(), otherwise
+        * If in ->submit_bio we need to use blk_queue_split(), otherwise
         * queue_limits for abnormal requests (e.g. discard, writesame, etc)
         * won't be imposed.
+        * If called from dm_wq_work() for deferred bio processing, bio
+        * was already handled by following code with previous ->submit_bio.
         */
        if (current->bio_list) {
                if (is_abnormal_io(bio))
                        blk_queue_split(&bio);
-               else
-                       dm_queue_split(md, ti, &bio);
+               /* regular IO is split by __split_and_process_bio */
        }
 
        if (dm_get_md_type(md) == DM_TYPE_NVME_BIO_BASED)
                return __process_bio(md, map, bio, ti);
-       else
-               return __split_and_process_bio(md, map, bio);
+       return __split_and_process_bio(md, map, bio);
 }
 
 static blk_qc_t dm_submit_bio(struct bio *bio)
index 6bbec89..2cf9737 100644 (file)
@@ -102,10 +102,10 @@ static int __init md_setup(char *str)
                                pername = "raid0";
                        break;
                }
-               /* FALL THROUGH */
+               fallthrough;
        case 1: /* the first device is numeric */
                str = str1;
-               /* FALL THROUGH */
+               fallthrough;
        case 0:
                md_setup_args[ent].level = LEVEL_NONE;
                pername="super-block";
index d61b524..b10c519 100644 (file)
@@ -1433,7 +1433,7 @@ int md_bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long s
                case 0:
                        md_bitmap_file_set_bit(bitmap, offset);
                        md_bitmap_count_page(&bitmap->counts, offset, 1);
-                       /* fall through */
+                       fallthrough;
                case 1:
                        *bmc = 2;
                }
index 749ec26..54c089a 100644 (file)
@@ -493,7 +493,7 @@ int dm_bm_write_lock(struct dm_block_manager *bm,
        void *p;
        int r;
 
-       if (bm->read_only)
+       if (dm_bm_is_read_only(bm))
                return -EPERM;
 
        p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result);
@@ -562,7 +562,7 @@ int dm_bm_write_lock_zero(struct dm_block_manager *bm,
        struct buffer_aux *aux;
        void *p;
 
-       if (bm->read_only)
+       if (dm_bm_is_read_only(bm))
                return -EPERM;
 
        p = dm_bufio_new(bm->bufio, b, (struct dm_buffer **) result);
@@ -602,7 +602,7 @@ EXPORT_SYMBOL_GPL(dm_bm_unlock);
 
 int dm_bm_flush(struct dm_block_manager *bm)
 {
-       if (bm->read_only)
+       if (dm_bm_is_read_only(bm))
                return -EPERM;
 
        return dm_bufio_write_dirty_buffers(bm->bufio);
@@ -616,19 +616,21 @@ void dm_bm_prefetch(struct dm_block_manager *bm, dm_block_t b)
 
 bool dm_bm_is_read_only(struct dm_block_manager *bm)
 {
-       return bm->read_only;
+       return (bm ? bm->read_only : true);
 }
 EXPORT_SYMBOL_GPL(dm_bm_is_read_only);
 
 void dm_bm_set_read_only(struct dm_block_manager *bm)
 {
-       bm->read_only = true;
+       if (bm)
+               bm->read_only = true;
 }
 EXPORT_SYMBOL_GPL(dm_bm_set_read_only);
 
 void dm_bm_set_read_write(struct dm_block_manager *bm)
 {
-       bm->read_only = false;
+       if (bm)
+               bm->read_only = false;
 }
 EXPORT_SYMBOL_GPL(dm_bm_set_read_write);
 
index ef0fd48..225380e 100644 (file)
@@ -4083,7 +4083,7 @@ static void handle_parity_checks5(struct r5conf *conf, struct stripe_head *sh,
                        break;
                }
                dev = &sh->dev[s->failed_num[0]];
-               /* fall through */
+               fallthrough;
        case check_state_compute_result:
                sh->check_state = check_state_idle;
                if (!dev)
@@ -4214,7 +4214,7 @@ static void handle_parity_checks6(struct r5conf *conf, struct stripe_head *sh,
 
                /* we have 2-disk failure */
                BUG_ON(s->failed != 2);
-               /* fall through */
+               fallthrough;
        case check_state_compute_result:
                sh->check_state = check_state_idle;
 
@@ -6514,9 +6514,12 @@ raid5_store_stripe_size(struct mddev  *mddev, const char *page, size_t len)
 
        /*
         * The value should not be bigger than PAGE_SIZE. It requires to
-        * be multiple of DEFAULT_STRIPE_SIZE.
+        * be multiple of DEFAULT_STRIPE_SIZE and the value should be power
+        * of two.
         */
-       if (new % DEFAULT_STRIPE_SIZE != 0 || new > PAGE_SIZE || new == 0)
+       if (new % DEFAULT_STRIPE_SIZE != 0 ||
+                       new > PAGE_SIZE || new == 0 ||
+                       new != roundup_pow_of_two(new))
                return -EINVAL;
 
        err = mddev_lock(mddev);
index 4efe801..926d65d 100644 (file)
@@ -1199,7 +1199,7 @@ void cec_received_msg_ts(struct cec_adapter *adap,
                        /* Cancel the pending timeout work */
                        if (!cancel_delayed_work(&data->work)) {
                                mutex_unlock(&adap->lock);
-                               flush_scheduled_work();
+                               cancel_delayed_work_sync(&data->work);
                                mutex_lock(&adap->lock);
                        }
                        /*
index 630a75e..7607b51 100644 (file)
@@ -210,7 +210,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
                tpg->vdownsampling[1] = 1;
                tpg->hdownsampling[1] = 1;
                tpg->planes = 2;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_RGB332:
        case V4L2_PIX_FMT_RGB565:
        case V4L2_PIX_FMT_RGB565X:
@@ -271,7 +271,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
        case V4L2_PIX_FMT_YUV420M:
        case V4L2_PIX_FMT_YVU420M:
                tpg->buffers = 3;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YVU420:
                tpg->vdownsampling[1] = 2;
@@ -284,7 +284,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
        case V4L2_PIX_FMT_YUV422M:
        case V4L2_PIX_FMT_YVU422M:
                tpg->buffers = 3;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_YUV422P:
                tpg->vdownsampling[1] = 1;
                tpg->vdownsampling[2] = 1;
@@ -296,7 +296,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
        case V4L2_PIX_FMT_NV16M:
        case V4L2_PIX_FMT_NV61M:
                tpg->buffers = 2;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_NV16:
        case V4L2_PIX_FMT_NV61:
                tpg->vdownsampling[1] = 1;
@@ -308,7 +308,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
        case V4L2_PIX_FMT_NV12M:
        case V4L2_PIX_FMT_NV21M:
                tpg->buffers = 2;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_NV12:
        case V4L2_PIX_FMT_NV21:
                tpg->vdownsampling[1] = 2;
@@ -1275,7 +1275,7 @@ static void gen_twopix(struct tpg_data *tpg,
        case V4L2_PIX_FMT_RGB444:
        case V4L2_PIX_FMT_XRGB444:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_YUV444:
        case V4L2_PIX_FMT_ARGB444:
                buf[0][offset] = (g_u_s << 4) | b_v;
@@ -1283,21 +1283,21 @@ static void gen_twopix(struct tpg_data *tpg,
                break;
        case V4L2_PIX_FMT_RGBX444:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_RGBA444:
                buf[0][offset] = (b_v << 4) | (alpha >> 4);
                buf[0][offset + 1] = (r_y_h << 4) | g_u_s;
                break;
        case V4L2_PIX_FMT_XBGR444:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_ABGR444:
                buf[0][offset] = (g_u_s << 4) | r_y_h;
                buf[0][offset + 1] = (alpha & 0xf0) | b_v;
                break;
        case V4L2_PIX_FMT_BGRX444:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_BGRA444:
                buf[0][offset] = (r_y_h << 4) | (alpha >> 4);
                buf[0][offset + 1] = (b_v << 4) | g_u_s;
@@ -1305,7 +1305,7 @@ static void gen_twopix(struct tpg_data *tpg,
        case V4L2_PIX_FMT_RGB555:
        case V4L2_PIX_FMT_XRGB555:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_YUV555:
        case V4L2_PIX_FMT_ARGB555:
                buf[0][offset] = (g_u_s << 5) | b_v;
@@ -1314,7 +1314,7 @@ static void gen_twopix(struct tpg_data *tpg,
                break;
        case V4L2_PIX_FMT_RGBX555:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_RGBA555:
                buf[0][offset] = (g_u_s << 6) | (b_v << 1) |
                                 ((alpha & 0x80) >> 7);
@@ -1322,7 +1322,7 @@ static void gen_twopix(struct tpg_data *tpg,
                break;
        case V4L2_PIX_FMT_XBGR555:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_ABGR555:
                buf[0][offset] = (g_u_s << 5) | r_y_h;
                buf[0][offset + 1] = (alpha & 0x80) | (b_v << 2)
@@ -1330,7 +1330,7 @@ static void gen_twopix(struct tpg_data *tpg,
                break;
        case V4L2_PIX_FMT_BGRX555:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_BGRA555:
                buf[0][offset] = (g_u_s << 6) | (r_y_h << 1) |
                                 ((alpha & 0x80) >> 7);
@@ -1339,7 +1339,7 @@ static void gen_twopix(struct tpg_data *tpg,
        case V4L2_PIX_FMT_RGB555X:
        case V4L2_PIX_FMT_XRGB555X:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_ARGB555X:
                buf[0][offset] = (alpha & 0x80) | (r_y_h << 2) | (g_u_s >> 3);
                buf[0][offset + 1] = (g_u_s << 5) | b_v;
@@ -1366,7 +1366,7 @@ static void gen_twopix(struct tpg_data *tpg,
        case V4L2_PIX_FMT_HSV32:
        case V4L2_PIX_FMT_XYUV32:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_YUV32:
        case V4L2_PIX_FMT_ARGB32:
        case V4L2_PIX_FMT_AYUV32:
@@ -1377,7 +1377,7 @@ static void gen_twopix(struct tpg_data *tpg,
                break;
        case V4L2_PIX_FMT_RGBX32:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_RGBA32:
                buf[0][offset] = r_y_h;
                buf[0][offset + 1] = g_u_s;
@@ -1388,7 +1388,7 @@ static void gen_twopix(struct tpg_data *tpg,
        case V4L2_PIX_FMT_XBGR32:
        case V4L2_PIX_FMT_VUYX32:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_ABGR32:
        case V4L2_PIX_FMT_VUYA32:
                buf[0][offset] = b_v;
@@ -1398,7 +1398,7 @@ static void gen_twopix(struct tpg_data *tpg,
                break;
        case V4L2_PIX_FMT_BGRX32:
                alpha = 0;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_BGRA32:
                buf[0][offset] = alpha;
                buf[0][offset + 1] = b_v;
index f544d33..4eab6d8 100644 (file)
@@ -721,39 +721,14 @@ int vb2_verify_memory_type(struct vb2_queue *q,
 }
 EXPORT_SYMBOL(vb2_verify_memory_type);
 
-static void set_queue_consistency(struct vb2_queue *q, bool consistent_mem)
-{
-       q->dma_attrs &= ~DMA_ATTR_NON_CONSISTENT;
-
-       if (!vb2_queue_allows_cache_hints(q))
-               return;
-       if (!consistent_mem)
-               q->dma_attrs |= DMA_ATTR_NON_CONSISTENT;
-}
-
-static bool verify_consistency_attr(struct vb2_queue *q, bool consistent_mem)
-{
-       bool queue_is_consistent = !(q->dma_attrs & DMA_ATTR_NON_CONSISTENT);
-
-       if (consistent_mem != queue_is_consistent) {
-               dprintk(q, 1, "memory consistency model mismatch\n");
-               return false;
-       }
-       return true;
-}
-
 int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
-                    unsigned int flags, unsigned int *count)
+                    unsigned int *count)
 {
        unsigned int num_buffers, allocated_buffers, num_planes = 0;
        unsigned plane_sizes[VB2_MAX_PLANES] = { };
-       bool consistent_mem = true;
        unsigned int i;
        int ret;
 
-       if (flags & V4L2_FLAG_MEMORY_NON_CONSISTENT)
-               consistent_mem = false;
-
        if (q->streaming) {
                dprintk(q, 1, "streaming active\n");
                return -EBUSY;
@@ -765,8 +740,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
        }
 
        if (*count == 0 || q->num_buffers != 0 ||
-           (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory) ||
-           !verify_consistency_attr(q, consistent_mem)) {
+           (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) {
                /*
                 * We already have buffers allocated, so first check if they
                 * are not in use and can be freed.
@@ -803,7 +777,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
        num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME);
        memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
        q->memory = memory;
-       set_queue_consistency(q, consistent_mem);
 
        /*
         * Ask the driver how many buffers and planes per buffer it requires.
@@ -888,18 +861,14 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
 EXPORT_SYMBOL_GPL(vb2_core_reqbufs);
 
 int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
-                        unsigned int flags, unsigned int *count,
+                        unsigned int *count,
                         unsigned int requested_planes,
                         const unsigned int requested_sizes[])
 {
        unsigned int num_planes = 0, num_buffers, allocated_buffers;
        unsigned plane_sizes[VB2_MAX_PLANES] = { };
-       bool consistent_mem = true;
        int ret;
 
-       if (flags & V4L2_FLAG_MEMORY_NON_CONSISTENT)
-               consistent_mem = false;
-
        if (q->num_buffers == VB2_MAX_FRAME) {
                dprintk(q, 1, "maximum number of buffers already allocated\n");
                return -ENOBUFS;
@@ -912,15 +881,12 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
                }
                memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
                q->memory = memory;
-               set_queue_consistency(q, consistent_mem);
                q->waiting_for_buffers = !q->is_output;
        } else {
                if (q->memory != memory) {
                        dprintk(q, 1, "memory model mismatch\n");
                        return -EINVAL;
                }
-               if (!verify_consistency_attr(q, consistent_mem))
-                       return -EINVAL;
        }
 
        num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers);
@@ -2581,7 +2547,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
        fileio->memory = VB2_MEMORY_MMAP;
        fileio->type = q->type;
        q->fileio = fileio;
-       ret = vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count);
+       ret = vb2_core_reqbufs(q, fileio->memory, &fileio->count);
        if (ret)
                goto err_kfree;
 
@@ -2638,7 +2604,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
 
 err_reqbufs:
        fileio->count = 0;
-       vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count);
+       vb2_core_reqbufs(q, fileio->memory, &fileio->count);
 
 err_kfree:
        q->fileio = NULL;
@@ -2658,7 +2624,7 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q)
                vb2_core_streamoff(q, q->type);
                q->fileio = NULL;
                fileio->count = 0;
-               vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count);
+               vb2_core_reqbufs(q, fileio->memory, &fileio->count);
                kfree(fileio);
                dprintk(q, 3, "file io emulator closed\n");
        }
index ec3446c..7b1b86e 100644 (file)
@@ -42,11 +42,6 @@ struct vb2_dc_buf {
        struct dma_buf_attachment       *db_attach;
 };
 
-static inline bool vb2_dc_buffer_consistent(unsigned long attr)
-{
-       return !(attr & DMA_ATTR_NON_CONSISTENT);
-}
-
 /*********************************************/
 /*        scatterlist table functions        */
 /*********************************************/
@@ -341,13 +336,6 @@ static int
 vb2_dc_dmabuf_ops_begin_cpu_access(struct dma_buf *dbuf,
                                   enum dma_data_direction direction)
 {
-       struct vb2_dc_buf *buf = dbuf->priv;
-       struct sg_table *sgt = buf->dma_sgt;
-
-       if (vb2_dc_buffer_consistent(buf->attrs))
-               return 0;
-
-       dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
        return 0;
 }
 
@@ -355,13 +343,6 @@ static int
 vb2_dc_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf,
                                 enum dma_data_direction direction)
 {
-       struct vb2_dc_buf *buf = dbuf->priv;
-       struct sg_table *sgt = buf->dma_sgt;
-
-       if (vb2_dc_buffer_consistent(buf->attrs))
-               return 0;
-
-       dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
        return 0;
 }
 
index 0a40e00..a86fce5 100644 (file)
@@ -123,8 +123,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs,
        /*
         * NOTE: dma-sg allocates memory using the page allocator directly, so
         * there is no memory consistency guarantee, hence dma-sg ignores DMA
-        * attributes passed from the upper layer. That means that
-        * V4L2_FLAG_MEMORY_NON_CONSISTENT has no effect on dma-sg buffers.
+        * attributes passed from the upper layer.
         */
        buf->pages = kvmalloc_array(buf->num_pages, sizeof(struct page *),
                                    GFP_KERNEL | __GFP_ZERO);
index 30caad2..cfe197d 100644 (file)
@@ -722,22 +722,12 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
 #endif
 }
 
-static void clear_consistency_attr(struct vb2_queue *q,
-                                  int memory,
-                                  unsigned int *flags)
-{
-       if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP)
-               *flags &= ~V4L2_FLAG_MEMORY_NON_CONSISTENT;
-}
-
 int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 {
        int ret = vb2_verify_memory_type(q, req->memory, req->type);
 
        fill_buf_caps(q, &req->capabilities);
-       clear_consistency_attr(q, req->memory, &req->flags);
-       return ret ? ret : vb2_core_reqbufs(q, req->memory,
-                                           req->flags, &req->count);
+       return ret ? ret : vb2_core_reqbufs(q, req->memory, &req->count);
 }
 EXPORT_SYMBOL_GPL(vb2_reqbufs);
 
@@ -769,7 +759,6 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
        unsigned i;
 
        fill_buf_caps(q, &create->capabilities);
-       clear_consistency_attr(q, create->memory, &create->flags);
        create->index = q->num_buffers;
        if (create->count == 0)
                return ret != -EBUSY ? ret : 0;
@@ -813,7 +802,6 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
                if (requested_sizes[i] == 0)
                        return -EINVAL;
        return ret ? ret : vb2_core_create_bufs(q, create->memory,
-                                               create->flags,
                                                &create->count,
                                                requested_planes,
                                                requested_sizes);
@@ -998,12 +986,11 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv,
        int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type);
 
        fill_buf_caps(vdev->queue, &p->capabilities);
-       clear_consistency_attr(vdev->queue, p->memory, &p->flags);
        if (res)
                return res;
        if (vb2_queue_is_busy(vdev, file))
                return -EBUSY;
-       res = vb2_core_reqbufs(vdev->queue, p->memory, p->flags, &p->count);
+       res = vb2_core_reqbufs(vdev->queue, p->memory, &p->count);
        /* If count == 0, then the owner has released all buffers and he
           is no longer owner of the queue. Otherwise we have a new owner. */
        if (res == 0)
@@ -1021,7 +1008,6 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
 
        p->index = vdev->queue->num_buffers;
        fill_buf_caps(vdev->queue, &p->capabilities);
-       clear_consistency_attr(vdev->queue, p->memory, &p->flags);
        /*
         * If count == 0, then just check if memory and type are valid.
         * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0.
index 630509e..89620da 100644 (file)
@@ -546,7 +546,7 @@ static int dvb_net_ule_new_payload(struct dvb_net_ule_handle *h)
                h->priv->ule_sndu_type_1 = 1;
                h->ts_remain -= 1;
                h->from_where += 1;
-               /* fallthrough */
+               fallthrough;
        case 0:
                h->new_ts = 1;
                h->ts += TS_SZ;
index 959d110..6974f17 100644 (file)
@@ -342,7 +342,7 @@ int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req)
 
        ctx->buf_siz = req->size;
        ctx->buf_cnt = req->count;
-       ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, 0, &req->count);
+       ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, &req->count);
        if (ret) {
                ctx->state = DVB_VB2_STATE_NONE;
                dprintk(1, "[%s] count=%d size=%d errno=%d\n", ctx->name,
index e92542b..da0ff7b 100644 (file)
@@ -773,7 +773,7 @@ static int bcm3510_init(struct dvb_frontend* fe)
                        deb_info("attempting to download firmware\n");
                        if ((ret = bcm3510_init_cold(st)) < 0)
                                return ret;
-                       /* fall-through */
+                       fallthrough;
                case JDEC_EEPROM_LOAD_WAIT:
                        deb_info("firmware is loaded\n");
                        bcm3510_check_firmware_version(st);
index bc37475..08a8583 100644 (file)
@@ -1693,7 +1693,7 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front
                if (state->identity.p1g)
                        state->dc = dc_p1g_table;
 
-               /* fall through */
+               fallthrough;
        case CT_TUNER_STEP_0:
                dprintk("Start/continue DC calibration for %s path\n",
                        (state->dc->i == 1) ? "I" : "Q");
index 0f0480d..a6c2fc4 100644 (file)
@@ -224,7 +224,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner)
        switch (c->hierarchy) {
                case HIERARCHY_NONE:
                        deb_setf("hierarchy: none\n");
-                       /* fall through */
+                       fallthrough;
                case HIERARCHY_1:
                        deb_setf("hierarchy: alpha=1\n");
                        wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_1);
index 0a7790c..55bee50 100644 (file)
@@ -276,7 +276,7 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p
                if (state->version != SOC7090)
                        reg_1280 &= ~((1 << 11));
                reg_1280 &= ~(1 << 6);
-               /* fall-through */
+               fallthrough;
        case DIB7000P_POWER_INTERFACE_ONLY:
                /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
                /* TODO power up either SDIO or I2C */
index 5de0164..237b9d0 100644 (file)
@@ -2306,7 +2306,7 @@ hi_command(struct i2c_device_addr *dev_addr, const struct drxj_hi_cmd *cmd, u16
                        pr_err("error %d\n", rc);
                        goto rw_error;
                }
-               /* fallthrough */
+               fallthrough;
        case SIO_HI_RA_RAM_CMD_BRDCTRL:
                rc = drxj_dap_write_reg16(dev_addr, SIO_HI_RA_RAM_PAR_2__A, cmd->param2, 0);
                if (rc != 0) {
@@ -2318,7 +2318,7 @@ hi_command(struct i2c_device_addr *dev_addr, const struct drxj_hi_cmd *cmd, u16
                        pr_err("error %d\n", rc);
                        goto rw_error;
                }
-               /* fallthrough */
+               fallthrough;
        case SIO_HI_RA_RAM_CMD_NULL:
                /* No parameters */
                break;
@@ -2841,7 +2841,7 @@ ctrl_set_cfg_mpeg_output(struct drx_demod_instance *demod, struct drx_cfg_mpeg_o
                        /* coef = 188/204                          */
                        max_bit_rate =
                            (ext_attr->curr_symbol_rate / 8) * nr_bits * 188;
-                       /* fall-through - as b/c Annex A/C need following settings */
+                       fallthrough;    /* as b/c Annex A/C need following settings */
                case DRX_STANDARD_ITU_B:
                        rc = drxj_dap_write_reg16(dev_addr, FEC_OC_FCT_USAGE__A, FEC_OC_FCT_USAGE__PRE, 0);
                        if (rc != 0) {
@@ -3555,8 +3555,8 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg
                if (!ext_attr->has_smatx)
                        return -EIO;
                switch (uio_cfg->mode) {
-               case DRX_UIO_MODE_FIRMWARE_SMA: /* fall through */
-               case DRX_UIO_MODE_FIRMWARE_SAW: /* fall through */
+               case DRX_UIO_MODE_FIRMWARE_SMA:
+               case DRX_UIO_MODE_FIRMWARE_SAW:
                case DRX_UIO_MODE_READWRITE:
                        ext_attr->uio_sma_tx_mode = uio_cfg->mode;
                        break;
@@ -3579,7 +3579,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg
                if (!ext_attr->has_smarx)
                        return -EIO;
                switch (uio_cfg->mode) {
-               case DRX_UIO_MODE_FIRMWARE0:    /* fall through */
+               case DRX_UIO_MODE_FIRMWARE0:
                case DRX_UIO_MODE_READWRITE:
                        ext_attr->uio_sma_rx_mode = uio_cfg->mode;
                        break;
@@ -3603,7 +3603,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg
                if (!ext_attr->has_gpio)
                        return -EIO;
                switch (uio_cfg->mode) {
-               case DRX_UIO_MODE_FIRMWARE0:    /* fall through */
+               case DRX_UIO_MODE_FIRMWARE0:
                case DRX_UIO_MODE_READWRITE:
                        ext_attr->uio_gpio_mode = uio_cfg->mode;
                        break;
@@ -3639,7 +3639,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg
                        }
                        ext_attr->uio_irqn_mode = uio_cfg->mode;
                        break;
-               case DRX_UIO_MODE_FIRMWARE0:    /* fall through */
+               case DRX_UIO_MODE_FIRMWARE0:
                default:
                        return -EINVAL;
                        break;
@@ -4004,31 +4004,36 @@ static int scu_command(struct i2c_device_addr *dev_addr, struct drxjscu_cmd *cmd
                if (rc != 0) {
                        pr_err("error %d\n", rc);
                        goto rw_error;
-               }       /* fallthrough */
+               }
+               fallthrough;
        case 4:
                rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_PARAM_3__A, *(cmd->parameter + 3), 0);
                if (rc != 0) {
                        pr_err("error %d\n", rc);
                        goto rw_error;
-               }       /* fallthrough */
+               }
+               fallthrough;
        case 3:
                rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_PARAM_2__A, *(cmd->parameter + 2), 0);
                if (rc != 0) {
                        pr_err("error %d\n", rc);
                        goto rw_error;
-               }       /* fallthrough */
+               }
+               fallthrough;
        case 2:
                rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_PARAM_1__A, *(cmd->parameter + 1), 0);
                if (rc != 0) {
                        pr_err("error %d\n", rc);
                        goto rw_error;
-               }       /* fallthrough */
+               }
+               fallthrough;
        case 1:
                rc = drxj_dap_write_reg16(dev_addr, SCU_RAM_PARAM_0__A, *(cmd->parameter + 0), 0);
                if (rc != 0) {
                        pr_err("error %d\n", rc);
                        goto rw_error;
-               }       /* fallthrough */
+               }
+               fallthrough;
        case 0:
                /* do nothing */
                break;
@@ -4068,25 +4073,29 @@ static int scu_command(struct i2c_device_addr *dev_addr, struct drxjscu_cmd *cmd
                        if (rc != 0) {
                                pr_err("error %d\n", rc);
                                goto rw_error;
-                       }       /* fallthrough */
+                       }
+                       fallthrough;
                case 3:
                        rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_PARAM_2__A, cmd->result + 2, 0);
                        if (rc != 0) {
                                pr_err("error %d\n", rc);
                                goto rw_error;
-                       }       /* fallthrough */
+                       }
+                       fallthrough;
                case 2:
                        rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_PARAM_1__A, cmd->result + 1, 0);
                        if (rc != 0) {
                                pr_err("error %d\n", rc);
                                goto rw_error;
-                       }       /* fallthrough */
+                       }
+                       fallthrough;
                case 1:
                        rc = drxj_dap_read_reg16(dev_addr, SCU_RAM_PARAM_0__A, cmd->result + 0, 0);
                        if (rc != 0) {
                                pr_err("error %d\n", rc);
                                goto rw_error;
-                       }       /* fallthrough */
+                       }
+                       fallthrough;
                case 0:
                        /* do nothing */
                        break;
@@ -4791,7 +4800,7 @@ set_frequency(struct drx_demod_instance *demod,
                   Sound carrier is already 3Mhz above centre frequency due
                   to tuner setting so now add an extra shift of 1MHz... */
                fm_frequency_shift = 1000;
-               /*fall through */
+               fallthrough;
        case DRX_STANDARD_ITU_B:
        case DRX_STANDARD_NTSC:
        case DRX_STANDARD_PAL_SECAM_BG:
@@ -10475,11 +10484,11 @@ ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel)
            (standard == DRX_STANDARD_NTSC)) {
                switch (channel->bandwidth) {
                case DRX_BANDWIDTH_6MHZ:
-               case DRX_BANDWIDTH_UNKNOWN:     /* fall through */
+               case DRX_BANDWIDTH_UNKNOWN:
                        channel->bandwidth = DRX_BANDWIDTH_6MHZ;
                        break;
-               case DRX_BANDWIDTH_8MHZ:        /* fall through */
-               case DRX_BANDWIDTH_7MHZ:        /* fall through */
+               case DRX_BANDWIDTH_8MHZ:
+               case DRX_BANDWIDTH_7MHZ:
                default:
                        return -EINVAL;
                }
@@ -10511,10 +10520,10 @@ ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel)
                }
 
                switch (channel->constellation) {
-               case DRX_CONSTELLATION_QAM16:   /* fall through */
-               case DRX_CONSTELLATION_QAM32:   /* fall through */
-               case DRX_CONSTELLATION_QAM64:   /* fall through */
-               case DRX_CONSTELLATION_QAM128:  /* fall through */
+               case DRX_CONSTELLATION_QAM16:
+               case DRX_CONSTELLATION_QAM32:
+               case DRX_CONSTELLATION_QAM64:
+               case DRX_CONSTELLATION_QAM128:
                case DRX_CONSTELLATION_QAM256:
                        bandwidth_temp = channel->symbolrate * bw_rolloff_factor;
                        bandwidth = bandwidth_temp / 100;
@@ -10628,8 +10637,8 @@ ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel)
                }
                break;
 #ifndef DRXJ_VSB_ONLY
-       case DRX_STANDARD_ITU_A:        /* fallthrough */
-       case DRX_STANDARD_ITU_B:        /* fallthrough */
+       case DRX_STANDARD_ITU_A:
+       case DRX_STANDARD_ITU_B:
        case DRX_STANDARD_ITU_C:
                rc = set_qam_channel(demod, channel, tuner_freq_offset);
                if (rc != 0) {
@@ -10820,7 +10829,7 @@ ctrl_lock_status(struct drx_demod_instance *demod, enum drx_lock_status *lock_st
                    SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK;
                break;
 #endif
-       case DRX_STANDARD_UNKNOWN:      /* fallthrough */
+       case DRX_STANDARD_UNKNOWN:
        default:
                return -EIO;
        }
@@ -10888,8 +10897,8 @@ ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard)
         */
        switch (prev_standard) {
 #ifndef DRXJ_VSB_ONLY
-       case DRX_STANDARD_ITU_A:        /* fallthrough */
-       case DRX_STANDARD_ITU_B:        /* fallthrough */
+       case DRX_STANDARD_ITU_A:
+       case DRX_STANDARD_ITU_B:
        case DRX_STANDARD_ITU_C:
                rc = power_down_qam(demod, false);
                if (rc != 0) {
@@ -10908,7 +10917,7 @@ ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard)
        case DRX_STANDARD_UNKNOWN:
                /* Do nothing */
                break;
-       case DRX_STANDARD_AUTO: /* fallthrough */
+       case DRX_STANDARD_AUTO:
        default:
                return -EINVAL;
        }
@@ -10921,8 +10930,8 @@ ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard)
 
        switch (*standard) {
 #ifndef DRXJ_VSB_ONLY
-       case DRX_STANDARD_ITU_A:        /* fallthrough */
-       case DRX_STANDARD_ITU_B:        /* fallthrough */
+       case DRX_STANDARD_ITU_A:
+       case DRX_STANDARD_ITU_B:
        case DRX_STANDARD_ITU_C:
                do {
                        u16 dummy;
@@ -11111,12 +11120,12 @@ ctrl_power_mode(struct drx_demod_instance *demod, enum drx_power_mode *mode)
                                goto rw_error;
                        }
                        break;
-               case DRX_STANDARD_PAL_SECAM_BG: /* fallthrough */
-               case DRX_STANDARD_PAL_SECAM_DK: /* fallthrough */
-               case DRX_STANDARD_PAL_SECAM_I:  /* fallthrough */
-               case DRX_STANDARD_PAL_SECAM_L:  /* fallthrough */
-               case DRX_STANDARD_PAL_SECAM_LP: /* fallthrough */
-               case DRX_STANDARD_NTSC: /* fallthrough */
+               case DRX_STANDARD_PAL_SECAM_BG:
+               case DRX_STANDARD_PAL_SECAM_DK:
+               case DRX_STANDARD_PAL_SECAM_I:
+               case DRX_STANDARD_PAL_SECAM_L:
+               case DRX_STANDARD_PAL_SECAM_LP:
+               case DRX_STANDARD_NTSC:
                case DRX_STANDARD_FM:
                        rc = power_down_atv(demod, ext_attr->standard, true);
                        if (rc != 0) {
@@ -11127,7 +11136,7 @@ ctrl_power_mode(struct drx_demod_instance *demod, enum drx_power_mode *mode)
                case DRX_STANDARD_UNKNOWN:
                        /* Do nothing */
                        break;
-               case DRX_STANDARD_AUTO: /* fallthrough */
+               case DRX_STANDARD_AUTO:
                default:
                        return -EIO;
                }
@@ -11220,8 +11229,8 @@ ctrl_set_cfg_pre_saw(struct drx_demod_instance *demod, struct drxj_cfg_pre_saw *
                ext_attr->vsb_pre_saw_cfg = *pre_saw;
                break;
 #ifndef DRXJ_VSB_ONLY
-       case DRX_STANDARD_ITU_A:        /* fallthrough */
-       case DRX_STANDARD_ITU_B:        /* fallthrough */
+       case DRX_STANDARD_ITU_A:
+       case DRX_STANDARD_ITU_B:
        case DRX_STANDARD_ITU_C:
                ext_attr->qam_pre_saw_cfg = *pre_saw;
                break;
@@ -11264,10 +11273,10 @@ ctrl_set_cfg_afe_gain(struct drx_demod_instance *demod, struct drxj_cfg_afe_gain
        ext_attr = (struct drxj_data *) demod->my_ext_attr;
 
        switch (afe_gain->standard) {
-       case DRX_STANDARD_8VSB: /* fallthrough */
+       case DRX_STANDARD_8VSB: fallthrough;
 #ifndef DRXJ_VSB_ONLY
-       case DRX_STANDARD_ITU_A:        /* fallthrough */
-       case DRX_STANDARD_ITU_B:        /* fallthrough */
+       case DRX_STANDARD_ITU_A:
+       case DRX_STANDARD_ITU_B:
        case DRX_STANDARD_ITU_C:
 #endif
                /* Do nothing */
@@ -11301,8 +11310,8 @@ ctrl_set_cfg_afe_gain(struct drx_demod_instance *demod, struct drxj_cfg_afe_gain
                ext_attr->vsb_pga_cfg = gain * 13 + 140;
                break;
 #ifndef DRXJ_VSB_ONLY
-       case DRX_STANDARD_ITU_A:        /* fallthrough */
-       case DRX_STANDARD_ITU_B:        /* fallthrough */
+       case DRX_STANDARD_ITU_A:
+       case DRX_STANDARD_ITU_B:
        case DRX_STANDARD_ITU_C:
                ext_attr->qam_pga_cfg = gain * 13 + 140;
                break;
index fae6f37..45f9828 100644 (file)
@@ -1512,14 +1512,14 @@ static int SetDeviceTypeId(struct drxd_state *state)
                        switch (deviceId) {
                        case 4:
                                state->diversity = 1;
-                               /* fall through */
+                               fallthrough;
                        case 3:
                        case 7:
                                state->PGA = 1;
                                break;
                        case 6:
                                state->diversity = 1;
-                               /* fall through */
+                               fallthrough;
                        case 5:
                        case 8:
                                break;
@@ -1966,7 +1966,7 @@ static int DRX_Start(struct drxd_state *state, s32 off)
                switch (p->transmission_mode) {
                default:        /* Not set, detect it automatically */
                        operationMode |= SC_RA_RAM_OP_AUTO_MODE__M;
-                       /* fall through - try first guess DRX_FFTMODE_8K */
+                       fallthrough;    /* try first guess DRX_FFTMODE_8K */
                case TRANSMISSION_MODE_8K:
                        transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_8K;
                        if (state->type_A) {
@@ -2139,7 +2139,7 @@ static int DRX_Start(struct drxd_state *state, s32 off)
                switch (p->modulation) {
                default:
                        operationMode |= SC_RA_RAM_OP_AUTO_CONST__M;
-                       /* fall through - try first guess DRX_CONSTELLATION_QAM64 */
+                       fallthrough;    /* try first guess DRX_CONSTELLATION_QAM64 */
                case QAM_64:
                        transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM64;
                        if (state->type_A) {
@@ -2266,7 +2266,7 @@ static int DRX_Start(struct drxd_state *state, s32 off)
                        break;
                default:
                        operationMode |= SC_RA_RAM_OP_AUTO_RATE__M;
-                       /* fall through */
+                       fallthrough;
                case FEC_2_3:
                        transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_2_3;
                        if (state->type_A)
@@ -2301,7 +2301,7 @@ static int DRX_Start(struct drxd_state *state, s32 off)
                switch (p->bandwidth_hz) {
                case 0:
                        p->bandwidth_hz = 8000000;
-                       /* fall through */
+                       fallthrough;
                case 8000000:
                        /* (64/7)*(8/8)*1000000 */
                        bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
index 0ae9d8c..32f9346 100644 (file)
@@ -1756,7 +1756,7 @@ static int setoperation_mode(struct drxk_state *state,
                        goto error;
                state->m_operation_mode = OM_NONE;
                break;
-       case OM_QAM_ITU_A:      /* fallthrough */
+       case OM_QAM_ITU_A:
        case OM_QAM_ITU_C:
                status = mpegts_stop(state);
                if (status < 0)
@@ -1783,7 +1783,7 @@ static int setoperation_mode(struct drxk_state *state,
                if (status < 0)
                        goto error;
                break;
-       case OM_QAM_ITU_A:      /* fallthrough */
+       case OM_QAM_ITU_A:
        case OM_QAM_ITU_C:
                dprintk(1, ": DVB-C Annex %c\n",
                        (state->m_operation_mode == OM_QAM_ITU_A) ? 'A' : 'C');
@@ -2012,7 +2012,7 @@ static int mpegts_dto_setup(struct drxk_state *state,
                fec_oc_rcn_ctl_rate = 0xC00000;
                static_clk = state->m_dvbt_static_clk;
                break;
-       case OM_QAM_ITU_A:      /* fallthrough */
+       case OM_QAM_ITU_A:
        case OM_QAM_ITU_C:
                fec_oc_tmd_mode = 0x0004;
                fec_oc_rcn_ctl_rate = 0xD2B4EE; /* good for >63 Mb/s */
@@ -3249,11 +3249,11 @@ static int dvbt_sc_command(struct drxk_state *state,
        case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
        case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
                status |= write16(state, OFDM_SC_RA_RAM_PARAM1__A, param1);
-               /* fall through - All commands using 1 parameters */
+               fallthrough;    /* All commands using 1 parameters */
        case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
        case OFDM_SC_RA_RAM_CMD_USER_IO:
                status |= write16(state, OFDM_SC_RA_RAM_PARAM0__A, param0);
-               /* fall through - All commands using 0 parameters */
+               fallthrough;    /* All commands using 0 parameters */
        case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
        case OFDM_SC_RA_RAM_CMD_NULL:
                /* Write command */
@@ -3761,7 +3761,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
        case TRANSMISSION_MODE_AUTO:
        default:
                operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
-               /* fall through - try first guess DRX_FFTMODE_8K */
+               fallthrough;    /* try first guess DRX_FFTMODE_8K */
        case TRANSMISSION_MODE_8K:
                transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
                break;
@@ -3775,7 +3775,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
        default:
        case GUARD_INTERVAL_AUTO:
                operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
-               /* fall through - try first guess DRX_GUARD_1DIV4 */
+               fallthrough;    /* try first guess DRX_GUARD_1DIV4 */
        case GUARD_INTERVAL_1_4:
                transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
                break;
@@ -3798,7 +3798,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
                operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
                /* try first guess SC_RA_RAM_OP_PARAM_HIER_NO */
                /* transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */
-               /* fall through */
+               fallthrough;
        case HIERARCHY_1:
                transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
                break;
@@ -3816,7 +3816,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
        case QAM_AUTO:
        default:
                operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
-               /* fall through - try first guess DRX_CONSTELLATION_QAM64 */
+               fallthrough;    /* try first guess DRX_CONSTELLATION_QAM64 */
        case QAM_64:
                transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
                break;
@@ -3841,7 +3841,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
                WR16(dev_addr, OFDM_EC_SB_PRIOR__A,
                        OFDM_EC_SB_PRIOR_HI));
                break;
-       case DRX_PRIORITY_UNKNOWN:      /* fall through */
+       case DRX_PRIORITY_UNKNOWN:
        default:
                status = -EINVAL;
                goto error;
@@ -3859,7 +3859,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
        case FEC_AUTO:
        default:
                operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
-               /* fall through - try first guess DRX_CODERATE_2DIV3 */
+               fallthrough;    /* try first guess DRX_CODERATE_2DIV3 */
        case FEC_2_3:
                transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
                break;
@@ -3893,7 +3893,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz,
        switch (state->props.bandwidth_hz) {
        case 0:
                state->props.bandwidth_hz = 8000000;
-               /* fall through */
+               fallthrough;
        case 8000000:
                bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ;
                status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A,
index d3c330e..722576f 100644 (file)
@@ -768,7 +768,7 @@ static int lgdt3306a_set_if(struct lgdt3306a_state *state,
        default:
                pr_warn("IF=%d KHz is not supported, 3250 assumed\n",
                        if_freq_khz);
-               /* fallthrough */
+               fallthrough;
        case 3250: /* 3.25Mhz */
                nco1 = 0x34;
                nco2 = 0x00;
index 8818975..399d5c5 100644 (file)
@@ -201,7 +201,7 @@ static int mt352_set_parameters(struct dvb_frontend *fe)
                        if (op->hierarchy == HIERARCHY_AUTO ||
                            op->hierarchy == HIERARCHY_NONE)
                                break;
-                       /* fall through */
+                       fallthrough;
                default:
                        return -EINVAL;
        }
index 290b9ea..4404ace 100644 (file)
@@ -739,7 +739,7 @@ static int get_frontend(struct dvb_frontend *fe,
                default:
                        break;
                }
-               /* Fall through */
+               fallthrough;
        case SYS_DVBS:
                switch ((enum MXL_HYDRA_MODULATION_E)
                        reg_data[DMD_MODULATION_SCHEME_ADDR]) {
index 35a3e47..24de1b1 100644 (file)
@@ -482,7 +482,7 @@ start:
        switch (reg&0xff) {
        case 0x06:
                if (reg & 0x1000) usK = 3 << 24;
-               /* fall through */
+               fallthrough;
        case 0x43: /* QAM64 */
                c = 150204167;
                break;
index 8940291..c1334d7 100644 (file)
@@ -398,7 +398,7 @@ static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz)
        default:
                dprintk("%s(%d KHz) Invalid, defaulting to 5380\n",
                        __func__, KHz);
-               /* fall through */
+               fallthrough;
        case 5380:
        case 44000:
                s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1be4);
index 2fc6aea..2a2cf20 100644 (file)
@@ -201,7 +201,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe)
                break;
        default:
                c->bandwidth_hz = 8000000;
-               /* fall through */
+               fallthrough;
        case 8000000:
                zl10353_single_write(fe, MCLK_RATIO, 0x75);
                zl10353_single_write(fe, 0x64, 0x36);
@@ -258,7 +258,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe)
                if (c->hierarchy == HIERARCHY_AUTO ||
                    c->hierarchy == HIERARCHY_NONE)
                        break;
-               /* fall through */
+               fallthrough;
        default:
                return -EINVAL;
        }
index 48ae60a..c7ba76f 100644 (file)
@@ -467,7 +467,7 @@ config VIDEO_VPX3220
 config VIDEO_MAX9286
        tristate "Maxim MAX9286 GMSL deserializer support"
        depends on I2C && I2C_MUX
-       depends on OF
+       depends on OF_GPIO
        select V4L2_FWNODE
        select VIDEO_V4L2_SUBDEV_API
        select MEDIA_CONTROLLER
@@ -741,7 +741,7 @@ config VIDEO_HI556
 config VIDEO_IMX214
        tristate "Sony IMX214 sensor support"
        depends on GPIOLIB && I2C && VIDEO_V4L2
-       depends on V4L2_FWNODE
+       select V4L2_FWNODE
        select MEDIA_CONTROLLER
        select VIDEO_V4L2_SUBDEV_API
        select REGMAP_I2C
index 570a4a0..03eee60 100644 (file)
@@ -2209,7 +2209,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
-               /* fall-through */
+               fallthrough;
        case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
                ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
                ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -2370,7 +2370,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                /* Currently only enabled for the integrated IR controller */
                if (!enable_885_ir)
                        break;
-               /* fall-through */
+               fallthrough;
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
        case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE:
index 7cabb9e..92fe051 100644 (file)
@@ -1310,7 +1310,7 @@ static void dvb_input_detach(struct ddb_input *input)
                        dvb_unregister_frontend(dvb->fe2);
                if (dvb->fe)
                        dvb_unregister_frontend(dvb->fe);
-               /* fallthrough */
+               fallthrough;
        case 0x30:
                dvb_module_release(dvb->i2c_client[0]);
                dvb->i2c_client[0] = NULL;
@@ -1321,22 +1321,22 @@ static void dvb_input_detach(struct ddb_input *input)
                        dvb_frontend_detach(dvb->fe);
                dvb->fe = NULL;
                dvb->fe2 = NULL;
-               /* fallthrough */
+               fallthrough;
        case 0x20:
                dvb_net_release(&dvb->dvbnet);
-               /* fallthrough */
+               fallthrough;
        case 0x12:
                dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
                                              &dvb->hw_frontend);
                dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
                                              &dvb->mem_frontend);
-               /* fallthrough */
+               fallthrough;
        case 0x11:
                dvb_dmxdev_release(&dvb->dmxdev);
-               /* fallthrough */
+               fallthrough;
        case 0x10:
                dvb_dmx_release(&dvb->demux);
-               /* fallthrough */
+               fallthrough;
        case 0x01:
                break;
        }
@@ -1559,7 +1559,7 @@ static int dvb_input_attach(struct ddb_input *input)
                        osc24 = 0;
                else
                        osc24 = 1;
-               /* fall-through */
+               fallthrough;
        case DDB_TUNER_DVBCT2_SONY_P:
        case DDB_TUNER_DVBC2T2_SONY_P:
        case DDB_TUNER_ISDBT_SONY_P:
@@ -1575,7 +1575,7 @@ static int dvb_input_attach(struct ddb_input *input)
                break;
        case DDB_TUNER_DVBC2T2I_SONY:
                osc24 = 1;
-               /* fall-through */
+               fallthrough;
        case DDB_TUNER_DVBCT2_SONY:
        case DDB_TUNER_DVBC2T2_SONY:
        case DDB_TUNER_ISDBT_SONY:
@@ -2036,7 +2036,7 @@ static int ddb_port_attach(struct ddb_port *port)
                ret = ddb_ci_attach(port, ci_bitrate);
                if (ret < 0)
                        break;
-               /* fall-through */
+               fallthrough;
        case DDB_PORT_LOOP:
                ret = dvb_register_device(port->dvb[0].adap,
                                          &port->dvb[0].dev,
@@ -2432,7 +2432,8 @@ void ddb_ports_init(struct ddb *dev)
                                        ddb_input_init(port, 4 + i, 1, 4 + i);
                                        ddb_output_init(port, i);
                                        break;
-                               } /* fallthrough */
+                               }
+                               fallthrough;
                        case DDB_OCTOPUS:
                                ddb_input_init(port, 2 * i, 0, 2 * i);
                                ddb_input_init(port, 2 * i + 1, 1, 2 * i + 1);
@@ -3417,7 +3418,7 @@ int ddb_exit_ddbridge(int stage, int error)
        default:
        case 2:
                destroy_workqueue(ddb_wq);
-               /* fall-through */
+               fallthrough;
        case 1:
                ddb_class_destroy();
                break;
index 7fb3b18..8944e4b 100644 (file)
@@ -952,7 +952,7 @@ static int meyeioc_sync(struct file *file, void *fh, int *i)
                        mutex_unlock(&meye.lock);
                        return -EINTR;
                }
-               /* fall through */
+               fallthrough;
        case MEYE_BUF_DONE:
                meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
                if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused,
index bf36b1e..45228f4 100644 (file)
@@ -637,7 +637,7 @@ static void gpioirq(unsigned long cookie)
                        iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
                        break;
                }
-               /* fall through */
+               fallthrough;
 
        case DATA_TS_RECORD:
        case DATA_PES_RECORD:
@@ -2176,7 +2176,7 @@ static int frontend_init(struct av7110 *av7110)
                                break;
                        }
                }
-               /* fall-thru */
+                       fallthrough;
 
                case 0x0008: // Hauppauge/TT DVB-T
                        // Grundig 29504-401
index e8a8ec5..93ca31e 100644 (file)
@@ -1107,7 +1107,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
                break;
        case OSD_SetRow:
                dc->y1 = dc->y0;
-               /* fall through */
+               fallthrough;
        case OSD_SetBlock:
                ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
                break;
index ec528fa..30330ed 100644 (file)
@@ -182,7 +182,7 @@ int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
                        case DSM_CC_STREAM  :
                        case ISO13522_STREAM:
                                p->done = 1;
-                               /* fall through */
+                               fallthrough;
                        case PRIVATE_STREAM1:
                        case VIDEO_STREAM_S ... VIDEO_STREAM_E:
                        case AUDIO_STREAM_S ... AUDIO_STREAM_E:
index 38cac50..3cb8300 100644 (file)
@@ -1226,7 +1226,7 @@ static void frontend_init(struct budget_av *budget_av)
                 * but so far it has been only confirmed for this type
                 */
                budget_av->reinitialise_demod = 1;
-               /* fall through */
+               fallthrough;
        case SUBID_DVBS_KNC1_PLUS:
        case SUBID_DVBS_EASYWATCH_1:
                if (saa->pci->subsystem_vendor == 0x1894) {
index 9c81127..a88711a 100644 (file)
@@ -613,7 +613,7 @@ static void frontend_init(struct budget *budget)
                        break;
                }
        }
-       /* fall through */
+               fallthrough;
        case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)
        {
                struct dvb_frontend *fe;
@@ -638,7 +638,7 @@ static void frontend_init(struct budget *budget)
                        break;
                }
        }
-       /* fall through */
+               fallthrough;
 
        case 0x101c: { /* TT S2-1600 */
                        const struct stv6110x_devctl *ctl;
index 36e5f2f..b22dc1d 100644 (file)
@@ -220,7 +220,7 @@ static void sh_vou_stream_config(struct sh_vou_device *vou_dev)
                break;
        case V4L2_PIX_FMT_RGB565:
                dataswap ^= 1;
-               /* fall through */
+               fallthrough;
        case V4L2_PIX_FMT_RGB565X:
                row_coeff = 2;
                break;
@@ -802,7 +802,7 @@ static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt)
        default:
                pr_warn("%s(): Invalid bus-format code %d, using default 8-bit\n",
                        __func__, bus_fmt);
-               /* fall through */
+               fallthrough;
        case SH_VOU_BUS_8BIT:
                return 1;
        case SH_VOU_BUS_16BIT:
index e496083..4123405 100644 (file)
@@ -226,7 +226,7 @@ static inline void cal_write_field(struct cal_dev *cal, u32 offset, u32 value,
        u32 val = cal_read(cal, offset);
 
        val &= ~mask;
-       val |= FIELD_PREP(mask, value);
+       val |= (value << __ffs(mask)) & mask;
        cal_write(cal, offset, val);
 }
 
index b203296..7e24602 100644 (file)
@@ -105,7 +105,8 @@ static inline enum phase_diversity_modes_idx
 si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode)
 {
        switch (mode) {
-       default:                /* FALLTHROUGH */
+       default:
+               fallthrough;
        case SI476X_PHDIV_DISABLED:
                return SI476X_IDX_PHDIV_DISABLED;
        case SI476X_PHDIV_PRIMARY_COMBINING:
index b0303cf..c373152 100644 (file)
@@ -249,7 +249,7 @@ int snd_tea575x_enum_freq_bands(struct snd_tea575x *tea,
                        index = BAND_AM;
                        break;
                }
-               /* Fall through */
+               fallthrough;
        default:
                return -EINVAL;
        }
index 5bb1444..3fe3edd 100644 (file)
@@ -112,7 +112,7 @@ lirc_mode2_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
        case BPF_FUNC_trace_printk:
                if (perfmon_capable())
                        return bpf_get_trace_printk_proto();
-               /* fall through */
+               fallthrough;
        default:
                return NULL;
        }
index f33b443..c6cd2e6 100644 (file)
@@ -19,8 +19,6 @@ struct gpio_ir {
        struct gpio_desc *gpio;
        unsigned int carrier;
        unsigned int duty_cycle;
-       /* we need a spinlock to hold the cpu while transmitting */
-       spinlock_t lock;
 };
 
 static const struct of_device_id gpio_ir_tx_of_match[] = {
@@ -53,12 +51,11 @@ static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u32 carrier)
 static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf,
                                   uint count)
 {
-       unsigned long flags;
        ktime_t edge;
        s32 delta;
        int i;
 
-       spin_lock_irqsave(&gpio_ir->lock, flags);
+       local_irq_disable();
 
        edge = ktime_get();
 
@@ -72,14 +69,11 @@ static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf,
        }
 
        gpiod_set_value(gpio_ir->gpio, 0);
-
-       spin_unlock_irqrestore(&gpio_ir->lock, flags);
 }
 
 static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf,
                                 uint count)
 {
-       unsigned long flags;
        ktime_t edge;
        /*
         * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on
@@ -95,7 +89,7 @@ static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf,
        space = DIV_ROUND_CLOSEST((100 - gpio_ir->duty_cycle) *
                                  (NSEC_PER_SEC / 100), gpio_ir->carrier);
 
-       spin_lock_irqsave(&gpio_ir->lock, flags);
+       local_irq_disable();
 
        edge = ktime_get();
 
@@ -128,19 +122,20 @@ static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf,
                        edge = last;
                }
        }
-
-       spin_unlock_irqrestore(&gpio_ir->lock, flags);
 }
 
 static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
                      unsigned int count)
 {
        struct gpio_ir *gpio_ir = dev->priv;
+       unsigned long flags;
 
+       local_irq_save(flags);
        if (gpio_ir->carrier)
                gpio_ir_tx_modulated(gpio_ir, txbuf, count);
        else
                gpio_ir_tx_unmodulated(gpio_ir, txbuf, count);
+       local_irq_restore(flags);
 
        return count;
 }
@@ -176,7 +171,6 @@ static int gpio_ir_tx_probe(struct platform_device *pdev)
 
        gpio_ir->carrier = 38000;
        gpio_ir->duty_cycle = 50;
-       spin_lock_init(&gpio_ir->lock);
 
        rc = devm_rc_register_device(&pdev->dev, rcdev);
        if (rc < 0)
index 95727ca..0cda78f 100644 (file)
@@ -64,7 +64,7 @@ static enum rc6_mode rc6_mode(struct rc6_dec *data)
        case 6:
                if (!data->toggle)
                        return RC6_MODE_6A;
-               /* fall through */
+               fallthrough;
        default:
                return RC6_MODE_UNKNOWN;
        }
index 9fa58d9..7d9a7c0 100644 (file)
@@ -102,7 +102,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
                }
 
                data->state = STATE_FINISHED;
-               /* Fall through */
+               fallthrough;
 
        case STATE_FINISHED:
                if (ev.pulse)
index f961615..98681ba 100644 (file)
@@ -1726,7 +1726,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
                goto mem_alloc_fail;
 
        ir->pipe_in = pipe;
-       ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in);
+       ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_KERNEL, &ir->dma_in);
        if (!ir->buf_in)
                goto buf_in_alloc_fail;
 
index 7b53066..dee8a9f 100644 (file)
@@ -1292,6 +1292,10 @@ static ssize_t store_protocols(struct device *device,
        }
 
        mutex_lock(&dev->lock);
+       if (!dev->registered) {
+               mutex_unlock(&dev->lock);
+               return -ENODEV;
+       }
 
        old_protocols = *current_protocols;
        new_protocols = old_protocols;
@@ -1430,6 +1434,10 @@ static ssize_t store_filter(struct device *device,
                return -EINVAL;
 
        mutex_lock(&dev->lock);
+       if (!dev->registered) {
+               mutex_unlock(&dev->lock);
+               return -ENODEV;
+       }
 
        new_filter = *filter;
        if (fattr->mask)
@@ -1544,6 +1552,10 @@ static ssize_t store_wakeup_protocols(struct device *device,
        int i;
 
        mutex_lock(&dev->lock);
+       if (!dev->registered) {
+               mutex_unlock(&dev->lock);
+               return -ENODEV;
+       }
 
        allowed = dev->allowed_wakeup_protocols;
 
@@ -1601,25 +1613,25 @@ static void rc_dev_release(struct device *device)
        kfree(dev);
 }
 
-#define ADD_HOTPLUG_VAR(fmt, val...)                                   \
-       do {                                                            \
-               int err = add_uevent_var(env, fmt, val);                \
-               if (err)                                                \
-                       return err;                                     \
-       } while (0)
-
 static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 {
        struct rc_dev *dev = to_rc_dev(device);
+       int ret = 0;
 
-       if (dev->rc_map.name)
-               ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name);
-       if (dev->driver_name)
-               ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name);
-       if (dev->device_name)
-               ADD_HOTPLUG_VAR("DEV_NAME=%s", dev->device_name);
+       mutex_lock(&dev->lock);
 
-       return 0;
+       if (!dev->registered)
+               ret = -ENODEV;
+       if (ret == 0 && dev->rc_map.name)
+               ret = add_uevent_var(env, "NAME=%s", dev->rc_map.name);
+       if (ret == 0 && dev->driver_name)
+               ret = add_uevent_var(env, "DRV_NAME=%s", dev->driver_name);
+       if (ret == 0 && dev->device_name)
+               ret = add_uevent_var(env, "DEV_NAME=%s", dev->device_name);
+
+       mutex_unlock(&dev->lock);
+
+       return ret;
 }
 
 /*
@@ -2011,14 +2023,14 @@ void rc_unregister_device(struct rc_dev *dev)
        del_timer_sync(&dev->timer_keyup);
        del_timer_sync(&dev->timer_repeat);
 
-       rc_free_rx_device(dev);
-
        mutex_lock(&dev->lock);
        if (dev->users && dev->close)
                dev->close(dev);
        dev->registered = false;
        mutex_unlock(&dev->lock);
 
+       rc_free_rx_device(dev);
+
        /*
         * lirc device should be freed with dev->registered = false, so
         * that userspace polling will get notified.
index 8941d73..71928e3 100644 (file)
@@ -1994,6 +1994,7 @@ static int vicodec_request_validate(struct media_request *req)
        }
        ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl,
                                               vicodec_ctrl_stateless_state.id);
+       v4l2_ctrl_request_hdl_put(hdl);
        if (!ctrl) {
                v4l2_info(&ctx->dev->v4l2_dev,
                          "Missing required codec control\n");
index 734a92c..7b7d9fe 100644 (file)
@@ -756,7 +756,7 @@ static int xc5000_set_digital_params(struct dvb_frontend *fe)
                if (!bw)
                        bw = 6000000;
                /* fall to OFDM handling */
-               /* fall through */
+               fallthrough;
        case SYS_DMBTH:
        case SYS_DVBT:
        case SYS_DVBT2:
index 198ddfb..e3234d1 100644 (file)
@@ -525,7 +525,7 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb)
        case USB_SPEED_HIGH:
                info("running at HIGH speed.");
                break;
-       case USB_SPEED_UNKNOWN: /* fall through */
+       case USB_SPEED_UNKNOWN:
        default:
                err("cannot handle USB speed because it is unknown.");
                return -ENODEV;
index 20c50c2..e747548 100644 (file)
@@ -165,7 +165,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_VP_BRIGHTNESS:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_VP_BRIGHTNESS:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -176,7 +176,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_CONTRAST:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_CONTRAST:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -184,7 +184,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_VP_SATURATION:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_VP_SATURATION:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -195,7 +195,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_VP_GPIO_DATA:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_VP_GPIO_DATA:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -203,7 +203,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_VP_GPIO_DIRECTION:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -211,7 +211,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_VC_MP_GPIO_DATA:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
                cmd.reg_count = 1;
@@ -219,7 +219,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION:
                cmd.buffer.block_data[0] = param;
-               /*fall through */
+               fallthrough;
        case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
                cmd.reg_count = 1;
@@ -234,7 +234,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_FLICKER_MODES:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_FLICKER_MODES:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -281,7 +281,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_USER_MODE:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_USER_MODE:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -301,7 +301,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_WAKEUP:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_WAKEUP:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
                cmd.reg_count = 1;
@@ -309,7 +309,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_PW_CONTROL:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_PW_CONTROL:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
                cmd.reg_count = 1;
@@ -322,7 +322,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_SYSTEM_CTRL:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_SYSTEM_CTRL:
                cmd.req_mode =
                    CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
@@ -331,7 +331,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_VP_SYSTEM_CTRL:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -339,7 +339,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_VP_EXP_MODES:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_VP_EXP_MODES:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -347,7 +347,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_DEVICE_CONFIG:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_DEVICE_CONFIG:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -368,7 +368,7 @@ int cpia2_do_command(struct camera_data *cam,
                break;
        case CPIA2_CMD_SET_VC_CONTROL:
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_VC_CONTROL:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
                cmd.reg_count = 1;
@@ -403,7 +403,7 @@ int cpia2_do_command(struct camera_data *cam,
                                             this register can also affect
                                             flicker modes */
                cmd.buffer.block_data[0] = param;
-               /* fall through */
+               fallthrough;
        case CPIA2_CMD_GET_USER_EFFECTS:
                cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
                cmd.reg_count = 1;
@@ -1751,7 +1751,7 @@ int cpia2_set_fps(struct camera_data *cam, int framerate)
                                                    CPIA2_VP_SENSOR_FLAGS_500) {
                                return -EINVAL;
                        }
-                       /* Fall through */
+                       fallthrough;
                case CPIA2_VP_FRAMERATE_15:
                case CPIA2_VP_FRAMERATE_12_5:
                case CPIA2_VP_FRAMERATE_7_5:
index d9f953f..425e470 100644 (file)
@@ -996,7 +996,7 @@ void cx231xx_v4l2_create_entities(struct cx231xx *dev)
                        /* The DVB core will handle it */
                        if (dev->tuner_type == TUNER_ABSENT)
                                continue;
-                       /* fall through */
+                       fallthrough;
                default: /* just to shut up a gcc warning */
                        ent->function = MEDIA_ENT_F_CONN_RF;
                        break;
index 4ef3fa9..52e648e 100644 (file)
@@ -1659,14 +1659,14 @@ static int dib8096_set_param_override(struct dvb_frontend *fe)
 
        switch (band) {
        default:
-                       deb_info("Warning : Rf frequency  (%iHz) is not in the supported range, using VHF switch ", fe->dtv_property_cache.frequency);
-                       /* fall through */
+               deb_info("Warning : Rf frequency  (%iHz) is not in the supported range, using VHF switch ", fe->dtv_property_cache.frequency);
+               fallthrough;
        case BAND_VHF:
-                       state->dib8000_ops.set_gpio(fe, 3, 0, 1);
-                       break;
+               state->dib8000_ops.set_gpio(fe, 3, 0, 1);
+               break;
        case BAND_UHF:
-                       state->dib8000_ops.set_gpio(fe, 3, 0, 0);
-                       break;
+               state->dib8000_ops.set_gpio(fe, 3, 0, 0);
+               break;
        }
 
        ret = state->set_param_save(fe);
index f96626f..a27a684 100644 (file)
@@ -1886,12 +1886,12 @@ static int dw2102_load_firmware(struct usb_device *dev,
                switch (le16_to_cpu(dev->descriptor.idProduct)) {
                case USB_PID_TEVII_S650:
                        dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC;
-                       /* fall through */
+                       fallthrough;
                case USB_PID_DW2104:
                        reset = 1;
                        dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
                                        DW210X_WRITE_MSG);
-                       /* fall through */
+                       fallthrough;
                case USB_PID_DW3101:
                        reset = 0;
                        dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
@@ -1924,7 +1924,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                                        break;
                                }
                        }
-                       /* fall through */
+                       fallthrough;
                case 0x2101:
                        dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2,
                                        DW210X_READ_MSG);
index 593bcf6..a99e82e 100644 (file)
@@ -246,9 +246,6 @@ struct v4l2_format32 {
  * @memory:    buffer memory type
  * @format:    frame format, for which buffers are requested
  * @capabilities: capabilities of this buffer type.
- * @flags:     additional buffer management attributes (ignored unless the
- *             queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and
- *             configured for MMAP streaming I/O).
  * @reserved:  future extensions
  */
 struct v4l2_create_buffers32 {
@@ -257,8 +254,7 @@ struct v4l2_create_buffers32 {
        __u32                   memory; /* enum v4l2_memory */
        struct v4l2_format32    format;
        __u32                   capabilities;
-       __u32                   flags;
-       __u32                   reserved[6];
+       __u32                   reserved[7];
 };
 
 static int __bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size)
@@ -359,8 +355,7 @@ static int get_v4l2_create32(struct v4l2_create_buffers __user *p64,
 {
        if (!access_ok(p32, sizeof(*p32)) ||
            copy_in_user(p64, p32,
-                        offsetof(struct v4l2_create_buffers32, format)) ||
-           assign_in_user(&p64->flags, &p32->flags))
+                        offsetof(struct v4l2_create_buffers32, format)))
                return -EFAULT;
        return __get_v4l2_format32(&p64->format, &p32->format,
                                   aux_buf, aux_space);
@@ -422,7 +417,6 @@ static int put_v4l2_create32(struct v4l2_create_buffers __user *p64,
            copy_in_user(p32, p64,
                         offsetof(struct v4l2_create_buffers32, format)) ||
            assign_in_user(&p32->capabilities, &p64->capabilities) ||
-           assign_in_user(&p32->flags, &p64->flags) ||
            copy_in_user(p32->reserved, p64->reserved, sizeof(p64->reserved)))
                return -EFAULT;
        return __put_v4l2_format32(&p64->format, &p32->format);
index 3f3fbcd..45a2403 100644 (file)
@@ -2200,7 +2200,7 @@ static int check_range(enum v4l2_ctrl_type type,
        case V4L2_CTRL_TYPE_BOOLEAN:
                if (step != 1 || max > 1 || min < 0)
                        return -ERANGE;
-               /* fall through */
+               fallthrough;
        case V4L2_CTRL_TYPE_U8:
        case V4L2_CTRL_TYPE_U16:
        case V4L2_CTRL_TYPE_U32:
index a556880..eeff398 100644 (file)
@@ -782,7 +782,6 @@ static void v4l_print_frmsizeenum(const void *arg, bool write_only)
                                p->stepwise.step_height);
                break;
        case V4L2_FRMSIZE_TYPE_CONTINUOUS:
-               /* fall through */
        default:
                pr_cont("\n");
                break;
@@ -816,7 +815,6 @@ static void v4l_print_frmivalenum(const void *arg, bool write_only)
                                p->stepwise.step.denominator);
                break;
        case V4L2_FRMIVAL_TYPE_CONTINUOUS:
-               /* fall through */
        default:
                pr_cont("\n");
                break;
@@ -2044,6 +2042,9 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops,
 
        if (ret)
                return ret;
+
+       CLEAR_AFTER_FIELD(p, capabilities);
+
        return ops->vidioc_reqbufs(file, fh, p);
 }
 
@@ -2083,7 +2084,7 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops,
        if (ret)
                return ret;
 
-       CLEAR_AFTER_FIELD(create, flags);
+       CLEAR_AFTER_FIELD(create, capabilities);
 
        v4l_sanitize_format(&create->format);
 
@@ -3189,14 +3190,16 @@ static int video_put_user(void __user *arg, void *parg, unsigned int cmd)
 #ifdef CONFIG_COMPAT_32BIT_TIME
        case VIDIOC_DQEVENT_TIME32: {
                struct v4l2_event *ev = parg;
-               struct v4l2_event_time32 ev32 = {
-                       .type           = ev->type,
-                       .pending        = ev->pending,
-                       .sequence       = ev->sequence,
-                       .timestamp.tv_sec  = ev->timestamp.tv_sec,
-                       .timestamp.tv_nsec = ev->timestamp.tv_nsec,
-                       .id             = ev->id,
-               };
+               struct v4l2_event_time32 ev32;
+
+               memset(&ev32, 0, sizeof(ev32));
+
+               ev32.type       = ev->type;
+               ev32.pending    = ev->pending;
+               ev32.sequence   = ev->sequence;
+               ev32.timestamp.tv_sec   = ev->timestamp.tv_sec;
+               ev32.timestamp.tv_nsec  = ev->timestamp.tv_nsec;
+               ev32.id         = ev->id;
 
                memcpy(&ev32.u, &ev->u, sizeof(ev->u));
                memcpy(&ev32.reserved, &ev->reserved, sizeof(ev->reserved));
@@ -3210,21 +3213,23 @@ static int video_put_user(void __user *arg, void *parg, unsigned int cmd)
        case VIDIOC_DQBUF_TIME32:
        case VIDIOC_PREPARE_BUF_TIME32: {
                struct v4l2_buffer *vb = parg;
-               struct v4l2_buffer_time32 vb32 = {
-                       .index          = vb->index,
-                       .type           = vb->type,
-                       .bytesused      = vb->bytesused,
-                       .flags          = vb->flags,
-                       .field          = vb->field,
-                       .timestamp.tv_sec       = vb->timestamp.tv_sec,
-                       .timestamp.tv_usec      = vb->timestamp.tv_usec,
-                       .timecode       = vb->timecode,
-                       .sequence       = vb->sequence,
-                       .memory         = vb->memory,
-                       .m.userptr      = vb->m.userptr,
-                       .length         = vb->length,
-                       .request_fd     = vb->request_fd,
-               };
+               struct v4l2_buffer_time32 vb32;
+
+               memset(&vb32, 0, sizeof(vb32));
+
+               vb32.index      = vb->index;
+               vb32.type       = vb->type;
+               vb32.bytesused  = vb->bytesused;
+               vb32.flags      = vb->flags;
+               vb32.field      = vb->field;
+               vb32.timestamp.tv_sec   = vb->timestamp.tv_sec;
+               vb32.timestamp.tv_usec  = vb->timestamp.tv_usec;
+               vb32.timecode   = vb->timecode;
+               vb32.sequence   = vb->sequence;
+               vb32.memory     = vb->memory;
+               vb32.m.userptr  = vb->m.userptr;
+               vb32.length     = vb->length;
+               vb32.request_fd = vb->request_fd;
 
                if (copy_to_user(arg, &vb32, sizeof(vb32)))
                        return -EFAULT;
index 5c91fc3..606a271 100644 (file)
@@ -354,7 +354,7 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
                break;
        case VIDEOBUF_ERROR:
                b->flags |= V4L2_BUF_FLAG_ERROR;
-               /* fall through */
+               fallthrough;
        case VIDEOBUF_DONE:
                b->flags |= V4L2_BUF_FLAG_DONE;
                break;
index f512cbc..ca00976 100644 (file)
@@ -313,7 +313,6 @@ static unsigned long gpmc_get_clk_period(int cs, enum gpmc_clk_domain cd)
                tick_ps *= div;
                break;
        case GPMC_CD_FCLK:
-               /* FALL-THROUGH */
        default:
                break;
        }
index 693ee73..ef03d6f 100644 (file)
@@ -441,6 +441,9 @@ static void memstick_check(struct work_struct *work)
        } else if (host->card->stop)
                host->card->stop(host->card);
 
+       if (host->removing)
+               goto out_power_off;
+
        card = memstick_alloc_card(host);
 
        if (!card) {
@@ -545,6 +548,7 @@ EXPORT_SYMBOL(memstick_add_host);
  */
 void memstick_remove_host(struct memstick_host *host)
 {
+       host->removing = 1;
        flush_workqueue(workqueue);
        mutex_lock(&host->lock);
        if (host->card)
index d9ee8e3..1789542 100644 (file)
@@ -371,7 +371,7 @@ again:
                        serial mode), then just fall through */
                if (msb_read_int_reg(msb, -1))
                        return 0;
-               /* fallthrough */
+               fallthrough;
 
        case MSB_RP_RECEIVE_INT_REQ_RESULT:
                intreg = mrq->data[0];
@@ -403,7 +403,7 @@ again:
        case MSB_RP_RECEIVE_STATUS_REG:
                msb->regs.status = *(struct ms_status_register *)mrq->data;
                msb->state = MSB_RP_SEND_OOB_READ;
-               /* fallthrough */
+               fallthrough;
 
        case MSB_RP_SEND_OOB_READ:
                if (!msb_read_regs(msb,
@@ -418,7 +418,7 @@ again:
                msb->regs.extra_data =
                        *(struct ms_extra_data_register *) mrq->data;
                msb->state = MSB_RP_SEND_READ_DATA;
-               /* fallthrough */
+               fallthrough;
 
        case MSB_RP_SEND_READ_DATA:
                /* Skip that state if we only read the oob */
@@ -518,7 +518,7 @@ again:
                msb->state = MSB_WB_RECEIVE_INT_REQ;
                if (msb_read_int_reg(msb, -1))
                        return 0;
-               /* fallthrough */
+               fallthrough;
 
        case MSB_WB_RECEIVE_INT_REQ:
                intreg = mrq->data[0];
@@ -549,7 +549,7 @@ again:
 
                msb->int_polling = false;
                msb->state = MSB_WB_SEND_WRITE_DATA;
-               /* fallthrough */
+               fallthrough;
 
        case MSB_WB_SEND_WRITE_DATA:
                sg_init_table(sg, ARRAY_SIZE(sg));
@@ -628,7 +628,7 @@ again:
                msb->state = MSB_SC_RECEIVE_INT_REQ;
                if (msb_read_int_reg(msb, -1))
                        return 0;
-               /* fallthrough */
+               fallthrough;
 
        case MSB_SC_RECEIVE_INT_REQ:
                intreg = mrq->data[0];
index 4a6b866..e83c3ad 100644 (file)
@@ -255,11 +255,11 @@ static unsigned int jmb38x_ms_write_data(struct jmb38x_ms_host *host,
        case 3:
                host->io_word[0] |= buf[off + 2] << 16;
                host->io_pos++;
-               /* fall through */
+               fallthrough;
        case 2:
                host->io_word[0] |= buf[off + 1] << 8;
                host->io_pos++;
-               /* fall through */
+               fallthrough;
        case 1:
                host->io_word[0] |= buf[off];
                host->io_pos++;
index fc35c74..786e467 100644 (file)
@@ -162,11 +162,11 @@ static unsigned int tifm_ms_write_data(struct tifm_ms *host,
        case 3:
                host->io_word |= buf[off + 2] << 16;
                host->io_pos++;
-               /* fall through */
+               fallthrough;
        case 2:
                host->io_word |= buf[off + 1] << 8;
                host->io_pos++;
-               /* fall through */
+               fallthrough;
        case 1:
                host->io_word |= buf[off];
                host->io_pos++;
index 5216487..9903e96 100644 (file)
@@ -642,7 +642,7 @@ mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
                        freereq = 0;
                if (event != MPI_EVENT_EVENT_CHANGE)
                        break;
-               /* fall through */
+               fallthrough;
        case MPI_FUNCTION_CONFIG:
        case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
                ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
@@ -1887,7 +1887,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        case MPI_MANUFACTPAGE_DEVICEID_FC939X:
        case MPI_MANUFACTPAGE_DEVICEID_FC949X:
                ioc->errata_flag_1064 = 1;
-               /* fall through */
+               fallthrough;
        case MPI_MANUFACTPAGE_DEVICEID_FC909:
        case MPI_MANUFACTPAGE_DEVICEID_FC929:
        case MPI_MANUFACTPAGE_DEVICEID_FC919:
@@ -1932,7 +1932,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
                        pcixcmd &= 0x8F;
                        pci_write_config_byte(pdev, 0x6a, pcixcmd);
                }
-               /* fall through */
+               fallthrough;
 
        case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
                ioc->bus_type = SPI;
index 6a79cd0..18b91ea 100644 (file)
@@ -4326,7 +4326,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
                        }
                }
                mpt_findImVolumes(ioc);
-               /* fall through */
+               fallthrough;
 
        case MPTSAS_ADD_DEVICE:
                memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
index 1491561..8543f03 100644 (file)
@@ -784,7 +784,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                        /*
                         * Allow non-SAS & non-NEXUS_LOSS to drop into below code
                         */
-                       /* Fall through */
+                       fallthrough;
 
                case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
                        /* Linux handles an unsolicited DID_RESET better
@@ -881,7 +881,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 
                case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:           /* 0x0044 */
                        scsi_set_resid(sc, 0);
-                       /* Fall through */
+                       fallthrough;
                case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:        /* 0x0040 */
                case MPI_IOCSTATUS_SUCCESS:                     /* 0x0000 */
                        sc->result = (DID_OK << 16) | scsi_status;
index a9d9c1c..a5983d5 100644 (file)
@@ -1515,10 +1515,10 @@ static unsigned long dsiclk_rate(u8 n)
        switch (divsel) {
        case PRCM_DSI_PLLOUT_SEL_PHI_4:
                div *= 2;
-               /* Fall through */
+               fallthrough;
        case PRCM_DSI_PLLOUT_SEL_PHI_2:
                div *= 2;
-               /* Fall through */
+               fallthrough;
        case PRCM_DSI_PLLOUT_SEL_PHI:
                return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
                        PLL_RAW) / div;
index af764bc..761b4ef 100644 (file)
@@ -136,7 +136,7 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
                if (val & IQS620_PROX_SETTINGS_4_SAR_EN)
                        iqs62x->ui_sel = IQS62X_UI_SAR1;
 
-               /* fall through */
+               fallthrough;
 
        case IQS621_PROD_NUM:
                ret = regmap_write(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
@@ -470,7 +470,7 @@ static irqreturn_t iqs62x_irq(int irq, void *context)
                case IQS62X_EVENT_UI_LO:
                        event_data.ui_data = get_unaligned_le16(&event_map[i]);
 
-                       /* fall through */
+                       fallthrough;
 
                case IQS62X_EVENT_UI_HI:
                case IQS62X_EVENT_NONE:
@@ -491,7 +491,7 @@ static irqreturn_t iqs62x_irq(int irq, void *context)
                case IQS62X_EVENT_HYST:
                        event_map[i] <<= iqs62x->dev_desc->hyst_shift;
 
-                       /* fall through */
+                       fallthrough;
 
                case IQS62X_EVENT_WHEEL:
                case IQS62X_EVENT_HALL:
index c3651f0..fc00aac 100644 (file)
@@ -126,10 +126,6 @@ static int mfd_match_of_node_to_dev(struct platform_device *pdev,
        const __be32 *reg;
        u64 of_node_addr;
 
-       /* Skip devices 'disabled' by Device Tree */
-       if (!of_device_is_available(np))
-               return -ENODEV;
-
        /* Skip if OF node has previously been allocated to a device */
        list_for_each_entry(of_entry, &mfd_of_node_list, list)
                if (of_entry->np == np)
@@ -212,6 +208,12 @@ static int mfd_add_device(struct device *parent, int id,
        if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) {
                for_each_child_of_node(parent->of_node, np) {
                        if (of_device_is_compatible(np, cell->of_compatible)) {
+                               /* Ignore 'disabled' devices error free */
+                               if (!of_device_is_available(np)) {
+                                       ret = 0;
+                                       goto fail_alias;
+                               }
+
                                ret = mfd_match_of_node_to_dev(pdev, np, cell);
                                if (ret == -EAGAIN)
                                        continue;
@@ -370,8 +372,6 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
        regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
                                               cell->num_parent_supplies);
 
-       kfree(cell);
-
        platform_device_unregister(pdev);
        return 0;
 }
index 5bef142..111d11f 100644 (file)
@@ -172,7 +172,7 @@ static int mxs_lradc_probe(struct platform_device *pdev)
                                        MXS_LRADC_TOUCHSCREEN_5WIRE;
                                break;
                        }
-                       /* fall through - to an error message for i.MX23 */
+                       fallthrough;    /* to an error message for i.MX23 */
                default:
                        dev_err(&pdev->dev,
                                "Unsupported number of touchscreen wires (%d)\n"
index 1e6431c..2a3a240 100644 (file)
@@ -308,7 +308,7 @@ static int usbhs_runtime_resume(struct device *dev)
                                         i, r);
                                }
                        }
-               /* Fall through - as HSIC mode needs utmi_clk */
+                       fallthrough;    /* as HSIC mode needs utmi_clk */
 
                case OMAP_EHCI_PORT_MODE_TLL:
                        if (!IS_ERR(omap->utmi_clk[i])) {
@@ -344,7 +344,7 @@ static int usbhs_runtime_suspend(struct device *dev)
 
                        if (!IS_ERR(omap->hsic480m_clk[i]))
                                clk_disable_unprepare(omap->hsic480m_clk[i]);
-               /* Fall through - as utmi_clks were used in HSIC mode */
+                       fallthrough;    /* as utmi_clks were used in HSIC mode */
 
                case OMAP_EHCI_PORT_MODE_TLL:
                        if (!IS_ERR(omap->utmi_clk[i]))
index abaab54..545196c 100644 (file)
@@ -270,7 +270,7 @@ static void *stuff(unsigned char *dest, const unsigned char *src, size_t n)
                case RAVE_SP_ETX:
                case RAVE_SP_DLE:
                        *dest++ = RAVE_SP_DLE;
-                       /* FALLTHROUGH */
+                       fallthrough;
                default:
                        *dest++ = byte;
                }
@@ -541,7 +541,7 @@ static int rave_sp_receive_buf(struct serdev_device *serdev,
                         * deframer buffer
                         */
 
-                       /* FALLTHROUGH */
+                       fallthrough;
 
                case RAVE_SP_EXPECT_ESCAPED_DATA:
                        if (deframer->length == sizeof(deframer->data)) {
index 75859e4..df5cebb 100644 (file)
@@ -95,7 +95,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
                        break;
                default:
                        pr_err("Failed to retrieve valid hwlock: %d\n", ret);
-                       /* fall-through */
+                       fallthrough;
                case -EPROBE_DEFER:
                        goto err_regmap;
                }
index 2591c21..26a23ab 100644 (file)
@@ -692,10 +692,6 @@ static int at24_probe(struct i2c_client *client)
        nvmem_config.word_size = 1;
        nvmem_config.size = byte_len;
 
-       at24->nvmem = devm_nvmem_register(dev, &nvmem_config);
-       if (IS_ERR(at24->nvmem))
-               return PTR_ERR(at24->nvmem);
-
        i2c_set_clientdata(client, at24);
 
        err = regulator_enable(at24->vcc_reg);
@@ -708,6 +704,13 @@ static int at24_probe(struct i2c_client *client)
        pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
 
+       at24->nvmem = devm_nvmem_register(dev, &nvmem_config);
+       if (IS_ERR(at24->nvmem)) {
+               pm_runtime_disable(dev);
+               regulator_disable(at24->vcc_reg);
+               return PTR_ERR(at24->nvmem);
+       }
+
        /*
         * Perform a one-byte test read to verify that the
         * chip is functional.
index cde9a2f..ed8d38b 100644 (file)
@@ -90,10 +90,10 @@ static int at25_ee_read(void *priv, unsigned int offset,
        switch (at25->addrlen) {
        default:        /* case 3 */
                *cp++ = offset >> 16;
-               /* fall through */
+               fallthrough;
        case 2:
                *cp++ = offset >> 8;
-               /* fall through */
+               fallthrough;
        case 1:
        case 0: /* can't happen: for better codegen */
                *cp++ = offset >> 0;
@@ -178,10 +178,10 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
                switch (at25->addrlen) {
                default:        /* case 3 */
                        *cp++ = offset >> 16;
-                       /* fall through */
+                       fallthrough;
                case 2:
                        *cp++ = offset >> 8;
-                       /* fall through */
+                       fallthrough;
                case 1:
                case 0: /* can't happen: for better codegen */
                        *cp++ = offset >> 0;
@@ -278,7 +278,7 @@ static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
                switch (val) {
                case 9:
                        chip->flags |= EE_INSTR_BIT3_IS_ADDR;
-                       /* fall through */
+                       fallthrough;
                case 8:
                        chip->flags |= EE_ADDR1;
                        break;
index 7c38c4f..a800491 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 #include <linux/genalloc.h>
 
 static void cb_fini(struct hl_device *hdev, struct hl_cb *cb)
@@ -300,7 +301,7 @@ int hl_cb_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma)
        struct hl_device *hdev = hpriv->hdev;
        struct hl_cb *cb;
        phys_addr_t address;
-       u32 handle;
+       u32 handle, user_cb_size;
        int rc;
 
        handle = vma->vm_pgoff;
@@ -314,7 +315,8 @@ int hl_cb_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma)
        }
 
        /* Validation check */
-       if ((vma->vm_end - vma->vm_start) != ALIGN(cb->size, PAGE_SIZE)) {
+       user_cb_size = vma->vm_end - vma->vm_start;
+       if (user_cb_size != ALIGN(cb->size, PAGE_SIZE)) {
                dev_err(hdev->dev,
                        "CB mmap failed, mmap size 0x%lx != 0x%x cb size\n",
                        vma->vm_end - vma->vm_start, cb->size);
@@ -322,6 +324,16 @@ int hl_cb_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma)
                goto put_cb;
        }
 
+       if (!access_ok((void __user *) (uintptr_t) vma->vm_start,
+                                                       user_cb_size)) {
+               dev_err(hdev->dev,
+                       "user pointer is invalid - 0x%lx\n",
+                       vma->vm_start);
+
+               rc = -EINVAL;
+               goto put_cb;
+       }
+
        spin_lock(&cb->lock);
 
        if (cb->mmap) {
index b9840e3..2e3fcbc 100644 (file)
@@ -808,6 +808,14 @@ static int cs_ioctl_signal_wait(struct hl_fpriv *hpriv, enum hl_cs_type cs_type,
 
        /* currently it is guaranteed to have only one chunk */
        chunk = &cs_chunk_array[0];
+
+       if (chunk->queue_index >= hdev->asic_prop.max_queues) {
+               dev_err(hdev->dev, "Queue index %d is invalid\n",
+                       chunk->queue_index);
+               rc = -EINVAL;
+               goto free_cs_chunk_array;
+       }
+
        q_idx = chunk->queue_index;
        hw_queue_prop = &hdev->asic_prop.hw_queues_props[q_idx];
        q_type = hw_queue_prop->type;
index c50c6fc..aa77771 100644 (file)
@@ -19,7 +19,7 @@
 static struct dentry *hl_debug_root;
 
 static int hl_debugfs_i2c_read(struct hl_device *hdev, u8 i2c_bus, u8 i2c_addr,
-                               u8 i2c_reg, u32 *val)
+                               u8 i2c_reg, long *val)
 {
        struct armcp_packet pkt;
        int rc;
@@ -36,7 +36,7 @@ static int hl_debugfs_i2c_read(struct hl_device *hdev, u8 i2c_bus, u8 i2c_addr,
        pkt.i2c_reg = i2c_reg;
 
        rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
-                                               0, (long *) val);
+                                               0, val);
 
        if (rc)
                dev_err(hdev->dev, "Failed to read from I2C, error %d\n", rc);
@@ -827,7 +827,7 @@ static ssize_t hl_i2c_data_read(struct file *f, char __user *buf,
        struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
        struct hl_device *hdev = entry->hdev;
        char tmp_buf[32];
-       u32 val;
+       long val;
        ssize_t rc;
 
        if (*ppos)
@@ -842,7 +842,7 @@ static ssize_t hl_i2c_data_read(struct file *f, char __user *buf,
                return rc;
        }
 
-       sprintf(tmp_buf, "0x%02x\n", val);
+       sprintf(tmp_buf, "0x%02lx\n", val);
        rc = simple_read_from_buffer(buf, count, ppos, tmp_buf,
                        strlen(tmp_buf));
 
@@ -982,7 +982,7 @@ static ssize_t hl_clk_gate_read(struct file *f, char __user *buf,
                return 0;
 
        sprintf(tmp_buf, "0x%llx\n", hdev->clock_gating_mask);
-       rc = simple_read_from_buffer(buf, strlen(tmp_buf) + 1, ppos, tmp_buf,
+       rc = simple_read_from_buffer(buf, count, ppos, tmp_buf,
                        strlen(tmp_buf) + 1);
 
        return rc;
index be16b75..24b01cc 100644 (file)
@@ -288,7 +288,7 @@ static int device_early_init(struct hl_device *hdev)
        for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++) {
                snprintf(workq_name, 32, "hl-free-jobs-%u", i);
                hdev->cq_wq[i] = create_singlethread_workqueue(workq_name);
-               if (hdev->cq_wq == NULL) {
+               if (hdev->cq_wq[i] == NULL) {
                        dev_err(hdev->dev, "Failed to allocate CQ workqueue\n");
                        rc = -ENOMEM;
                        goto free_cq_wq;
@@ -1069,7 +1069,7 @@ again:
                        goto out_err;
                }
 
-               hl_set_max_power(hdev, hdev->max_power);
+               hl_set_max_power(hdev);
        } else {
                rc = hdev->asic_funcs->soft_reset_late_init(hdev);
                if (rc) {
@@ -1318,6 +1318,11 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
                goto out_disabled;
        }
 
+       /* Need to call this again because the max power might change,
+        * depending on card type for certain ASICs
+        */
+       hl_set_max_power(hdev);
+
        /*
         * hl_hwmon_init() must be called after device_late_init(), because only
         * there we get the information from the device about which
index f70302c..f52bc69 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/slab.h>
 
+#define FW_FILE_MAX_SIZE       0x1400000 /* maximum size of 20MB */
 /**
  * hl_fw_load_fw_to_device() - Load F/W code to device's memory.
  *
@@ -48,6 +49,14 @@ int hl_fw_load_fw_to_device(struct hl_device *hdev, const char *fw_name,
 
        dev_dbg(hdev->dev, "%s firmware size == %zu\n", fw_name, fw_size);
 
+       if (fw_size > FW_FILE_MAX_SIZE) {
+               dev_err(hdev->dev,
+                       "FW file size %zu exceeds maximum of %u bytes\n",
+                       fw_size, FW_FILE_MAX_SIZE);
+               rc = -EINVAL;
+               goto out;
+       }
+
        fw_data = (const u64 *) fw->data;
 
        memcpy_toio(dst, fw_data, fw_size);
index 018d9d6..edbd627 100644 (file)
@@ -1462,6 +1462,8 @@ struct hl_device_idle_busy_ts {
  *                     details.
  * @in_reset: is device in reset flow.
  * @curr_pll_profile: current PLL profile.
+ * @card_type: Various ASICs have several card types. This indicates the card
+ *             type of the current device.
  * @cs_active_cnt: number of active command submissions on this device (active
  *                 means already in H/W queues)
  * @major: habanalabs kernel driver major.
@@ -1566,6 +1568,7 @@ struct hl_device {
        u64                             clock_gating_mask;
        atomic_t                        in_reset;
        enum hl_pll_frequency           curr_pll_profile;
+       enum armcp_card_types           card_type;
        int                             cs_active_cnt;
        u32                             major;
        u32                             high_pll;
@@ -1651,7 +1654,7 @@ struct hl_ioctl_desc {
  *
  * Return: true if the area is inside the valid range, false otherwise.
  */
-static inline bool hl_mem_area_inside_range(u64 address, u32 size,
+static inline bool hl_mem_area_inside_range(u64 address, u64 size,
                                u64 range_start_address, u64 range_end_address)
 {
        u64 end_address = address + size;
@@ -1858,7 +1861,7 @@ int hl_get_pwm_info(struct hl_device *hdev,
 void hl_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr,
                        long value);
 u64 hl_get_max_power(struct hl_device *hdev);
-void hl_set_max_power(struct hl_device *hdev, u64 value);
+void hl_set_max_power(struct hl_device *hdev);
 int hl_set_voltage(struct hl_device *hdev,
                        int sensor_index, u32 attr, long value);
 int hl_set_current(struct hl_device *hdev,
index dce9273..5ff4688 100644 (file)
@@ -66,6 +66,11 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args,
        num_pgs = (args->alloc.mem_size + (page_size - 1)) >> page_shift;
        total_size = num_pgs << page_shift;
 
+       if (!total_size) {
+               dev_err(hdev->dev, "Cannot allocate 0 bytes\n");
+               return -EINVAL;
+       }
+
        contiguous = args->flags & HL_MEM_CONTIGUOUS;
 
        if (contiguous) {
@@ -93,7 +98,7 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args,
        phys_pg_pack->contiguous = contiguous;
 
        phys_pg_pack->pages = kvmalloc_array(num_pgs, sizeof(u64), GFP_KERNEL);
-       if (!phys_pg_pack->pages) {
+       if (ZERO_OR_NULL_PTR(phys_pg_pack->pages)) {
                rc = -ENOMEM;
                goto pages_arr_err;
        }
@@ -683,7 +688,7 @@ static int init_phys_pg_pack_from_userptr(struct hl_ctx *ctx,
 
        phys_pg_pack->pages = kvmalloc_array(total_npages, sizeof(u64),
                                                GFP_KERNEL);
-       if (!phys_pg_pack->pages) {
+       if (ZERO_OR_NULL_PTR(phys_pg_pack->pages)) {
                rc = -ENOMEM;
                goto page_pack_arr_mem_err;
        }
index edcc11d..3fc0f49 100644 (file)
@@ -450,7 +450,7 @@ int hl_mmu_init(struct hl_device *hdev)
        hdev->mmu_shadow_hop0 = kvmalloc_array(prop->max_asid,
                                        prop->mmu_hop_table_size,
                                        GFP_KERNEL | __GFP_ZERO);
-       if (!hdev->mmu_shadow_hop0) {
+       if (ZERO_OR_NULL_PTR(hdev->mmu_shadow_hop0)) {
                rc = -ENOMEM;
                goto err_pool_add;
        }
index 7bd3737..2770f03 100644 (file)
@@ -227,7 +227,7 @@ int hl_pci_set_inbound_region(struct hl_device *hdev, u8 region,
        }
 
        /* Point to the specified address */
-       rc = hl_pci_iatu_write(hdev, offset + 0x14,
+       rc |= hl_pci_iatu_write(hdev, offset + 0x14,
                        lower_32_bits(pci_region->addr));
        rc |= hl_pci_iatu_write(hdev, offset + 0x18,
                        upper_32_bits(pci_region->addr));
@@ -369,15 +369,17 @@ int hl_pci_init(struct hl_device *hdev)
        rc = hdev->asic_funcs->init_iatu(hdev);
        if (rc) {
                dev_err(hdev->dev, "Failed to initialize iATU\n");
-               goto disable_device;
+               goto unmap_pci_bars;
        }
 
        rc = hl_pci_set_dma_mask(hdev);
        if (rc)
-               goto disable_device;
+               goto unmap_pci_bars;
 
        return 0;
 
+unmap_pci_bars:
+       hl_pci_bars_unmap(hdev);
 disable_device:
        pci_clear_master(pdev);
        pci_disable_device(pdev);
index b3cb0ac..5ae484c 100644 (file)
@@ -81,7 +81,7 @@ u64 hl_get_max_power(struct hl_device *hdev)
        return result;
 }
 
-void hl_set_max_power(struct hl_device *hdev, u64 value)
+void hl_set_max_power(struct hl_device *hdev)
 {
        struct armcp_packet pkt;
        int rc;
@@ -90,7 +90,7 @@ void hl_set_max_power(struct hl_device *hdev, u64 value)
 
        pkt.ctl = cpu_to_le32(ARMCP_PACKET_MAX_POWER_SET <<
                                ARMCP_PKT_CTL_OPCODE_SHIFT);
-       pkt.value = cpu_to_le64(value);
+       pkt.value = cpu_to_le64(hdev->max_power);
 
        rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
                                                0, NULL);
@@ -316,7 +316,7 @@ static ssize_t max_power_store(struct device *dev,
        }
 
        hdev->max_power = value;
-       hl_set_max_power(hdev, value);
+       hl_set_max_power(hdev);
 
 out:
        return count;
@@ -422,6 +422,7 @@ int hl_sysfs_init(struct hl_device *hdev)
                hdev->pm_mng_profile = PM_AUTO;
        else
                hdev->pm_mng_profile = PM_MANUAL;
+
        hdev->max_power = hdev->asic_prop.max_power_default;
 
        hdev->asic_funcs->add_device_attr(hdev, &hl_dev_clks_attr_group);
index 00a0a72..4009b7d 100644 (file)
@@ -154,6 +154,29 @@ static const u16 gaudi_packet_sizes[MAX_PACKET_ID] = {
        [PACKET_LOAD_AND_EXE]   = sizeof(struct packet_load_and_exe)
 };
 
+static inline bool validate_packet_id(enum packet_id id)
+{
+       switch (id) {
+       case PACKET_WREG_32:
+       case PACKET_WREG_BULK:
+       case PACKET_MSG_LONG:
+       case PACKET_MSG_SHORT:
+       case PACKET_CP_DMA:
+       case PACKET_REPEAT:
+       case PACKET_MSG_PROT:
+       case PACKET_FENCE:
+       case PACKET_LIN_DMA:
+       case PACKET_NOP:
+       case PACKET_STOP:
+       case PACKET_ARB_POINT:
+       case PACKET_WAIT:
+       case PACKET_LOAD_AND_EXE:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static const char * const
 gaudi_tpc_interrupts_cause[GAUDI_NUM_OF_TPC_INTR_CAUSE] = {
        "tpc_address_exceed_slm",
@@ -433,7 +456,7 @@ static int gaudi_get_fixed_properties(struct hl_device *hdev)
        prop->num_of_events = GAUDI_EVENT_SIZE;
        prop->tpc_enabled_mask = TPC_ENABLED_MASK;
 
-       prop->max_power_default = MAX_POWER_DEFAULT;
+       prop->max_power_default = MAX_POWER_DEFAULT_PCI;
 
        prop->cb_pool_cb_cnt = GAUDI_CB_POOL_CB_CNT;
        prop->cb_pool_cb_size = GAUDI_CB_POOL_CB_SIZE;
@@ -2485,6 +2508,7 @@ static void gaudi_set_clock_gating(struct hl_device *hdev)
 {
        struct gaudi_device *gaudi = hdev->asic_specific;
        u32 qman_offset;
+       bool enable;
        int i;
 
        /* In case we are during debug session, don't enable the clock gate
@@ -2494,46 +2518,43 @@ static void gaudi_set_clock_gating(struct hl_device *hdev)
                return;
 
        for (i = GAUDI_PCI_DMA_1, qman_offset = 0 ; i < GAUDI_HBM_DMA_1 ; i++) {
-               if (!(hdev->clock_gating_mask &
-                                       (BIT_ULL(gaudi_dma_assignment[i]))))
-                       continue;
+               enable = !!(hdev->clock_gating_mask &
+                               (BIT_ULL(gaudi_dma_assignment[i])));
 
                qman_offset = gaudi_dma_assignment[i] * DMA_QMAN_OFFSET;
-               WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset, QMAN_CGM1_PWR_GATE_EN);
+               WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset,
+                               enable ? QMAN_CGM1_PWR_GATE_EN : 0);
                WREG32(mmDMA0_QM_CGM_CFG + qman_offset,
-                               QMAN_UPPER_CP_CGM_PWR_GATE_EN);
+                               enable ? QMAN_UPPER_CP_CGM_PWR_GATE_EN : 0);
        }
 
        for (i = GAUDI_HBM_DMA_1 ; i < GAUDI_DMA_MAX ; i++) {
-               if (!(hdev->clock_gating_mask &
-                                       (BIT_ULL(gaudi_dma_assignment[i]))))
-                       continue;
+               enable = !!(hdev->clock_gating_mask &
+                               (BIT_ULL(gaudi_dma_assignment[i])));
 
                qman_offset = gaudi_dma_assignment[i] * DMA_QMAN_OFFSET;
-               WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset, QMAN_CGM1_PWR_GATE_EN);
+               WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset,
+                               enable ? QMAN_CGM1_PWR_GATE_EN : 0);
                WREG32(mmDMA0_QM_CGM_CFG + qman_offset,
-                               QMAN_COMMON_CP_CGM_PWR_GATE_EN);
+                               enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
        }
 
-       if (hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_0))) {
-               WREG32(mmMME0_QM_CGM_CFG1, QMAN_CGM1_PWR_GATE_EN);
-               WREG32(mmMME0_QM_CGM_CFG, QMAN_COMMON_CP_CGM_PWR_GATE_EN);
-       }
+       enable = !!(hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_0)));
+       WREG32(mmMME0_QM_CGM_CFG1, enable ? QMAN_CGM1_PWR_GATE_EN : 0);
+       WREG32(mmMME0_QM_CGM_CFG, enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
 
-       if (hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_2))) {
-               WREG32(mmMME2_QM_CGM_CFG1, QMAN_CGM1_PWR_GATE_EN);
-               WREG32(mmMME2_QM_CGM_CFG, QMAN_COMMON_CP_CGM_PWR_GATE_EN);
-       }
+       enable = !!(hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_2)));
+       WREG32(mmMME2_QM_CGM_CFG1, enable ? QMAN_CGM1_PWR_GATE_EN : 0);
+       WREG32(mmMME2_QM_CGM_CFG, enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
 
        for (i = 0, qman_offset = 0 ; i < TPC_NUMBER_OF_ENGINES ; i++) {
-               if (!(hdev->clock_gating_mask &
-                                       (BIT_ULL(GAUDI_ENGINE_ID_TPC_0 + i))))
-                       continue;
+               enable = !!(hdev->clock_gating_mask &
+                               (BIT_ULL(GAUDI_ENGINE_ID_TPC_0 + i)));
 
                WREG32(mmTPC0_QM_CGM_CFG1 + qman_offset,
-                               QMAN_CGM1_PWR_GATE_EN);
+                               enable ? QMAN_CGM1_PWR_GATE_EN : 0);
                WREG32(mmTPC0_QM_CGM_CFG + qman_offset,
-                               QMAN_COMMON_CP_CGM_PWR_GATE_EN);
+                               enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
 
                qman_offset += TPC_QMAN_OFFSET;
        }
@@ -3772,6 +3793,12 @@ static int gaudi_validate_cb(struct hl_device *hdev,
                                PACKET_HEADER_PACKET_ID_MASK) >>
                                        PACKET_HEADER_PACKET_ID_SHIFT);
 
+               if (!validate_packet_id(pkt_id)) {
+                       dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id);
+                       rc = -EINVAL;
+                       break;
+               }
+
                pkt_size = gaudi_packet_sizes[pkt_id];
                cb_parsed_length += pkt_size;
                if (cb_parsed_length > parser->user_cb_size) {
@@ -3995,6 +4022,12 @@ static int gaudi_patch_cb(struct hl_device *hdev,
                                PACKET_HEADER_PACKET_ID_MASK) >>
                                        PACKET_HEADER_PACKET_ID_SHIFT);
 
+               if (!validate_packet_id(pkt_id)) {
+                       dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id);
+                       rc = -EINVAL;
+                       break;
+               }
+
                pkt_size = gaudi_packet_sizes[pkt_id];
                cb_parsed_length += pkt_size;
                if (cb_parsed_length > parser->user_cb_size) {
@@ -5215,7 +5248,7 @@ static int gaudi_extract_ecc_info(struct hl_device *hdev,
        *memory_wrapper_idx = 0xFF;
 
        /* Iterate through memory wrappers, a single bit must be set */
-       for (i = 0 ; i > num_mem_regs ; i++) {
+       for (i = 0 ; i < num_mem_regs ; i++) {
                err_addr += i * 4;
                err_word = RREG32(err_addr);
                if (err_word) {
@@ -6022,6 +6055,15 @@ static int gaudi_armcp_info_get(struct hl_device *hdev)
                strncpy(prop->armcp_info.card_name, GAUDI_DEFAULT_CARD_NAME,
                                CARD_NAME_MAX_LEN);
 
+       hdev->card_type = le32_to_cpu(hdev->asic_prop.armcp_info.card_type);
+
+       if (hdev->card_type == armcp_card_type_pci)
+               prop->max_power_default = MAX_POWER_DEFAULT_PCI;
+       else if (hdev->card_type == armcp_card_type_pmc)
+               prop->max_power_default = MAX_POWER_DEFAULT_PMC;
+
+       hdev->max_power = prop->max_power_default;
+
        return 0;
 }
 
index 5dc99f6..82137c3 100644 (file)
@@ -41,7 +41,8 @@
 
 #define GAUDI_MAX_CLK_FREQ             2200000000ull   /* 2200 MHz */
 
-#define MAX_POWER_DEFAULT              200000          /* 200W */
+#define MAX_POWER_DEFAULT_PCI          200000          /* 200W */
+#define MAX_POWER_DEFAULT_PMC          350000          /* 350W */
 
 #define GAUDI_CPU_TIMEOUT_USEC         15000000        /* 15s */
 
index 5673ee4..881531d 100644 (file)
@@ -527,7 +527,7 @@ static int gaudi_config_etf(struct hl_device *hdev,
 }
 
 static bool gaudi_etr_validate_address(struct hl_device *hdev, u64 addr,
-                                       u32 size, bool *is_host)
+                                       u64 size, bool *is_host)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
        struct gaudi_device *gaudi = hdev->asic_specific;
@@ -539,6 +539,12 @@ static bool gaudi_etr_validate_address(struct hl_device *hdev, u64 addr,
                return false;
        }
 
+       if (addr > (addr + size)) {
+               dev_err(hdev->dev,
+                       "ETR buffer size %llu overflow\n", size);
+               return false;
+       }
+
        /* PMMU and HPMMU addresses are equal, check only one of them */
        if ((gaudi->hw_cap_initialized & HW_CAP_MMU) &&
                hl_mem_area_inside_range(addr, size,
index 8503075..33cd2ae 100644 (file)
@@ -139,6 +139,25 @@ static u16 goya_packet_sizes[MAX_PACKET_ID] = {
        [PACKET_STOP]           = sizeof(struct packet_stop)
 };
 
+static inline bool validate_packet_id(enum packet_id id)
+{
+       switch (id) {
+       case PACKET_WREG_32:
+       case PACKET_WREG_BULK:
+       case PACKET_MSG_LONG:
+       case PACKET_MSG_SHORT:
+       case PACKET_CP_DMA:
+       case PACKET_MSG_PROT:
+       case PACKET_FENCE:
+       case PACKET_LIN_DMA:
+       case PACKET_NOP:
+       case PACKET_STOP:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static u64 goya_mmu_regs[GOYA_MMU_REGS_NUM] = {
        mmDMA_QM_0_GLBL_NON_SECURE_PROPS,
        mmDMA_QM_1_GLBL_NON_SECURE_PROPS,
@@ -3455,6 +3474,12 @@ static int goya_validate_cb(struct hl_device *hdev,
                                PACKET_HEADER_PACKET_ID_MASK) >>
                                        PACKET_HEADER_PACKET_ID_SHIFT);
 
+               if (!validate_packet_id(pkt_id)) {
+                       dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id);
+                       rc = -EINVAL;
+                       break;
+               }
+
                pkt_size = goya_packet_sizes[pkt_id];
                cb_parsed_length += pkt_size;
                if (cb_parsed_length > parser->user_cb_size) {
@@ -3690,6 +3715,12 @@ static int goya_patch_cb(struct hl_device *hdev,
                                PACKET_HEADER_PACKET_ID_MASK) >>
                                        PACKET_HEADER_PACKET_ID_SHIFT);
 
+               if (!validate_packet_id(pkt_id)) {
+                       dev_err(hdev->dev, "Invalid packet id %u\n", pkt_id);
+                       rc = -EINVAL;
+                       break;
+               }
+
                pkt_size = goya_packet_sizes[pkt_id];
                cb_parsed_length += pkt_size;
                if (cb_parsed_length > parser->user_cb_size) {
index b039124..4027a6a 100644 (file)
@@ -362,11 +362,17 @@ static int goya_config_etf(struct hl_device *hdev,
 }
 
 static int goya_etr_validate_address(struct hl_device *hdev, u64 addr,
-               u32 size)
+               u64 size)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
        u64 range_start, range_end;
 
+       if (addr > (addr + size)) {
+               dev_err(hdev->dev,
+                       "ETR buffer size %llu overflow\n", size);
+               return false;
+       }
+
        if (hdev->mmu_enable) {
                range_start = prop->dmmu.start_addr;
                range_end = prop->dmmu.end_addr;
index 13ef6b2..3510c42 100644 (file)
@@ -378,15 +378,15 @@ enum axi_id {
        ((((y) & RAZWI_INITIATOR_Y_MASK) << RAZWI_INITIATOR_Y_SHIFT) | \
                (((x) & RAZWI_INITIATOR_X_MASK) << RAZWI_INITIATOR_X_SHIFT))
 
-#define RAZWI_INITIATOR_ID_X_Y_TPC0_NIC0       RAZWI_INITIATOR_ID_X_Y(1, 0)
-#define RAZWI_INITIATOR_ID_X_Y_TPC1            RAZWI_INITIATOR_ID_X_Y(2, 0)
-#define RAZWI_INITIATOR_ID_X_Y_MME0_0          RAZWI_INITIATOR_ID_X_Y(3, 0)
-#define RAZWI_INITIATOR_ID_X_Y_MME0_1          RAZWI_INITIATOR_ID_X_Y(4, 0)
-#define RAZWI_INITIATOR_ID_X_Y_MME1_0          RAZWI_INITIATOR_ID_X_Y(5, 0)
-#define RAZWI_INITIATOR_ID_X_Y_MME1_1          RAZWI_INITIATOR_ID_X_Y(6, 0)
-#define RAZWI_INITIATOR_ID_X_Y_TPC2            RAZWI_INITIATOR_ID_X_Y(7, 0)
+#define RAZWI_INITIATOR_ID_X_Y_TPC0_NIC0       RAZWI_INITIATOR_ID_X_Y(1, 1)
+#define RAZWI_INITIATOR_ID_X_Y_TPC1            RAZWI_INITIATOR_ID_X_Y(2, 1)
+#define RAZWI_INITIATOR_ID_X_Y_MME0_0          RAZWI_INITIATOR_ID_X_Y(3, 1)
+#define RAZWI_INITIATOR_ID_X_Y_MME0_1          RAZWI_INITIATOR_ID_X_Y(4, 1)
+#define RAZWI_INITIATOR_ID_X_Y_MME1_0          RAZWI_INITIATOR_ID_X_Y(5, 1)
+#define RAZWI_INITIATOR_ID_X_Y_MME1_1          RAZWI_INITIATOR_ID_X_Y(6, 1)
+#define RAZWI_INITIATOR_ID_X_Y_TPC2            RAZWI_INITIATOR_ID_X_Y(7, 1)
 #define RAZWI_INITIATOR_ID_X_Y_TPC3_PCI_CPU_PSOC \
-                                               RAZWI_INITIATOR_ID_X_Y(8, 0)
+                                               RAZWI_INITIATOR_ID_X_Y(8, 1)
 #define RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_S_0    RAZWI_INITIATOR_ID_X_Y(0, 1)
 #define RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_S_0    RAZWI_INITIATOR_ID_X_Y(9, 1)
 #define RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_S_1    RAZWI_INITIATOR_ID_X_Y(0, 2)
@@ -395,14 +395,14 @@ enum axi_id {
 #define RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_N_0    RAZWI_INITIATOR_ID_X_Y(9, 3)
 #define RAZWI_INITIATOR_ID_X_Y_DMA_IF_W_N_1    RAZWI_INITIATOR_ID_X_Y(0, 4)
 #define RAZWI_INITIATOR_ID_X_Y_DMA_IF_E_N_1    RAZWI_INITIATOR_ID_X_Y(9, 4)
-#define RAZWI_INITIATOR_ID_X_Y_TPC4_NIC1_NIC2  RAZWI_INITIATOR_ID_X_Y(1, 5)
-#define RAZWI_INITIATOR_ID_X_Y_TPC5            RAZWI_INITIATOR_ID_X_Y(2, 5)
-#define RAZWI_INITIATOR_ID_X_Y_MME2_0          RAZWI_INITIATOR_ID_X_Y(3, 5)
-#define RAZWI_INITIATOR_ID_X_Y_MME2_1          RAZWI_INITIATOR_ID_X_Y(4, 5)
-#define RAZWI_INITIATOR_ID_X_Y_MME3_0          RAZWI_INITIATOR_ID_X_Y(5, 5)
-#define RAZWI_INITIATOR_ID_X_Y_MME3_1          RAZWI_INITIATOR_ID_X_Y(6, 5)
-#define RAZWI_INITIATOR_ID_X_Y_TPC6            RAZWI_INITIATOR_ID_X_Y(7, 5)
-#define RAZWI_INITIATOR_ID_X_Y_TPC7_NIC4_NIC5  RAZWI_INITIATOR_ID_X_Y(8, 5)
+#define RAZWI_INITIATOR_ID_X_Y_TPC4_NIC1_NIC2  RAZWI_INITIATOR_ID_X_Y(1, 6)
+#define RAZWI_INITIATOR_ID_X_Y_TPC5            RAZWI_INITIATOR_ID_X_Y(2, 6)
+#define RAZWI_INITIATOR_ID_X_Y_MME2_0          RAZWI_INITIATOR_ID_X_Y(3, 6)
+#define RAZWI_INITIATOR_ID_X_Y_MME2_1          RAZWI_INITIATOR_ID_X_Y(4, 6)
+#define RAZWI_INITIATOR_ID_X_Y_MME3_0          RAZWI_INITIATOR_ID_X_Y(5, 6)
+#define RAZWI_INITIATOR_ID_X_Y_MME3_1          RAZWI_INITIATOR_ID_X_Y(6, 6)
+#define RAZWI_INITIATOR_ID_X_Y_TPC6            RAZWI_INITIATOR_ID_X_Y(7, 6)
+#define RAZWI_INITIATOR_ID_X_Y_TPC7_NIC4_NIC5  RAZWI_INITIATOR_ID_X_Y(8, 6)
 
 #define PSOC_ETR_AXICTL_PROTCTRLBIT1_SHIFT                           1
 
index d1d3e02..9ae9669 100644 (file)
@@ -546,38 +546,46 @@ static int mei_hdcp_verify_mprime(struct device *dev,
                                  struct hdcp_port_data *data,
                                  struct hdcp2_rep_stream_ready *stream_ready)
 {
-       struct wired_cmd_repeater_auth_stream_req_in
-                                       verify_mprime_in = { { 0 } };
+       struct wired_cmd_repeater_auth_stream_req_in *verify_mprime_in;
        struct wired_cmd_repeater_auth_stream_req_out
                                        verify_mprime_out = { { 0 } };
        struct mei_cl_device *cldev;
        ssize_t byte;
+       size_t cmd_size;
 
        if (!dev || !stream_ready || !data)
                return -EINVAL;
 
        cldev = to_mei_cl_device(dev);
 
-       verify_mprime_in.header.api_version = HDCP_API_VERSION;
-       verify_mprime_in.header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ;
-       verify_mprime_in.header.status = ME_HDCP_STATUS_SUCCESS;
-       verify_mprime_in.header.buffer_len =
+       cmd_size = struct_size(verify_mprime_in, streams, data->k);
+       if (cmd_size == SIZE_MAX)
+               return -EINVAL;
+
+       verify_mprime_in = kzalloc(cmd_size, GFP_KERNEL);
+       if (!verify_mprime_in)
+               return -ENOMEM;
+
+       verify_mprime_in->header.api_version = HDCP_API_VERSION;
+       verify_mprime_in->header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ;
+       verify_mprime_in->header.status = ME_HDCP_STATUS_SUCCESS;
+       verify_mprime_in->header.buffer_len =
                        WIRED_CMD_BUF_LEN_REPEATER_AUTH_STREAM_REQ_MIN_IN;
 
-       verify_mprime_in.port.integrated_port_type = data->port_type;
-       verify_mprime_in.port.physical_port = (u8)data->fw_ddi;
-       verify_mprime_in.port.attached_transcoder = (u8)data->fw_tc;
+       verify_mprime_in->port.integrated_port_type = data->port_type;
+       verify_mprime_in->port.physical_port = (u8)data->fw_ddi;
+       verify_mprime_in->port.attached_transcoder = (u8)data->fw_tc;
+
+       memcpy(verify_mprime_in->m_prime, stream_ready->m_prime, HDCP_2_2_MPRIME_LEN);
+       drm_hdcp_cpu_to_be24(verify_mprime_in->seq_num_m, data->seq_num_m);
 
-       memcpy(verify_mprime_in.m_prime, stream_ready->m_prime,
-              HDCP_2_2_MPRIME_LEN);
-       drm_hdcp_cpu_to_be24(verify_mprime_in.seq_num_m, data->seq_num_m);
-       memcpy(verify_mprime_in.streams, data->streams,
+       memcpy(verify_mprime_in->streams, data->streams,
               array_size(data->k, sizeof(*data->streams)));
 
-       verify_mprime_in.k = cpu_to_be16(data->k);
+       verify_mprime_in->k = cpu_to_be16(data->k);
 
-       byte = mei_cldev_send(cldev, (u8 *)&verify_mprime_in,
-                             sizeof(verify_mprime_in));
+       byte = mei_cldev_send(cldev, (u8 *)verify_mprime_in, cmd_size);
+       kfree(verify_mprime_in);
        if (byte < 0) {
                dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
                return byte;
index 9cc6b2a..304d6c8 100644 (file)
@@ -178,7 +178,7 @@ int scif_close(scif_epd_t epd)
        case SCIFEP_ZOMBIE:
                dev_err(scif_info.mdev.this_device,
                        "SCIFAPI close: zombie state unexpected\n");
-               /* fall through */
+               fallthrough;
        case SCIFEP_DISCONNECTED:
                spin_unlock(&ep->lock);
                scif_unregister_all_windows(epd);
@@ -645,7 +645,7 @@ int __scif_connect(scif_epd_t epd, struct scif_port_id *dst, bool non_block)
                ep->port.port = err;
                ep->port.node = scif_info.nodeid;
                ep->conn_async_state = ASYNC_CONN_IDLE;
-               /* Fall through */
+               fallthrough;
        case SCIFEP_BOUND:
                /*
                 * If a non-blocking connect has been already initiated
index de8f61e..2da3b47 100644 (file)
@@ -657,7 +657,7 @@ int scif_unregister_window(struct scif_window *window)
                window->unreg_state = OP_IN_PROGRESS;
                send_msg = true;
        }
-               /* fall through */
+               fallthrough;
        case OP_IN_PROGRESS:
        {
                scif_get_window(window, 1);
index 93bb49d..7ffcfc0 100644 (file)
@@ -7,6 +7,7 @@
  * This file supports the user system call for file open, close, mmap, etc.
  * This also incudes the driver initialization code.
  *
+ *  (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  *  Copyright (c) 2008-2014 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
@@ -516,7 +517,7 @@ static int __init gru_init(void)
 #if defined CONFIG_IA64
        gru_start_paddr = 0xd000000000UL; /* ZZZZZZZZZZZZZZZZZZZ fixme */
 #else
-       gru_start_paddr = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR) &
+       gru_start_paddr = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG) &
                                0x7fffffffffffUL;
 #endif
        gru_start_vaddr = __va(gru_start_paddr);
index f6e600b..0ea923f 100644 (file)
@@ -622,7 +622,7 @@ static int send_noop_message(void *cb, struct gru_message_queue_desc *mqd,
                        break;
                case CBSS_PAGE_OVERFLOW:
                        STAT(mesq_noop_page_overflow);
-                       /* fall through */
+                       fallthrough;
                default:
                        BUG();
                }
@@ -780,7 +780,7 @@ static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd,
                break;
        case CBSS_PAGE_OVERFLOW:
                STAT(mesq_page_overflow);
-               /* fall through */
+               fallthrough;
        default:
                BUG();
        }
index 06469b1..9f9af77 100644 (file)
@@ -3,6 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  * Copyright (C) 2004-2008 Silicon Graphics, Inc. All rights reserved.
  */
 
 
 #if defined CONFIG_X86_UV || defined CONFIG_IA64_SGI_UV
 #include <asm/uv/uv.h>
-#define is_uv()                is_uv_system()
-#endif
-
-#ifndef is_uv
-#define is_uv()                0
 #endif
 
 #ifdef USE_DBUG_ON
@@ -79,7 +75,7 @@
 
 #define XPC_MSG_SIZE(_payload_size) \
                                ALIGN(XPC_MSG_HDR_MAX_SIZE + (_payload_size), \
-                                     is_uv() ? 64 : 128)
+                                     is_uv_system() ? 64 : 128)
 
 
 /*
index 61b03fc..cf2965a 100644 (file)
@@ -3,6 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  * Copyright (c) 2004-2008 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
@@ -233,7 +234,7 @@ xp_init(void)
        for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++)
                mutex_init(&xpc_registrations[ch_number].mutex);
 
-       if (is_uv())
+       if (is_uv_system())
                ret = xp_init_uv();
        else
                ret = 0;
@@ -249,7 +250,7 @@ module_init(xp_init);
 static void __exit
 xp_exit(void)
 {
-       if (is_uv())
+       if (is_uv_system())
                xp_exit_uv();
 }
 
index f15a9f2..19fc707 100644 (file)
@@ -3,6 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  * Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
@@ -148,7 +149,9 @@ xp_restrict_memprotect_uv(unsigned long phys_addr, unsigned long size)
 enum xp_retval
 xp_init_uv(void)
 {
-       BUG_ON(!is_uv());
+       WARN_ON(!is_uv_system());
+       if (!is_uv_system())
+               return xpUnsupported;
 
        xp_max_npartitions = XP_MAX_NPARTITIONS_UV;
 #ifdef CONFIG_X86
@@ -168,5 +171,5 @@ xp_init_uv(void)
 void
 xp_exit_uv(void)
 {
-       BUG_ON(!is_uv());
+       WARN_ON(!is_uv_system());
 }
index d5e097c..e5244fc 100644 (file)
@@ -3,6 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  * Copyright (c) 2004-2009 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
@@ -1043,7 +1044,7 @@ xpc_do_exit(enum xp_retval reason)
 
        xpc_teardown_partitions();
 
-       if (is_uv())
+       if (is_uv_system())
                xpc_exit_uv();
 }
 
@@ -1173,7 +1174,7 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *_die_args)
                if (!xpc_kdebug_ignore)
                        break;
 
-               /* fall through */
+               fallthrough;
        case DIE_MCA_MONARCH_ENTER:
        case DIE_INIT_MONARCH_ENTER:
                xpc_arch_ops.offline_heartbeat();
@@ -1184,7 +1185,7 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *_die_args)
                if (!xpc_kdebug_ignore)
                        break;
 
-               /* fall through */
+               fallthrough;
        case DIE_MCA_MONARCH_LEAVE:
        case DIE_INIT_MONARCH_LEAVE:
                xpc_arch_ops.online_heartbeat();
@@ -1226,7 +1227,7 @@ xpc_init(void)
        dev_set_name(xpc_part, "part");
        dev_set_name(xpc_chan, "chan");
 
-       if (is_uv()) {
+       if (is_uv_system()) {
                ret = xpc_init_uv();
 
        } else {
@@ -1312,7 +1313,7 @@ out_2:
 
        xpc_teardown_partitions();
 out_1:
-       if (is_uv())
+       if (is_uv_system())
                xpc_exit_uv();
        return ret;
 }
index 21a04bc..57df068 100644 (file)
@@ -3,6 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  * Copyright (c) 2004-2008 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
@@ -433,7 +434,7 @@ xpc_discovery(void)
         */
        region_size = xp_region_size;
 
-       if (is_uv())
+       if (is_uv_system())
                max_regions = 256;
        else {
                max_regions = 64;
@@ -441,10 +442,10 @@ xpc_discovery(void)
                switch (region_size) {
                case 128:
                        max_regions *= 2;
-                       /* fall through */
+                       fallthrough;
                case 64:
                        max_regions *= 2;
-                       /* fall through */
+                       fallthrough;
                case 32:
                        max_regions *= 2;
                        region_size = 16;
index 98c60f1..7791bde 100644 (file)
@@ -574,7 +574,7 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
 
                xpc_wakeup_channel_mgr(part);
        }
-               /* fall through */
+               fallthrough;
        case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV:
                spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
                part_uv->flags |= XPC_P_ENGAGED_UV;
index 837d6c3..23837d0 100644 (file)
@@ -3,6 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * (C) Copyright 2020 Hewlett Packard Enterprise Development LP
  * Copyright (C) 1999-2009 Silicon Graphics, Inc. All rights reserved.
  */
 
@@ -515,7 +516,7 @@ xpnet_init(void)
 {
        int result;
 
-       if (!is_uv())
+       if (!is_uv_system())
                return -ENODEV;
 
        dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME);
index a5b8dab..4cb7a5b 100644 (file)
@@ -93,7 +93,7 @@ static long uacce_fops_compat_ioctl(struct file *filep,
 
 static int uacce_bind_queue(struct uacce_device *uacce, struct uacce_queue *q)
 {
-       int pasid;
+       u32 pasid;
        struct iommu_sva *handle;
 
        if (!(uacce->flags & UACCE_DEV_SVA))
index ce43f75..c8fae66 100644 (file)
@@ -191,7 +191,7 @@ int mmc_of_parse(struct mmc_host *host)
        switch (bus_width) {
        case 8:
                host->caps |= MMC_CAP_8_BIT_DATA;
-               /* fall through - Hosts capable of 8-bit can also do 4 bits */
+               fallthrough;    /* Hosts capable of 8-bit can also do 4 bits */
        case 4:
                host->caps |= MMC_CAP_4_BIT_DATA;
                break;
index 6c022ef..350d0cc 100644 (file)
@@ -190,7 +190,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,
        q->limits.discard_granularity = card->pref_erase << 9;
        /* granularity must not be greater than max. discard */
        if (card->pref_erase > max_discard)
-               q->limits.discard_granularity = 0;
+               q->limits.discard_granularity = SECTOR_SIZE;
        if (mmc_can_secure_erase_trim(card))
                blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);
 }
index 93d346c..4c229dd 100644 (file)
@@ -121,6 +121,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        struct sg_table sgtable;
        unsigned int nents, left_size, i;
        unsigned int seg_size = card->host->max_seg_size;
+       int err;
 
        WARN_ON(blksz == 0);
 
@@ -170,28 +171,32 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
 
        mmc_set_data_timeout(&data, card);
 
-       mmc_wait_for_req(card->host, &mrq);
+       mmc_pre_req(card->host, &mrq);
 
-       if (nents > 1)
-               sg_free_table(&sgtable);
+       mmc_wait_for_req(card->host, &mrq);
 
        if (cmd.error)
-               return cmd.error;
-       if (data.error)
-               return data.error;
-
-       if (mmc_host_is_spi(card->host)) {
+               err = cmd.error;
+       else if (data.error)
+               err = data.error;
+       else if (mmc_host_is_spi(card->host))
                /* host driver already reported errors */
-       } else {
-               if (cmd.resp[0] & R5_ERROR)
-                       return -EIO;
-               if (cmd.resp[0] & R5_FUNCTION_NUMBER)
-                       return -EINVAL;
-               if (cmd.resp[0] & R5_OUT_OF_RANGE)
-                       return -ERANGE;
-       }
+               err = 0;
+       else if (cmd.resp[0] & R5_ERROR)
+               err = -EIO;
+       else if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+               err = -EINVAL;
+       else if (cmd.resp[0] & R5_OUT_OF_RANGE)
+               err = -ERANGE;
+       else
+               err = 0;
 
-       return 0;
+       mmc_post_req(card->host, &mrq, err);
+
+       if (nents > 1)
+               sg_free_table(&sgtable);
+
+       return err;
 }
 
 int sdio_reset(struct mmc_host *host)
index 9c89a5b..9a34c82 100644 (file)
@@ -602,7 +602,7 @@ config MMC_GOLDFISH
 
 config MMC_SPI
        tristate "MMC/SD/SDIO over SPI"
-       depends on SPI_MASTER && HAS_DMA
+       depends on SPI_MASTER
        select CRC7
        select CRC_ITU_T
        help
index 3009014..3fc3bbe 100644 (file)
@@ -2418,7 +2418,7 @@ static void atmci_get_cap(struct atmel_mci *host)
        case 0x600:
        case 0x500:
                host->caps.has_odd_clk_div = 1;
-               /* Fall through */
+               fallthrough;
        case 0x400:
        case 0x300:
                host->caps.has_dma_conf_reg = 1;
@@ -2426,16 +2426,16 @@ static void atmci_get_cap(struct atmel_mci *host)
                host->caps.has_cfg_reg = 1;
                host->caps.has_cstor_reg = 1;
                host->caps.has_highspeed = 1;
-               /* Fall through */
+               fallthrough;
        case 0x200:
                host->caps.has_rwproof = 1;
                host->caps.need_blksz_mul_4 = 0;
                host->caps.need_notbusy_for_read_ops = 1;
-               /* Fall through */
+               fallthrough;
        case 0x100:
                host->caps.has_bad_data_ordering = 0;
                host->caps.need_reset_after_xfer = 0;
-               /* Fall through */
+               fallthrough;
        case 0x0:
                break;
        default:
index f01fecd..e50a08b 100644 (file)
@@ -300,7 +300,7 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
                 * then it's harmless for us to allow it.
                 */
                cmd_reg |= MMCCMD_BSYEXP;
-               /* FALLTHROUGH */
+               fallthrough;
        case MMC_RSP_R1:                /* 48 bits, CRC */
                cmd_reg |= MMCCMD_RSPFMT_R1456;
                break;
index 50977ff..db1a84b 100644 (file)
@@ -238,7 +238,7 @@ static void dw_mci_hs_set_timing(struct dw_mci *host, int timing,
                if (smpl_phase >= USE_DLY_MIN_SMPL &&
                                smpl_phase <= USE_DLY_MAX_SMPL)
                        use_smpl_dly = 1;
-                       /* fallthrough */
+               fallthrough;
        case MMC_TIMING_UHS_SDR50:
                if (smpl_phase >= ENABLE_SHIFT_MIN_SMPL &&
                                smpl_phase <= ENABLE_SHIFT_MAX_SMPL)
index 35ae573..0fba940 100644 (file)
@@ -2030,7 +2030,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        }
 
                        prev_state = state = STATE_SENDING_DATA;
-                       /* fall through */
+                       fallthrough;
 
                case STATE_SENDING_DATA:
                        /*
@@ -2088,7 +2088,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        }
                        prev_state = state = STATE_DATA_BUSY;
 
-                       /* fall through */
+                       fallthrough;
 
                case STATE_DATA_BUSY:
                        if (!dw_mci_clear_pending_data_complete(host)) {
@@ -2141,7 +2141,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
                         */
                        prev_state = state = STATE_SENDING_STOP;
 
-                       /* fall through */
+                       fallthrough;
 
                case STATE_SENDING_STOP:
                        if (!dw_mci_clear_pending_cmd_complete(host))
index 447552a..81d7101 100644 (file)
@@ -739,7 +739,7 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
                        break;
 
                jz_mmc_prepare_data_transfer(host);
-               /* fall through */
+               fallthrough;
 
        case JZ4740_MMC_STATE_TRANSFER_DATA:
                if (host->use_dma) {
@@ -774,7 +774,7 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
                        break;
                }
                jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_DATA_TRAN_DONE);
-               /* fall through */
+               fallthrough;
 
        case JZ4740_MMC_STATE_SEND_STOP:
                if (!req->stop)
index 9b2cf7a..703d583 100644 (file)
@@ -294,7 +294,7 @@ static void meson_mx_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        switch (ios->power_mode) {
        case MMC_POWER_OFF:
                vdd = 0;
-               /* fall through */
+               fallthrough;
        case MMC_POWER_UP:
                if (!IS_ERR(mmc->supply.vmmc)) {
                        host->error = mmc_regulator_set_ocr(mmc,
index 39bb1e3..18a850f 100644 (file)
@@ -1278,6 +1278,52 @@ mmc_spi_detect_irq(int irq, void *mmc)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_HAS_DMA
+static int mmc_spi_dma_alloc(struct mmc_spi_host *host)
+{
+       struct spi_device *spi = host->spi;
+       struct device *dev;
+
+       if (!spi->master->dev.parent->dma_mask)
+               return 0;
+
+       dev = spi->master->dev.parent;
+
+       host->ones_dma = dma_map_single(dev, host->ones, MMC_SPI_BLOCKSIZE,
+                                       DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, host->ones_dma))
+               return -ENOMEM;
+
+       host->data_dma = dma_map_single(dev, host->data, sizeof(*host->data),
+                                       DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(dev, host->data_dma)) {
+               dma_unmap_single(dev, host->ones_dma, MMC_SPI_BLOCKSIZE,
+                                DMA_TO_DEVICE);
+               return -ENOMEM;
+       }
+
+       dma_sync_single_for_cpu(dev, host->data_dma, sizeof(*host->data),
+                               DMA_BIDIRECTIONAL);
+
+       host->dma_dev = dev;
+       return 0;
+}
+
+static void mmc_spi_dma_free(struct mmc_spi_host *host)
+{
+       if (!host->dma_dev)
+               return;
+
+       dma_unmap_single(host->dma_dev, host->ones_dma, MMC_SPI_BLOCKSIZE,
+                        DMA_TO_DEVICE);
+       dma_unmap_single(host->dma_dev, host->data_dma, sizeof(*host->data),
+                        DMA_BIDIRECTIONAL);
+}
+#else
+static inline int mmc_spi_dma_alloc(struct mmc_spi_host *host) { return 0; }
+static inline void mmc_spi_dma_free(struct mmc_spi_host *host) {}
+#endif
+
 static int mmc_spi_probe(struct spi_device *spi)
 {
        void                    *ones;
@@ -1374,23 +1420,9 @@ static int mmc_spi_probe(struct spi_device *spi)
        if (!host->data)
                goto fail_nobuf1;
 
-       if (spi->master->dev.parent->dma_mask) {
-               struct device   *dev = spi->master->dev.parent;
-
-               host->dma_dev = dev;
-               host->ones_dma = dma_map_single(dev, ones,
-                               MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
-               if (dma_mapping_error(dev, host->ones_dma))
-                       goto fail_ones_dma;
-               host->data_dma = dma_map_single(dev, host->data,
-                               sizeof(*host->data), DMA_BIDIRECTIONAL);
-               if (dma_mapping_error(dev, host->data_dma))
-                       goto fail_data_dma;
-
-               dma_sync_single_for_cpu(host->dma_dev,
-                               host->data_dma, sizeof(*host->data),
-                               DMA_BIDIRECTIONAL);
-       }
+       status = mmc_spi_dma_alloc(host);
+       if (status)
+               goto fail_dma;
 
        /* setup message for status/busy readback */
        spi_message_init(&host->readback);
@@ -1458,20 +1490,12 @@ static int mmc_spi_probe(struct spi_device *spi)
 fail_add_host:
        mmc_remove_host(mmc);
 fail_glue_init:
-       if (host->dma_dev)
-               dma_unmap_single(host->dma_dev, host->data_dma,
-                               sizeof(*host->data), DMA_BIDIRECTIONAL);
-fail_data_dma:
-       if (host->dma_dev)
-               dma_unmap_single(host->dma_dev, host->ones_dma,
-                               MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
-fail_ones_dma:
+       mmc_spi_dma_free(host);
+fail_dma:
        kfree(host->data);
-
 fail_nobuf1:
        mmc_free_host(mmc);
        mmc_spi_put_pdata(spi);
-
 nomem:
        kfree(ones);
        return status;
@@ -1489,13 +1513,7 @@ static int mmc_spi_remove(struct spi_device *spi)
 
        mmc_remove_host(mmc);
 
-       if (host->dma_dev) {
-               dma_unmap_single(host->dma_dev, host->ones_dma,
-                       MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
-               dma_unmap_single(host->dma_dev, host->data_dma,
-                       sizeof(*host->data), DMA_BIDIRECTIONAL);
-       }
-
+       mmc_spi_dma_free(host);
        kfree(host->data);
        kfree(host->ones);
 
index 4e2583f..b0c2794 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/reset.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/core.h>
@@ -419,6 +420,7 @@ struct msdc_host {
        struct pinctrl_state *pins_uhs;
        struct delayed_work req_timeout;
        int irq;                /* host interrupt */
+       struct reset_control *reset;
 
        struct clk *src_clk;    /* msdc source clock */
        struct clk *h_clk;      /* msdc h_clk */
@@ -1592,6 +1594,12 @@ static void msdc_init_hw(struct msdc_host *host)
        u32 val;
        u32 tune_reg = host->dev_comp->pad_tune_reg;
 
+       if (host->reset) {
+               reset_control_assert(host->reset);
+               usleep_range(10, 50);
+               reset_control_deassert(host->reset);
+       }
+
        /* Configure to MMC/SD mode, clock free running */
        sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN);
 
@@ -2390,6 +2398,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
        if (IS_ERR(host->src_clk_cg))
                host->src_clk_cg = NULL;
 
+       host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
+                                                               "hrst");
+       if (IS_ERR(host->reset))
+               return PTR_ERR(host->reset);
+
        host->irq = platform_get_irq(pdev, 0);
        if (host->irq < 0) {
                ret = -EINVAL;
index 15e2189..904f523 100644 (file)
@@ -685,7 +685,7 @@ static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
        case HOST_MODE:
                if (host->pdata->flags & TMIO_MMC_HAVE_CBSY)
                        bit = TMIO_STAT_CMD_BUSY;
-               /* fallthrough */
+               fallthrough;
        case CTL_SD_CARD_CLK_CTL:
                return renesas_sdhi_wait_idle(host, bit);
        }
index 48ecbd0..284cba1 100644 (file)
@@ -535,6 +535,11 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
        .caps    = MMC_CAP_NONREMOVABLE,
 };
 
+struct amd_sdhci_host {
+       bool    tuned_clock;
+       bool    dll_enabled;
+};
+
 /* AMD sdhci reset dll register. */
 #define SDHCI_AMD_RESET_DLL_REGISTER    0x908
 
@@ -546,39 +551,96 @@ static int amd_select_drive_strength(struct mmc_card *card,
        return MMC_SET_DRIVER_TYPE_A;
 }
 
-static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host)
+static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host, bool enable)
 {
+       struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
+       struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
+
        /* AMD Platform requires dll setting */
        sdhci_writel(host, 0x40003210, SDHCI_AMD_RESET_DLL_REGISTER);
        usleep_range(10, 20);
-       sdhci_writel(host, 0x40033210, SDHCI_AMD_RESET_DLL_REGISTER);
+       if (enable)
+               sdhci_writel(host, 0x40033210, SDHCI_AMD_RESET_DLL_REGISTER);
+
+       amd_host->dll_enabled = enable;
 }
 
 /*
- * For AMD Platform it is required to disable the tuning
- * bit first controller to bring to HS Mode from HS200
- * mode, later enable to tune to HS400 mode.
+ * The initialization sequence for HS400 is:
+ *     HS->HS200->Perform Tuning->HS->HS400
+ *
+ * The re-tuning sequence is:
+ *     HS400->DDR52->HS->HS200->Perform Tuning->HS->HS400
+ *
+ * The AMD eMMC Controller can only use the tuned clock while in HS200 and HS400
+ * mode. If we switch to a different mode, we need to disable the tuned clock.
+ * If we have previously performed tuning and switch back to HS200 or
+ * HS400, we can re-enable the tuned clock.
+ *
  */
 static void amd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct sdhci_host *host = mmc_priv(mmc);
+       struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
+       struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
        unsigned int old_timing = host->timing;
+       u16 val;
 
        sdhci_set_ios(mmc, ios);
-       if (old_timing == MMC_TIMING_MMC_HS200 &&
-           ios->timing == MMC_TIMING_MMC_HS)
-               sdhci_writew(host, 0x9, SDHCI_HOST_CONTROL2);
-       if (old_timing != MMC_TIMING_MMC_HS400 &&
-           ios->timing == MMC_TIMING_MMC_HS400) {
-               sdhci_writew(host, 0x80, SDHCI_HOST_CONTROL2);
-               sdhci_acpi_amd_hs400_dll(host);
+
+       if (old_timing != host->timing && amd_host->tuned_clock) {
+               if (host->timing == MMC_TIMING_MMC_HS400 ||
+                   host->timing == MMC_TIMING_MMC_HS200) {
+                       val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+                       val |= SDHCI_CTRL_TUNED_CLK;
+                       sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
+               } else {
+                       val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+                       val &= ~SDHCI_CTRL_TUNED_CLK;
+                       sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
+               }
+
+               /* DLL is only required for HS400 */
+               if (host->timing == MMC_TIMING_MMC_HS400 &&
+                   !amd_host->dll_enabled)
+                       sdhci_acpi_amd_hs400_dll(host, true);
+       }
+}
+
+static int amd_sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+       int err;
+       struct sdhci_host *host = mmc_priv(mmc);
+       struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
+       struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
+
+       amd_host->tuned_clock = false;
+
+       err = sdhci_execute_tuning(mmc, opcode);
+
+       if (!err && !host->tuning_err)
+               amd_host->tuned_clock = true;
+
+       return err;
+}
+
+static void amd_sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+       struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
+       struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
+
+       if (mask & SDHCI_RESET_ALL) {
+               amd_host->tuned_clock = false;
+               sdhci_acpi_amd_hs400_dll(host, false);
        }
+
+       sdhci_reset(host, mask);
 }
 
 static const struct sdhci_ops sdhci_acpi_ops_amd = {
        .set_clock      = sdhci_set_clock,
        .set_bus_width  = sdhci_set_bus_width,
-       .reset          = sdhci_reset,
+       .reset          = amd_sdhci_reset,
        .set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
@@ -602,6 +664,7 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev,
 
        host->mmc_host_ops.select_drive_strength = amd_select_drive_strength;
        host->mmc_host_ops.set_ios = amd_set_ios;
+       host->mmc_host_ops.execute_tuning = amd_sdhci_execute_tuning;
        return 0;
 }
 
@@ -613,6 +676,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_amd_emmc = {
                          SDHCI_QUIRK_32BIT_ADMA_SIZE,
        .quirks2        = SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
        .probe_slot     = sdhci_acpi_emmc_amd_probe_slot,
+       .priv_size      = sizeof(struct amd_sdhci_host),
 };
 
 struct sdhci_acpi_uid_slot {
index a76b451..d738907 100644 (file)
@@ -1556,7 +1556,7 @@ static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
                                "failed to request card-detect gpio!\n");
                        return err;
                }
-               /* fall through */
+               fallthrough;
 
        case ESDHC_CD_CONTROLLER:
                /* we have a working card_detect back */
index 5a33389..729868a 100644 (file)
@@ -1166,7 +1166,7 @@ static void sdhci_msm_set_cdr(struct sdhci_host *host, bool enable)
 static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct sdhci_host *host = mmc_priv(mmc);
-       int tuning_seq_cnt = 3;
+       int tuning_seq_cnt = 10;
        u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
        int rc;
        struct mmc_ios ios = host->mmc->ios;
@@ -1222,6 +1222,22 @@ retry:
        } while (++phase < ARRAY_SIZE(tuned_phases));
 
        if (tuned_phase_cnt) {
+               if (tuned_phase_cnt == ARRAY_SIZE(tuned_phases)) {
+                       /*
+                        * All phases valid is _almost_ as bad as no phases
+                        * valid.  Probably all phases are not really reliable
+                        * but we didn't detect where the unreliable place is.
+                        * That means we'll essentially be guessing and hoping
+                        * we get a good phase.  Better to try a few times.
+                        */
+                       dev_dbg(mmc_dev(mmc), "%s: All phases valid; try again\n",
+                               mmc_hostname(mmc));
+                       if (--tuning_seq_cnt) {
+                               tuned_phase_cnt = 0;
+                               goto retry;
+                       }
+               }
+
                rc = msm_find_most_appropriate_phase(host, tuned_phases,
                                                     tuned_phase_cnt);
                if (rc < 0)
index 7c73d24..45881b3 100644 (file)
@@ -81,6 +81,7 @@ struct sdhci_esdhc {
        bool quirk_tuning_erratum_type2;
        bool quirk_ignore_data_inhibit;
        bool quirk_delay_before_data_reset;
+       bool quirk_trans_complete_erratum;
        bool in_sw_tuning;
        unsigned int peripheral_clock;
        const struct esdhc_clk_fixup *clk_fixup;
@@ -1177,10 +1178,11 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host,
 
 static u32 esdhc_irq(struct sdhci_host *host, u32 intmask)
 {
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
        u32 command;
 
-       if (of_find_compatible_node(NULL, NULL,
-                               "fsl,p2020-esdhc")) {
+       if (esdhc->quirk_trans_complete_erratum) {
                command = SDHCI_GET_CMD(sdhci_readw(host,
                                        SDHCI_COMMAND));
                if (command == MMC_WRITE_MULTIPLE_BLOCK &&
@@ -1334,8 +1336,10 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
                esdhc->clk_fixup = match->data;
        np = pdev->dev.of_node;
 
-       if (of_device_is_compatible(np, "fsl,p2020-esdhc"))
+       if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
                esdhc->quirk_delay_before_data_reset = true;
+               esdhc->quirk_trans_complete_erratum = true;
+       }
 
        clk = of_clk_get(np, 0);
        if (!IS_ERR(clk)) {
index bb68024..914f518 100644 (file)
@@ -232,6 +232,14 @@ static void sdhci_pci_dumpregs(struct mmc_host *mmc)
        sdhci_dumpregs(mmc_priv(mmc));
 }
 
+static void sdhci_cqhci_reset(struct sdhci_host *host, u8 mask)
+{
+       if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) &&
+           host->mmc->cqe_private)
+               cqhci_deactivate(host->mmc);
+       sdhci_reset(host, mask);
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Hardware specific quirk handling                                          *
@@ -718,7 +726,7 @@ static const struct sdhci_ops sdhci_intel_glk_ops = {
        .set_power              = sdhci_intel_set_power,
        .enable_dma             = sdhci_pci_enable_dma,
        .set_bus_width          = sdhci_set_bus_width,
-       .reset                  = sdhci_reset,
+       .reset                  = sdhci_cqhci_reset,
        .set_uhs_signaling      = sdhci_set_uhs_signaling,
        .hw_reset               = sdhci_pci_hw_reset,
        .irq                    = sdhci_cqhci_irq,
@@ -786,7 +794,8 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
 static bool glk_broken_cqhci(struct sdhci_pci_slot *slot)
 {
        return slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC &&
-              dmi_match(DMI_BIOS_VENDOR, "LENOVO");
+              (dmi_match(DMI_BIOS_VENDOR, "LENOVO") ||
+               dmi_match(DMI_SYS_VENDOR, "IRBIS"));
 }
 
 static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot)
index 9194bb7..080ced1 100644 (file)
@@ -609,7 +609,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
        switch (pdata->max_width) {
        case 8:
                host->mmc->caps |= MMC_CAP_8_BIT_DATA;
-               /* Fall through */
+               fallthrough;
        case 4:
                host->mmc->caps |= MMC_CAP_4_BIT_DATA;
                break;
index a910cb4..bafa2e4 100644 (file)
@@ -470,7 +470,7 @@ static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
                break;
 
        default:
-               /* fall-through */
+               fallthrough;
        case MMC_SIGNAL_VOLTAGE_330:
                ret = pinctrl_select_state(sprd_host->pinctrl,
                                           sprd_host->pins_default);
index 0a3f9d0..13fbf70 100644 (file)
 #define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP                        BIT(8)
 #define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING              BIT(9)
 
+/*
+ * NVQUIRK_HAS_TMCLK is for SoC's having separate timeout clock for Tegra
+ * SDMMC hardware data timeout.
+ */
+#define NVQUIRK_HAS_TMCLK                              BIT(10)
+
 /* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */
 #define SDHCI_TEGRA_CQE_BASE_ADDR                      0xF000
 
@@ -140,6 +146,7 @@ struct sdhci_tegra_autocal_offsets {
 struct sdhci_tegra {
        const struct sdhci_tegra_soc_data *soc_data;
        struct gpio_desc *power_gpio;
+       struct clk *tmclk;
        bool ddr_signaling;
        bool pad_calib_required;
        bool pad_control_available;
@@ -1418,7 +1425,6 @@ static const struct sdhci_ops tegra210_sdhci_ops = {
 
 static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
        .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
-                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
                  SDHCI_QUIRK_SINGLE_POWER_WRITE |
                  SDHCI_QUIRK_NO_HISPD_BIT |
                  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
@@ -1434,7 +1440,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
                    NVQUIRK_HAS_PADCALIB |
                    NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
                    NVQUIRK_ENABLE_SDR50 |
-                   NVQUIRK_ENABLE_SDR104,
+                   NVQUIRK_ENABLE_SDR104 |
+                   NVQUIRK_HAS_TMCLK,
        .min_tap_delay = 106,
        .max_tap_delay = 185,
 };
@@ -1456,7 +1463,6 @@ static const struct sdhci_ops tegra186_sdhci_ops = {
 
 static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
        .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
-                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
                  SDHCI_QUIRK_SINGLE_POWER_WRITE |
                  SDHCI_QUIRK_NO_HISPD_BIT |
                  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
@@ -1473,6 +1479,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra186 = {
                    NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
                    NVQUIRK_ENABLE_SDR50 |
                    NVQUIRK_ENABLE_SDR104 |
+                   NVQUIRK_HAS_TMCLK |
                    NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING,
        .min_tap_delay = 84,
        .max_tap_delay = 136,
@@ -1485,7 +1492,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra194 = {
                    NVQUIRK_HAS_PADCALIB |
                    NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
                    NVQUIRK_ENABLE_SDR50 |
-                   NVQUIRK_ENABLE_SDR104,
+                   NVQUIRK_ENABLE_SDR104 |
+                   NVQUIRK_HAS_TMCLK,
        .min_tap_delay = 96,
        .max_tap_delay = 139,
 };
@@ -1613,6 +1621,43 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
                goto err_power_req;
        }
 
+       /*
+        * Tegra210 has a separate SDMMC_LEGACY_TM clock used for host
+        * timeout clock and SW can choose TMCLK or SDCLK for hardware
+        * data timeout through the bit USE_TMCLK_FOR_DATA_TIMEOUT of
+        * the register SDHCI_TEGRA_VENDOR_SYS_SW_CTRL.
+        *
+        * USE_TMCLK_FOR_DATA_TIMEOUT bit default is set to 1 and SDMMC uses
+        * 12Mhz TMCLK which is advertised in host capability register.
+        * With TMCLK of 12Mhz provides maximum data timeout period that can
+        * be achieved is 11s better than using SDCLK for data timeout.
+        *
+        * So, TMCLK is set to 12Mhz and kept enabled all the time on SoC's
+        * supporting separate TMCLK.
+        */
+
+       if (soc_data->nvquirks & NVQUIRK_HAS_TMCLK) {
+               clk = devm_clk_get(&pdev->dev, "tmclk");
+               if (IS_ERR(clk)) {
+                       rc = PTR_ERR(clk);
+                       if (rc == -EPROBE_DEFER)
+                               goto err_power_req;
+
+                       dev_warn(&pdev->dev, "failed to get tmclk: %d\n", rc);
+                       clk = NULL;
+               }
+
+               clk_set_rate(clk, 12000000);
+               rc = clk_prepare_enable(clk);
+               if (rc) {
+                       dev_err(&pdev->dev,
+                               "failed to enable tmclk: %d\n", rc);
+                       goto err_power_req;
+               }
+
+               tegra_host->tmclk = clk;
+       }
+
        clk = devm_clk_get(mmc_dev(host->mmc), NULL);
        if (IS_ERR(clk)) {
                rc = PTR_ERR(clk);
@@ -1656,6 +1701,7 @@ err_add_host:
 err_rst_get:
        clk_disable_unprepare(pltfm_host->clk);
 err_clk_get:
+       clk_disable_unprepare(tegra_host->tmclk);
 err_power_req:
 err_parse_dt:
        sdhci_pltfm_free(pdev);
@@ -1673,6 +1719,7 @@ static int sdhci_tegra_remove(struct platform_device *pdev)
        reset_control_assert(tegra_host->rst);
        usleep_range(2000, 4000);
        clk_disable_unprepare(pltfm_host->clk);
+       clk_disable_unprepare(tegra_host->tmclk);
 
        sdhci_pltfm_free(pdev);
 
index e6e9e28..03ce57e 100644 (file)
@@ -527,7 +527,7 @@ static bool xenon_emmc_phy_slow_mode(struct sdhci_host *host,
                        ret = true;
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                reg &= ~XENON_TIMING_ADJUST_SLOW_MODE;
                ret = false;
index 3ad394b..592a55a 100644 (file)
@@ -2825,7 +2825,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        case MMC_TIMING_UHS_SDR50:
                if (host->flags & SDHCI_SDR50_NEEDS_TUNING)
                        break;
-               /* FALLTHROUGH */
+               fallthrough;
 
        default:
                goto out;
index 5987656..fd8b72d 100644 (file)
@@ -335,7 +335,7 @@ static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
                break;
        case MMC_RSP_R1B:
                rc |= TIFM_MMCSD_RSP_BUSY;
-               /* fall-through */
+               fallthrough;
        case MMC_RSP_R1:
                rc |= TIFM_MMCSD_RSP_R1;
                break;
index 369b8de..7666c90 100644 (file)
@@ -1343,7 +1343,7 @@ static int usdhi6_stop_cmd(struct usdhi6_host *host)
                        host->wait = USDHI6_WAIT_FOR_STOP;
                        return 0;
                }
-               /* fall through - Unsupported STOP command. */
+               fallthrough;    /* Unsupported STOP command */
        default:
                dev_err(mmc_dev(host->mmc),
                        "unsupported stop CMD%d for CMD%d\n",
@@ -1691,7 +1691,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
        switch (host->wait) {
        default:
                dev_err(mmc_dev(host->mmc), "Invalid state %u\n", host->wait);
-               /* fall through - mrq can be NULL, but is impossible. */
+               fallthrough;    /* mrq can be NULL, but is impossible */
        case USDHI6_WAIT_FOR_CMD:
                usdhi6_error_code(host);
                if (mrq)
@@ -1713,7 +1713,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
                        host->offset, data->blocks, data->blksz, data->sg_len,
                        sg_dma_len(sg), sg->offset);
                usdhi6_sg_unmap(host, true);
-               /* fall through - page unmapped in USDHI6_WAIT_FOR_DATA_END. */
+               fallthrough;    /* page unmapped in USDHI6_WAIT_FOR_DATA_END */
        case USDHI6_WAIT_FOR_DATA_END:
                usdhi6_error_code(host);
                data->error = -ETIMEDOUT;
index 65eff4c..0369d98 100644 (file)
@@ -1907,16 +1907,15 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 }
 
 /**
- * spi_nor_sr1_bit6_quad_enable() - Set/Unset the Quad Enable BIT(6) in the
- *                                  Status Register 1.
+ * spi_nor_sr1_bit6_quad_enable() - Set the Quad Enable BIT(6) in the Status
+ * Register 1.
  * @nor:       pointer to a 'struct spi_nor'
- * @enable:    true to enable Quad mode, false to disable Quad mode.
  *
  * Bit 6 of the Status Register 1 is the QE bit for Macronix like QSPI memories.
  *
  * Return: 0 on success, -errno otherwise.
  */
-int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable)
+int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor)
 {
        int ret;
 
@@ -1924,56 +1923,45 @@ int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable)
        if (ret)
                return ret;
 
-       if ((enable && (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)) ||
-           (!enable && !(nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)))
+       if (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)
                return 0;
 
-       if (enable)
-               nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6;
-       else
-               nor->bouncebuf[0] &= ~SR1_QUAD_EN_BIT6;
+       nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6;
 
        return spi_nor_write_sr1_and_check(nor, nor->bouncebuf[0]);
 }
 
 /**
- * spi_nor_sr2_bit1_quad_enable() - set/unset the Quad Enable BIT(1) in the
- *                                  Status Register 2.
+ * spi_nor_sr2_bit1_quad_enable() - set the Quad Enable BIT(1) in the Status
+ * Register 2.
  * @nor:       pointer to a 'struct spi_nor'.
- * @enable:    true to enable Quad mode, false to disable Quad mode.
  *
  * Bit 1 of the Status Register 2 is the QE bit for Spansion like QSPI memories.
  *
  * Return: 0 on success, -errno otherwise.
  */
-int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable)
+int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor)
 {
        int ret;
 
        if (nor->flags & SNOR_F_NO_READ_CR)
-               return spi_nor_write_16bit_cr_and_check(nor,
-                                               enable ? SR2_QUAD_EN_BIT1 : 0);
+               return spi_nor_write_16bit_cr_and_check(nor, SR2_QUAD_EN_BIT1);
 
        ret = spi_nor_read_cr(nor, nor->bouncebuf);
        if (ret)
                return ret;
 
-       if ((enable && (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)) ||
-           (!enable && !(nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)))
+       if (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)
                return 0;
 
-       if (enable)
-               nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1;
-       else
-               nor->bouncebuf[0] &= ~SR2_QUAD_EN_BIT1;
+       nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1;
 
        return spi_nor_write_16bit_cr_and_check(nor, nor->bouncebuf[0]);
 }
 
 /**
- * spi_nor_sr2_bit7_quad_enable() - set/unset QE bit in Status Register 2.
+ * spi_nor_sr2_bit7_quad_enable() - set QE bit in Status Register 2.
  * @nor:       pointer to a 'struct spi_nor'
- * @enable:    true to enable Quad mode, false to disable Quad mode.
  *
  * Set the Quad Enable (QE) bit in the Status Register 2.
  *
@@ -1983,7 +1971,7 @@ int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable)
  *
  * Return: 0 on success, -errno otherwise.
  */
-int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable)
+int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor)
 {
        u8 *sr2 = nor->bouncebuf;
        int ret;
@@ -1993,15 +1981,11 @@ int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable)
        ret = spi_nor_read_sr2(nor, sr2);
        if (ret)
                return ret;
-       if ((enable && (*sr2 & SR2_QUAD_EN_BIT7)) ||
-           (!enable && !(*sr2 & SR2_QUAD_EN_BIT7)))
+       if (*sr2 & SR2_QUAD_EN_BIT7)
                return 0;
 
        /* Update the Quad Enable bit. */
-       if (enable)
-               *sr2 |= SR2_QUAD_EN_BIT7;
-       else
-               *sr2 &= ~SR2_QUAD_EN_BIT7;
+       *sr2 |= SR2_QUAD_EN_BIT7;
 
        ret = spi_nor_write_sr2(nor, sr2);
        if (ret)
@@ -2914,13 +2898,12 @@ static int spi_nor_init_params(struct spi_nor *nor)
 }
 
 /**
- * spi_nor_quad_enable() - enable/disable Quad I/O if needed.
+ * spi_nor_quad_enable() - enable Quad I/O if needed.
  * @nor:                pointer to a 'struct spi_nor'
- * @enable:             true to enable Quad mode. false to disable Quad mode.
  *
  * Return: 0 on success, -errno otherwise.
  */
-static int spi_nor_quad_enable(struct spi_nor *nor, bool enable)
+static int spi_nor_quad_enable(struct spi_nor *nor)
 {
        if (!nor->params->quad_enable)
                return 0;
@@ -2929,7 +2912,7 @@ static int spi_nor_quad_enable(struct spi_nor *nor, bool enable)
              spi_nor_get_protocol_width(nor->write_proto) == 4))
                return 0;
 
-       return nor->params->quad_enable(nor, enable);
+       return nor->params->quad_enable(nor);
 }
 
 /**
@@ -2953,7 +2936,7 @@ static int spi_nor_init(struct spi_nor *nor)
 {
        int err;
 
-       err = spi_nor_quad_enable(nor, true);
+       err = spi_nor_quad_enable(nor);
        if (err) {
                dev_dbg(nor->dev, "quad mode not supported\n");
                return err;
@@ -3000,8 +2983,6 @@ void spi_nor_restore(struct spi_nor *nor)
        if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
            nor->flags & SNOR_F_BROKEN_RESET)
                nor->params->set_4byte_addr_mode(nor, false);
-
-       spi_nor_quad_enable(nor, false);
 }
 EXPORT_SYMBOL_GPL(spi_nor_restore);
 
index 95aa32f..6f2f6b2 100644 (file)
@@ -198,7 +198,7 @@ struct spi_nor_locking_ops {
  *                      higher index in the array, the higher priority.
  * @erase_map:         the erase map parsed from the SFDP Sector Map Parameter
  *                      Table.
- * @quad_enable:       enables/disables SPI NOR Quad mode.
+ * @quad_enable:       enables SPI NOR quad mode.
  * @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode.
  * @convert_addr:      converts an absolute address into something the flash
  *                      will understand. Particularly useful when pagesize is
@@ -219,7 +219,7 @@ struct spi_nor_flash_parameter {
 
        struct spi_nor_erase_map        erase_map;
 
-       int (*quad_enable)(struct spi_nor *nor, bool enable);
+       int (*quad_enable)(struct spi_nor *nor);
        int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable);
        u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
        int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps);
@@ -406,9 +406,9 @@ int spi_nor_write_ear(struct spi_nor *nor, u8 ear);
 int spi_nor_wait_till_ready(struct spi_nor *nor);
 int spi_nor_lock_and_prep(struct spi_nor *nor);
 void spi_nor_unlock_and_unprep(struct spi_nor *nor);
-int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable);
-int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable);
-int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable);
+int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
+int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);
+int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor);
 
 int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr);
 ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
index 12466b0..22ed051 100644 (file)
@@ -93,7 +93,7 @@ static int adgs1408_probe(struct spi_device *spi)
                        mux->idle_state = idle_state;
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                dev_err(dev, "invalid idle-state %d\n", idle_state);
                return -EINVAL;
index 18428e1..1c6c27f 100644 (file)
@@ -301,7 +301,7 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr)
                        dev->irq = cops_irq(ioaddr, board);
                        if (dev->irq)
                                break;
-                       /* fall through - Once no IRQ found on this port. */
+                       fallthrough;    /* Once no IRQ found on this port */
                case 1:
                        retval = -EINVAL;
                        goto err_out;
index 14a5fb3..98df38f 100644 (file)
@@ -363,13 +363,13 @@ static int __init arcrimi_setup(char *s)
        switch (ints[0]) {
        default:                /* ERROR */
                pr_err("Too many arguments\n");
-               /* Fall through */
+               fallthrough;
        case 3:         /* Node ID */
                node = ints[3];
-               /* Fall through */
+               fallthrough;
        case 2:         /* IRQ */
                irq = ints[2];
-               /* Fall through */
+               fallthrough;
        case 1:         /* IO address */
                io = ints[1];
        }
index cd27fdc..f983c4c 100644 (file)
@@ -197,22 +197,22 @@ static int __init com20020isa_setup(char *s)
        switch (ints[0]) {
        default:                /* ERROR */
                pr_info("Too many arguments\n");
-               /* Fall through */
+               fallthrough;
        case 6:         /* Timeout */
                timeout = ints[6];
-               /* Fall through */
+               fallthrough;
        case 5:         /* CKP value */
                clockp = ints[5];
-               /* Fall through */
+               fallthrough;
        case 4:         /* Backplane flag */
                backplane = ints[4];
-               /* Fall through */
+               fallthrough;
        case 3:         /* Node ID */
                node = ints[3];
-               /* Fall through */
+               fallthrough;
        case 2:         /* IRQ */
                irq = ints[2];
-               /* Fall through */
+               fallthrough;
        case 1:         /* IO address */
                io = ints[1];
        }
index 186bbf8..cf214b7 100644 (file)
@@ -363,10 +363,10 @@ static int __init com90io_setup(char *s)
        switch (ints[0]) {
        default:                /* ERROR */
                pr_err("Too many arguments\n");
-               /* Fall through */
+               fallthrough;
        case 2:         /* IRQ */
                irq = ints[2];
-               /* Fall through */
+               fallthrough;
        case 1:         /* IO address */
                io = ints[1];
        }
index bd75d06..3dc3d53 100644 (file)
@@ -693,13 +693,13 @@ static int __init com90xx_setup(char *s)
        switch (ints[0]) {
        default:                /* ERROR */
                pr_err("Too many arguments\n");
-               /* Fall through */
+               fallthrough;
        case 3:         /* Mem address */
                shmem = ints[3];
-               /* Fall through */
+               fallthrough;
        case 2:         /* IRQ */
                irq = ints[2];
-               /* Fall through */
+               fallthrough;
        case 1:         /* IO address */
                io = ints[1];
        }
index cddaa43..aa001b1 100644 (file)
@@ -1149,7 +1149,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        port->actor_oper_port_state &= ~LACP_STATE_EXPIRED;
                        port->sm_rx_state = AD_RX_PORT_DISABLED;
 
-                       /* Fall Through */
+                       fallthrough;
                case AD_RX_PORT_DISABLED:
                        port->sm_vars &= ~AD_PORT_MATCHED;
                        break;
@@ -1588,7 +1588,7 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best,
                if (__agg_active_ports(curr) < __agg_active_ports(best))
                        return best;
 
-               /*FALLTHROUGH*/
+               fallthrough;
        case BOND_AD_STABLE:
        case BOND_AD_BANDWIDTH:
                if (__get_agg_bandwidth(curr) > __get_agg_bandwidth(best))
index 4e1b7de..c3091e0 100644 (file)
@@ -942,9 +942,10 @@ struct alb_walk_data {
        bool strict_match;
 };
 
-static int alb_upper_dev_walk(struct net_device *upper, void *_data)
+static int alb_upper_dev_walk(struct net_device *upper,
+                             struct netdev_nested_priv *priv)
 {
-       struct alb_walk_data *data = _data;
+       struct alb_walk_data *data = (struct alb_walk_data *)priv->data;
        bool strict_match = data->strict_match;
        struct bonding *bond = data->bond;
        struct slave *slave = data->slave;
@@ -983,6 +984,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
                                      bool strict_match)
 {
        struct bonding *bond = bond_get_bond_by_slave(slave);
+       struct netdev_nested_priv priv;
        struct alb_walk_data data = {
                .strict_match = strict_match,
                .mac_addr = mac_addr,
@@ -990,6 +992,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
                .bond = bond,
        };
 
+       priv.data = (void *)&data;
        /* send untagged */
        alb_send_lp_vid(slave, mac_addr, 0, 0);
 
@@ -997,7 +1000,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
         * for that device.
         */
        rcu_read_lock();
-       netdev_walk_all_upper_dev_rcu(bond->dev, alb_upper_dev_walk, &data);
+       netdev_walk_all_upper_dev_rcu(bond->dev, alb_upper_dev_walk, &priv);
        rcu_read_unlock();
 }
 
index c5d3032..84ecbc6 100644 (file)
@@ -1315,6 +1315,7 @@ static void bond_setup_by_slave(struct net_device *bond_dev,
 
        bond_dev->type              = slave_dev->type;
        bond_dev->hard_header_len   = slave_dev->hard_header_len;
+       bond_dev->needed_headroom   = slave_dev->needed_headroom;
        bond_dev->addr_len          = slave_dev->addr_len;
 
        memcpy(bond_dev->broadcast, slave_dev->broadcast,
@@ -2274,7 +2275,7 @@ static int bond_miimon_inspect(struct bonding *bond)
                                             "active " : "backup ") : "",
                                           bond->params.downdelay * bond->params.miimon);
                        }
-                       /*FALLTHRU*/
+                       fallthrough;
                case BOND_LINK_FAIL:
                        if (link_state) {
                                /* recovered before downdelay expired */
@@ -2310,7 +2311,7 @@ static int bond_miimon_inspect(struct bonding *bond)
                                           bond->params.updelay *
                                           bond->params.miimon);
                        }
-                       /*FALLTHRU*/
+                       fallthrough;
                case BOND_LINK_BACK:
                        if (!link_state) {
                                bond_propose_link_state(slave, BOND_LINK_DOWN);
@@ -2510,22 +2511,26 @@ re_arm:
        }
 }
 
-static int bond_upper_dev_walk(struct net_device *upper, void *data)
+static int bond_upper_dev_walk(struct net_device *upper,
+                              struct netdev_nested_priv *priv)
 {
-       __be32 ip = *((__be32 *)data);
+       __be32 ip = *(__be32 *)priv->data;
 
        return ip == bond_confirm_addr(upper, 0, ip);
 }
 
 static bool bond_has_this_ip(struct bonding *bond, __be32 ip)
 {
+       struct netdev_nested_priv priv = {
+               .data = (void *)&ip,
+       };
        bool ret = false;
 
        if (ip == bond_confirm_addr(bond->dev, 0, ip))
                return true;
 
        rcu_read_lock();
-       if (netdev_walk_all_upper_dev_rcu(bond->dev, bond_upper_dev_walk, &ip))
+       if (netdev_walk_all_upper_dev_rcu(bond->dev, bond_upper_dev_walk, &priv))
                ret = true;
        rcu_read_unlock();
 
@@ -3322,7 +3327,7 @@ static int bond_slave_netdev_event(unsigned long event,
 
                if (BOND_MODE(bond) == BOND_MODE_8023AD)
                        bond_3ad_adapter_speed_duplex_changed(slave);
-               /* Fallthrough */
+               fallthrough;
        case NETDEV_DOWN:
                /* Refresh slave-array if applicable!
                 * If the setup does not use miimon or arpmon (mode-specific!),
@@ -3760,7 +3765,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
                        return -EINVAL;
 
                mii->phy_id = 0;
-               /* Fall Through */
+               fallthrough;
        case SIOCGMIIREG:
                /* We do this again just in case we were called by SIOCGMIIREG
                 * instead of SIOCGMIIPHY.
index 9df2007..38e9f80 100644 (file)
@@ -898,7 +898,7 @@ static void at91_irq_err_state(struct net_device *dev,
                                CAN_ERR_CRTL_TX_WARNING :
                                CAN_ERR_CRTL_RX_WARNING;
                }
-               /* fall through */
+               fallthrough;
        case CAN_STATE_ERROR_WARNING:
                /*
                 * from: ERROR_ACTIVE, ERROR_WARNING
@@ -948,7 +948,7 @@ static void at91_irq_err_state(struct net_device *dev,
                netdev_dbg(dev, "Error Active\n");
                cf->can_id |= CAN_ERR_PROT;
                cf->data[2] = CAN_ERR_PROT_ACTIVE;
-               /* fall through */
+               fallthrough;
        case CAN_STATE_ERROR_WARNING:
                reg_idr = AT91_IRQ_ERRA | AT91_IRQ_WARN | AT91_IRQ_BOFF;
                reg_ier = AT91_IRQ_ERRP;
index 6ad83a8..9469d44 100644 (file)
@@ -659,7 +659,7 @@ static int pciefd_can_probe(struct pciefd_board *pciefd)
                pciefd_can_writereg(priv, CANFD_CLK_SEL_80MHZ,
                                    PCIEFD_REG_CAN_CLK_SEL);
 
-               /* fall through */
+               fallthrough;
        case CANFD_CLK_SEL_80MHZ:
                priv->ucan.can.clock.freq = 80 * 1000 * 1000;
                break;
index d7222ba..d7c2ec5 100644 (file)
@@ -150,7 +150,7 @@ static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of)
                priv->read_reg = sp_read_reg16;
                priv->write_reg = sp_write_reg16;
                break;
-       case 1: /* fallthrough */
+       case 1:
        default:
                priv->read_reg = sp_read_reg8;
                priv->write_reg = sp_write_reg8;
index 91cdc0a..b4a39f0 100644 (file)
@@ -153,7 +153,7 @@ static void slc_bump(struct slcan *sl)
        switch (*cmd) {
        case 'r':
                cf.can_id = CAN_RTR_FLAG;
-               /* fallthrough */
+               fallthrough;
        case 't':
                /* store dlc ASCII value and terminate SFF CAN ID string */
                cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN];
@@ -163,7 +163,7 @@ static void slc_bump(struct slcan *sl)
                break;
        case 'R':
                cf.can_id = CAN_RTR_FLAG;
-               /* fallthrough */
+               fallthrough;
        case 'T':
                cf.can_id |= CAN_EFF_FLAG;
                /* store dlc ASCII value and terminate EFF CAN ID string */
index 5009ff2..d176088 100644 (file)
@@ -864,7 +864,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
                        if (new_state >= CAN_STATE_ERROR_WARNING &&
                            new_state <= CAN_STATE_BUS_OFF)
                                priv->can.can_stats.error_warning++;
-                       /* fall through */
+                       fallthrough;
                case CAN_STATE_ERROR_WARNING:
                        if (new_state >= CAN_STATE_ERROR_PASSIVE &&
                            new_state <= CAN_STATE_BUS_OFF)
index d2539c9..66d0198 100644 (file)
@@ -415,7 +415,7 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
                        new_state = CAN_STATE_ERROR_WARNING;
                        break;
                }
-               /* fall through */
+               fallthrough;
 
        case CAN_STATE_ERROR_WARNING:
                if (n & PCAN_USB_ERROR_BUS_HEAVY) {
index 0b7766b..d91df34 100644 (file)
@@ -345,7 +345,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
                default:
                        netdev_warn(netdev, "tx urb submitting failed err=%d\n",
                                    err);
-                       /* fall through */
+                       fallthrough;
                case -ENOENT:
                        /* cable unplugged */
                        stats->tx_dropped++;
index 53cb2f7..1689ab3 100644 (file)
@@ -133,10 +133,10 @@ static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, int id, ...)
        switch (id) {
        case PCAN_USBPRO_TXMSG8:
                i += 4;
-               /* fall through */
+               fallthrough;
        case PCAN_USBPRO_TXMSG4:
                i += 4;
-               /* fall through */
+               fallthrough;
        case PCAN_USBPRO_TXMSG0:
                *pc++ = va_arg(ap, int);
                *pc++ = va_arg(ap, int);
index 0837ae0..e731db9 100644 (file)
@@ -1061,7 +1061,7 @@ static void b53_force_port_config(struct b53_device *dev, int port,
        switch (speed) {
        case 2000:
                reg |= PORT_OVERRIDE_SPEED_2000M;
-               /* fallthrough */
+               fallthrough;
        case SPEED_1000:
                reg |= PORT_OVERRIDE_SPEED_1000M;
                break;
index 629bf14..5ae3d97 100644 (file)
@@ -170,7 +170,7 @@ void b53_serdes_phylink_validate(struct b53_device *dev, int port,
        switch (lane) {
        case 0:
                phylink_set(supported, 2500baseX_Full);
-               /* fallthrough */
+               fallthrough;
        case 1:
                phylink_set(supported, 1000baseX_Full);
                break;
index bafddb3..5ebff98 100644 (file)
@@ -566,7 +566,7 @@ static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port,
        switch (state->interface) {
        case PHY_INTERFACE_MODE_RGMII:
                id_mode_dis = 1;
-               /* fallthrough */
+               fallthrough;
        case PHY_INTERFACE_MODE_RGMII_TXID:
                port_mode = EXT_GPHY;
                break;
index 8f1d15e..f5779e1 100644 (file)
@@ -932,11 +932,19 @@ static void ksz8795_port_setup(struct ksz_device *dev, int port, bool cpu_port)
        ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true);
 
        if (cpu_port) {
+               if (!p->interface && dev->compat_interface) {
+                       dev_warn(dev->dev,
+                                "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. "
+                                "Please update your device tree.\n",
+                                port);
+                       p->interface = dev->compat_interface;
+               }
+
                /* Configure MII interface for proper network communication. */
                ksz_read8(dev, REG_PORT_5_CTRL_6, &data8);
                data8 &= ~PORT_INTERFACE_TYPE;
                data8 &= ~PORT_GMII_1GPS_MODE;
-               switch (dev->interface) {
+               switch (p->interface) {
                case PHY_INTERFACE_MODE_MII:
                        p->phydev.speed = SPEED_100;
                        break;
@@ -952,11 +960,11 @@ static void ksz8795_port_setup(struct ksz_device *dev, int port, bool cpu_port)
                default:
                        data8 &= ~PORT_RGMII_ID_IN_ENABLE;
                        data8 &= ~PORT_RGMII_ID_OUT_ENABLE;
-                       if (dev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-                           dev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+                       if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+                           p->interface == PHY_INTERFACE_MODE_RGMII_RXID)
                                data8 |= PORT_RGMII_ID_IN_ENABLE;
-                       if (dev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-                           dev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+                       if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+                           p->interface == PHY_INTERFACE_MODE_RGMII_TXID)
                                data8 |= PORT_RGMII_ID_OUT_ENABLE;
                        data8 |= PORT_GMII_1GPS_MODE;
                        data8 |= PORT_INTERFACE_RGMII;
@@ -1252,7 +1260,7 @@ static int ksz8795_switch_init(struct ksz_device *dev)
        }
 
        /* set the real number of ports */
-       dev->ds->num_ports = dev->port_cnt;
+       dev->ds->num_ports = dev->port_cnt + 1;
 
        return 0;
 }
index dc99940..2f5506a 100644 (file)
@@ -1083,7 +1083,7 @@ static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port)
                interface = PHY_INTERFACE_MODE_GMII;
                if (gbit)
                        break;
-               /* fall through */
+               fallthrough;
        case 0:
                interface = PHY_INTERFACE_MODE_MII;
                break;
@@ -1208,7 +1208,7 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
 
                /* configure MAC to 1G & RGMII mode */
                ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8);
-               switch (dev->interface) {
+               switch (p->interface) {
                case PHY_INTERFACE_MODE_MII:
                        ksz9477_set_xmii(dev, 0, &data8);
                        ksz9477_set_gbit(dev, false, &data8);
@@ -1229,11 +1229,11 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
                        ksz9477_set_gbit(dev, true, &data8);
                        data8 &= ~PORT_RGMII_ID_IG_ENABLE;
                        data8 &= ~PORT_RGMII_ID_EG_ENABLE;
-                       if (dev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-                           dev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+                       if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+                           p->interface == PHY_INTERFACE_MODE_RGMII_RXID)
                                data8 |= PORT_RGMII_ID_IG_ENABLE;
-                       if (dev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-                           dev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+                       if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+                           p->interface == PHY_INTERFACE_MODE_RGMII_TXID)
                                data8 |= PORT_RGMII_ID_EG_ENABLE;
                        p->phydev.speed = SPEED_1000;
                        break;
@@ -1269,23 +1269,32 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds)
                        dev->cpu_port = i;
                        dev->host_mask = (1 << dev->cpu_port);
                        dev->port_mask |= dev->host_mask;
+                       p = &dev->ports[i];
 
                        /* Read from XMII register to determine host port
                         * interface.  If set specifically in device tree
                         * note the difference to help debugging.
                         */
                        interface = ksz9477_get_interface(dev, i);
-                       if (!dev->interface)
-                               dev->interface = interface;
-                       if (interface && interface != dev->interface)
+                       if (!p->interface) {
+                               if (dev->compat_interface) {
+                                       dev_warn(dev->dev,
+                                                "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. "
+                                                "Please update your device tree.\n",
+                                                i);
+                                       p->interface = dev->compat_interface;
+                               } else {
+                                       p->interface = interface;
+                               }
+                       }
+                       if (interface && interface != p->interface)
                                dev_info(dev->dev,
                                         "use %s instead of %s\n",
-                                         phy_modes(dev->interface),
+                                         phy_modes(p->interface),
                                          phy_modes(interface));
 
                        /* enable cpu port */
                        ksz9477_port_setup(dev, i, true);
-                       p = &dev->ports[dev->cpu_port];
                        p->vid_member = dev->port_mask;
                        p->on = 1;
                }
index 8d53b12..c796d42 100644 (file)
@@ -387,7 +387,9 @@ EXPORT_SYMBOL(ksz_switch_alloc);
 int ksz_switch_register(struct ksz_device *dev,
                        const struct ksz_dev_ops *ops)
 {
+       struct device_node *port, *ports;
        phy_interface_t interface;
+       unsigned int port_num;
        int ret;
 
        if (dev->pdata)
@@ -421,10 +423,23 @@ int ksz_switch_register(struct ksz_device *dev,
        /* Host port interface will be self detected, or specifically set in
         * device tree.
         */
+       for (port_num = 0; port_num < dev->port_cnt; ++port_num)
+               dev->ports[port_num].interface = PHY_INTERFACE_MODE_NA;
        if (dev->dev->of_node) {
                ret = of_get_phy_mode(dev->dev->of_node, &interface);
                if (ret == 0)
-                       dev->interface = interface;
+                       dev->compat_interface = interface;
+               ports = of_get_child_by_name(dev->dev->of_node, "ports");
+               if (ports)
+                       for_each_available_child_of_node(ports, port) {
+                               if (of_property_read_u32(port, "reg",
+                                                        &port_num))
+                                       continue;
+                               if (port_num >= dev->port_cnt)
+                                       return -EINVAL;
+                               of_get_phy_mode(port,
+                                               &dev->ports[port_num].interface);
+                       }
                dev->synclko_125 = of_property_read_bool(dev->dev->of_node,
                                                         "microchip,synclko-125");
        }
index 2068381..cf866e4 100644 (file)
@@ -39,6 +39,7 @@ struct ksz_port {
        u32 freeze:1;                   /* MIB counter freeze is enabled */
 
        struct ksz_port_mib mib;
+       phy_interface_t interface;
 };
 
 struct ksz_device {
@@ -72,7 +73,7 @@ struct ksz_device {
        int mib_cnt;
        int mib_port_cnt;
        int last_port;                  /* ports after that not used */
-       phy_interface_t interface;
+       phy_interface_t compat_interface;
        u32 regs_size;
        bool phy_errata_9477;
        bool synclko_125;
index 8dcb8a4..1aaf47a 100644 (file)
@@ -566,7 +566,7 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
        case P5_INTF_SEL_PHY_P0:
                /* MT7530_P5_MODE_GPHY_P0: 2nd GMAC -> P5 -> P0 */
                val |= MHWTRAP_PHY0_SEL;
-               /* fall through */
+               fallthrough;
        case P5_INTF_SEL_PHY_P4:
                /* MT7530_P5_MODE_GPHY_P4: 2nd GMAC -> P5 -> P4 */
                val &= ~MHWTRAP_P5_MAC_SEL & ~MHWTRAP_P5_DIS;
@@ -1326,14 +1326,17 @@ mt7530_setup(struct dsa_switch *ds)
 
                        if (phy_node->parent == priv->dev->of_node->parent) {
                                ret = of_get_phy_mode(mac_np, &interface);
-                               if (ret && ret != -ENODEV)
+                               if (ret && ret != -ENODEV) {
+                                       of_node_put(mac_np);
                                        return ret;
+                               }
                                id = of_mdio_parse_addr(ds->dev, phy_node);
                                if (id == 0)
                                        priv->p5_intf_sel = P5_INTF_SEL_PHY_P0;
                                if (id == 4)
                                        priv->p5_intf_sel = P5_INTF_SEL_PHY_P4;
                        }
+                       of_node_put(mac_np);
                        of_node_put(phy_node);
                        break;
                }
@@ -1501,7 +1504,7 @@ unsupported:
                phylink_set(mask, 100baseT_Full);
 
                if (state->interface != PHY_INTERFACE_MODE_MII) {
-                       phylink_set(mask, 1000baseT_Half);
+                       /* This switch only supports 1G full-duplex. */
                        phylink_set(mask, 1000baseT_Full);
                        if (port == 5)
                                phylink_set(mask, 1000baseX_Full);
index 7a71c99..f0dbc05 100644 (file)
@@ -875,7 +875,7 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
                break;
        case STATS_TYPE_BANK1:
                reg = bank1_select;
-               /* fall through */
+               fallthrough;
        case STATS_TYPE_BANK0:
                reg |= s->reg | histogram;
                mv88e6xxx_g1_stats_read(chip, reg, &low);
index c69d959..01427cd 100644 (file)
@@ -400,6 +400,7 @@ static int felix_parse_ports_node(struct felix *felix,
                if (err < 0) {
                        dev_err(dev, "Unsupported PHY mode %s on port %d\n",
                                phy_modes(phy_mode), port);
+                       of_node_put(child);
                        return err;
                }
 
@@ -584,7 +585,10 @@ static int felix_setup(struct dsa_switch *ds)
        if (err)
                return err;
 
-       ocelot_init(ocelot);
+       err = ocelot_init(ocelot);
+       if (err)
+               return err;
+
        if (ocelot->ptp) {
                err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info);
                if (err) {
@@ -639,10 +643,13 @@ static void felix_teardown(struct dsa_switch *ds)
 {
        struct ocelot *ocelot = ds->priv;
        struct felix *felix = ocelot_to_felix(ocelot);
+       int port;
 
        if (felix->info->mdio_bus_free)
                felix->info->mdio_bus_free(ocelot);
 
+       for (port = 0; port < ocelot->num_phys_ports; port++)
+               ocelot_deinit_port(ocelot, port);
        ocelot_deinit_timestamp(ocelot);
        /* stop workqueue thread */
        ocelot_deinit(ocelot);
index 9b720c8..3a96374 100644 (file)
@@ -645,17 +645,17 @@ static struct vcap_field vsc9959_vcap_is2_keys[] = {
        [VCAP_IS2_HK_DIP_EQ_SIP]                = {118,   1},
        /* IP4_TCP_UDP (TYPE=100) */
        [VCAP_IS2_HK_TCP]                       = {119,   1},
-       [VCAP_IS2_HK_L4_SPORT]                  = {120,  16},
-       [VCAP_IS2_HK_L4_DPORT]                  = {136,  16},
+       [VCAP_IS2_HK_L4_DPORT]                  = {120,  16},
+       [VCAP_IS2_HK_L4_SPORT]                  = {136,  16},
        [VCAP_IS2_HK_L4_RNG]                    = {152,   8},
        [VCAP_IS2_HK_L4_SPORT_EQ_DPORT]         = {160,   1},
        [VCAP_IS2_HK_L4_SEQUENCE_EQ0]           = {161,   1},
-       [VCAP_IS2_HK_L4_URG]                    = {162,   1},
-       [VCAP_IS2_HK_L4_ACK]                    = {163,   1},
-       [VCAP_IS2_HK_L4_PSH]                    = {164,   1},
-       [VCAP_IS2_HK_L4_RST]                    = {165,   1},
-       [VCAP_IS2_HK_L4_SYN]                    = {166,   1},
-       [VCAP_IS2_HK_L4_FIN]                    = {167,   1},
+       [VCAP_IS2_HK_L4_FIN]                    = {162,   1},
+       [VCAP_IS2_HK_L4_SYN]                    = {163,   1},
+       [VCAP_IS2_HK_L4_RST]                    = {164,   1},
+       [VCAP_IS2_HK_L4_PSH]                    = {165,   1},
+       [VCAP_IS2_HK_L4_ACK]                    = {166,   1},
+       [VCAP_IS2_HK_L4_URG]                    = {167,   1},
        [VCAP_IS2_HK_L4_1588_DOM]               = {168,   8},
        [VCAP_IS2_HK_L4_1588_VER]               = {176,   4},
        /* IP4_OTHER (TYPE=101) */
@@ -685,12 +685,12 @@ static struct vcap_field vsc9959_vcap_is2_actions[] = {
        [VCAP_IS2_ACT_POLICE_ENA]               = {  9,  1},
        [VCAP_IS2_ACT_POLICE_IDX]               = { 10,  9},
        [VCAP_IS2_ACT_POLICE_VCAP_ONLY]         = { 19,  1},
-       [VCAP_IS2_ACT_PORT_MASK]                = { 20, 11},
-       [VCAP_IS2_ACT_REW_OP]                   = { 31,  9},
-       [VCAP_IS2_ACT_SMAC_REPLACE_ENA]         = { 40,  1},
-       [VCAP_IS2_ACT_RSV]                      = { 41,  2},
-       [VCAP_IS2_ACT_ACL_ID]                   = { 43,  6},
-       [VCAP_IS2_ACT_HIT_CNT]                  = { 49, 32},
+       [VCAP_IS2_ACT_PORT_MASK]                = { 20,  6},
+       [VCAP_IS2_ACT_REW_OP]                   = { 26,  9},
+       [VCAP_IS2_ACT_SMAC_REPLACE_ENA]         = { 35,  1},
+       [VCAP_IS2_ACT_RSV]                      = { 36,  2},
+       [VCAP_IS2_ACT_ACL_ID]                   = { 38,  6},
+       [VCAP_IS2_ACT_HIT_CNT]                  = { 44, 32},
 };
 
 static const struct vcap_props vsc9959_vcap_props[] = {
@@ -1171,6 +1171,8 @@ static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port,
  */
 static u16 vsc9959_wm_enc(u16 value)
 {
+       WARN_ON(value >= 16 * BIT(8));
+
        if (value >= BIT(8))
                return BIT(8) | (value / 16);
 
@@ -1284,8 +1286,28 @@ void vsc9959_mdio_bus_free(struct ocelot *ocelot)
 static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
                                    u32 speed)
 {
+       u8 tas_speed;
+
+       switch (speed) {
+       case SPEED_10:
+               tas_speed = OCELOT_SPEED_10;
+               break;
+       case SPEED_100:
+               tas_speed = OCELOT_SPEED_100;
+               break;
+       case SPEED_1000:
+               tas_speed = OCELOT_SPEED_1000;
+               break;
+       case SPEED_2500:
+               tas_speed = OCELOT_SPEED_2500;
+               break;
+       default:
+               tas_speed = OCELOT_SPEED_1000;
+               break;
+       }
+
        ocelot_rmw_rix(ocelot,
-                      QSYS_TAG_CONFIG_LINK_SPEED(speed),
+                      QSYS_TAG_CONFIG_LINK_SPEED(tas_speed),
                       QSYS_TAG_CONFIG_LINK_SPEED_M,
                       QSYS_TAG_CONFIG, port);
 }
index 625b189..9e9fd19 100644 (file)
@@ -659,17 +659,17 @@ static struct vcap_field vsc9953_vcap_is2_keys[] = {
        [VCAP_IS2_HK_DIP_EQ_SIP]                = {122,   1},
        /* IP4_TCP_UDP (TYPE=100) */
        [VCAP_IS2_HK_TCP]                       = {123,   1},
-       [VCAP_IS2_HK_L4_SPORT]                  = {124,  16},
-       [VCAP_IS2_HK_L4_DPORT]                  = {140,  16},
+       [VCAP_IS2_HK_L4_DPORT]                  = {124,  16},
+       [VCAP_IS2_HK_L4_SPORT]                  = {140,  16},
        [VCAP_IS2_HK_L4_RNG]                    = {156,   8},
        [VCAP_IS2_HK_L4_SPORT_EQ_DPORT]         = {164,   1},
        [VCAP_IS2_HK_L4_SEQUENCE_EQ0]           = {165,   1},
-       [VCAP_IS2_HK_L4_URG]                    = {166,   1},
-       [VCAP_IS2_HK_L4_ACK]                    = {167,   1},
-       [VCAP_IS2_HK_L4_PSH]                    = {168,   1},
-       [VCAP_IS2_HK_L4_RST]                    = {169,   1},
-       [VCAP_IS2_HK_L4_SYN]                    = {170,   1},
-       [VCAP_IS2_HK_L4_FIN]                    = {171,   1},
+       [VCAP_IS2_HK_L4_FIN]                    = {166,   1},
+       [VCAP_IS2_HK_L4_SYN]                    = {167,   1},
+       [VCAP_IS2_HK_L4_RST]                    = {168,   1},
+       [VCAP_IS2_HK_L4_PSH]                    = {169,   1},
+       [VCAP_IS2_HK_L4_ACK]                    = {170,   1},
+       [VCAP_IS2_HK_L4_URG]                    = {171,   1},
        /* IP4_OTHER (TYPE=101) */
        [VCAP_IS2_HK_IP4_L3_PROTO]              = {123,   8},
        [VCAP_IS2_HK_L3_PAYLOAD]                = {131,  56},
@@ -706,7 +706,7 @@ static const struct vcap_props vsc9953_vcap_props[] = {
                .action_type_width = 1,
                .action_table = {
                        [IS2_ACTION_TYPE_NORMAL] = {
-                               .width = 44,
+                               .width = 50, /* HIT_CNT not included */
                                .count = 2
                        },
                        [IS2_ACTION_TYPE_SMAC_SIP] = {
@@ -911,6 +911,8 @@ static int vsc9953_prevalidate_phy_mode(struct ocelot *ocelot, int port,
  */
 static u16 vsc9953_wm_enc(u16 value)
 {
+       WARN_ON(value >= 16 * BIT(9));
+
        if (value >= BIT(9))
                return BIT(9) | (value / 16);
 
@@ -1008,7 +1010,7 @@ static const struct felix_info seville_info_vsc9953 = {
        .vcap_is2_keys          = vsc9953_vcap_is2_keys,
        .vcap_is2_actions       = vsc9953_vcap_is2_actions,
        .vcap                   = vsc9953_vcap_props,
-       .shared_queue_sz        = 128 * 1024,
+       .shared_queue_sz        = 2048 * 1024,
        .num_mact_rows          = 2048,
        .num_ports              = 10,
        .mdio_bus_alloc         = vsc9953_mdio_bus_alloc,
index 8f40fbf..a8c5a93 100644 (file)
@@ -452,13 +452,19 @@ int rtl8366_vlan_del(struct dsa_switch *ds, int port,
                                return ret;
 
                        if (vid == vlanmc.vid) {
-                               /* clear VLAN member configurations */
-                               vlanmc.vid = 0;
-                               vlanmc.priority = 0;
-                               vlanmc.member = 0;
-                               vlanmc.untag = 0;
-                               vlanmc.fid = 0;
-
+                               /* Remove this port from the VLAN */
+                               vlanmc.member &= ~BIT(port);
+                               vlanmc.untag &= ~BIT(port);
+                               /*
+                                * If no ports are members of this VLAN
+                                * anymore then clear the whole member
+                                * config so it can be reused.
+                                */
+                               if (!vlanmc.member && vlanmc.untag) {
+                                       vlanmc.vid = 0;
+                                       vlanmc.priority = 0;
+                                       vlanmc.fid = 0;
+                               }
                                ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
                                if (ret) {
                                        dev_err(smi->dev,
index c3f6f12..5a28dfb 100644 (file)
@@ -3415,7 +3415,7 @@ static int sja1105_check_device_id(struct sja1105_private *priv)
 
        sja1105_unpack(prod_id, &part_no, 19, 4, SJA1105_SIZE_DEVICE_ID);
 
-       for (match = sja1105_dt_ids; match->compatible; match++) {
+       for (match = sja1105_dt_ids; match->compatible[0]; match++) {
                const struct sja1105_info *info = match->data;
 
                /* Is what's been probed in our match table at all? */
index 139d012..667f38c 100644 (file)
@@ -1259,14 +1259,14 @@ el3_up(struct net_device *dev)
                                        pr_cont("Forcing 3c5x9b full-duplex mode");
                                        break;
                                }
-                               /* fall through */
+                               fallthrough;
                        case 8:
                                /* set full-duplex mode based on eeprom config setting */
                                if ((sw_info & 0x000f) && (sw_info & 0x8000)) {
                                        pr_cont("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)");
                                        break;
                                }
-                               /* fall through */
+                               fallthrough;
                        default:
                                /* xcvr=(0 || 4) OR user has an old 3c5x9 non "B" model */
                                pr_cont("Setting 3c5x9/3c5x9B half-duplex mode");
index bd0ada4..f66e7fb 100644 (file)
@@ -1046,7 +1046,7 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        switch(cmd) {
        case SIOCGMIIPHY:               /* Get the address of the PHY in use. */
                data->phy_id = phy;
-               /* fall through */
+               fallthrough;
        case SIOCGMIIREG:               /* Read the specified MII register. */
                {
                        int saved_window;
index d3b30ba..049cc01 100644 (file)
@@ -1419,8 +1419,7 @@ typhoon_download_firmware(struct typhoon *tp)
                         * the checksum, we can do this once, at the end.
                         */
                        csum = csum_fold(csum_partial_copy_nocheck(image_data,
-                                                                  dpage, len,
-                                                                  0));
+                                                                  dpage, len));
 
                        iowrite32(len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
                        iowrite32(le16_to_cpu((__force __le16)csum),
index 2f634c6..38e6dca 100644 (file)
@@ -33,7 +33,7 @@ struct basic_ring {
        u32 lastWrite;
 };
 
-/* The Typoon transmit ring -- same as a basic ring, plus:
+/* The Typhoon transmit ring -- same as a basic ring, plus:
  * lastRead:      where we're at in regard to cleaning up the ring
  * writeRegister: register to use for writing (different for Hi & Lo rings)
  */
index 08db4c9..a00b36f 100644 (file)
@@ -610,7 +610,7 @@ static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
     switch (cmd) {
     case SIOCGMIIPHY:
        data->phy_id = info->phy_id;
-       /* Fall through */
+       fallthrough;
     case SIOCGMIIREG:          /* Read MII PHY register. */
        data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f);
        return 0;
index 645efac..164c3ed 100644 (file)
@@ -1108,7 +1108,7 @@ static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
     switch (cmd) {
     case SIOCGMIIPHY:
        data->phy_id = info->phy_id;
-       /* fall through */
+       fallthrough;
     case SIOCGMIIREG:          /* Read MII PHY register. */
        data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f);
        return 0;
index 6234fcd..696517e 100644 (file)
@@ -1712,13 +1712,13 @@ static bool slic_is_fiber(unsigned short subdev)
 {
        switch (subdev) {
        /* Mojave */
-       case PCI_SUBDEVICE_ID_ALACRITECH_1000X1F: /* fallthrough */
-       case PCI_SUBDEVICE_ID_ALACRITECH_SES1001F: /* fallthrough */
+       case PCI_SUBDEVICE_ID_ALACRITECH_1000X1F:
+       case PCI_SUBDEVICE_ID_ALACRITECH_SES1001F: fallthrough;
        /* Oasis */
-       case PCI_SUBDEVICE_ID_ALACRITECH_SEN2002XF: /* fallthrough */
-       case PCI_SUBDEVICE_ID_ALACRITECH_SEN2001XF: /* fallthrough */
-       case PCI_SUBDEVICE_ID_ALACRITECH_SEN2104EF: /* fallthrough */
-       case PCI_SUBDEVICE_ID_ALACRITECH_SEN2102EF: /* fallthrough */
+       case PCI_SUBDEVICE_ID_ALACRITECH_SEN2002XF:
+       case PCI_SUBDEVICE_ID_ALACRITECH_SEN2001XF:
+       case PCI_SUBDEVICE_ID_ALACRITECH_SEN2104EF:
+       case PCI_SUBDEVICE_ID_ALACRITECH_SEN2102EF:
                return true;
        }
        return false;
index ac86fca..8470c83 100644 (file)
@@ -547,7 +547,7 @@ static int acenic_probe_one(struct pci_dev *pdev,
                               ap->name);
                        break;
                }
-               /* Fall through */
+               fallthrough;
        case PCI_VENDOR_ID_SGI:
                printk(KERN_INFO "%s: SGI AceNIC ", ap->name);
                break;
index b6c43b5..960d483 100644 (file)
@@ -1475,7 +1475,7 @@ static int amd8111e_ioctl(struct net_device *dev , struct ifreq *ifr, int cmd)
        case SIOCGMIIPHY:
                data->phy_id = lp->ext_phy_addr;
 
-       /* fallthru */
+               fallthrough;
        case SIOCGMIIREG:
 
                spin_lock_irq(&lp->lock);
index 43294a1..4ba7555 100644 (file)
@@ -1538,7 +1538,7 @@ static int xgbe_set_hwtstamp_settings(struct xgbe_prv_data *pdata,
        /* PTP v2, UDP, any kind of event packet */
        case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
                XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1);
-               /* Fall through - to PTP v1, UDP, any kind of event packet */
+               fallthrough;    /* to PTP v1, UDP, any kind of event packet */
        case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
                XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1);
                XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1);
@@ -1549,7 +1549,7 @@ static int xgbe_set_hwtstamp_settings(struct xgbe_prv_data *pdata,
        /* PTP v2, UDP, Sync packet */
        case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
                XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1);
-               /* Fall through - to PTP v1, UDP, Sync packet */
+               fallthrough;    /* to PTP v1, UDP, Sync packet */
        case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
                XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1);
                XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1);
@@ -1560,7 +1560,7 @@ static int xgbe_set_hwtstamp_settings(struct xgbe_prv_data *pdata,
        /* PTP v2, UDP, Delay_req packet */
        case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
                XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1);
-               /* Fall through - to PTP v1, UDP, Delay_req packet */
+               fallthrough;    /* to PTP v1, UDP, Delay_req packet */
        case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
                XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1);
                XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1);
index 46c3c1c..859ded0 100644 (file)
@@ -166,6 +166,7 @@ enum xgbe_port_mode {
        XGBE_PORT_MODE_10GBASE_T,
        XGBE_PORT_MODE_10GBASE_R,
        XGBE_PORT_MODE_SFP,
+       XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG,
        XGBE_PORT_MODE_MAX,
 };
 
@@ -1634,6 +1635,7 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
        if (ad_reg & 0x80) {
                switch (phy_data->port_mode) {
                case XGBE_PORT_MODE_BACKPLANE:
+               case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
                        mode = XGBE_MODE_KR;
                        break;
                default:
@@ -1643,6 +1645,7 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
        } else if (ad_reg & 0x20) {
                switch (phy_data->port_mode) {
                case XGBE_PORT_MODE_BACKPLANE:
+               case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
                        mode = XGBE_MODE_KX_1000;
                        break;
                case XGBE_PORT_MODE_1000BASE_X:
@@ -1782,6 +1785,7 @@ static void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata,
 
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_BACKPLANE:
+       case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
                XGBE_SET_ADV(dlks, 10000baseKR_Full);
                break;
        case XGBE_PORT_MODE_BACKPLANE_2500:
@@ -1874,6 +1878,7 @@ static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata)
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_BACKPLANE:
                return XGBE_AN_MODE_CL73;
+       case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
        case XGBE_PORT_MODE_BACKPLANE_2500:
                return XGBE_AN_MODE_NONE;
        case XGBE_PORT_MODE_1000BASE_T:
@@ -2156,6 +2161,7 @@ static enum xgbe_mode xgbe_phy_switch_mode(struct xgbe_prv_data *pdata)
 
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_BACKPLANE:
+       case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
                return xgbe_phy_switch_bp_mode(pdata);
        case XGBE_PORT_MODE_BACKPLANE_2500:
                return xgbe_phy_switch_bp_2500_mode(pdata);
@@ -2251,6 +2257,7 @@ static enum xgbe_mode xgbe_phy_get_mode(struct xgbe_prv_data *pdata,
 
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_BACKPLANE:
+       case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
                return xgbe_phy_get_bp_mode(speed);
        case XGBE_PORT_MODE_BACKPLANE_2500:
                return xgbe_phy_get_bp_2500_mode(speed);
@@ -2426,6 +2433,7 @@ static bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
 
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_BACKPLANE:
+       case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
                return xgbe_phy_use_bp_mode(pdata, mode);
        case XGBE_PORT_MODE_BACKPLANE_2500:
                return xgbe_phy_use_bp_2500_mode(pdata, mode);
@@ -2515,6 +2523,7 @@ static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
 
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_BACKPLANE:
+       case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
                return xgbe_phy_valid_speed_bp_mode(speed);
        case XGBE_PORT_MODE_BACKPLANE_2500:
                return xgbe_phy_valid_speed_bp_2500_mode(speed);
@@ -2792,6 +2801,7 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata)
 
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_BACKPLANE:
+       case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
                if ((phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) ||
                    (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000))
                        return false;
@@ -2844,6 +2854,7 @@ static bool xgbe_phy_conn_type_mismatch(struct xgbe_prv_data *pdata)
 
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_BACKPLANE:
+       case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
        case XGBE_PORT_MODE_BACKPLANE_2500:
                if (phy_data->conn_type == XGBE_CONN_TYPE_BACKPLANE)
                        return false;
@@ -3160,6 +3171,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
        /* Backplane support */
        case XGBE_PORT_MODE_BACKPLANE:
                XGBE_SET_SUP(lks, Autoneg);
+               fallthrough;
+       case XGBE_PORT_MODE_BACKPLANE_NO_AUTONEG:
                XGBE_SET_SUP(lks, Pause);
                XGBE_SET_SUP(lks, Asym_Pause);
                XGBE_SET_SUP(lks, Backplane);
index 130a105..8ebcc68 100644 (file)
@@ -8,7 +8,7 @@
 
 obj-$(CONFIG_AQTION) += atlantic.o
 
-ccflags-y += -I$(src)
+ccflags-y += -I$(srctree)/$(src)
 
 atlantic-objs := aq_main.o \
        aq_nic.o \
@@ -33,4 +33,4 @@ atlantic-objs := aq_main.o \
 
 atlantic-$(CONFIG_MACSEC) += aq_macsec.o
 
-atlantic-$(CONFIG_PTP_1588_CLOCK) += aq_ptp.o
\ No newline at end of file
+atlantic-$(CONFIG_PTP_1588_CLOCK) += aq_ptp.o
index 0187dbf..54cdafd 100644 (file)
@@ -153,6 +153,7 @@ int arc_mdio_probe(struct arc_emac_priv *priv)
        if (IS_ERR(data->reset_gpio)) {
                error = PTR_ERR(data->reset_gpio);
                dev_err(priv->dev, "Failed to request gpio: %d\n", error);
+               mdiobus_free(bus);
                return error;
        }
 
index dfed9ad..0762d5d 100644 (file)
@@ -2491,8 +2491,10 @@ static int bcm_sysport_probe(struct platform_device *pdev)
        priv->tx_rings = devm_kcalloc(&pdev->dev, txq,
                                      sizeof(struct bcm_sysport_tx_ring),
                                      GFP_KERNEL);
-       if (!priv->tx_rings)
-               return -ENOMEM;
+       if (!priv->tx_rings) {
+               ret = -ENOMEM;
+               goto err_free_netdev;
+       }
 
        priv->is_lite = params->is_lite;
        priv->num_rx_desc_words = params->num_rx_desc_words;
index 34d1830..a5fd161 100644 (file)
@@ -217,7 +217,7 @@ static int bgmac_probe(struct bcma_device *core)
        /* BCM 471X/535X family */
        case BCMA_CHIP_ID_BCM4716:
                bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
-               /* fallthrough */
+               fallthrough;
        case BCMA_CHIP_ID_BCM47162:
                bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL2;
                bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
index 6795b6d..f37f1c5 100644 (file)
@@ -131,7 +131,7 @@ static void bgmac_nicpm_speed_set(struct net_device *net_dev)
        switch (bgmac->net_dev->phydev->speed) {
        default:
                netdev_err(net_dev, "Unsupported speed. Defaulting to 1000Mb\n");
-               /* fall through */
+               fallthrough;
        case SPEED_1000:
                val |= NICPM_IOMUX_CTRL_SPD_1000M << NICPM_IOMUX_CTRL_SPD_SHIFT;
                break;
index c8cc14e..3e8a179 100644 (file)
@@ -1337,13 +1337,13 @@ bnx2_set_mac_link(struct bnx2 *bp)
                                        val |= BNX2_EMAC_MODE_PORT_MII_10M;
                                        break;
                                }
-                               /* fall through */
+                               fallthrough;
                        case SPEED_100:
                                val |= BNX2_EMAC_MODE_PORT_MII;
                                break;
                        case SPEED_2500:
                                val |= BNX2_EMAC_MODE_25G_MODE;
-                               /* fall through */
+                               fallthrough;
                        case SPEED_1000:
                                val |= BNX2_EMAC_MODE_PORT_GMII;
                                break;
@@ -1995,26 +1995,26 @@ bnx2_remote_phy_event(struct bnx2 *bp)
                switch (speed) {
                        case BNX2_LINK_STATUS_10HALF:
                                bp->duplex = DUPLEX_HALF;
-                               /* fall through */
+                               fallthrough;
                        case BNX2_LINK_STATUS_10FULL:
                                bp->line_speed = SPEED_10;
                                break;
                        case BNX2_LINK_STATUS_100HALF:
                                bp->duplex = DUPLEX_HALF;
-                               /* fall through */
+                               fallthrough;
                        case BNX2_LINK_STATUS_100BASE_T4:
                        case BNX2_LINK_STATUS_100FULL:
                                bp->line_speed = SPEED_100;
                                break;
                        case BNX2_LINK_STATUS_1000HALF:
                                bp->duplex = DUPLEX_HALF;
-                               /* fall through */
+                               fallthrough;
                        case BNX2_LINK_STATUS_1000FULL:
                                bp->line_speed = SPEED_1000;
                                break;
                        case BNX2_LINK_STATUS_2500HALF:
                                bp->duplex = DUPLEX_HALF;
-                               /* fall through */
+                               fallthrough;
                        case BNX2_LINK_STATUS_2500FULL:
                                bp->line_speed = SPEED_2500;
                                break;
@@ -7856,7 +7856,7 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCGMIIPHY:
                data->phy_id = bp->phy_addr;
 
-               /* fallthru */
+               fallthrough;
        case SIOCGMIIREG: {
                u32 mii_regval;
 
index 1426c69..4e85e7d 100644 (file)
@@ -4712,14 +4712,14 @@ static void bnx2x_sync_link(struct link_params *params,
                        LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
                case LINK_10THD:
                        vars->duplex = DUPLEX_HALF;
-                       /* Fall thru */
+                       fallthrough;
                case LINK_10TFD:
                        vars->line_speed = SPEED_10;
                        break;
 
                case LINK_100TXHD:
                        vars->duplex = DUPLEX_HALF;
-                       /* Fall thru */
+                       fallthrough;
                case LINK_100T4:
                case LINK_100TXFD:
                        vars->line_speed = SPEED_100;
@@ -4727,14 +4727,14 @@ static void bnx2x_sync_link(struct link_params *params,
 
                case LINK_1000THD:
                        vars->duplex = DUPLEX_HALF;
-                       /* Fall thru */
+                       fallthrough;
                case LINK_1000TFD:
                        vars->line_speed = SPEED_1000;
                        break;
 
                case LINK_2500THD:
                        vars->duplex = DUPLEX_HALF;
-                       /* Fall thru */
+                       fallthrough;
                case LINK_2500TFD:
                        vars->line_speed = SPEED_2500;
                        break;
@@ -6339,7 +6339,7 @@ int bnx2x_set_led(struct link_params *params,
                 */
                if (!vars->link_up)
                        break;
-               /* fall through */
+               fallthrough;
        case LED_MODE_ON:
                if (((params->phy[EXT_PHY1].type ==
                          PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
@@ -12508,13 +12508,13 @@ static void bnx2x_phy_def_cfg(struct link_params *params,
        switch (link_config  & PORT_FEATURE_LINK_SPEED_MASK) {
        case PORT_FEATURE_LINK_SPEED_10M_HALF:
                phy->req_duplex = DUPLEX_HALF;
-               /* fall through */
+               fallthrough;
        case PORT_FEATURE_LINK_SPEED_10M_FULL:
                phy->req_line_speed = SPEED_10;
                break;
        case PORT_FEATURE_LINK_SPEED_100M_HALF:
                phy->req_duplex = DUPLEX_HALF;
-               /* fall through */
+               fallthrough;
        case PORT_FEATURE_LINK_SPEED_100M_FULL:
                phy->req_line_speed = SPEED_100;
                break;
index 7f24d26..3c543dd 100644 (file)
@@ -8600,11 +8600,11 @@ int bnx2x_set_int_mode(struct bnx2x *bp)
                               bp->num_queues,
                               1 + bp->num_cnic_queues);
 
-               /* fall through */
+               fallthrough;
        case BNX2X_INT_MODE_MSI:
                bnx2x_enable_msi(bp);
 
-               /* fall through */
+               fallthrough;
        case BNX2X_INT_MODE_INTX:
                bp->num_ethernet_queues = 1;
                bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
index bfc0e45..5caa75b 100644 (file)
 #define CCM_REG_GR_ARB_TYPE                                     0xd015c
 /* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the
    highest priority is 3. It is supposed; that the Store channel priority is
-   the compliment to 4 of the rest priorities - Aggregation channel; Load
+   the complement to 4 of the rest priorities - Aggregation channel; Load
    (FIC0) channel and Load (FIC1). */
 #define CCM_REG_GR_LD0_PR                                       0xd0164
 /* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the
    highest priority is 3. It is supposed; that the Store channel priority is
-   the compliment to 4 of the rest priorities - Aggregation channel; Load
+   the complement to 4 of the rest priorities - Aggregation channel; Load
    (FIC0) channel and Load (FIC1). */
 #define CCM_REG_GR_LD1_PR                                       0xd0168
 /* [RW 2] General flags index. */
 #define TCM_REG_GR_ARB_TYPE                                     0x50114
 /* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the
    highest priority is 3. It is supposed that the Store channel is the
-   compliment of the other 3 groups. */
+   complement of the other 3 groups. */
 #define TCM_REG_GR_LD0_PR                                       0x5011c
 /* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the
    highest priority is 3. It is supposed that the Store channel is the
-   compliment of the other 3 groups. */
+   complement of the other 3 groups. */
 #define TCM_REG_GR_LD1_PR                                       0x50120
 /* [RW 4] The number of double REG-pairs; loaded from the STORM context and
    sent to STORM; for a specific connection type. The double REG-pairs are
 #define UCM_REG_GR_ARB_TYPE                                     0xe0144
 /* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the
    highest priority is 3. It is supposed that the Store channel group is
-   compliment to the others. */
+   complement to the others. */
 #define UCM_REG_GR_LD0_PR                                       0xe014c
 /* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the
    highest priority is 3. It is supposed that the Store channel group is
-   compliment to the others. */
+   complement to the others. */
 #define UCM_REG_GR_LD1_PR                                       0xe0150
 /* [RW 2] The queue index for invalidate counter flag decision. */
 #define UCM_REG_INV_CFLG_Q                                      0xe00e4
 #define XCM_REG_GR_ARB_TYPE                                     0x2020c
 /* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the
    highest priority is 3. It is supposed that the Channel group is the
-   compliment of the other 3 groups. */
+   complement of the other 3 groups. */
 #define XCM_REG_GR_LD0_PR                                       0x20214
 /* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the
    highest priority is 3. It is supposed that the Channel group is the
-   compliment of the other 3 groups. */
+   complement of the other 3 groups. */
 #define XCM_REG_GR_LD1_PR                                       0x20218
 /* [RW 1] Input nig0 Interface enable. If 0 - the valid input is
    disregarded; acknowledge output is deasserted; all other signals are
index 80d250a..e26f4da 100644 (file)
@@ -3258,7 +3258,7 @@ static int bnx2x_mcast_validate_e2(struct bnx2x *bp,
        /* DEL command deletes all currently configured MACs */
        case BNX2X_MCAST_CMD_DEL:
                o->set_registry_size(o, 0);
-               /* fall through */
+               fallthrough;
 
        /* RESTORE command will restore the entire multicast configuration */
        case BNX2X_MCAST_CMD_RESTORE:
@@ -3592,7 +3592,7 @@ static int bnx2x_mcast_validate_e1(struct bnx2x *bp,
        /* DEL command deletes all currently configured MACs */
        case BNX2X_MCAST_CMD_DEL:
                o->set_registry_size(o, 0);
-               /* fall through */
+               fallthrough;
 
        /* RESTORE command will restore the entire multicast configuration */
        case BNX2X_MCAST_CMD_RESTORE:
index b4476f4..9c2f51f 100644 (file)
@@ -1809,7 +1809,7 @@ get_vf:
                DP(BNX2X_MSG_IOV, "got VF [%d:%d] RSS update ramrod\n",
                   vf->abs_vfid, qidx);
                bnx2x_vf_handle_rss_update_eqe(bp, vf);
-               /* fall through */
+               fallthrough;
        case EVENT_RING_OPCODE_VF_FLR:
                /* Do nothing for now */
                return 0;
@@ -2207,7 +2207,7 @@ int bnx2x_vf_free(struct bnx2x *bp, struct bnx2x_virtf *vf)
                rc = bnx2x_vf_close(bp, vf);
                if (rc)
                        goto op_err;
-               /* Fall through - to release resources */
+               fallthrough;    /* to release resources */
        case VF_ACQUIRED:
                DP(BNX2X_MSG_IOV, "about to free resources\n");
                bnx2x_vf_free_resc(bp, vf);
index 31fb5a2..7b7e8b7 100644 (file)
@@ -1141,6 +1141,9 @@ static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
 
 static void bnxt_queue_fw_reset_work(struct bnxt *bp, unsigned long delay)
 {
+       if (!(test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)))
+               return;
+
        if (BNXT_PF(bp))
                queue_delayed_work(bnxt_pf_wq, &bp->fw_reset_task, delay);
        else
@@ -1157,10 +1160,12 @@ static void bnxt_queue_sp_work(struct bnxt *bp)
 
 static void bnxt_cancel_sp_work(struct bnxt *bp)
 {
-       if (BNXT_PF(bp))
+       if (BNXT_PF(bp)) {
                flush_workqueue(bnxt_pf_wq);
-       else
+       } else {
                cancel_work_sync(&bp->sp_task);
+               cancel_delayed_work_sync(&bp->fw_reset_task);
+       }
 }
 
 static void bnxt_sched_reset(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
@@ -1923,7 +1928,7 @@ u32 bnxt_fw_health_readl(struct bnxt *bp, int reg_idx)
                break;
        case BNXT_FW_HEALTH_REG_TYPE_GRC:
                reg_off = fw_health->mapped_regs[reg_idx];
-               /* fall through */
+               fallthrough;
        case BNXT_FW_HEALTH_REG_TYPE_BAR0:
                val = readl(bp->bar0 + reg_off);
                break;
@@ -1966,11 +1971,11 @@ static int bnxt_async_event_process(struct bnxt *bp,
                }
                set_bit(BNXT_LINK_SPEED_CHNG_SP_EVENT, &bp->sp_event);
        }
-       /* fall through */
+               fallthrough;
        case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE:
        case ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE:
                set_bit(BNXT_LINK_CFG_CHANGE_SP_EVENT, &bp->sp_event);
-               /* fall through */
+               fallthrough;
        case ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE:
                set_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event);
                break;
@@ -3777,6 +3782,7 @@ static int bnxt_hwrm_func_qstat_ext(struct bnxt *bp,
                return -EOPNOTSUPP;
 
        bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QSTATS_EXT, -1, -1);
+       req.fid = cpu_to_le16(0xffff);
        req.flags = FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK;
        mutex_lock(&bp->hwrm_cmd_lock);
        rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
@@ -3847,7 +3853,7 @@ static void bnxt_init_stats(struct bnxt *bp)
                tx_masks = stats->hw_masks;
                tx_count = sizeof(struct tx_port_stats_ext) / 8;
 
-               flags = FUNC_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK;
+               flags = PORT_QSTATS_EXT_REQ_FLAGS_COUNTER_MASK;
                rc = bnxt_hwrm_port_qstats_ext(bp, flags);
                if (rc) {
                        mask = (1ULL << 40) - 1;
@@ -4300,7 +4306,7 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
        u32 bar_offset = BNXT_GRCPF_REG_CHIMP_COMM;
        u16 dst = BNXT_HWRM_CHNL_CHIMP;
 
-       if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
+       if (BNXT_NO_FW_ACCESS(bp))
                return -EBUSY;
 
        if (msg_len > BNXT_HWRM_MAX_REQ_LEN) {
@@ -5718,7 +5724,7 @@ static int hwrm_ring_free_send_msg(struct bnxt *bp,
        struct hwrm_ring_free_output *resp = bp->hwrm_cmd_resp_addr;
        u16 error_code;
 
-       if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
+       if (BNXT_NO_FW_ACCESS(bp))
                return 0;
 
        bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_FREE, cmpl_ring_id, -1);
@@ -6102,6 +6108,21 @@ static int bnxt_get_func_stat_ctxs(struct bnxt *bp)
        return cp + ulp_stat;
 }
 
+/* Check if a default RSS map needs to be setup.  This function is only
+ * used on older firmware that does not require reserving RX rings.
+ */
+static void bnxt_check_rss_tbl_no_rmgr(struct bnxt *bp)
+{
+       struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
+
+       /* The RSS map is valid for RX rings set to resv_rx_rings */
+       if (hw_resc->resv_rx_rings != bp->rx_nr_rings) {
+               hw_resc->resv_rx_rings = bp->rx_nr_rings;
+               if (!netif_is_rxfh_configured(bp->dev))
+                       bnxt_set_dflt_rss_indir_tbl(bp);
+       }
+}
+
 static bool bnxt_need_reserve_rings(struct bnxt *bp)
 {
        struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
@@ -6110,22 +6131,28 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp)
        int rx = bp->rx_nr_rings, stat;
        int vnic = 1, grp = rx;
 
-       if (bp->hwrm_spec_code < 0x10601)
-               return false;
-
-       if (hw_resc->resv_tx_rings != bp->tx_nr_rings)
+       if (hw_resc->resv_tx_rings != bp->tx_nr_rings &&
+           bp->hwrm_spec_code >= 0x10601)
                return true;
 
+       /* Old firmware does not need RX ring reservations but we still
+        * need to setup a default RSS map when needed.  With new firmware
+        * we go through RX ring reservations first and then set up the
+        * RSS map for the successfully reserved RX rings when needed.
+        */
+       if (!BNXT_NEW_RM(bp)) {
+               bnxt_check_rss_tbl_no_rmgr(bp);
+               return false;
+       }
        if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5))
                vnic = rx + 1;
        if (bp->flags & BNXT_FLAG_AGG_RINGS)
                rx <<= 1;
        stat = bnxt_get_func_stat_ctxs(bp);
-       if (BNXT_NEW_RM(bp) &&
-           (hw_resc->resv_rx_rings != rx || hw_resc->resv_cp_rings != cp ||
-            hw_resc->resv_vnics != vnic || hw_resc->resv_stat_ctxs != stat ||
-            (hw_resc->resv_hw_ring_grps != grp &&
-             !(bp->flags & BNXT_FLAG_CHIP_P5))))
+       if (hw_resc->resv_rx_rings != rx || hw_resc->resv_cp_rings != cp ||
+           hw_resc->resv_vnics != vnic || hw_resc->resv_stat_ctxs != stat ||
+           (hw_resc->resv_hw_ring_grps != grp &&
+            !(bp->flags & BNXT_FLAG_CHIP_P5)))
                return true;
        if ((bp->flags & BNXT_FLAG_CHIP_P5) && BNXT_PF(bp) &&
            hw_resc->resv_irqs != nq)
@@ -6214,6 +6241,9 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
        if (!tx || !rx || !cp || !grp || !vnic || !stat)
                return -ENOMEM;
 
+       if (!netif_is_rxfh_configured(bp->dev))
+               bnxt_set_dflt_rss_indir_tbl(bp);
+
        return rc;
 }
 
@@ -7788,7 +7818,7 @@ static int bnxt_set_tpa(struct bnxt *bp, bool set_tpa)
 
        if (set_tpa)
                tpa_flags = bp->flags & BNXT_FLAG_TPA;
-       else if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
+       else if (BNXT_NO_FW_ACCESS(bp))
                return 0;
        for (i = 0; i < bp->nr_vnics; i++) {
                rc = bnxt_hwrm_vnic_set_tpa(bp, i, tpa_flags);
@@ -8495,9 +8525,6 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
                        rc = bnxt_init_int_mode(bp);
                bnxt_ulp_irq_restart(bp, rc);
        }
-       if (!netif_is_rxfh_configured(bp->dev))
-               bnxt_set_dflt_rss_indir_tbl(bp);
-
        if (rc) {
                netdev_err(bp->dev, "ring reservation/IRQ init failure rc: %d\n", rc);
                return rc;
@@ -9284,16 +9311,17 @@ static ssize_t bnxt_show_temp(struct device *dev,
        struct hwrm_temp_monitor_query_input req = {0};
        struct hwrm_temp_monitor_query_output *resp;
        struct bnxt *bp = dev_get_drvdata(dev);
-       u32 temp = 0;
+       u32 len = 0;
+       int rc;
 
        resp = bp->hwrm_cmd_resp_addr;
        bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_TEMP_MONITOR_QUERY, -1, -1);
        mutex_lock(&bp->hwrm_cmd_lock);
-       if (!_hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT))
-               temp = resp->temp * 1000; /* display millidegree */
+       rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (!rc)
+               len = sprintf(buf, "%u\n", resp->temp * 1000); /* display millidegree */
        mutex_unlock(&bp->hwrm_cmd_lock);
-
-       return sprintf(buf, "%u\n", temp);
+       return rc ?: len;
 }
 static SENSOR_DEVICE_ATTR(temp1_input, 0444, bnxt_show_temp, NULL, 0);
 
@@ -9313,7 +9341,16 @@ static void bnxt_hwmon_close(struct bnxt *bp)
 
 static void bnxt_hwmon_open(struct bnxt *bp)
 {
+       struct hwrm_temp_monitor_query_input req = {0};
        struct pci_dev *pdev = bp->pdev;
+       int rc;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_TEMP_MONITOR_QUERY, -1, -1);
+       rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (rc == -EACCES || rc == -EOPNOTSUPP) {
+               bnxt_hwmon_close(bp);
+               return;
+       }
 
        if (bp->hwmon_dev)
                return;
@@ -9475,15 +9512,15 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
                }
        }
 
-       bnxt_enable_napi(bp);
-       bnxt_debug_dev_init(bp);
-
        rc = bnxt_init_nic(bp, irq_re_init);
        if (rc) {
                netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc);
-               goto open_err;
+               goto open_err_irq;
        }
 
+       bnxt_enable_napi(bp);
+       bnxt_debug_dev_init(bp);
+
        if (link_re_init) {
                mutex_lock(&bp->link_lock);
                rc = bnxt_update_phy_setting(bp);
@@ -9514,10 +9551,6 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
                bnxt_vf_reps_open(bp);
        return 0;
 
-open_err:
-       bnxt_debug_dev_exit(bp);
-       bnxt_disable_napi(bp);
-
 open_err_irq:
        bnxt_del_napi(bp);
 
@@ -9765,7 +9798,7 @@ static int bnxt_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCGMIIPHY:
                mdio->phy_id = bp->link_info.phy_addr;
 
-               /* fallthru */
+               fallthrough;
        case SIOCGMIIREG: {
                u16 mii_regval = 0;
 
@@ -11022,7 +11055,7 @@ static void bnxt_fw_reset_writel(struct bnxt *bp, int reg_idx)
                writel(reg_off & BNXT_GRC_BASE_MASK,
                       bp->bar0 + BNXT_GRCPF_REG_WINDOW_BASE_OUT + 4);
                reg_off = (reg_off & BNXT_GRC_OFFSET_MASK) + 0x2000;
-               /* fall through */
+               fallthrough;
        case BNXT_FW_HEALTH_REG_TYPE_BAR0:
                writel(val, bp->bar0 + reg_off);
                break;
@@ -11135,7 +11168,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
                }
                bp->fw_reset_state = BNXT_FW_RESET_STATE_RESET_FW;
        }
-       /* fall through */
+               fallthrough;
        case BNXT_FW_RESET_STATE_RESET_FW:
                bnxt_reset_all(bp);
                bp->fw_reset_state = BNXT_FW_RESET_STATE_ENABLE_DEV;
@@ -11158,7 +11191,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
                }
                pci_set_master(bp->pdev);
                bp->fw_reset_state = BNXT_FW_RESET_STATE_POLL_FW;
-               /* fall through */
+               fallthrough;
        case BNXT_FW_RESET_STATE_POLL_FW:
                bp->hwrm_cmd_timeout = SHORT_HWRM_CMD_TIMEOUT;
                rc = __bnxt_hwrm_ver_get(bp, true);
@@ -11173,7 +11206,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
                }
                bp->hwrm_cmd_timeout = DFLT_HWRM_CMD_TIMEOUT;
                bp->fw_reset_state = BNXT_FW_RESET_STATE_OPENING;
-               /* fall through */
+               fallthrough;
        case BNXT_FW_RESET_STATE_OPENING:
                while (!rtnl_trylock()) {
                        bnxt_queue_fw_reset_work(bp, HZ / 10);
@@ -11754,6 +11787,10 @@ static void bnxt_remove_one(struct pci_dev *pdev)
        if (BNXT_PF(bp))
                bnxt_sriov_disable(bp);
 
+       clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
+       bnxt_cancel_sp_work(bp);
+       bp->sp_event = 0;
+
        bnxt_dl_fw_reporters_destroy(bp, true);
        if (BNXT_PF(bp))
                devlink_port_type_clear(&bp->dl_port);
@@ -11761,8 +11798,6 @@ static void bnxt_remove_one(struct pci_dev *pdev)
        unregister_netdev(dev);
        bnxt_dl_unregister(bp);
        bnxt_shutdown_tc(bp);
-       bnxt_cancel_sp_work(bp);
-       bp->sp_event = 0;
 
        bnxt_clear_int_mode(bp);
        bnxt_hwrm_func_drv_unrgtr(bp);
@@ -12063,7 +12098,7 @@ static int bnxt_init_mac_addr(struct bnxt *bp)
 static void bnxt_vpd_read_info(struct bnxt *bp)
 {
        struct pci_dev *pdev = bp->pdev;
-       int i, len, pos, ro_size;
+       int i, len, pos, ro_size, size;
        ssize_t vpd_size;
        u8 *vpd_data;
 
@@ -12098,7 +12133,8 @@ static void bnxt_vpd_read_info(struct bnxt *bp)
        if (len + pos > vpd_size)
                goto read_sn;
 
-       strlcpy(bp->board_partno, &vpd_data[pos], min(len, BNXT_VPD_FLD_LEN));
+       size = min(len, BNXT_VPD_FLD_LEN - 1);
+       memcpy(bp->board_partno, &vpd_data[pos], size);
 
 read_sn:
        pos = pci_vpd_find_info_keyword(vpd_data, i, ro_size,
@@ -12111,7 +12147,8 @@ read_sn:
        if (len + pos > vpd_size)
                goto exit;
 
-       strlcpy(bp->board_serialno, &vpd_data[pos], min(len, BNXT_VPD_FLD_LEN));
+       size = min(len, BNXT_VPD_FLD_LEN - 1);
+       memcpy(bp->board_serialno, &vpd_data[pos], size);
 exit:
        kfree(vpd_data);
 }
@@ -12200,6 +12237,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (BNXT_CHIP_P5(bp))
                bp->flags |= BNXT_FLAG_CHIP_P5;
 
+       rc = bnxt_alloc_rss_indir_tbl(bp);
+       if (rc)
+               goto init_err_pci_clean;
+
        rc = bnxt_fw_init_one_p2(bp);
        if (rc)
                goto init_err_pci_clean;
@@ -12304,11 +12345,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
         */
        bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
 
-       rc = bnxt_alloc_rss_indir_tbl(bp);
-       if (rc)
-               goto init_err_pci_clean;
-       bnxt_set_dflt_rss_indir_tbl(bp);
-
        if (BNXT_PF(bp)) {
                if (!bnxt_pf_wq) {
                        bnxt_pf_wq =
@@ -12339,6 +12375,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                    (long)pci_resource_start(pdev, 0), dev->dev_addr);
        pcie_print_link_status(pdev);
 
+       pci_save_state(pdev);
        return 0;
 
 init_err_cleanup:
@@ -12536,6 +12573,8 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev)
                        "Cannot re-enable PCI device after reset.\n");
        } else {
                pci_set_master(pdev);
+               pci_restore_state(pdev);
+               pci_save_state(pdev);
 
                err = bnxt_hwrm_func_reset(bp);
                if (!err) {
index 5a13eb6..0ef89da 100644 (file)
@@ -1737,6 +1737,10 @@ struct bnxt {
 #define BNXT_STATE_FW_FATAL_COND       6
 #define BNXT_STATE_DRV_REGISTERED      7
 
+#define BNXT_NO_FW_ACCESS(bp)                                  \
+       (test_bit(BNXT_STATE_FW_FATAL_COND, &(bp)->state) ||    \
+        pci_channel_offline((bp)->pdev))
+
        struct bnxt_irq *irq_tbl;
        int                     total_irqs;
        u8                      mac_addr[ETH_ALEN];
index 64da654..fecdfd8 100644 (file)
@@ -472,20 +472,13 @@ static int bnxt_get_num_tpa_ring_stats(struct bnxt *bp)
 static int bnxt_get_num_ring_stats(struct bnxt *bp)
 {
        int rx, tx, cmn;
-       bool sh = false;
-
-       if (bp->flags & BNXT_FLAG_SHARED_RINGS)
-               sh = true;
 
        rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS +
             bnxt_get_num_tpa_ring_stats(bp);
        tx = NUM_RING_TX_HW_STATS;
        cmn = NUM_RING_CMN_SW_STATS;
-       if (sh)
-               return (rx + tx + cmn) * bp->cp_nr_rings;
-       else
-               return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings +
-                      cmn * bp->cp_nr_rings;
+       return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings +
+              cmn * bp->cp_nr_rings;
 }
 
 static int bnxt_get_num_stats(struct bnxt *bp)
@@ -806,7 +799,7 @@ static void bnxt_get_channels(struct net_device *dev,
        int max_tx_sch_inputs;
 
        /* Get the most up-to-date max_tx_sch_inputs. */
-       if (BNXT_NEW_RM(bp))
+       if (netif_running(dev) && BNXT_NEW_RM(bp))
                bnxt_hwrm_func_resc_qcaps(bp, false);
        max_tx_sch_inputs = hw_resc->max_tx_sch_inputs;
 
@@ -1073,7 +1066,7 @@ static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
                if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4)
                        cmd->data |= RXH_IP_SRC | RXH_IP_DST |
                                     RXH_L4_B_0_1 | RXH_L4_B_2_3;
-               /* fall through */
+               fallthrough;
        case SCTP_V4_FLOW:
        case AH_ESP_V4_FLOW:
        case AH_V4_FLOW:
@@ -1092,7 +1085,7 @@ static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
                if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6)
                        cmd->data |= RXH_IP_SRC | RXH_IP_DST |
                                     RXH_L4_B_0_1 | RXH_L4_B_2_3;
-               /* fall through */
+               fallthrough;
        case SCTP_V6_FLOW:
        case AH_ESP_V6_FLOW:
        case AH_V6_FLOW:
@@ -1329,6 +1322,9 @@ static int bnxt_get_regs_len(struct net_device *dev)
        struct bnxt *bp = netdev_priv(dev);
        int reg_len;
 
+       if (!BNXT_PF(bp))
+               return -EOPNOTSUPP;
+
        reg_len = BNXT_PXP_REG_LEN;
 
        if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)
@@ -1795,9 +1791,12 @@ static int bnxt_set_pauseparam(struct net_device *dev,
        if (!BNXT_PHY_CFG_ABLE(bp))
                return -EOPNOTSUPP;
 
+       mutex_lock(&bp->link_lock);
        if (epause->autoneg) {
-               if (!(link_info->autoneg & BNXT_AUTONEG_SPEED))
-                       return -EINVAL;
+               if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
+                       rc = -EINVAL;
+                       goto pause_exit;
+               }
 
                link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
                if (bp->hwrm_spec_code >= 0x10201)
@@ -1818,11 +1817,11 @@ static int bnxt_set_pauseparam(struct net_device *dev,
        if (epause->tx_pause)
                link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX;
 
-       if (netif_running(dev)) {
-               mutex_lock(&bp->link_lock);
+       if (netif_running(dev))
                rc = bnxt_hwrm_set_pause(bp);
-               mutex_unlock(&bp->link_lock);
-       }
+
+pause_exit:
+       mutex_unlock(&bp->link_lock);
        return rc;
 }
 
@@ -2323,6 +2322,9 @@ static int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data)
        if (rc != 0)
                return rc;
 
+       if (!dir_entries || !entry_length)
+               return -EIO;
+
        /* Insert 2 bytes of directory info (count and size of entries) */
        if (len < 2)
                return -EINVAL;
@@ -2556,8 +2558,7 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
        struct bnxt *bp = netdev_priv(dev);
        struct ethtool_eee *eee = &bp->eee;
        struct bnxt_link_info *link_info = &bp->link_info;
-       u32 advertising =
-                _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
+       u32 advertising;
        int rc = 0;
 
        if (!BNXT_PHY_CFG_ABLE(bp))
@@ -2566,19 +2567,23 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
        if (!(bp->flags & BNXT_FLAG_EEE_CAP))
                return -EOPNOTSUPP;
 
+       mutex_lock(&bp->link_lock);
+       advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
        if (!edata->eee_enabled)
                goto eee_ok;
 
        if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
                netdev_warn(dev, "EEE requires autoneg\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto eee_exit;
        }
        if (edata->tx_lpi_enabled) {
                if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi ||
                                       edata->tx_lpi_timer < bp->lpi_tmr_lo)) {
                        netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n",
                                    bp->lpi_tmr_lo, bp->lpi_tmr_hi);
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto eee_exit;
                } else if (!bp->lpi_tmr_hi) {
                        edata->tx_lpi_timer = eee->tx_lpi_timer;
                }
@@ -2588,7 +2593,8 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
        } else if (edata->advertised & ~advertising) {
                netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n",
                            edata->advertised, advertising);
-               return -EINVAL;
+               rc = -EINVAL;
+               goto eee_exit;
        }
 
        eee->advertised = edata->advertised;
@@ -2600,6 +2606,8 @@ eee_ok:
        if (netif_running(dev))
                rc = bnxt_hwrm_set_link_setting(bp, false, true);
 
+eee_exit:
+       mutex_unlock(&bp->link_lock);
        return rc;
 }
 
index 2704a47..fcc2620 100644 (file)
@@ -201,10 +201,10 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
                break;
        default:
                bpf_warn_invalid_xdp_action(act);
-               /* Fall thru */
+               fallthrough;
        case XDP_ABORTED:
                trace_xdp_exception(bp->dev, xdp_prog, act);
-               /* Fall thru */
+               fallthrough;
        case XDP_DROP:
                bnxt_reuse_rx_data(rxr, cons, page);
                break;
index c5cca63..8453629 100644 (file)
@@ -3311,7 +3311,7 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info)
        }
        case CNIC_CTL_FCOE_STATS_GET_CMD:
                ulp_type = CNIC_ULP_FCOE;
-               /* fall through */
+               fallthrough;
        case CNIC_CTL_ISCSI_STATS_GET_CMD:
                cnic_hold(dev);
                cnic_copy_ulp_stats(dev, ulp_type);
@@ -4044,7 +4044,7 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
                            l4kcqe->status, l5kcqe->completion_status);
                opcode = L4_KCQE_OPCODE_VALUE_CLOSE_COMP;
        }
-               /* Fall through */
+               fallthrough;
        case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
        case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
        case L4_KCQE_OPCODE_VALUE_RESET_COMP:
index 1fecc25..be85dad 100644 (file)
@@ -1185,10 +1185,10 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
                        continue;
                case BCMGENET_STAT_RUNT:
                        offset += BCMGENET_STAT_OFFSET;
-                       /* fall through */
+                       fallthrough;
                case BCMGENET_STAT_MIB_TX:
                        offset += BCMGENET_STAT_OFFSET;
-                       /* fall through */
+                       fallthrough;
                case BCMGENET_STAT_MIB_RX:
                        val = bcmgenet_umac_readl(priv,
                                                  UMAC_MIB_START + j + offset);
@@ -1364,7 +1364,7 @@ static int bcmgenet_validate_flow(struct net_device *dev,
        case ETHER_FLOW:
                eth_mask = &cmd->fs.m_u.ether_spec;
                /* don't allow mask which isn't valid */
-               if (VALIDATE_MASK(eth_mask->h_source) ||
+               if (VALIDATE_MASK(eth_mask->h_dest) ||
                    VALIDATE_MASK(eth_mask->h_source) ||
                    VALIDATE_MASK(eth_mask->h_proto)) {
                        netdev_err(dev, "rxnfc: Unsupported mask\n");
index 511d553..6fb6c35 100644 (file)
@@ -192,7 +192,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
        switch (priv->phy_interface) {
        case PHY_INTERFACE_MODE_INTERNAL:
                phy_name = "internal PHY";
-               /* fall through */
+               fallthrough;
        case PHY_INTERFACE_MODE_MOCA:
                /* Irrespective of the actually configured PHY speed (100 or
                 * 1000) GENETv4 only has an internal GPHY so we will just end
index ebff1fc..5143cdd 100644 (file)
@@ -715,7 +715,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
        case TG3_APE_LOCK_GPIO:
                if (tg3_asic_rev(tp) == ASIC_REV_5761)
                        return 0;
-               /* fall through */
+               fallthrough;
        case TG3_APE_LOCK_GRC:
        case TG3_APE_LOCK_MEM:
                if (!tp->pci_fn)
@@ -776,7 +776,7 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
        case TG3_APE_LOCK_GPIO:
                if (tg3_asic_rev(tp) == ASIC_REV_5761)
                        return;
-               /* fall through */
+               fallthrough;
        case TG3_APE_LOCK_GRC:
        case TG3_APE_LOCK_MEM:
                if (!tp->pci_fn)
@@ -1586,7 +1586,7 @@ static int tg3_mdio_init(struct tg3 *tp)
                        phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE;
                if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN))
                        phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE;
-               /* fall through */
+               fallthrough;
        case PHY_ID_RTL8211C:
                phydev->interface = PHY_INTERFACE_MODE_RGMII;
                break;
@@ -2114,7 +2114,7 @@ static int tg3_phy_init(struct tg3 *tp)
                        phy_support_asym_pause(phydev);
                        break;
                }
-               /* fall through */
+               fallthrough;
        case PHY_INTERFACE_MODE_MII:
                phy_set_max_speed(phydev, SPEED_100);
                phy_support_asym_pause(phydev);
@@ -4390,7 +4390,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
                                      MII_TG3_DSP_TAP26_RMRXSTO |
                                      MII_TG3_DSP_TAP26_OPCSINPT;
                        tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val);
-                       /* Fall through */
+                       fallthrough;
                case ASIC_REV_5720:
                case ASIC_REV_5762:
                        if (!tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val))
@@ -4538,7 +4538,7 @@ static int tg3_phy_pull_config(struct tg3 *tp)
                                tp->link_config.speed = SPEED_1000;
                                break;
                        }
-                       /* Fall through */
+                       fallthrough;
                default:
                        goto done;
                }
@@ -5209,7 +5209,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
                if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN))
                        ap->state = ANEG_STATE_AN_ENABLE;
 
-               /* fall through */
+               fallthrough;
        case ANEG_STATE_AN_ENABLE:
                ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX);
                if (ap->flags & MR_AN_ENABLE) {
@@ -5239,7 +5239,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
                ret = ANEG_TIMER_ENAB;
                ap->state = ANEG_STATE_RESTART;
 
-               /* fall through */
+               fallthrough;
        case ANEG_STATE_RESTART:
                delta = ap->cur_time - ap->link_time;
                if (delta > ANEG_STATE_SETTLE_TIME)
@@ -5282,7 +5282,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
 
                ap->state = ANEG_STATE_ACK_DETECT;
 
-               /* fall through */
+               fallthrough;
        case ANEG_STATE_ACK_DETECT:
                if (ap->ack_match != 0) {
                        if ((ap->rxconfig & ~ANEG_CFG_ACK) ==
@@ -7221,8 +7221,8 @@ static inline void tg3_reset_task_schedule(struct tg3 *tp)
 
 static inline void tg3_reset_task_cancel(struct tg3 *tp)
 {
-       cancel_work_sync(&tp->reset_task);
-       tg3_flag_clear(tp, RESET_TASK_PENDING);
+       if (test_and_clear_bit(TG3_FLAG_RESET_TASK_PENDING, tp->tg3_flags))
+               cancel_work_sync(&tp->reset_task);
        tg3_flag_clear(tp, TX_RECOVERY_PENDING);
 }
 
@@ -10720,40 +10720,40 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
        switch (limit) {
        case 16:
                tw32(MAC_RCV_RULE_15,  0); tw32(MAC_RCV_VALUE_15,  0);
-               /* fall through */
+               fallthrough;
        case 15:
                tw32(MAC_RCV_RULE_14,  0); tw32(MAC_RCV_VALUE_14,  0);
-               /* fall through */
+               fallthrough;
        case 14:
                tw32(MAC_RCV_RULE_13,  0); tw32(MAC_RCV_VALUE_13,  0);
-               /* fall through */
+               fallthrough;
        case 13:
                tw32(MAC_RCV_RULE_12,  0); tw32(MAC_RCV_VALUE_12,  0);
-               /* fall through */
+               fallthrough;
        case 12:
                tw32(MAC_RCV_RULE_11,  0); tw32(MAC_RCV_VALUE_11,  0);
-               /* fall through */
+               fallthrough;
        case 11:
                tw32(MAC_RCV_RULE_10,  0); tw32(MAC_RCV_VALUE_10,  0);
-               /* fall through */
+               fallthrough;
        case 10:
                tw32(MAC_RCV_RULE_9,  0); tw32(MAC_RCV_VALUE_9,  0);
-               /* fall through */
+               fallthrough;
        case 9:
                tw32(MAC_RCV_RULE_8,  0); tw32(MAC_RCV_VALUE_8,  0);
-               /* fall through */
+               fallthrough;
        case 8:
                tw32(MAC_RCV_RULE_7,  0); tw32(MAC_RCV_VALUE_7,  0);
-               /* fall through */
+               fallthrough;
        case 7:
                tw32(MAC_RCV_RULE_6,  0); tw32(MAC_RCV_VALUE_6,  0);
-               /* fall through */
+               fallthrough;
        case 6:
                tw32(MAC_RCV_RULE_5,  0); tw32(MAC_RCV_VALUE_5,  0);
-               /* fall through */
+               fallthrough;
        case 5:
                tw32(MAC_RCV_RULE_4,  0); tw32(MAC_RCV_VALUE_4,  0);
-               /* fall through */
+               fallthrough;
        case 4:
                /* tw32(MAC_RCV_RULE_3,  0); tw32(MAC_RCV_VALUE_3,  0); */
        case 3:
@@ -11209,18 +11209,27 @@ static void tg3_reset_task(struct work_struct *work)
 
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
        err = tg3_init_hw(tp, true);
-       if (err)
+       if (err) {
+               tg3_full_unlock(tp);
+               tp->irq_sync = 0;
+               tg3_napi_enable(tp);
+               /* Clear this flag so that tg3_reset_task_cancel() will not
+                * call cancel_work_sync() and wait forever.
+                */
+               tg3_flag_clear(tp, RESET_TASK_PENDING);
+               dev_close(tp->dev);
                goto out;
+       }
 
        tg3_netif_start(tp);
 
-out:
        tg3_full_unlock(tp);
 
        if (!err)
                tg3_phy_start(tp);
 
        tg3_flag_clear(tp, RESET_TASK_PENDING);
+out:
        rtnl_unlock();
 }
 
@@ -13998,7 +14007,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCGMIIPHY:
                data->phy_id = tp->phy_addr;
 
-               /* fall through */
+               fallthrough;
        case SIOCGMIIREG: {
                u32 mii_regval;
 
@@ -17136,7 +17145,7 @@ static u32 tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
                                val |= DMA_RWCTRL_WRITE_BNDRY_64_PCIE;
                                break;
                        }
-                       /* fallthrough */
+                       fallthrough;
                case 128:
                default:
                        val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
@@ -17151,28 +17160,28 @@ static u32 tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
                                        DMA_RWCTRL_WRITE_BNDRY_16);
                                break;
                        }
-                       /* fallthrough */
+                       fallthrough;
                case 32:
                        if (goal == BOUNDARY_SINGLE_CACHELINE) {
                                val |= (DMA_RWCTRL_READ_BNDRY_32 |
                                        DMA_RWCTRL_WRITE_BNDRY_32);
                                break;
                        }
-                       /* fallthrough */
+                       fallthrough;
                case 64:
                        if (goal == BOUNDARY_SINGLE_CACHELINE) {
                                val |= (DMA_RWCTRL_READ_BNDRY_64 |
                                        DMA_RWCTRL_WRITE_BNDRY_64);
                                break;
                        }
-                       /* fallthrough */
+                       fallthrough;
                case 128:
                        if (goal == BOUNDARY_SINGLE_CACHELINE) {
                                val |= (DMA_RWCTRL_READ_BNDRY_128 |
                                        DMA_RWCTRL_WRITE_BNDRY_128);
                                break;
                        }
-                       /* fallthrough */
+                       fallthrough;
                case 256:
                        val |= (DMA_RWCTRL_READ_BNDRY_256 |
                                DMA_RWCTRL_WRITE_BNDRY_256);
index 49358d4..b9dd06b 100644 (file)
@@ -321,7 +321,7 @@ bfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
        case IOC_E_PFFAILED:
        case IOC_E_HWERROR:
                del_timer(&ioc->ioc_timer);
-               /* fall through */
+               fallthrough;
        case IOC_E_TIMEOUT:
                ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
                bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
@@ -780,7 +780,7 @@ bfa_iocpf_sm_enabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
 
        case IOCPF_E_INITFAIL:
                del_timer(&ioc->iocpf_timer);
-               /* fall through */
+               fallthrough;
 
        case IOCPF_E_TIMEOUT:
                bfa_nw_ioc_hw_sem_release(ioc);
@@ -849,7 +849,7 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
 
        case IOCPF_E_FAIL:
                del_timer(&ioc->iocpf_timer);
-               /* fall through*/
+               fallthrough;
 
        case IOCPF_E_TIMEOUT:
                bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
index 40107a9..a2c983f 100644 (file)
@@ -1084,7 +1084,7 @@ bna_enet_sm_cfg_wait(struct bna_enet *enet,
 
        case ENET_E_CHLD_STOPPED:
                bna_enet_rx_start(enet);
-               /* Fall through */
+               fallthrough;
        case ENET_E_FWRESP_PAUSE:
                if (enet->flags & BNA_ENET_F_PAUSE_CHANGED) {
                        enet->flags &= ~BNA_ENET_F_PAUSE_CHANGED;
index b5ecbfe..2623a0d 100644 (file)
@@ -1636,7 +1636,7 @@ bna_bfi_rx_enet_start(struct bna_rx *rx)
                                                &q1->qpt);
                        cfg_req->q_cfg[i].qs.rx_buffer_size =
                                htons((u16)q1->buffer_size);
-                       /* Fall through */
+                       fallthrough;
 
                case BNA_RXP_SINGLE:
                        /* Large/Single RxQ */
index 6761f40..9179f7b 100644 (file)
@@ -647,8 +647,7 @@ static void macb_mac_link_up(struct phylink_config *config,
                                ctrl |= GEM_BIT(GBE);
                }
 
-               /* We do not support MLO_PAUSE_RX yet */
-               if (tx_pause)
+               if (rx_pause)
                        ctrl |= MACB_BIT(PAE);
 
                macb_set_tx_clk(bp->tx_clk, speed, ndev);
index 31ebf3e..283918a 100644 (file)
@@ -460,7 +460,7 @@ int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd)
        case HWTSTAMP_TX_ONESTEP_SYNC:
                if (gem_ptp_set_one_step_sync(bp, 1) != 0)
                        return -ERANGE;
-               /* fall through */
+               fallthrough;
        case HWTSTAMP_TX_ON:
                tx_bd_control = TSTAMP_ALL_FRAMES;
                break;
index e73bc21..8e0ed01 100644 (file)
@@ -977,15 +977,14 @@ static void octeon_destroy_resources(struct octeon_device *oct)
 
                schedule_timeout_uninterruptible(HZ / 10);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_HOST_OK:
 
-               /* fallthrough */
        case OCT_DEV_CONSOLE_INIT_DONE:
                /* Remove any consoles */
                octeon_remove_consoles(oct);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_IO_QUEUES_DONE:
                if (lio_wait_for_instr_fetch(oct))
                        dev_err(&oct->pci_dev->dev, "IQ had pending instructions\n");
@@ -1027,7 +1026,7 @@ static void octeon_destroy_resources(struct octeon_device *oct)
                octeon_free_sc_done_list(oct);
                octeon_free_sc_zombie_list(oct);
 
-       /* fallthrough */
+               fallthrough;
        case OCT_DEV_INTR_SET_DONE:
                /* Disable interrupts  */
                oct->fn_list.disable_interrupt(oct, OCTEON_ALL_INTR);
@@ -1062,17 +1061,17 @@ static void octeon_destroy_resources(struct octeon_device *oct)
                kfree(oct->irq_name_storage);
                oct->irq_name_storage = NULL;
 
-       /* fallthrough */
+               fallthrough;
        case OCT_DEV_MSIX_ALLOC_VECTOR_DONE:
                if (OCTEON_CN23XX_PF(oct))
                        octeon_free_ioq_vector(oct);
 
-       /* fallthrough */
+               fallthrough;
        case OCT_DEV_MBOX_SETUP_DONE:
                if (OCTEON_CN23XX_PF(oct))
                        oct->fn_list.free_mbox(oct);
 
-       /* fallthrough */
+               fallthrough;
        case OCT_DEV_IN_RESET:
        case OCT_DEV_DROQ_INIT_DONE:
                /* Wait for any pending operations */
@@ -1095,11 +1094,11 @@ static void octeon_destroy_resources(struct octeon_device *oct)
                        }
                }
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_RESP_LIST_INIT_DONE:
                octeon_delete_response_list(oct);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_INSTR_QUEUE_INIT_DONE:
                for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
                        if (!(oct->io_qmask.iq & BIT_ULL(i)))
@@ -1110,16 +1109,16 @@ static void octeon_destroy_resources(struct octeon_device *oct)
                if (oct->sriov_info.sriov_enabled)
                        pci_disable_sriov(oct->pci_dev);
 #endif
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_SC_BUFF_POOL_INIT_DONE:
                octeon_free_sc_buffer_pool(oct);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_DISPATCH_INIT_DONE:
                octeon_delete_dispatch_list(oct);
                cancel_delayed_work_sync(&oct->nic_poll_work.work);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_PCI_MAP_DONE:
                refcount = octeon_deregister_device(oct);
 
@@ -1137,13 +1136,13 @@ static void octeon_destroy_resources(struct octeon_device *oct)
                octeon_unmap_pci_barx(oct, 0);
                octeon_unmap_pci_barx(oct, 1);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_PCI_ENABLE_DONE:
                pci_clear_master(oct->pci_dev);
                /* Disable the device, releasing the PCI INT */
                pci_disable_device(oct->pci_dev);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_BEGIN_STATE:
                /* Nothing to be done here either */
                break;
@@ -2168,7 +2167,7 @@ static int liquidio_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
        case SIOCSHWTSTAMP:
                if (lio->oct_dev->ptp_enable)
                        return hwtstamp_ioctl(netdev, ifr);
-               /* fall through */
+               fallthrough;
        default:
                return -EOPNOTSUPP;
        }
index 90ef210..8c5879e 100644 (file)
@@ -460,9 +460,8 @@ static void octeon_destroy_resources(struct octeon_device *oct)
 
                schedule_timeout_uninterruptible(HZ / 10);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_HOST_OK:
-               /* fallthrough */
        case OCT_DEV_IO_QUEUES_DONE:
                if (lio_wait_for_instr_fetch(oct))
                        dev_err(&oct->pci_dev->dev, "IQ had pending instructions\n");
@@ -504,7 +503,7 @@ static void octeon_destroy_resources(struct octeon_device *oct)
                octeon_free_sc_done_list(oct);
                octeon_free_sc_zombie_list(oct);
 
-       /* fall through */
+               fallthrough;
        case OCT_DEV_INTR_SET_DONE:
                /* Disable interrupts  */
                oct->fn_list.disable_interrupt(oct, OCTEON_ALL_INTR);
@@ -533,15 +532,15 @@ static void octeon_destroy_resources(struct octeon_device *oct)
                else
                        cn23xx_vf_ask_pf_to_do_flr(oct);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_MSIX_ALLOC_VECTOR_DONE:
                octeon_free_ioq_vector(oct);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_MBOX_SETUP_DONE:
                oct->fn_list.free_mbox(oct);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_IN_RESET:
        case OCT_DEV_DROQ_INIT_DONE:
                mdelay(100);
@@ -551,11 +550,11 @@ static void octeon_destroy_resources(struct octeon_device *oct)
                        octeon_delete_droq(oct, i);
                }
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_RESP_LIST_INIT_DONE:
                octeon_delete_response_list(oct);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_INSTR_QUEUE_INIT_DONE:
                for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
                        if (!(oct->io_qmask.iq & BIT_ULL(i)))
@@ -563,27 +562,27 @@ static void octeon_destroy_resources(struct octeon_device *oct)
                        octeon_delete_instr_queue(oct, i);
                }
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_SC_BUFF_POOL_INIT_DONE:
                octeon_free_sc_buffer_pool(oct);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_DISPATCH_INIT_DONE:
                octeon_delete_dispatch_list(oct);
                cancel_delayed_work_sync(&oct->nic_poll_work.work);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_PCI_MAP_DONE:
                octeon_unmap_pci_barx(oct, 0);
                octeon_unmap_pci_barx(oct, 1);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_PCI_ENABLE_DONE:
                pci_clear_master(oct->pci_dev);
                /* Disable the device, releasing the PCI INT */
                pci_disable_device(oct->pci_dev);
 
-               /* fallthrough */
+               fallthrough;
        case OCT_DEV_BEGIN_STATE:
                /* Nothing to be done here either */
                break;
index 3e17ce0..6cb2162 100644 (file)
@@ -1219,7 +1219,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
         */
        if (netdev->phydev) {
                netif_carrier_off(netdev);
-               phy_start_aneg(netdev->phydev);
+               phy_start(netdev->phydev);
        }
 
        netif_wake_queue(netdev);
@@ -1247,8 +1247,10 @@ static int octeon_mgmt_stop(struct net_device *netdev)
        napi_disable(&p->napi);
        netif_stop_queue(netdev);
 
-       if (netdev->phydev)
+       if (netdev->phydev) {
+               phy_stop(netdev->phydev);
                phy_disconnect(netdev->phydev);
+       }
 
        netif_carrier_off(netdev);
 
index 83dabcf..c7bdac7 100644 (file)
@@ -522,7 +522,7 @@ static int nicvf_get_rss_hash_opts(struct nicvf *nic,
        case SCTP_V4_FLOW:
        case SCTP_V6_FLOW:
                info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
-               /* Fall through */
+               fallthrough;
        case IPV4_FLOW:
        case IPV6_FLOW:
                info->data |= RXH_IP_SRC | RXH_IP_DST;
index c1378b5..063e560 100644 (file)
@@ -594,10 +594,10 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
                return true;
        default:
                bpf_warn_invalid_xdp_action(action);
-               /* fall through */
+               fallthrough;
        case XDP_ABORTED:
                trace_xdp_exception(nic->netdev, prog, action);
-               /* fall through */
+               fallthrough;
        case XDP_DROP:
                /* Check if it's a recycled page, if not
                 * unmap the DMA mapping.
index 42c6e93..387c357 100644 (file)
@@ -2543,7 +2543,7 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
                    !(data->phy_id & 0xe0e0))
                        data->phy_id = mdio_phy_id_c45(data->phy_id >> 8,
                                                       data->phy_id & 0x1f);
-               /* FALLTHRU */
+               fallthrough;
        case SIOCGMIIPHY:
                return mdio_mii_ioctl(&pi->phy.mdio, data, cmd);
        case SIOCCHIOCTL:
index b3e4118..9749d12 100644 (file)
@@ -136,7 +136,7 @@ again:
                if (e->state == L2T_STATE_STALE)
                        e->state = L2T_STATE_VALID;
                spin_unlock_bh(&e->lock);
-               /* fall through */
+               fallthrough;
        case L2T_STATE_VALID:   /* fast-path, send the packet on */
                return cxgb3_ofld_send(dev, skb);
        case L2T_STATE_RESOLVING:
index 650db92..4814985 100644 (file)
@@ -1911,13 +1911,16 @@ out:
 static int configure_filter_tcb(struct adapter *adap, unsigned int tid,
                                struct filter_entry *f)
 {
-       if (f->fs.hitcnts)
+       if (f->fs.hitcnts) {
                set_tcb_field(adap, f, tid, TCB_TIMESTAMP_W,
-                             TCB_TIMESTAMP_V(TCB_TIMESTAMP_M) |
+                             TCB_TIMESTAMP_V(TCB_TIMESTAMP_M),
+                             TCB_TIMESTAMP_V(0ULL),
+                             1);
+               set_tcb_field(adap, f, tid, TCB_RTT_TS_RECENT_AGE_W,
                              TCB_RTT_TS_RECENT_AGE_V(TCB_RTT_TS_RECENT_AGE_M),
-                             TCB_TIMESTAMP_V(0ULL) |
                              TCB_RTT_TS_RECENT_AGE_V(0ULL),
                              1);
+       }
 
        if (f->fs.newdmac)
                set_tcb_tflag(adap, f, tid, TF_CCTRL_ECE_S, 1,
index b1a073e..a020e84 100644 (file)
@@ -229,7 +229,7 @@ void cxgb4_free_mps_ref_entries(struct adapter *adap)
 {
        struct mps_entries_ref *mps_entry, *tmp;
 
-       if (!list_empty(&adap->mps_ref))
+       if (list_empty(&adap->mps_ref))
                return;
 
        spin_lock(&adap->mps_ref_lock);
index e3510e9..9a6d652 100644 (file)
@@ -62,6 +62,7 @@ static struct thermal_zone_device_ops cxgb4_thermal_ops = {
 int cxgb4_thermal_init(struct adapter *adap)
 {
        struct ch_thermal *ch_thermal = &adap->ch_thermal;
+       char ch_tz_name[THERMAL_NAME_LENGTH];
        int num_trip = CXGB4_NUM_TRIPS;
        u32 param, val;
        int ret;
@@ -82,7 +83,8 @@ int cxgb4_thermal_init(struct adapter *adap)
                ch_thermal->trip_type = THERMAL_TRIP_CRITICAL;
        }
 
-       ch_thermal->tzdev = thermal_zone_device_register("cxgb4", num_trip,
+       snprintf(ch_tz_name, sizeof(ch_tz_name), "cxgb4_%s", adap->name);
+       ch_thermal->tzdev = thermal_zone_device_register(ch_tz_name, num_trip,
                                                         0, adap,
                                                         &cxgb4_thermal_ops,
                                                         NULL, 0, 0);
@@ -105,7 +107,9 @@ int cxgb4_thermal_init(struct adapter *adap)
 
 int cxgb4_thermal_remove(struct adapter *adap)
 {
-       if (adap->ch_thermal.tzdev)
+       if (adap->ch_thermal.tzdev) {
                thermal_zone_device_unregister(adap->ch_thermal.tzdev);
+               adap->ch_thermal.tzdev = NULL;
+       }
        return 0;
 }
index c486412..a10a686 100644 (file)
@@ -231,7 +231,7 @@ again:
                if (e->state == L2T_STATE_STALE)
                        e->state = L2T_STATE_VALID;
                spin_unlock_bh(&e->lock);
-               /* fall through */
+               fallthrough;
        case L2T_STATE_VALID:     /* fast-path, send the packet on */
                return t4_ofld_send(adap, skb);
        case L2T_STATE_RESOLVING:
index 8a56491..fa33679 100644 (file)
@@ -7656,13 +7656,13 @@ int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
                switch (nmac) {
                case 5:
                        memcpy(mac + 24, c.nmac3, sizeof(c.nmac3));
-                       /* Fall through */
+                       fallthrough;
                case 4:
                        memcpy(mac + 18, c.nmac2, sizeof(c.nmac2));
-                       /* Fall through */
+                       fallthrough;
                case 3:
                        memcpy(mac + 12, c.nmac1, sizeof(c.nmac1));
-                       /* Fall through */
+                       fallthrough;
                case 2:
                        memcpy(mac + 6,  c.nmac0, sizeof(c.nmac0));
                }
index dbe8ee7..e2fe78e 100644 (file)
@@ -517,7 +517,7 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp,
                }
                cpl = (void *)p;
        }
-               /* Fall through */
+               fallthrough;
 
        case CPL_SGE_EGR_UPDATE: {
                /*
index 6bc7e7b..552d89f 100644 (file)
@@ -272,7 +272,7 @@ static netdev_features_t enic_features_check(struct sk_buff *skb,
        case ntohs(ETH_P_IPV6):
                if (!(enic->vxlan.flags & ENIC_VXLAN_INNER_IPV6))
                        goto out;
-               /* Fall through */
+               fallthrough;
        case ntohs(ETH_P_IP):
                break;
        default:
index 62e271a..ffec0f3 100644 (file)
@@ -2446,8 +2446,8 @@ static int gemini_ethernet_port_probe(struct platform_device *pdev)
        port->reset = devm_reset_control_get_exclusive(dev, NULL);
        if (IS_ERR(port->reset)) {
                dev_err(dev, "no reset\n");
-               clk_disable_unprepare(port->pclk);
-               return PTR_ERR(port->reset);
+               ret = PTR_ERR(port->reset);
+               goto unprepare;
        }
        reset_control_reset(port->reset);
        usleep_range(100, 500);
@@ -2502,25 +2502,25 @@ static int gemini_ethernet_port_probe(struct platform_device *pdev)
                                        IRQF_SHARED,
                                        port_names[port->id],
                                        port);
-       if (ret) {
-               clk_disable_unprepare(port->pclk);
-               return ret;
-       }
+       if (ret)
+               goto unprepare;
 
        ret = register_netdev(netdev);
-       if (!ret) {
+       if (ret)
+               goto unprepare;
+
+       netdev_info(netdev,
+                   "irq %d, DMA @ 0x%pap, GMAC @ 0x%pap\n",
+                   port->irq, &dmares->start,
+                   &gmacres->start);
+       ret = gmac_setup_phy(netdev);
+       if (ret)
                netdev_info(netdev,
-                           "irq %d, DMA @ 0x%pap, GMAC @ 0x%pap\n",
-                           port->irq, &dmares->start,
-                           &gmacres->start);
-               ret = gmac_setup_phy(netdev);
-               if (ret)
-                       netdev_info(netdev,
-                                   "PHY init failed, deferring to ifup time\n");
-               return 0;
-       }
+                           "PHY init failed, deferring to ifup time\n");
+       return 0;
 
-       port->netdev = NULL;
+unprepare:
+       clk_disable_unprepare(port->pclk);
        return ret;
 }
 
index 7f77051..5c6c8c5 100644 (file)
@@ -385,7 +385,7 @@ static void dm9000_set_io(struct board_info *db, int byte_width)
 
        case 3:
                dev_dbg(db->dev, ": 3 byte IO, falling back to 16bit\n");
-               /* fall through */
+               fallthrough;
        case 2:
                db->dumpblk = dm9000_dumpblk_16bit;
                db->outblk  = dm9000_outblk_16bit;
index cb116b5..2610efe 100644 (file)
@@ -85,7 +85,7 @@ MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copi
 #define DSL                    CONFIG_DE2104X_DSL
 #endif
 
-#define DE_RX_RING_SIZE                64
+#define DE_RX_RING_SIZE                128
 #define DE_TX_RING_SIZE                64
 #define DE_RING_BYTES          \
                ((sizeof(struct de_desc) * DE_RX_RING_SIZE) +   \
index 0ccd999..f9dd1aa 100644 (file)
@@ -3203,7 +3203,7 @@ srom_map_media(struct net_device *dev)
       case SROM_10BASETF:
        if (!lp->params.fdx) return -1;
        lp->fdx = true;
-       /* fall through */
+       fallthrough;
 
       case SROM_10BASET:
        if (lp->params.fdx && !lp->fdx) return -1;
@@ -3225,7 +3225,7 @@ srom_map_media(struct net_device *dev)
       case SROM_100BASETF:
         if (!lp->params.fdx) return -1;
        lp->fdx = true;
-       /* fall through */
+       fallthrough;
 
       case SROM_100BASET:
        if (lp->params.fdx && !lp->fdx) return -1;
@@ -3239,7 +3239,7 @@ srom_map_media(struct net_device *dev)
       case SROM_100BASEFF:
        if (!lp->params.fdx) return -1;
        lp->fdx = true;
-       /* fall through */
+       fallthrough;
 
       case SROM_100BASEF:
        if (lp->params.fdx && !lp->fdx) return -1;
index 9db2352..3a8659c 100644 (file)
@@ -911,7 +911,7 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
                        data->phy_id = 1;
                else
                        return -ENODEV;
-               /* Fall through */
+               fallthrough;
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
                if (data->phy_id == 32 && (tp->flags & HAS_NWAY)) {
index 5dcc66f..5a43be3 100644 (file)
@@ -1443,7 +1443,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        switch(cmd) {
        case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
                data->phy_id = ((struct netdev_private *)netdev_priv(dev))->phys[0] & 0x1f;
-               /* Fall Through */
+               fallthrough;
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
                spin_lock_irq(&np->lock);
index d6ed1d9..99cc1c4 100644 (file)
@@ -571,7 +571,7 @@ static u32 convert_to_et_setting(struct be_adapter *adapter, u32 if_speeds)
                                break;
                        }
                }
-               /* fall through */
+               fallthrough;
        case PHY_TYPE_SFP_PLUS_10GB:
        case PHY_TYPE_XFP_10GB:
        case PHY_TYPE_SFP_1GB:
index 43570f4..fdff3b4 100644 (file)
@@ -945,7 +945,7 @@ static void dpaa_fq_setup(struct dpaa_priv *priv,
                        break;
                case FQ_TYPE_TX_CONF_MQ:
                        priv->conf_fqs[conf_cnt++] = &fq->fq_base;
-                       /* fall through */
+                       fallthrough;
                case FQ_TYPE_TX_CONFIRM:
                        dpaa_setup_ingress(priv, fq, &fq_cbs->tx_defq);
                        break;
index 9db2a02..1268996 100644 (file)
@@ -375,7 +375,7 @@ static int dpaa_get_hash_opts(struct net_device *dev,
        case UDP_V6_FLOW:
                if (priv->keygen_in_use)
                        cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
-               /* Fall through */
+               fallthrough;
        case IPV4_FLOW:
        case IPV6_FLOW:
        case SCTP_V4_FLOW:
index 457106e..cf5383b 100644 (file)
@@ -376,10 +376,10 @@ static u32 run_xdp(struct dpaa2_eth_priv *priv,
                break;
        default:
                bpf_warn_invalid_xdp_action(xdp_act);
-               /* fall through */
+               fallthrough;
        case XDP_ABORTED:
                trace_xdp_exception(priv->net_dev, xdp_prog, xdp_act);
-               /* fall through */
+               fallthrough;
        case XDP_DROP:
                xdp_release_buf(priv, ch, addr);
                ch->stats.xdp_drop++;
index 3ea51dd..a24b20f 100644 (file)
@@ -66,8 +66,8 @@ struct dpmac_cmd_get_counter {
 };
 
 struct dpmac_rsp_get_counter {
-       u64 pad;
-       u64 counter;
+       __le64 pad;
+       __le64 counter;
 };
 
 #endif /* _FSL_DPMAC_CMD_H */
index 593e381..3c06f5f 100644 (file)
 #define DPNI_VER_MAJOR                         7
 #define DPNI_VER_MINOR                         0
 #define DPNI_CMD_BASE_VERSION                  1
+#define DPNI_CMD_2ND_VERSION                   2
 #define DPNI_CMD_ID_OFFSET                     4
 
 #define DPNI_CMD(id)   (((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_BASE_VERSION)
+#define DPNI_CMD_V2(id)        (((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_2ND_VERSION)
 
 #define DPNI_CMDID_OPEN                                        DPNI_CMD(0x801)
 #define DPNI_CMDID_CLOSE                               DPNI_CMD(0x800)
@@ -45,7 +47,7 @@
 #define DPNI_CMDID_SET_MAX_FRAME_LENGTH                        DPNI_CMD(0x216)
 #define DPNI_CMDID_GET_MAX_FRAME_LENGTH                        DPNI_CMD(0x217)
 #define DPNI_CMDID_SET_LINK_CFG                                DPNI_CMD(0x21A)
-#define DPNI_CMDID_SET_TX_SHAPING                      DPNI_CMD(0x21B)
+#define DPNI_CMDID_SET_TX_SHAPING                      DPNI_CMD_V2(0x21B)
 
 #define DPNI_CMDID_SET_MCAST_PROMISC                   DPNI_CMD(0x220)
 #define DPNI_CMDID_GET_MCAST_PROMISC                   DPNI_CMD(0x221)
index 26d5981..177334f 100644 (file)
@@ -1053,7 +1053,6 @@ static int enetc_pf_probe(struct pci_dev *pdev,
 
 err_reg_netdev:
        enetc_teardown_serdes(priv);
-       enetc_mdio_remove(pf);
        enetc_free_msix(priv);
 err_alloc_msix:
        enetc_free_si_resources(priv);
@@ -1061,6 +1060,7 @@ err_alloc_si_res:
        si->ndev = NULL;
        free_netdev(ndev);
 err_alloc_netdev:
+       enetc_mdio_remove(pf);
        enetc_of_put_phy(pf);
 err_map_pf_space:
        enetc_pci_remove(pdev);
index 645764a..bb9887f 100644 (file)
@@ -528,7 +528,7 @@ static void setup_sgmii_internal_phy(struct fman_mac *memac,
                case 100:
                        tmp_reg16 |= IF_MODE_SGMII_SPEED_100M;
                break;
-               case 1000: /* fallthrough */
+               case 1000:
                default:
                        tmp_reg16 |= IF_MODE_SGMII_SPEED_1G;
                break;
index c27df15..624b2eb 100644 (file)
@@ -1344,10 +1344,10 @@ int fman_port_config(struct fman_port *port, struct fman_port_params *params)
        switch (port->port_type) {
        case FMAN_PORT_TYPE_RX:
                set_rx_dflt_cfg(port, params);
-               /* fall through */
+               fallthrough;
        case FMAN_PORT_TYPE_TX:
                set_tx_dflt_cfg(port, params, &port->dts_params);
-               /* fall through */
+               fallthrough;
        default:
                set_dflt_cfg(port, params);
        }
index db791f6..714b501 100644 (file)
@@ -1348,7 +1348,7 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
                switch (ugeth->max_speed) {
                case SPEED_10:
                        upsmr |= UCC_GETH_UPSMR_R10M;
-                       /* FALLTHROUGH */
+                       fallthrough;
                case SPEED_100:
                        if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI)
                                upsmr |= UCC_GETH_UPSMR_RMM;
index 98be51d..bfa2826 100644 (file)
@@ -229,7 +229,7 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
        /* Return all Fs if nothing was there */
        if ((xgmac_read32(&regs->mdio_stat, endian) & MDIO_STAT_RD_ER) &&
            !priv->has_a011043) {
-               dev_err(&bus->dev,
+               dev_dbg(&bus->dev,
                        "Error while reading PHY%d reg at %d.%hhu\n",
                        phy_id, dev_addr, regnum);
                return 0xffff;
index ed3829a..a769273 100644 (file)
@@ -334,7 +334,7 @@ static void hns_dsaf_xge_srst_by_port_acpi(struct dsaf_device *dsaf_dev,
  * bit6-11 for ppe0-5
  * bit12-17 for roce0-5
  * bit18-19 for com/dfx
- * @enable: false - request reset , true - drop reset
+ * @dereset: false - request reset , true - drop reset
  */
 static void
 hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool dereset)
@@ -357,7 +357,7 @@ hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool dereset)
  * bit6-11 for ppe0-5
  * bit12-17 for roce0-5
  * bit18-19 for com/dfx
- * @enable: false - request reset , true - drop reset
+ * @dereset: false - request reset , true - drop reset
  */
 static void
 hns_dsaf_srst_chns_acpi(struct dsaf_device *dsaf_dev, u32 msk, bool dereset)
index 23f278e..22522f8 100644 (file)
@@ -2282,8 +2282,10 @@ static int hns_nic_dev_probe(struct platform_device *pdev)
                        priv->enet_ver = AE_VERSION_1;
                else if (acpi_dev_found(hns_enet_acpi_match[1].id))
                        priv->enet_ver = AE_VERSION_2;
-               else
-                       return -ENXIO;
+               else {
+                       ret = -ENXIO;
+                       goto out_read_prop_fail;
+               }
 
                /* try to find port-idx-in-ae first */
                ret = acpi_node_get_property_reference(dev->fwnode,
@@ -2299,7 +2301,8 @@ static int hns_nic_dev_probe(struct platform_device *pdev)
                priv->fwnode = args.fwnode;
        } else {
                dev_err(dev, "cannot read cfg data from OF or acpi\n");
-               return -ENXIO;
+               ret = -ENXIO;
+               goto out_read_prop_fail;
        }
 
        ret = device_property_read_u32(dev, "port-idx-in-ae", &port_id);
index 49624ac..14e60c9 100644 (file)
@@ -305,7 +305,7 @@ static int __lb_setup(struct net_device *ndev,
                break;
        case MAC_LOOP_PHY_NONE:
                ret = hns_nic_config_phy_loopback(phy_dev, 0x0);
-               /* fall through */
+               fallthrough;
        case MAC_LOOP_NONE:
                if (!ret && h->dev->ops->set_loopback) {
                        if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII)
@@ -463,8 +463,8 @@ static int __lb_clean_rings(struct hns_nic_priv *priv,
 
 /**
  * nic_run_loopback_test -  run loopback test
- * @nic_dev: net device
- * @loopback_type: loopback type
+ * @ndev: net device
+ * @loop_mode: loopback mode
  */
 static int __lb_run_test(struct net_device *ndev,
                         enum hnae_loop loop_mode)
@@ -572,7 +572,7 @@ static int __lb_down(struct net_device *ndev, enum hnae_loop loop)
 
 /**
  * hns_nic_self_test - self test
- * @dev: net device
+ * @ndev: net device
  * @eth_test: test cmd
  * @data: test result
  */
@@ -633,7 +633,7 @@ static void hns_nic_self_test(struct net_device *ndev,
 
 /**
  * hns_nic_get_drvinfo - get net driver info
- * @dev: net device
+ * @net_dev: net device
  * @drvinfo: driver info
  */
 static void hns_nic_get_drvinfo(struct net_device *net_dev,
@@ -658,7 +658,7 @@ static void hns_nic_get_drvinfo(struct net_device *net_dev,
 
 /**
  * hns_get_ringparam - get ring parameter
- * @dev: net device
+ * @net_dev: net device
  * @param: ethtool parameter
  */
 static void hns_get_ringparam(struct net_device *net_dev,
@@ -683,7 +683,7 @@ static void hns_get_ringparam(struct net_device *net_dev,
 
 /**
  * hns_get_pauseparam - get pause parameter
- * @dev: net device
+ * @net_dev: net device
  * @param: pause parameter
  */
 static void hns_get_pauseparam(struct net_device *net_dev,
@@ -701,7 +701,7 @@ static void hns_get_pauseparam(struct net_device *net_dev,
 
 /**
  * hns_set_pauseparam - set pause parameter
- * @dev: net device
+ * @net_dev: net device
  * @param: pause parameter
  *
  * Return 0 on success, negative on failure
@@ -725,7 +725,7 @@ static int hns_set_pauseparam(struct net_device *net_dev,
 
 /**
  * hns_get_coalesce - get coalesce info.
- * @dev: net device
+ * @net_dev: net device
  * @ec: coalesce info.
  *
  * Return 0 on success, negative on failure.
@@ -769,7 +769,7 @@ static int hns_get_coalesce(struct net_device *net_dev,
 
 /**
  * hns_set_coalesce - set coalesce info.
- * @dev: net device
+ * @net_dev: net device
  * @ec: coalesce info.
  *
  * Return 0 on success, negative on failure.
@@ -808,7 +808,7 @@ static int hns_set_coalesce(struct net_device *net_dev,
 
 /**
  * hns_get_channels - get channel info.
- * @dev: net device
+ * @net_dev: net device
  * @ch: channel info.
  */
 static void
@@ -825,7 +825,7 @@ hns_get_channels(struct net_device *net_dev, struct ethtool_channels *ch)
 
 /**
  * get_ethtool_stats - get detail statistics.
- * @dev: net device
+ * @netdev: net device
  * @stats: statistics info.
  * @data: statistics data.
  */
@@ -883,8 +883,8 @@ static void hns_get_ethtool_stats(struct net_device *netdev,
 
 /**
  * get_strings: Return a set of strings that describe the requested objects
- * @dev: net device
- * @stats: string set ID.
+ * @netdev: net device
+ * @stringset: string set ID.
  * @data: objects data.
  */
 static void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
@@ -972,7 +972,7 @@ static void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
 
 /**
  * nic_get_sset_count - get string set count witch returned by nic_get_strings.
- * @dev: net device
+ * @netdev: net device
  * @stringset: string set index, 0: self test string; 1: statistics string.
  *
  * Return string set count.
@@ -1006,7 +1006,7 @@ static int hns_get_sset_count(struct net_device *netdev, int stringset)
 
 /**
  * hns_phy_led_set - set phy LED status.
- * @dev: net device
+ * @netdev: net device
  * @value: LED state.
  *
  * Return 0 on success, negative on failure.
@@ -1028,7 +1028,7 @@ static int hns_phy_led_set(struct net_device *netdev, int value)
 
 /**
  * nic_set_phys_id - set phy identify LED.
- * @dev: net device
+ * @netdev: net device
  * @state: LED state.
  *
  * Return 0 on success, negative on failure.
@@ -1104,9 +1104,9 @@ hns_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state)
 
 /**
  * hns_get_regs - get net device register
- * @dev: net device
+ * @net_dev: net device
  * @cmd: ethtool cmd
- * @date: register data
+ * @data: register data
  */
 static void hns_get_regs(struct net_device *net_dev, struct ethtool_regs *cmd,
                         void *data)
@@ -1126,7 +1126,7 @@ static void hns_get_regs(struct net_device *net_dev, struct ethtool_regs *cmd,
 
 /**
  * nic_get_regs_len - get total register len.
- * @dev: net device
+ * @net_dev: net device
  *
  * Return total register len.
  */
@@ -1151,7 +1151,7 @@ static int hns_get_regs_len(struct net_device *net_dev)
 
 /**
  * hns_nic_nway_reset - nway reset
- * @dev: net device
+ * @netdev: net device
  *
  * Return 0 on success, negative on failure
  */
index 87776ce..a4f1d51 100644 (file)
@@ -21,6 +21,7 @@
 #include <net/pkt_cls.h>
 #include <net/tcp.h>
 #include <net/vxlan.h>
+#include <net/geneve.h>
 
 #include "hnae3.h"
 #include "hns3_enet.h"
@@ -780,7 +781,7 @@ static int hns3_get_l4_protocol(struct sk_buff *skb, u8 *ol4_proto,
  * and it is udp packet, which has a dest port as the IANA assigned.
  * the hardware is expected to do the checksum offload, but the
  * hardware will not do the checksum offload when udp dest port is
- * 4789.
+ * 4789 or 6081.
  */
 static bool hns3_tunnel_csum_bug(struct sk_buff *skb)
 {
@@ -789,7 +790,8 @@ static bool hns3_tunnel_csum_bug(struct sk_buff *skb)
        l4.hdr = skb_transport_header(skb);
 
        if (!(!skb->encapsulation &&
-             l4.udp->dest == htons(IANA_VXLAN_UDP_PORT)))
+             (l4.udp->dest == htons(IANA_VXLAN_UDP_PORT) ||
+             l4.udp->dest == htons(GENEVE_UDP_PORT))))
                return false;
 
        skb_checksum_help(skb);
@@ -2746,7 +2748,7 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
        case HNS3_OL4_TYPE_MAC_IN_UDP:
        case HNS3_OL4_TYPE_NVGRE:
                skb->csum_level = 1;
-               /* fall through */
+               fallthrough;
        case HNS3_OL4_TYPE_NO_TUN:
                l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M,
                                          HNS3_RXD_L3ID_S);
index 36575e7..d553ed7 100644 (file)
@@ -3061,7 +3061,7 @@ static irqreturn_t hclge_misc_irq_handle(int irq, void *data)
                 *    by first decoding the types of errors.
                 */
                set_bit(HNAE3_UNKNOWN_RESET, &hdev->reset_request);
-               /* fall through */
+               fallthrough;
        case HCLGE_VECTOR0_EVENT_RST:
                hclge_reset_task_schedule(hdev);
                break;
@@ -3686,12 +3686,10 @@ static int hclge_reset_prepare_up(struct hclge_dev *hdev)
 
        switch (hdev->reset_type) {
        case HNAE3_FUNC_RESET:
-               /* fall through */
        case HNAE3_FLR_RESET:
                ret = hclge_set_all_vf_rst(hdev, false);
                break;
        case HNAE3_GLOBAL_RESET:
-               /* fall through */
        case HNAE3_IMP_RESET:
                ret = hclge_set_rst_done(hdev);
                break;
index 936e2dd..b47bd54 100644 (file)
@@ -6,6 +6,7 @@
 config HINIC
        tristate "Huawei Intelligent PCIE Network Interface Card"
        depends on (PCI_MSI && (X86 || ARM64))
+       select NET_DEVLINK
        help
          This driver supports HiNIC PCIE Ethernet cards.
          To compile this driver as part of the kernel, choose Y here.
index 6bb65ad..c340d9a 100644 (file)
@@ -1654,6 +1654,7 @@ static void hinic_diag_test(struct net_device *netdev,
        }
 
        netif_carrier_off(netdev);
+       netif_tx_disable(netdev);
 
        err = do_lp_test(nic_dev, eth_test->flags, LP_DEFAULT_TIME,
                         &test_index);
@@ -1662,9 +1663,12 @@ static void hinic_diag_test(struct net_device *netdev,
                data[test_index] = 1;
        }
 
+       netif_tx_wake_all_queues(netdev);
+
        err = hinic_port_link_state(nic_dev, &link_state);
        if (!err && link_state == HINIC_LINK_STATE_UP)
                netif_carrier_on(netdev);
+
 }
 
 static int hinic_set_phys_id(struct net_device *netdev,
index c6ce596..2ebae6c 100644 (file)
 
 #define MGMT_MSG_TIMEOUT                5000
 
+#define SET_FUNC_PORT_MBOX_TIMEOUT     30000
+
 #define SET_FUNC_PORT_MGMT_TIMEOUT     25000
 
+#define UPDATE_FW_MGMT_TIMEOUT         20000
+
 #define mgmt_to_pfhwdev(pf_mgmt)        \
                container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt)
 
@@ -361,16 +365,22 @@ int hinic_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt,
                return -EINVAL;
        }
 
-       if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
-               timeout = SET_FUNC_PORT_MGMT_TIMEOUT;
+       if (HINIC_IS_VF(hwif)) {
+               if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
+                       timeout = SET_FUNC_PORT_MBOX_TIMEOUT;
 
-       if (HINIC_IS_VF(hwif))
                return hinic_mbox_to_pf(pf_to_mgmt->hwdev, mod, cmd, buf_in,
-                                       in_size, buf_out, out_size, 0);
-       else
+                                       in_size, buf_out, out_size, timeout);
+       } else {
+               if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
+                       timeout = SET_FUNC_PORT_MGMT_TIMEOUT;
+               else if (cmd == HINIC_PORT_CMD_UPDATE_FW)
+                       timeout = UPDATE_FW_MGMT_TIMEOUT;
+
                return msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
                                buf_out, out_size, MGMT_DIRECT_SEND,
                                MSG_NOT_RESP, timeout);
+       }
 }
 
 static void recv_mgmt_msg_work_handler(struct work_struct *work)
index 501056f..28581bd 100644 (file)
@@ -174,6 +174,24 @@ err_init_txq:
        return err;
 }
 
+static void enable_txqs_napi(struct hinic_dev *nic_dev)
+{
+       int num_txqs = hinic_hwdev_num_qps(nic_dev->hwdev);
+       int i;
+
+       for (i = 0; i < num_txqs; i++)
+               napi_enable(&nic_dev->txqs[i].napi);
+}
+
+static void disable_txqs_napi(struct hinic_dev *nic_dev)
+{
+       int num_txqs = hinic_hwdev_num_qps(nic_dev->hwdev);
+       int i;
+
+       for (i = 0; i < num_txqs; i++)
+               napi_disable(&nic_dev->txqs[i].napi);
+}
+
 /**
  * free_txqs - Free the Logical Tx Queues of specific NIC device
  * @nic_dev: the specific NIC device
@@ -400,6 +418,8 @@ int hinic_open(struct net_device *netdev)
                goto err_create_txqs;
        }
 
+       enable_txqs_napi(nic_dev);
+
        err = create_rxqs(nic_dev);
        if (err) {
                netif_err(nic_dev, drv, netdev,
@@ -484,6 +504,7 @@ err_port_state:
        }
 
 err_create_rxqs:
+       disable_txqs_napi(nic_dev);
        free_txqs(nic_dev);
 
 err_create_txqs:
@@ -497,6 +518,9 @@ int hinic_close(struct net_device *netdev)
        struct hinic_dev *nic_dev = netdev_priv(netdev);
        unsigned int flags;
 
+       /* Disable txq napi firstly to aviod rewaking txq in free_tx_poll */
+       disable_txqs_napi(nic_dev);
+
        down(&nic_dev->mgmt_lock);
 
        flags = nic_dev->flags;
index 02cd635..eb97f2d 100644 (file)
@@ -58,9 +58,9 @@ static int change_mac(struct hinic_dev *nic_dev, const u8 *addr,
                                 sizeof(port_mac_cmd),
                                 &port_mac_cmd, &out_size);
        if (err || out_size != sizeof(port_mac_cmd) ||
-           (port_mac_cmd.status  &&
-           port_mac_cmd.status != HINIC_PF_SET_VF_ALREADY &&
-           port_mac_cmd.status != HINIC_MGMT_STATUS_EXIST)) {
+           (port_mac_cmd.status &&
+            (port_mac_cmd.status != HINIC_PF_SET_VF_ALREADY || !HINIC_IS_VF(hwif)) &&
+            port_mac_cmd.status != HINIC_MGMT_STATUS_EXIST)) {
                dev_err(&pdev->dev, "Failed to change MAC, err: %d, status: 0x%x, out size: 0x%x\n",
                        err, port_mac_cmd.status, out_size);
                return -EFAULT;
index 5bee951..d0072f5 100644 (file)
@@ -543,18 +543,25 @@ static int rx_request_irq(struct hinic_rxq *rxq)
        if (err) {
                netif_err(nic_dev, drv, rxq->netdev,
                          "Failed to set RX interrupt coalescing attribute\n");
-               rx_del_napi(rxq);
-               return err;
+               goto err_req_irq;
        }
 
        err = request_irq(rq->irq, rx_irq, 0, rxq->irq_name, rxq);
-       if (err) {
-               rx_del_napi(rxq);
-               return err;
-       }
+       if (err)
+               goto err_req_irq;
 
        cpumask_set_cpu(qp->q_id % num_online_cpus(), &rq->affinity_mask);
-       return irq_set_affinity_hint(rq->irq, &rq->affinity_mask);
+       err = irq_set_affinity_hint(rq->irq, &rq->affinity_mask);
+       if (err)
+               goto err_irq_affinity;
+
+       return 0;
+
+err_irq_affinity:
+       free_irq(rq->irq, rxq);
+err_req_irq:
+       rx_del_napi(rxq);
+       return err;
 }
 
 static void rx_free_irq(struct hinic_rxq *rxq)
index 4d63680..f8a2645 100644 (file)
@@ -38,8 +38,7 @@ static int hinic_set_mac(struct hinic_hwdev *hwdev, const u8 *mac_addr,
        err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_MAC, &mac_info,
                                 sizeof(mac_info), &mac_info, &out_size);
        if (err || out_size != sizeof(mac_info) ||
-           (mac_info.status && mac_info.status != HINIC_PF_SET_VF_ALREADY &&
-           mac_info.status != HINIC_MGMT_STATUS_EXIST)) {
+           (mac_info.status && mac_info.status != HINIC_MGMT_STATUS_EXIST)) {
                dev_err(&hwdev->func_to_io.hwif->pdev->dev, "Failed to set MAC, err: %d, status: 0x%x, out size: 0x%x\n",
                        err, mac_info.status, out_size);
                return -EIO;
@@ -503,8 +502,7 @@ struct hinic_sriov_info *hinic_get_sriov_info_by_pcidev(struct pci_dev *pdev)
 
 static int hinic_check_mac_info(u8 status, u16 vlan_id)
 {
-       if ((status && status != HINIC_MGMT_STATUS_EXIST &&
-            status != HINIC_PF_SET_VF_ALREADY) ||
+       if ((status && status != HINIC_MGMT_STATUS_EXIST) ||
            (vlan_id & CHECK_IPSU_15BIT &&
             status == HINIC_MGMT_STATUS_EXIST))
                return -EINVAL;
@@ -546,12 +544,6 @@ static int hinic_update_mac(struct hinic_hwdev *hwdev, u8 *old_mac,
                return -EINVAL;
        }
 
-       if (mac_info.status == HINIC_PF_SET_VF_ALREADY) {
-               dev_warn(&hwdev->hwif->pdev->dev,
-                        "PF has already set VF MAC. Ignore update operation\n");
-               return HINIC_PF_SET_VF_ALREADY;
-       }
-
        if (mac_info.status == HINIC_MGMT_STATUS_EXIST)
                dev_warn(&hwdev->hwif->pdev->dev, "MAC is repeated. Ignore update operation\n");
 
index a97498e..c1f81e9 100644 (file)
@@ -717,8 +717,8 @@ static int free_tx_poll(struct napi_struct *napi, int budget)
                netdev_txq = netdev_get_tx_queue(txq->netdev, qp->q_id);
 
                __netif_tx_lock(netdev_txq, smp_processor_id());
-
-               netif_wake_subqueue(nic_dev->netdev, qp->q_id);
+               if (!netif_testing(nic_dev->netdev))
+                       netif_wake_subqueue(nic_dev->netdev, qp->q_id);
 
                __netif_tx_unlock(netdev_txq);
 
@@ -745,18 +745,6 @@ static int free_tx_poll(struct napi_struct *napi, int budget)
        return budget;
 }
 
-static void tx_napi_add(struct hinic_txq *txq, int weight)
-{
-       netif_napi_add(txq->netdev, &txq->napi, free_tx_poll, weight);
-       napi_enable(&txq->napi);
-}
-
-static void tx_napi_del(struct hinic_txq *txq)
-{
-       napi_disable(&txq->napi);
-       netif_napi_del(&txq->napi);
-}
-
 static irqreturn_t tx_irq(int irq, void *data)
 {
        struct hinic_txq *txq = data;
@@ -790,7 +778,7 @@ static int tx_request_irq(struct hinic_txq *txq)
 
        qp = container_of(sq, struct hinic_qp, sq);
 
-       tx_napi_add(txq, nic_dev->tx_weight);
+       netif_napi_add(txq->netdev, &txq->napi, free_tx_poll, nic_dev->tx_weight);
 
        hinic_hwdev_msix_set(nic_dev->hwdev, sq->msix_entry,
                             TX_IRQ_NO_PENDING, TX_IRQ_NO_COALESC,
@@ -807,14 +795,14 @@ static int tx_request_irq(struct hinic_txq *txq)
        if (err) {
                netif_err(nic_dev, drv, txq->netdev,
                          "Failed to set TX interrupt coalescing attribute\n");
-               tx_napi_del(txq);
+               netif_napi_del(&txq->napi);
                return err;
        }
 
        err = request_irq(sq->irq, tx_irq, 0, txq->irq_name, txq);
        if (err) {
                dev_err(&pdev->dev, "Failed to request Tx irq\n");
-               tx_napi_del(txq);
+               netif_napi_del(&txq->napi);
                return err;
        }
 
@@ -826,7 +814,7 @@ static void tx_free_irq(struct hinic_txq *txq)
        struct hinic_sq *sq = txq->sq;
 
        free_irq(sq->irq, txq);
-       tx_napi_del(txq);
+       netif_napi_del(&txq->napi);
 }
 
 /**
index 0273fb7..3153d62 100644 (file)
@@ -3247,7 +3247,7 @@ static int ehea_mem_notifier(struct notifier_block *nb,
        switch (action) {
        case MEM_CANCEL_OFFLINE:
                pr_info("memory offlining canceled");
-               /* Fall through - re-add canceled memory block */
+               fallthrough;    /* re-add canceled memory block */
 
        case MEM_ONLINE:
                pr_info("memory is going online");
index 06248a7..c00b909 100644 (file)
@@ -2319,7 +2319,7 @@ static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
        switch (cmd) {
        case SIOCGMIIPHY:
                data->phy_id = dev->phy.address;
-               /* Fall through */
+               fallthrough;
        case SIOCGMIIREG:
                data->val_out = emac_mdio_read(ndev, dev->phy.address,
                                               data->reg_num);
index 5afb3c9..1b702a4 100644 (file)
@@ -479,6 +479,9 @@ static int reset_rx_pools(struct ibmvnic_adapter *adapter)
        int i, j, rc;
        u64 *size_array;
 
+       if (!adapter->rx_pool)
+               return -1;
+
        size_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
                be32_to_cpu(adapter->login_rsp_buf->off_rxadd_buff_size));
 
@@ -649,6 +652,9 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
        int tx_scrqs;
        int i, rc;
 
+       if (!adapter->tx_pool)
+               return -1;
+
        tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
        for (i = 0; i < tx_scrqs; i++) {
                rc = reset_one_tx_pool(adapter, &adapter->tso_pool[i]);
@@ -2011,7 +2017,10 @@ static int do_reset(struct ibmvnic_adapter *adapter,
                    adapter->req_rx_add_entries_per_subcrq !=
                    old_num_rx_slots ||
                    adapter->req_tx_entries_per_subcrq !=
-                   old_num_tx_slots) {
+                   old_num_tx_slots ||
+                   !adapter->rx_pool ||
+                   !adapter->tso_pool ||
+                   !adapter->tx_pool) {
                        release_rx_pools(adapter);
                        release_tx_pools(adapter);
                        release_napi(adapter);
@@ -2023,12 +2032,18 @@ static int do_reset(struct ibmvnic_adapter *adapter,
 
                } else {
                        rc = reset_tx_pools(adapter);
-                       if (rc)
+                       if (rc) {
+                               netdev_dbg(adapter->netdev, "reset tx pools failed (%d)\n",
+                                               rc);
                                goto out;
+                       }
 
                        rc = reset_rx_pools(adapter);
-                       if (rc)
+                       if (rc) {
+                               netdev_dbg(adapter->netdev, "reset rx pools failed (%d)\n",
+                                               rc);
                                goto out;
+                       }
                }
                ibmvnic_disable_irqs(adapter);
        }
index 63dde3b..664e8cc 100644 (file)
@@ -4079,7 +4079,6 @@ void e1000e_reset(struct e1000_adapter *adapter)
        case e1000_pch_lpt:
        case e1000_pch_spt:
        case e1000_pch_cnp:
-               fallthrough;
        case e1000_pch_tgp:
        case e1000_pch_adp:
                fc->refresh_time = 0xFFFF;
index 8e133d6..47bfb2e 100644 (file)
@@ -1115,7 +1115,7 @@ static int i40e_quiesce_vf_pci(struct i40e_vf *vf)
 static int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
 {
        struct i40e_mac_filter *f;
-       int num_vlans = 0, bkt;
+       u16 num_vlans = 0, bkt;
 
        hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
                if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID)
@@ -1134,8 +1134,8 @@ static int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
  *
  * Called to get number of VLANs and VLAN list present in mac_filter_hash.
  **/
-static void i40e_get_vlan_list_sync(struct i40e_vsi *vsi, int *num_vlans,
-                                          s16 **vlan_list)
+static void i40e_get_vlan_list_sync(struct i40e_vsi *vsi, u16 *num_vlans,
+                                   s16 **vlan_list)
 {
        struct i40e_mac_filter *f;
        int i = 0;
@@ -1169,11 +1169,11 @@ err:
  **/
 static i40e_status
 i40e_set_vsi_promisc(struct i40e_vf *vf, u16 seid, bool multi_enable,
-                    bool unicast_enable, s16 *vl, int num_vlans)
+                    bool unicast_enable, s16 *vl, u16 num_vlans)
 {
+       i40e_status aq_ret, aq_tmp = 0;
        struct i40e_pf *pf = vf->pf;
        struct i40e_hw *hw = &pf->hw;
-       i40e_status aq_ret;
        int i;
 
        /* No VLAN to set promisc on, set on VSI */
@@ -1222,6 +1222,9 @@ i40e_set_vsi_promisc(struct i40e_vf *vf, u16 seid, bool multi_enable,
                                vf->vf_id,
                                i40e_stat_str(&pf->hw, aq_ret),
                                i40e_aq_str(&pf->hw, aq_err));
+
+                       if (!aq_tmp)
+                               aq_tmp = aq_ret;
                }
 
                aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, seid,
@@ -1235,8 +1238,15 @@ i40e_set_vsi_promisc(struct i40e_vf *vf, u16 seid, bool multi_enable,
                                vf->vf_id,
                                i40e_stat_str(&pf->hw, aq_ret),
                                i40e_aq_str(&pf->hw, aq_err));
+
+                       if (!aq_tmp)
+                               aq_tmp = aq_ret;
                }
        }
+
+       if (aq_tmp)
+               aq_ret = aq_tmp;
+
        return aq_ret;
 }
 
@@ -1258,7 +1268,7 @@ static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
        i40e_status aq_ret = I40E_SUCCESS;
        struct i40e_pf *pf = vf->pf;
        struct i40e_vsi *vsi;
-       int num_vlans;
+       u16 num_vlans;
        s16 *vl;
 
        vsi = i40e_find_vsi_from_id(pf, vsi_id);
index d870343..cf539db 100644 (file)
@@ -3806,8 +3806,8 @@ static int __maybe_unused iavf_suspend(struct device *dev_d)
 static int __maybe_unused iavf_resume(struct device *dev_d)
 {
        struct pci_dev *pdev = to_pci_dev(dev_d);
-       struct iavf_adapter *adapter = pci_get_drvdata(pdev);
-       struct net_device *netdev = adapter->netdev;
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct iavf_adapter *adapter = netdev_priv(netdev);
        u32 err;
 
        pci_set_master(pdev);
index 34abfce..7db5fd9 100644 (file)
@@ -2288,26 +2288,28 @@ void ice_set_safe_mode_caps(struct ice_hw *hw)
 {
        struct ice_hw_func_caps *func_caps = &hw->func_caps;
        struct ice_hw_dev_caps *dev_caps = &hw->dev_caps;
-       u32 valid_func, rxq_first_id, txq_first_id;
-       u32 msix_vector_first_id, max_mtu;
+       struct ice_hw_common_caps cached_caps;
        u32 num_funcs;
 
        /* cache some func_caps values that should be restored after memset */
-       valid_func = func_caps->common_cap.valid_functions;
-       txq_first_id = func_caps->common_cap.txq_first_id;
-       rxq_first_id = func_caps->common_cap.rxq_first_id;
-       msix_vector_first_id = func_caps->common_cap.msix_vector_first_id;
-       max_mtu = func_caps->common_cap.max_mtu;
+       cached_caps = func_caps->common_cap;
 
        /* unset func capabilities */
        memset(func_caps, 0, sizeof(*func_caps));
 
+#define ICE_RESTORE_FUNC_CAP(name) \
+       func_caps->common_cap.name = cached_caps.name
+
        /* restore cached values */
-       func_caps->common_cap.valid_functions = valid_func;
-       func_caps->common_cap.txq_first_id = txq_first_id;
-       func_caps->common_cap.rxq_first_id = rxq_first_id;
-       func_caps->common_cap.msix_vector_first_id = msix_vector_first_id;
-       func_caps->common_cap.max_mtu = max_mtu;
+       ICE_RESTORE_FUNC_CAP(valid_functions);
+       ICE_RESTORE_FUNC_CAP(txq_first_id);
+       ICE_RESTORE_FUNC_CAP(rxq_first_id);
+       ICE_RESTORE_FUNC_CAP(msix_vector_first_id);
+       ICE_RESTORE_FUNC_CAP(max_mtu);
+       ICE_RESTORE_FUNC_CAP(nvm_unified_update);
+       ICE_RESTORE_FUNC_CAP(nvm_update_pending_nvm);
+       ICE_RESTORE_FUNC_CAP(nvm_update_pending_orom);
+       ICE_RESTORE_FUNC_CAP(nvm_update_pending_netlist);
 
        /* one Tx and one Rx queue in safe mode */
        func_caps->common_cap.num_rxq = 1;
@@ -2318,22 +2320,25 @@ void ice_set_safe_mode_caps(struct ice_hw *hw)
        func_caps->guar_num_vsi = 1;
 
        /* cache some dev_caps values that should be restored after memset */
-       valid_func = dev_caps->common_cap.valid_functions;
-       txq_first_id = dev_caps->common_cap.txq_first_id;
-       rxq_first_id = dev_caps->common_cap.rxq_first_id;
-       msix_vector_first_id = dev_caps->common_cap.msix_vector_first_id;
-       max_mtu = dev_caps->common_cap.max_mtu;
+       cached_caps = dev_caps->common_cap;
        num_funcs = dev_caps->num_funcs;
 
        /* unset dev capabilities */
        memset(dev_caps, 0, sizeof(*dev_caps));
 
+#define ICE_RESTORE_DEV_CAP(name) \
+       dev_caps->common_cap.name = cached_caps.name
+
        /* restore cached values */
-       dev_caps->common_cap.valid_functions = valid_func;
-       dev_caps->common_cap.txq_first_id = txq_first_id;
-       dev_caps->common_cap.rxq_first_id = rxq_first_id;
-       dev_caps->common_cap.msix_vector_first_id = msix_vector_first_id;
-       dev_caps->common_cap.max_mtu = max_mtu;
+       ICE_RESTORE_DEV_CAP(valid_functions);
+       ICE_RESTORE_DEV_CAP(txq_first_id);
+       ICE_RESTORE_DEV_CAP(rxq_first_id);
+       ICE_RESTORE_DEV_CAP(msix_vector_first_id);
+       ICE_RESTORE_DEV_CAP(max_mtu);
+       ICE_RESTORE_DEV_CAP(nvm_unified_update);
+       ICE_RESTORE_DEV_CAP(nvm_update_pending_nvm);
+       ICE_RESTORE_DEV_CAP(nvm_update_pending_orom);
+       ICE_RESTORE_DEV_CAP(nvm_update_pending_netlist);
        dev_caps->num_funcs = num_funcs;
 
        /* one Tx and one Rx queue per function in safe mode */
index deaefe0..8968fdd 100644 (file)
@@ -289,7 +289,13 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
                return -EIO;
        }
 
-       err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write, HZ, &event);
+       /* In most cases, firmware reports a write completion within a few
+        * milliseconds. However, it has been observed that a completion might
+        * take more than a second to complete in some cases. The timeout here
+        * is conservative and is intended to prevent failure to update when
+        * firmware is slow to respond.
+        */
+       err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write, 15 * HZ, &event);
        if (err) {
                dev_err(dev, "Timed out waiting for firmware write completion for module 0x%02x, err %d\n",
                        module, err);
@@ -513,7 +519,7 @@ static int ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
                return -EIO;
        }
 
-       err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write_activate, HZ,
+       err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write_activate, 30 * HZ,
                                    &event);
        if (err) {
                dev_err(dev, "Timed out waiting for firmware to switch active flash banks, err %d\n",
index f268277..ebbb8f5 100644 (file)
@@ -246,7 +246,7 @@ static int ice_get_free_slot(void *array, int size, int curr)
  * ice_vsi_delete - delete a VSI from the switch
  * @vsi: pointer to VSI being removed
  */
-void ice_vsi_delete(struct ice_vsi *vsi)
+static void ice_vsi_delete(struct ice_vsi *vsi)
 {
        struct ice_pf *pf = vsi->back;
        struct ice_vsi_ctx *ctxt;
@@ -313,7 +313,7 @@ static void ice_vsi_free_arrays(struct ice_vsi *vsi)
  *
  * Returns 0 on success, negative on failure
  */
-int ice_vsi_clear(struct ice_vsi *vsi)
+static int ice_vsi_clear(struct ice_vsi *vsi)
 {
        struct ice_pf *pf = NULL;
        struct device *dev;
@@ -563,7 +563,7 @@ static int ice_vsi_get_qs(struct ice_vsi *vsi)
  * ice_vsi_put_qs - Release queues from VSI to PF
  * @vsi: the VSI that is going to release queues
  */
-void ice_vsi_put_qs(struct ice_vsi *vsi)
+static void ice_vsi_put_qs(struct ice_vsi *vsi)
 {
        struct ice_pf *pf = vsi->back;
        int i;
@@ -1196,6 +1196,18 @@ static void ice_vsi_clear_rings(struct ice_vsi *vsi)
 {
        int i;
 
+       /* Avoid stale references by clearing map from vector to ring */
+       if (vsi->q_vectors) {
+               ice_for_each_q_vector(vsi, i) {
+                       struct ice_q_vector *q_vector = vsi->q_vectors[i];
+
+                       if (q_vector) {
+                               q_vector->tx.ring = NULL;
+                               q_vector->rx.ring = NULL;
+                       }
+               }
+       }
+
        if (vsi->tx_rings) {
                for (i = 0; i < vsi->alloc_txq; i++) {
                        if (vsi->tx_rings[i]) {
@@ -2291,7 +2303,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
        if (status) {
                dev_err(dev, "VSI %d failed lan queue config, error %s\n",
                        vsi->vsi_num, ice_stat_str(status));
-               goto unroll_vector_base;
+               goto unroll_clear_rings;
        }
 
        /* Add switch rule to drop all Tx Flow Control Frames, of look up
index 981f3a1..3da1789 100644 (file)
@@ -45,10 +45,6 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc);
 
 void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create);
 
-void ice_vsi_delete(struct ice_vsi *vsi);
-
-int ice_vsi_clear(struct ice_vsi *vsi);
-
 #ifdef CONFIG_DCB
 int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc);
 #endif /* CONFIG_DCB */
@@ -79,8 +75,6 @@ bool ice_is_reset_in_progress(unsigned long *state);
 void
 ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio);
 
-void ice_vsi_put_qs(struct ice_vsi *vsi);
-
 void ice_vsi_dis_irq(struct ice_vsi *vsi);
 
 void ice_vsi_free_irq(struct ice_vsi *vsi);
index 4634b48..54a7f55 100644 (file)
@@ -3169,10 +3169,8 @@ static int ice_setup_pf_sw(struct ice_pf *pf)
                return -EBUSY;
 
        vsi = ice_pf_vsi_setup(pf, pf->hw.port_info);
-       if (!vsi) {
-               status = -ENOMEM;
-               goto unroll_vsi_setup;
-       }
+       if (!vsi)
+               return -ENOMEM;
 
        status = ice_cfg_netdev(vsi);
        if (status) {
@@ -3219,12 +3217,7 @@ unroll_napi_add:
        }
 
 unroll_vsi_setup:
-       if (vsi) {
-               ice_vsi_free_q_vectors(vsi);
-               ice_vsi_delete(vsi);
-               ice_vsi_put_qs(vsi);
-               ice_vsi_clear(vsi);
-       }
+       ice_vsi_release(vsi);
        return status;
 }
 
@@ -4522,6 +4515,7 @@ static int __maybe_unused ice_suspend(struct device *dev)
        }
        ice_clear_interrupt_scheme(pf);
 
+       pci_save_state(pdev);
        pci_wake_from_d3(pdev, pf->wol_ena);
        pci_set_power_state(pdev, PCI_D3hot);
        return 0;
index 4f05f6e..d9c3a6b 100644 (file)
@@ -718,7 +718,6 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
        case e1000_i354:
        case e1000_i210:
        case e1000_i211:
-               fallthrough;
        default:
                for (; i < adapter->num_rx_queues; i++)
                        adapter->rx_ring[i]->reg_idx = rbase_offset + i;
index 3070dfd..2d566f3 100644 (file)
@@ -299,18 +299,14 @@ extern char igc_driver_name[];
 #define IGC_RX_HDR_LEN                 IGC_RXBUFFER_256
 
 /* Transmit and receive latency (for PTP timestamps) */
-/* FIXME: These values were estimated using the ones that i225 has as
- * basis, they seem to provide good numbers with ptp4l/phc2sys, but we
- * need to confirm them.
- */
-#define IGC_I225_TX_LATENCY_10         9542
-#define IGC_I225_TX_LATENCY_100                1024
-#define IGC_I225_TX_LATENCY_1000       178
-#define IGC_I225_TX_LATENCY_2500       64
-#define IGC_I225_RX_LATENCY_10         20662
-#define IGC_I225_RX_LATENCY_100                2213
-#define IGC_I225_RX_LATENCY_1000       448
-#define IGC_I225_RX_LATENCY_2500       160
+#define IGC_I225_TX_LATENCY_10         240
+#define IGC_I225_TX_LATENCY_100                58
+#define IGC_I225_TX_LATENCY_1000       80
+#define IGC_I225_TX_LATENCY_2500       1325
+#define IGC_I225_RX_LATENCY_10         6450
+#define IGC_I225_RX_LATENCY_100                185
+#define IGC_I225_RX_LATENCY_1000       300
+#define IGC_I225_RX_LATENCY_2500       1485
 
 /* RX and TX descriptor control thresholds.
  * PTHRESH - MAC will consider prefetch if it has fewer than this number of
index 36c9992..6a9b510 100644 (file)
@@ -364,6 +364,7 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
        struct sk_buff *skb = adapter->ptp_tx_skb;
        struct skb_shared_hwtstamps shhwtstamps;
        struct igc_hw *hw = &adapter->hw;
+       int adjust = 0;
        u64 regval;
 
        if (WARN_ON_ONCE(!skb))
@@ -373,6 +374,24 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
        regval |= (u64)rd32(IGC_TXSTMPH) << 32;
        igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
 
+       switch (adapter->link_speed) {
+       case SPEED_10:
+               adjust = IGC_I225_TX_LATENCY_10;
+               break;
+       case SPEED_100:
+               adjust = IGC_I225_TX_LATENCY_100;
+               break;
+       case SPEED_1000:
+               adjust = IGC_I225_TX_LATENCY_1000;
+               break;
+       case SPEED_2500:
+               adjust = IGC_I225_TX_LATENCY_2500;
+               break;
+       }
+
+       shhwtstamps.hwtstamp =
+               ktime_add_ns(shhwtstamps.hwtstamp, adjust);
+
        /* Clear the lock early before calling skb_tstamp_tx so that
         * applications are not woken up before the lock bit is clear. We use
         * a copy of the skb pointer to ensure other threads can't change it
index 2f8a4cf..86ca8b9 100644 (file)
@@ -5396,9 +5396,10 @@ static int ixgbe_fwd_ring_up(struct ixgbe_adapter *adapter,
        return err;
 }
 
-static int ixgbe_macvlan_up(struct net_device *vdev, void *data)
+static int ixgbe_macvlan_up(struct net_device *vdev,
+                           struct netdev_nested_priv *priv)
 {
-       struct ixgbe_adapter *adapter = data;
+       struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)priv->data;
        struct ixgbe_fwd_adapter *accel;
 
        if (!netif_is_macvlan(vdev))
@@ -5415,8 +5416,12 @@ static int ixgbe_macvlan_up(struct net_device *vdev, void *data)
 
 static void ixgbe_configure_dfwd(struct ixgbe_adapter *adapter)
 {
+       struct netdev_nested_priv priv = {
+               .data = (void *)adapter,
+       };
+
        netdev_walk_all_upper_dev_rcu(adapter->netdev,
-                                     ixgbe_macvlan_up, adapter);
+                                     ixgbe_macvlan_up, &priv);
 }
 
 static void ixgbe_configure(struct ixgbe_adapter *adapter)
@@ -9023,9 +9028,10 @@ static void ixgbe_set_prio_tc_map(struct ixgbe_adapter *adapter)
 }
 
 #endif /* CONFIG_IXGBE_DCB */
-static int ixgbe_reassign_macvlan_pool(struct net_device *vdev, void *data)
+static int ixgbe_reassign_macvlan_pool(struct net_device *vdev,
+                                      struct netdev_nested_priv *priv)
 {
-       struct ixgbe_adapter *adapter = data;
+       struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)priv->data;
        struct ixgbe_fwd_adapter *accel;
        int pool;
 
@@ -9062,13 +9068,16 @@ static int ixgbe_reassign_macvlan_pool(struct net_device *vdev, void *data)
 static void ixgbe_defrag_macvlan_pools(struct net_device *dev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(dev);
+       struct netdev_nested_priv priv = {
+               .data = (void *)adapter,
+       };
 
        /* flush any stale bits out of the fwd bitmask */
        bitmap_clear(adapter->fwd_bitmask, 1, 63);
 
        /* walk through upper devices reassigning pools */
        netdev_walk_all_upper_dev_rcu(dev, ixgbe_reassign_macvlan_pool,
-                                     adapter);
+                                     &priv);
 }
 
 /**
@@ -9242,14 +9251,18 @@ struct upper_walk_data {
        u8 queue;
 };
 
-static int get_macvlan_queue(struct net_device *upper, void *_data)
+static int get_macvlan_queue(struct net_device *upper,
+                            struct netdev_nested_priv *priv)
 {
        if (netif_is_macvlan(upper)) {
                struct ixgbe_fwd_adapter *vadapter = macvlan_accel_priv(upper);
-               struct upper_walk_data *data = _data;
-               struct ixgbe_adapter *adapter = data->adapter;
-               int ifindex = data->ifindex;
+               struct ixgbe_adapter *adapter;
+               struct upper_walk_data *data;
+               int ifindex;
 
+               data = (struct upper_walk_data *)priv->data;
+               ifindex = data->ifindex;
+               adapter = data->adapter;
                if (vadapter && upper->ifindex == ifindex) {
                        data->queue = adapter->rx_ring[vadapter->rx_base_queue]->reg_idx;
                        data->action = data->queue;
@@ -9265,6 +9278,7 @@ static int handle_redirect_action(struct ixgbe_adapter *adapter, int ifindex,
 {
        struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
        unsigned int num_vfs = adapter->num_vfs, vf;
+       struct netdev_nested_priv priv;
        struct upper_walk_data data;
        struct net_device *upper;
 
@@ -9284,8 +9298,9 @@ static int handle_redirect_action(struct ixgbe_adapter *adapter, int ifindex,
        data.ifindex = ifindex;
        data.action = 0;
        data.queue = 0;
+       priv.data = (void *)&data;
        if (netdev_walk_all_upper_dev_rcu(adapter->netdev,
-                                         get_macvlan_queue, &data)) {
+                                         get_macvlan_queue, &priv)) {
                *action = data.action;
                *queue = data.queue;
 
index 1645e4e..51ed8a5 100644 (file)
@@ -230,8 +230,8 @@ static int xrx200_poll_rx(struct napi_struct *napi, int budget)
        }
 
        if (rx < budget) {
-               napi_complete(&ch->napi);
-               ltq_dma_enable_irq(&ch->dma);
+               if (napi_complete_done(&ch->napi, rx))
+                       ltq_dma_enable_irq(&ch->dma);
        }
 
        return rx;
@@ -245,6 +245,7 @@ static int xrx200_tx_housekeeping(struct napi_struct *napi, int budget)
        int pkts = 0;
        int bytes = 0;
 
+       netif_tx_lock(net_dev);
        while (pkts < budget) {
                struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->tx_free];
 
@@ -268,9 +269,13 @@ static int xrx200_tx_housekeeping(struct napi_struct *napi, int budget)
        net_dev->stats.tx_bytes += bytes;
        netdev_completed_queue(ch->priv->net_dev, pkts, bytes);
 
+       netif_tx_unlock(net_dev);
+       if (netif_queue_stopped(net_dev))
+               netif_wake_queue(net_dev);
+
        if (pkts < budget) {
-               napi_complete(&ch->napi);
-               ltq_dma_enable_irq(&ch->dma);
+               if (napi_complete_done(&ch->napi, pkts))
+                       ltq_dma_enable_irq(&ch->dma);
        }
 
        return pkts;
@@ -342,10 +347,12 @@ static irqreturn_t xrx200_dma_irq(int irq, void *ptr)
 {
        struct xrx200_chan *ch = ptr;
 
-       ltq_dma_disable_irq(&ch->dma);
-       ltq_dma_ack_irq(&ch->dma);
+       if (napi_schedule_prep(&ch->napi)) {
+               __napi_schedule(&ch->napi);
+               ltq_dma_disable_irq(&ch->dma);
+       }
 
-       napi_schedule(&ch->napi);
+       ltq_dma_ack_irq(&ch->dma);
 
        return IRQ_HANDLED;
 }
@@ -499,7 +506,7 @@ static int xrx200_probe(struct platform_device *pdev)
 
        /* setup NAPI */
        netif_napi_add(net_dev, &priv->chan_rx.napi, xrx200_poll_rx, 32);
-       netif_napi_add(net_dev, &priv->chan_tx.napi, xrx200_tx_housekeeping, 32);
+       netif_tx_napi_add(net_dev, &priv->chan_tx.napi, xrx200_tx_housekeeping, 32);
 
        platform_set_drvdata(pdev, priv);
 
index 832bbb8..5bf0409 100644 (file)
@@ -2029,11 +2029,11 @@ mvneta_xdp_put_buff(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
        struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
        int i;
 
-       page_pool_put_page(rxq->page_pool, virt_to_head_page(xdp->data),
-                          sync_len, napi);
        for (i = 0; i < sinfo->nr_frags; i++)
                page_pool_put_full_page(rxq->page_pool,
                                        skb_frag_page(&sinfo->frags[i]), napi);
+       page_pool_put_page(rxq->page_pool, virt_to_head_page(xdp->data),
+                          sync_len, napi);
 }
 
 static int
@@ -2205,10 +2205,10 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
                break;
        default:
                bpf_warn_invalid_xdp_action(act);
-               /* fall through */
+               fallthrough;
        case XDP_ABORTED:
                trace_xdp_exception(pp->dev, prog, act);
-               /* fall through */
+               fallthrough;
        case XDP_DROP:
                mvneta_xdp_put_buff(pp, rxq, xdp, sync, true);
                ret = MVNETA_XDP_DROPPED;
@@ -2383,8 +2383,12 @@ static int mvneta_rx_swbm(struct napi_struct *napi,
                        mvneta_swbm_rx_frame(pp, rx_desc, rxq, &xdp_buf,
                                             &size, page, &ps);
                } else {
-                       if (unlikely(!xdp_buf.data_hard_start))
+                       if (unlikely(!xdp_buf.data_hard_start)) {
+                               rx_desc->buf_phys_addr = 0;
+                               page_pool_put_full_page(rxq->page_pool, page,
+                                                       true);
                                continue;
+                       }
 
                        mvneta_swbm_add_rx_fragment(pp, rx_desc, rxq, &xdp_buf,
                                                    &size, page);
@@ -3396,24 +3400,15 @@ static int mvneta_txq_sw_init(struct mvneta_port *pp,
        txq->last_desc = txq->size - 1;
 
        txq->buf = kmalloc_array(txq->size, sizeof(*txq->buf), GFP_KERNEL);
-       if (!txq->buf) {
-               dma_free_coherent(pp->dev->dev.parent,
-                                 txq->size * MVNETA_DESC_ALIGNED_SIZE,
-                                 txq->descs, txq->descs_phys);
+       if (!txq->buf)
                return -ENOMEM;
-       }
 
        /* Allocate DMA buffers for TSO MAC/IP/TCP headers */
        txq->tso_hdrs = dma_alloc_coherent(pp->dev->dev.parent,
                                           txq->size * TSO_HEADER_SIZE,
                                           &txq->tso_hdrs_phys, GFP_KERNEL);
-       if (!txq->tso_hdrs) {
-               kfree(txq->buf);
-               dma_free_coherent(pp->dev->dev.parent,
-                                 txq->size * MVNETA_DESC_ALIGNED_SIZE,
-                                 txq->descs, txq->descs_phys);
+       if (!txq->tso_hdrs)
                return -ENOMEM;
-       }
 
        /* Setup XPS mapping */
        if (txq_number > 1)
index d4a4e24..41d935d 100644 (file)
@@ -1638,7 +1638,7 @@ int mvpp2_ethtool_rxfh_set(struct mvpp2_port *port, struct ethtool_rxnfc *info)
                        hash_opts |= MVPP22_CLS_HEK_OPT_L4SIP;
                if (info->data & RXH_L4_B_2_3)
                        hash_opts |= MVPP22_CLS_HEK_OPT_L4DIP;
-               /* Fallthrough */
+               fallthrough;
        case MVPP22_FLOW_IP4:
        case MVPP22_FLOW_IP6:
                if (info->data & RXH_L2DA)
index 2a8a584..6e140d1 100644 (file)
@@ -5437,7 +5437,7 @@ static void mvpp2_phylink_validate(struct phylink_config *config,
                }
                if (state->interface != PHY_INTERFACE_MODE_NA)
                        break;
-               /* Fall-through */
+               fallthrough;
        case PHY_INTERFACE_MODE_RGMII:
        case PHY_INTERFACE_MODE_RGMII_ID:
        case PHY_INTERFACE_MODE_RGMII_RXID:
@@ -5451,7 +5451,7 @@ static void mvpp2_phylink_validate(struct phylink_config *config,
                phylink_set(mask, 1000baseX_Full);
                if (state->interface != PHY_INTERFACE_MODE_NA)
                        break;
-               /* Fall-through */
+               fallthrough;
        case PHY_INTERFACE_MODE_1000BASEX:
        case PHY_INTERFACE_MODE_2500BASEX:
                if (port->comphy ||
index 387e33f..2718fe2 100644 (file)
@@ -17,7 +17,7 @@
 
 static const u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
 
-void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
+void __otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
 {
        void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE);
        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
@@ -26,13 +26,21 @@ void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
        tx_hdr = hw_mbase + mbox->tx_start;
        rx_hdr = hw_mbase + mbox->rx_start;
 
-       spin_lock(&mdev->mbox_lock);
        mdev->msg_size = 0;
        mdev->rsp_size = 0;
        tx_hdr->num_msgs = 0;
        tx_hdr->msg_size = 0;
        rx_hdr->num_msgs = 0;
        rx_hdr->msg_size = 0;
+}
+EXPORT_SYMBOL(__otx2_mbox_reset);
+
+void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
+{
+       struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+
+       spin_lock(&mdev->mbox_lock);
+       __otx2_mbox_reset(mbox, devid);
        spin_unlock(&mdev->mbox_lock);
 }
 EXPORT_SYMBOL(otx2_mbox_reset);
index 6dfd0f9..ab43378 100644 (file)
@@ -93,6 +93,7 @@ struct mbox_msghdr {
 };
 
 void otx2_mbox_reset(struct otx2_mbox *mbox, int devid);
+void __otx2_mbox_reset(struct otx2_mbox *mbox, int devid);
 void otx2_mbox_destroy(struct otx2_mbox *mbox);
 int otx2_mbox_init(struct otx2_mbox *mbox, void __force *hwbase,
                   struct pci_dev *pdev, void __force *reg_base,
index dcf25a0..b89dde2 100644 (file)
@@ -463,6 +463,7 @@ void rvu_nix_freemem(struct rvu *rvu);
 int rvu_get_nixlf_count(struct rvu *rvu);
 void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int npalf);
 int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf, int *nix_blkaddr);
+int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add);
 
 /* NPC APIs */
 int rvu_npc_init(struct rvu *rvu);
@@ -477,7 +478,7 @@ void rvu_npc_disable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf);
 void rvu_npc_enable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf);
 void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
                                       int nixlf, u64 chan);
-void rvu_npc_disable_bcast_entry(struct rvu *rvu, u16 pcifunc);
+void rvu_npc_enable_bcast_entry(struct rvu *rvu, u16 pcifunc, bool enable);
 int rvu_npc_update_rxvlan(struct rvu *rvu, u16 pcifunc, int nixlf);
 void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
 void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
index 36953d4..0fc7082 100644 (file)
@@ -17,7 +17,6 @@
 #include "npc.h"
 #include "cgx.h"
 
-static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add);
 static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req,
                            int type, int chan_id);
 
@@ -737,7 +736,7 @@ static int rvu_nix_aq_enq_inst(struct rvu *rvu, struct nix_aq_enq_req *req,
                else if (req->ctype == NIX_AQ_CTYPE_MCE)
                        memcpy(mask, &req->mce_mask,
                               sizeof(struct nix_rx_mce_s));
-               /* Fall through */
+               fallthrough;
        case NIX_AQ_INSTOP_INIT:
                if (req->ctype == NIX_AQ_CTYPE_RQ)
                        memcpy(ctx, &req->rq, sizeof(struct nix_rq_ctx_s));
@@ -2020,7 +2019,7 @@ static int nix_update_mce_list(struct nix_mce_list *mce_list,
        return 0;
 }
 
-static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add)
+int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add)
 {
        int err = 0, idx, next_idx, last_idx;
        struct nix_mce_list *mce_list;
@@ -2065,7 +2064,7 @@ static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add)
 
        /* Disable MCAM entry in NPC */
        if (!mce_list->count) {
-               rvu_npc_disable_bcast_entry(rvu, pcifunc);
+               rvu_npc_enable_bcast_entry(rvu, pcifunc, false);
                goto end;
        }
 
index 0a21408..fbaf9bc 100644 (file)
@@ -530,7 +530,7 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
                              NIX_INTF_RX, &entry, true);
 }
 
-void rvu_npc_disable_bcast_entry(struct rvu *rvu, u16 pcifunc)
+void rvu_npc_enable_bcast_entry(struct rvu *rvu, u16 pcifunc, bool enable)
 {
        struct npc_mcam *mcam = &rvu->hw->mcam;
        int blkaddr, index;
@@ -543,7 +543,7 @@ void rvu_npc_disable_bcast_entry(struct rvu *rvu, u16 pcifunc)
        pcifunc = pcifunc & ~RVU_PFVF_FUNC_MASK;
 
        index = npc_get_nixlf_mcam_index(mcam, pcifunc, 0, NIXLF_BCAST_ENTRY);
-       npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
+       npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
 }
 
 void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
@@ -622,23 +622,35 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
                                         nixlf, NIXLF_UCAST_ENTRY);
        npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
 
-       /* For PF, ena/dis promisc and bcast MCAM match entries */
-       if (pcifunc & RVU_PFVF_FUNC_MASK)
+       /* For PF, ena/dis promisc and bcast MCAM match entries.
+        * For VFs add/delete from bcast list when RX multicast
+        * feature is present.
+        */
+       if (pcifunc & RVU_PFVF_FUNC_MASK && !rvu->hw->cap.nix_rx_multicast)
                return;
 
        /* For bcast, enable/disable only if it's action is not
         * packet replication, incase if action is replication
-        * then this PF's nixlf is removed from bcast replication
+        * then this PF/VF's nixlf is removed from bcast replication
         * list.
         */
-       index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+       index = npc_get_nixlf_mcam_index(mcam, pcifunc & ~RVU_PFVF_FUNC_MASK,
                                         nixlf, NIXLF_BCAST_ENTRY);
        bank = npc_get_bank(mcam, index);
        *(u64 *)&action = rvu_read64(rvu, blkaddr,
             NPC_AF_MCAMEX_BANKX_ACTION(index & (mcam->banksize - 1), bank));
-       if (action.op != NIX_RX_ACTIONOP_MCAST)
+
+       /* VFs will not have BCAST entry */
+       if (action.op != NIX_RX_ACTIONOP_MCAST &&
+           !(pcifunc & RVU_PFVF_FUNC_MASK)) {
                npc_enable_mcam_entry(rvu, mcam,
                                      blkaddr, index, enable);
+       } else {
+               nix_update_bcast_mce_list(rvu, pcifunc, enable);
+               /* Enable PF's BCAST entry for packet replication */
+               rvu_npc_enable_bcast_entry(rvu, pcifunc, enable);
+       }
+
        if (enable)
                rvu_npc_enable_promisc_entry(rvu, pcifunc, nixlf);
        else
index 75a8c40..2fb4567 100644 (file)
@@ -370,8 +370,8 @@ static int otx2_forward_vf_mbox_msgs(struct otx2_nic *pf,
                dst_mbox = &pf->mbox;
                dst_size = dst_mbox->mbox.tx_size -
                                ALIGN(sizeof(*mbox_hdr), MBOX_MSG_ALIGN);
-               /* Check if msgs fit into destination area */
-               if (mbox_hdr->msg_size > dst_size)
+               /* Check if msgs fit into destination area and has valid size */
+               if (mbox_hdr->msg_size > dst_size || !mbox_hdr->msg_size)
                        return -EINVAL;
 
                dst_mdev = &dst_mbox->mbox.dev[0];
@@ -526,10 +526,10 @@ static void otx2_pfvf_mbox_up_handler(struct work_struct *work)
 
 end:
                offset = mbox->rx_start + msg->next_msgoff;
+               if (mdev->msgs_acked == (vf_mbox->up_num_msgs - 1))
+                       __otx2_mbox_reset(mbox, 0);
                mdev->msgs_acked++;
        }
-
-       otx2_mbox_reset(mbox, vf_idx);
 }
 
 static irqreturn_t otx2_pfvf_mbox_intr_handler(int irq, void *pf_irq)
@@ -803,10 +803,11 @@ static void otx2_pfaf_mbox_handler(struct work_struct *work)
                msg = (struct mbox_msghdr *)(mdev->mbase + offset);
                otx2_process_pfaf_mbox_msg(pf, msg);
                offset = mbox->rx_start + msg->next_msgoff;
+               if (mdev->msgs_acked == (af_mbox->num_msgs - 1))
+                       __otx2_mbox_reset(mbox, 0);
                mdev->msgs_acked++;
        }
 
-       otx2_mbox_reset(mbox, 0);
 }
 
 static void otx2_handle_link_event(struct otx2_nic *pf)
@@ -1560,10 +1561,13 @@ int otx2_open(struct net_device *netdev)
 
        err = otx2_rxtx_enable(pf, true);
        if (err)
-               goto err_free_cints;
+               goto err_tx_stop_queues;
 
        return 0;
 
+err_tx_stop_queues:
+       netif_tx_stop_all_queues(netdev);
+       netif_carrier_off(netdev);
 err_free_cints:
        otx2_free_cints(pf, qidx);
        vec = pci_irq_vector(pf->pdev,
index 3a5b34a..e46834e 100644 (file)
@@ -524,6 +524,7 @@ static void otx2_sqe_add_hdr(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
                        sqe_hdr->ol3type = NIX_SENDL3TYPE_IP4_CKSUM;
                } else if (skb->protocol == htons(ETH_P_IPV6)) {
                        proto = ipv6_hdr(skb)->nexthdr;
+                       sqe_hdr->ol3type = NIX_SENDL3TYPE_IP6;
                }
 
                if (proto == IPPROTO_TCP)
index 92a3db6..2f90f17 100644 (file)
@@ -99,10 +99,10 @@ static void otx2vf_vfaf_mbox_handler(struct work_struct *work)
                msg = (struct mbox_msghdr *)(mdev->mbase + offset);
                otx2vf_process_vfaf_mbox_msg(af_mbox->pfvf, msg);
                offset = mbox->rx_start + msg->next_msgoff;
+               if (mdev->msgs_acked == (af_mbox->num_msgs - 1))
+                       __otx2_mbox_reset(mbox, 0);
                mdev->msgs_acked++;
        }
-
-       otx2_mbox_reset(mbox, 0);
 }
 
 static int otx2vf_process_mbox_msg_up(struct otx2_nic *vf,
index b792f63..6a93035 100644 (file)
@@ -2448,7 +2448,7 @@ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCGMIIPHY:
                data->phy_id = hw->phy_addr;
 
-               /* fallthru */
+               fallthrough;
        case SIOCGMIIREG: {
                u16 val = 0;
                spin_lock_bh(&hw->phy_lock);
index cec8124..3448642 100644 (file)
@@ -1376,7 +1376,7 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCGMIIPHY:
                data->phy_id = PHY_ADDR_MARV;
 
-               /* fallthru */
+               fallthrough;
        case SIOCGMIIREG: {
                u16 val = 0;
 
@@ -2764,7 +2764,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
 
                case OP_RXCHKSVLAN:
                        sky2_rx_tag(sky2, length);
-                       /* fall through */
+                       fallthrough;
                case OP_RXCHKS:
                        if (likely(dev->features & NETIF_F_RXCSUM))
                                sky2_rx_checksum(sky2, status);
index 0870fe7..6d2d606 100644 (file)
@@ -228,7 +228,7 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
                        if (!MTK_HAS_CAPS(mac->hw->soc->caps,
                                          MTK_GMAC1_TRGMII))
                                goto err_phy;
-                       /* fall through */
+                       fallthrough;
                case PHY_INTERFACE_MODE_RGMII_TXID:
                case PHY_INTERFACE_MODE_RGMII_RXID:
                case PHY_INTERFACE_MODE_RGMII_ID:
@@ -501,11 +501,11 @@ static void mtk_validate(struct phylink_config *config,
        case PHY_INTERFACE_MODE_RGMII_RXID:
        case PHY_INTERFACE_MODE_RGMII_TXID:
                phylink_set(mask, 1000baseT_Half);
-               /* fall through */
+               fallthrough;
        case PHY_INTERFACE_MODE_SGMII:
                phylink_set(mask, 1000baseT_Full);
                phylink_set(mask, 1000baseX_Full);
-               /* fall through */
+               fallthrough;
        case PHY_INTERFACE_MODE_MII:
        case PHY_INTERFACE_MODE_RMII:
        case PHY_INTERFACE_MODE_REVMII:
index d2986f1..d744478 100644 (file)
@@ -114,7 +114,7 @@ static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
                goto err_out;
 
        for (i = 0; i <= buddy->max_order; ++i) {
-               s = BITS_TO_LONGS(1 << (buddy->max_order - i));
+               s = BITS_TO_LONGS(1UL << (buddy->max_order - i));
                buddy->bits[i] = kvmalloc_array(s, sizeof(long), GFP_KERNEL | __GFP_ZERO);
                if (!buddy->bits[i])
                        goto err_out_free;
index 1d91a0d..2d1f4b3 100644 (file)
@@ -69,12 +69,10 @@ enum {
        MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR            = 0x10,
 };
 
-static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
-                                          struct mlx5_cmd_msg *in,
-                                          struct mlx5_cmd_msg *out,
-                                          void *uout, int uout_size,
-                                          mlx5_cmd_cbk_t cbk,
-                                          void *context, int page_queue)
+static struct mlx5_cmd_work_ent *
+cmd_alloc_ent(struct mlx5_cmd *cmd, struct mlx5_cmd_msg *in,
+             struct mlx5_cmd_msg *out, void *uout, int uout_size,
+             mlx5_cmd_cbk_t cbk, void *context, int page_queue)
 {
        gfp_t alloc_flags = cbk ? GFP_ATOMIC : GFP_KERNEL;
        struct mlx5_cmd_work_ent *ent;
@@ -83,6 +81,7 @@ static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
        if (!ent)
                return ERR_PTR(-ENOMEM);
 
+       ent->idx        = -EINVAL;
        ent->in         = in;
        ent->out        = out;
        ent->uout       = uout;
@@ -91,10 +90,16 @@ static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,
        ent->context    = context;
        ent->cmd        = cmd;
        ent->page_queue = page_queue;
+       refcount_set(&ent->refcnt, 1);
 
        return ent;
 }
 
+static void cmd_free_ent(struct mlx5_cmd_work_ent *ent)
+{
+       kfree(ent);
+}
+
 static u8 alloc_token(struct mlx5_cmd *cmd)
 {
        u8 token;
@@ -109,7 +114,7 @@ static u8 alloc_token(struct mlx5_cmd *cmd)
        return token;
 }
 
-static int alloc_ent(struct mlx5_cmd *cmd)
+static int cmd_alloc_index(struct mlx5_cmd *cmd)
 {
        unsigned long flags;
        int ret;
@@ -123,7 +128,7 @@ static int alloc_ent(struct mlx5_cmd *cmd)
        return ret < cmd->max_reg_cmds ? ret : -ENOMEM;
 }
 
-static void free_ent(struct mlx5_cmd *cmd, int idx)
+static void cmd_free_index(struct mlx5_cmd *cmd, int idx)
 {
        unsigned long flags;
 
@@ -132,6 +137,22 @@ static void free_ent(struct mlx5_cmd *cmd, int idx)
        spin_unlock_irqrestore(&cmd->alloc_lock, flags);
 }
 
+static void cmd_ent_get(struct mlx5_cmd_work_ent *ent)
+{
+       refcount_inc(&ent->refcnt);
+}
+
+static void cmd_ent_put(struct mlx5_cmd_work_ent *ent)
+{
+       if (!refcount_dec_and_test(&ent->refcnt))
+               return;
+
+       if (ent->idx >= 0)
+               cmd_free_index(ent->cmd, ent->idx);
+
+       cmd_free_ent(ent);
+}
+
 static struct mlx5_cmd_layout *get_inst(struct mlx5_cmd *cmd, int idx)
 {
        return cmd->cmd_buf + (idx << cmd->log_stride);
@@ -219,11 +240,6 @@ static void poll_timeout(struct mlx5_cmd_work_ent *ent)
        ent->ret = -ETIMEDOUT;
 }
 
-static void free_cmd(struct mlx5_cmd_work_ent *ent)
-{
-       kfree(ent);
-}
-
 static int verify_signature(struct mlx5_cmd_work_ent *ent)
 {
        struct mlx5_cmd_mailbox *next = ent->out->next;
@@ -837,11 +853,22 @@ static void cb_timeout_handler(struct work_struct *work)
        struct mlx5_core_dev *dev = container_of(ent->cmd, struct mlx5_core_dev,
                                                 cmd);
 
+       mlx5_cmd_eq_recover(dev);
+
+       /* Maybe got handled by eq recover ? */
+       if (!test_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state)) {
+               mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) Async, recovered after timeout\n", ent->idx,
+                              mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
+               goto out; /* phew, already handled */
+       }
+
        ent->ret = -ETIMEDOUT;
-       mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n",
-                      mlx5_command_str(msg_to_opcode(ent->in)),
-                      msg_to_opcode(ent->in));
+       mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) Async, timeout. Will cause a leak of a command resource\n",
+                      ent->idx, mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
        mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
+
+out:
+       cmd_ent_put(ent); /* for the cmd_ent_get() took on schedule delayed work */
 }
 
 static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg);
@@ -856,6 +883,32 @@ static bool opcode_allowed(struct mlx5_cmd *cmd, u16 opcode)
        return cmd->allowed_opcode == opcode;
 }
 
+static int cmd_alloc_index_retry(struct mlx5_cmd *cmd)
+{
+       unsigned long alloc_end = jiffies + msecs_to_jiffies(1000);
+       int idx;
+
+retry:
+       idx = cmd_alloc_index(cmd);
+       if (idx < 0 && time_before(jiffies, alloc_end)) {
+               /* Index allocation can fail on heavy load of commands. This is a temporary
+                * situation as the current command already holds the semaphore, meaning that
+                * another command completion is being handled and it is expected to release
+                * the entry index soon.
+                */
+               cpu_relax();
+               goto retry;
+       }
+       return idx;
+}
+
+bool mlx5_cmd_is_down(struct mlx5_core_dev *dev)
+{
+       return pci_channel_offline(dev->pdev) ||
+              dev->cmd.state != MLX5_CMDIF_STATE_UP ||
+              dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR;
+}
+
 static void cmd_work_handler(struct work_struct *work)
 {
        struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
@@ -873,14 +926,14 @@ static void cmd_work_handler(struct work_struct *work)
        sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
        down(sem);
        if (!ent->page_queue) {
-               alloc_ret = alloc_ent(cmd);
+               alloc_ret = cmd_alloc_index_retry(cmd);
                if (alloc_ret < 0) {
                        mlx5_core_err_rl(dev, "failed to allocate command entry\n");
                        if (ent->callback) {
                                ent->callback(-EAGAIN, ent->context);
                                mlx5_free_cmd_msg(dev, ent->out);
                                free_msg(dev, ent->in);
-                               free_cmd(ent);
+                               cmd_ent_put(ent);
                        } else {
                                ent->ret = -EAGAIN;
                                complete(&ent->done);
@@ -916,15 +969,12 @@ static void cmd_work_handler(struct work_struct *work)
        ent->ts1 = ktime_get_ns();
        cmd_mode = cmd->mode;
 
-       if (ent->callback)
-               schedule_delayed_work(&ent->cb_timeout_work, cb_timeout);
+       if (ent->callback && schedule_delayed_work(&ent->cb_timeout_work, cb_timeout))
+               cmd_ent_get(ent);
        set_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state);
 
        /* Skip sending command to fw if internal error */
-       if (pci_channel_offline(dev->pdev) ||
-           dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR ||
-           cmd->state != MLX5_CMDIF_STATE_UP ||
-           !opcode_allowed(&dev->cmd, ent->op)) {
+       if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, ent->op)) {
                u8 status = 0;
                u32 drv_synd;
 
@@ -933,13 +983,10 @@ static void cmd_work_handler(struct work_struct *work)
                MLX5_SET(mbox_out, ent->out, syndrome, drv_synd);
 
                mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
-               /* no doorbell, no need to keep the entry */
-               free_ent(cmd, ent->idx);
-               if (ent->callback)
-                       free_cmd(ent);
                return;
        }
 
+       cmd_ent_get(ent); /* for the _real_ FW event on completion */
        /* ring doorbell after the descriptor is valid */
        mlx5_core_dbg(dev, "writing 0x%x to command doorbell\n", 1 << ent->idx);
        wmb();
@@ -983,6 +1030,35 @@ static const char *deliv_status_to_str(u8 status)
        }
 }
 
+enum {
+       MLX5_CMD_TIMEOUT_RECOVER_MSEC   = 5 * 1000,
+};
+
+static void wait_func_handle_exec_timeout(struct mlx5_core_dev *dev,
+                                         struct mlx5_cmd_work_ent *ent)
+{
+       unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_RECOVER_MSEC);
+
+       mlx5_cmd_eq_recover(dev);
+
+       /* Re-wait on the ent->done after executing the recovery flow. If the
+        * recovery flow (or any other recovery flow running simultaneously)
+        * has recovered an EQE, it should cause the entry to be completed by
+        * the command interface.
+        */
+       if (wait_for_completion_timeout(&ent->done, timeout)) {
+               mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) recovered after timeout\n", ent->idx,
+                              mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
+               return;
+       }
+
+       mlx5_core_warn(dev, "cmd[%d]: %s(0x%x) No done completion\n", ent->idx,
+                      mlx5_command_str(msg_to_opcode(ent->in)), msg_to_opcode(ent->in));
+
+       ent->ret = -ETIMEDOUT;
+       mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
+}
+
 static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
 {
        unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC);
@@ -994,12 +1070,10 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
                ent->ret = -ECANCELED;
                goto out_err;
        }
-       if (cmd->mode == CMD_MODE_POLLING || ent->polling) {
+       if (cmd->mode == CMD_MODE_POLLING || ent->polling)
                wait_for_completion(&ent->done);
-       } else if (!wait_for_completion_timeout(&ent->done, timeout)) {
-               ent->ret = -ETIMEDOUT;
-               mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
-       }
+       else if (!wait_for_completion_timeout(&ent->done, timeout))
+               wait_func_handle_exec_timeout(dev, ent);
 
 out_err:
        err = ent->ret;
@@ -1039,11 +1113,16 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
        if (callback && page_queue)
                return -EINVAL;
 
-       ent = alloc_cmd(cmd, in, out, uout, uout_size, callback, context,
-                       page_queue);
+       ent = cmd_alloc_ent(cmd, in, out, uout, uout_size,
+                           callback, context, page_queue);
        if (IS_ERR(ent))
                return PTR_ERR(ent);
 
+       /* put for this ent is when consumed, depending on the use case
+        * 1) (!callback) blocking flow: by caller after wait_func completes
+        * 2) (callback) flow: by mlx5_cmd_comp_handler() when ent is handled
+        */
+
        ent->token = token;
        ent->polling = force_polling;
 
@@ -1062,12 +1141,10 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
        }
 
        if (callback)
-               goto out;
+               goto out; /* mlx5_cmd_comp_handler() will put(ent) */
 
        err = wait_func(dev, ent);
-       if (err == -ETIMEDOUT)
-               goto out;
-       if (err == -ECANCELED)
+       if (err == -ETIMEDOUT || err == -ECANCELED)
                goto out_free;
 
        ds = ent->ts2 - ent->ts1;
@@ -1085,7 +1162,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
        *status = ent->status;
 
 out_free:
-       free_cmd(ent);
+       cmd_ent_put(ent);
 out:
        return err;
 }
@@ -1516,14 +1593,19 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
                                if (!forced) {
                                        mlx5_core_err(dev, "Command completion arrived after timeout (entry idx = %d).\n",
                                                      ent->idx);
-                                       free_ent(cmd, ent->idx);
-                                       free_cmd(ent);
+                                       cmd_ent_put(ent);
                                }
                                continue;
                        }
 
-                       if (ent->callback)
-                               cancel_delayed_work(&ent->cb_timeout_work);
+                       if (ent->callback && cancel_delayed_work(&ent->cb_timeout_work))
+                               cmd_ent_put(ent); /* timeout work was canceled */
+
+                       if (!forced || /* Real FW completion */
+                           pci_channel_offline(dev->pdev) || /* FW is inaccessible */
+                           dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
+                               cmd_ent_put(ent);
+
                        if (ent->page_queue)
                                sem = &cmd->pages_sem;
                        else
@@ -1545,10 +1627,6 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
                                              ent->ret, deliv_status_to_str(ent->status), ent->status);
                        }
 
-                       /* only real completion will free the entry slot */
-                       if (!forced)
-                               free_ent(cmd, ent->idx);
-
                        if (ent->callback) {
                                ds = ent->ts2 - ent->ts1;
                                if (ent->op < MLX5_CMD_OP_MAX) {
@@ -1576,10 +1654,13 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
                                free_msg(dev, ent->in);
 
                                err = err ? err : ent->status;
-                               if (!forced)
-                                       free_cmd(ent);
+                               /* final consumer is done, release ent */
+                               cmd_ent_put(ent);
                                callback(err, context);
                        } else {
+                               /* release wait_func() so mlx5_cmd_invoke()
+                                * can make the final ent_put()
+                                */
                                complete(&ent->done);
                        }
                        up(sem);
@@ -1589,8 +1670,11 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
 
 void mlx5_cmd_trigger_completions(struct mlx5_core_dev *dev)
 {
+       struct mlx5_cmd *cmd = &dev->cmd;
+       unsigned long bitmask;
        unsigned long flags;
        u64 vector;
+       int i;
 
        /* wait for pending handlers to complete */
        mlx5_eq_synchronize_cmd_irq(dev);
@@ -1599,11 +1683,20 @@ void mlx5_cmd_trigger_completions(struct mlx5_core_dev *dev)
        if (!vector)
                goto no_trig;
 
+       bitmask = vector;
+       /* we must increment the allocated entries refcount before triggering the completions
+        * to guarantee pending commands will not get freed in the meanwhile.
+        * For that reason, it also has to be done inside the alloc_lock.
+        */
+       for_each_set_bit(i, &bitmask, (1 << cmd->log_sz))
+               cmd_ent_get(cmd->ent_arr[i]);
        vector |= MLX5_TRIGGERED_CMD_COMP;
        spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
 
        mlx5_core_dbg(dev, "vector 0x%llx\n", vector);
        mlx5_cmd_comp_handler(dev, vector, true);
+       for_each_set_bit(i, &bitmask, (1 << cmd->log_sz))
+               cmd_ent_put(cmd->ent_arr[i]);
        return;
 
 no_trig:
@@ -1711,10 +1804,7 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
        u8 token;
 
        opcode = MLX5_GET(mbox_in, in, opcode);
-       if (pci_channel_offline(dev->pdev) ||
-           dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR ||
-           dev->cmd.state != MLX5_CMDIF_STATE_UP ||
-           !opcode_allowed(&dev->cmd, opcode)) {
+       if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, opcode)) {
                err = mlx5_internal_err_ret_value(dev, opcode, &drv_synd, &status);
                MLX5_SET(mbox_out, out, status, status);
                MLX5_SET(mbox_out, out, syndrome, drv_synd);
index 0cc2080..356f585 100644 (file)
@@ -91,7 +91,12 @@ struct page_pool;
 #define MLX5_MPWRQ_PAGES_PER_WQE               BIT(MLX5_MPWRQ_WQE_PAGE_ORDER)
 
 #define MLX5_MTT_OCTW(npages) (ALIGN(npages, 8) / 2)
-#define MLX5E_REQUIRED_WQE_MTTS                (ALIGN(MLX5_MPWRQ_PAGES_PER_WQE, 8))
+/* Add another page to MLX5E_REQUIRED_WQE_MTTS as a buffer between
+ * WQEs, This page will absorb write overflow by the hardware, when
+ * receiving packets larger than MTU. These oversize packets are
+ * dropped by the driver at a later stage.
+ */
+#define MLX5E_REQUIRED_WQE_MTTS                (ALIGN(MLX5_MPWRQ_PAGES_PER_WQE + 1, 8))
 #define MLX5E_LOG_ALIGNED_MPWQE_PPW    (ilog2(MLX5E_REQUIRED_WQE_MTTS))
 #define MLX5E_REQUIRED_MTTS(wqes)      (wqes * MLX5E_REQUIRED_WQE_MTTS)
 #define MLX5E_MAX_RQ_NUM_MTTS  \
@@ -600,7 +605,7 @@ struct mlx5e_rq {
        struct dim         dim; /* Dynamic Interrupt Moderation */
 
        /* XDP */
-       struct bpf_prog       *xdp_prog;
+       struct bpf_prog __rcu *xdp_prog;
        struct mlx5e_xdpsq    *xdpsq;
        DECLARE_BITMAP(flags, 8);
        struct page_pool      *page_pool;
@@ -617,6 +622,7 @@ struct mlx5e_rq {
        u32                    rqn;
        struct mlx5_core_dev  *mdev;
        struct mlx5_core_mkey  umr_mkey;
+       struct mlx5e_dma_info  wqe_overflow;
 
        /* XDP read-mostly */
        struct xdp_rxq_info    xdp_rxq;
@@ -1005,7 +1011,6 @@ int mlx5e_update_nic_rx(struct mlx5e_priv *priv);
 void mlx5e_update_carrier(struct mlx5e_priv *priv);
 int mlx5e_close(struct net_device *netdev);
 int mlx5e_open(struct net_device *netdev);
-void mlx5e_update_ndo_stats(struct mlx5e_priv *priv);
 
 void mlx5e_queue_update_stats(struct mlx5e_priv *priv);
 int mlx5e_bits_invert(unsigned long a, int size);
index 8fe8b4d..254c847 100644 (file)
@@ -51,7 +51,7 @@ static void mlx5e_monitor_counters_work(struct work_struct *work)
                                               monitor_counters_work);
 
        mutex_lock(&priv->state_lock);
-       mlx5e_update_ndo_stats(priv);
+       mlx5e_stats_update_ndo_stats(priv);
        mutex_unlock(&priv->state_lock);
        mlx5e_monitor_counter_arm(priv);
 }
index 5de1cb9..308fd27 100644 (file)
@@ -490,11 +490,8 @@ bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy)
        int err;
        int i;
 
-       if (!MLX5_CAP_GEN(dev, pcam_reg))
-               return -EOPNOTSUPP;
-
-       if (!MLX5_CAP_PCAM_REG(dev, pplm))
-               return -EOPNOTSUPP;
+       if (!MLX5_CAP_GEN(dev, pcam_reg) || !MLX5_CAP_PCAM_REG(dev, pplm))
+               return false;
 
        MLX5_SET(pplm_reg, in, local_port, 1);
        err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
@@ -572,6 +569,9 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
        if (fec_policy >= (1 << MLX5E_FEC_LLRS_272_257_1) && !fec_50g_per_lane)
                return -EOPNOTSUPP;
 
+       if (fec_policy && !mlx5e_fec_in_caps(dev, fec_policy))
+               return -EOPNOTSUPP;
+
        MLX5_SET(pplm_reg, in, local_port, 1);
        err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
        if (err)
index 9062920..58e2703 100644 (file)
@@ -110,11 +110,25 @@ static void mlx5e_rep_neigh_stats_work(struct work_struct *work)
        rtnl_unlock();
 }
 
+struct neigh_update_work {
+       struct work_struct work;
+       struct neighbour *n;
+       struct mlx5e_neigh_hash_entry *nhe;
+};
+
+static void mlx5e_release_neigh_update_work(struct neigh_update_work *update_work)
+{
+       neigh_release(update_work->n);
+       mlx5e_rep_neigh_entry_release(update_work->nhe);
+       kfree(update_work);
+}
+
 static void mlx5e_rep_neigh_update(struct work_struct *work)
 {
-       struct mlx5e_neigh_hash_entry *nhe =
-               container_of(work, struct mlx5e_neigh_hash_entry, neigh_update_work);
-       struct neighbour *n = nhe->n;
+       struct neigh_update_work *update_work = container_of(work, struct neigh_update_work,
+                                                            work);
+       struct mlx5e_neigh_hash_entry *nhe = update_work->nhe;
+       struct neighbour *n = update_work->n;
        struct mlx5e_encap_entry *e;
        unsigned char ha[ETH_ALEN];
        struct mlx5e_priv *priv;
@@ -146,30 +160,42 @@ static void mlx5e_rep_neigh_update(struct work_struct *work)
                mlx5e_rep_update_flows(priv, e, neigh_connected, ha);
                mlx5e_encap_put(priv, e);
        }
-       mlx5e_rep_neigh_entry_release(nhe);
        rtnl_unlock();
-       neigh_release(n);
+       mlx5e_release_neigh_update_work(update_work);
 }
 
-static void mlx5e_rep_queue_neigh_update_work(struct mlx5e_priv *priv,
-                                             struct mlx5e_neigh_hash_entry *nhe,
-                                             struct neighbour *n)
+static struct neigh_update_work *mlx5e_alloc_neigh_update_work(struct mlx5e_priv *priv,
+                                                              struct neighbour *n)
 {
-       /* Take a reference to ensure the neighbour and mlx5 encap
-        * entry won't be destructed until we drop the reference in
-        * delayed work.
-        */
-       neigh_hold(n);
+       struct neigh_update_work *update_work;
+       struct mlx5e_neigh_hash_entry *nhe;
+       struct mlx5e_neigh m_neigh = {};
 
-       /* This assignment is valid as long as the the neigh reference
-        * is taken
-        */
-       nhe->n = n;
+       update_work = kzalloc(sizeof(*update_work), GFP_ATOMIC);
+       if (WARN_ON(!update_work))
+               return NULL;
 
-       if (!queue_work(priv->wq, &nhe->neigh_update_work)) {
-               mlx5e_rep_neigh_entry_release(nhe);
-               neigh_release(n);
+       m_neigh.dev = n->dev;
+       m_neigh.family = n->ops->family;
+       memcpy(&m_neigh.dst_ip, n->primary_key, n->tbl->key_len);
+
+       /* Obtain reference to nhe as last step in order not to release it in
+        * atomic context.
+        */
+       rcu_read_lock();
+       nhe = mlx5e_rep_neigh_entry_lookup(priv, &m_neigh);
+       rcu_read_unlock();
+       if (!nhe) {
+               kfree(update_work);
+               return NULL;
        }
+
+       INIT_WORK(&update_work->work, mlx5e_rep_neigh_update);
+       neigh_hold(n);
+       update_work->n = n;
+       update_work->nhe = nhe;
+
+       return update_work;
 }
 
 static int mlx5e_rep_netevent_event(struct notifier_block *nb,
@@ -181,7 +207,7 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb,
        struct net_device *netdev = rpriv->netdev;
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5e_neigh_hash_entry *nhe = NULL;
-       struct mlx5e_neigh m_neigh = {};
+       struct neigh_update_work *update_work;
        struct neigh_parms *p;
        struct neighbour *n;
        bool found = false;
@@ -196,17 +222,11 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb,
 #endif
                        return NOTIFY_DONE;
 
-               m_neigh.dev = n->dev;
-               m_neigh.family = n->ops->family;
-               memcpy(&m_neigh.dst_ip, n->primary_key, n->tbl->key_len);
-
-               rcu_read_lock();
-               nhe = mlx5e_rep_neigh_entry_lookup(priv, &m_neigh);
-               rcu_read_unlock();
-               if (!nhe)
+               update_work = mlx5e_alloc_neigh_update_work(priv, n);
+               if (!update_work)
                        return NOTIFY_DONE;
 
-               mlx5e_rep_queue_neigh_update_work(priv, nhe, n);
+               queue_work(priv->wq, &update_work->work);
                break;
 
        case NETEVENT_DELAY_PROBE_TIME_UPDATE:
@@ -352,7 +372,6 @@ int mlx5e_rep_neigh_entry_create(struct mlx5e_priv *priv,
 
        (*nhe)->priv = priv;
        memcpy(&(*nhe)->m_neigh, &e->m_neigh, sizeof(e->m_neigh));
-       INIT_WORK(&(*nhe)->neigh_update_work, mlx5e_rep_neigh_update);
        spin_lock_init(&(*nhe)->encap_list_lock);
        INIT_LIST_HEAD(&(*nhe)->encap_list);
        refcount_set(&(*nhe)->refcnt, 1);
index c6bc922..a8be40c 100644 (file)
@@ -246,8 +246,10 @@ mlx5_tc_ct_rule_to_tuple_nat(struct mlx5_ct_tuple *tuple,
                case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
                        ip6_offset = (offset - offsetof(struct ipv6hdr, saddr));
                        ip6_offset /= 4;
-                       if (ip6_offset < 8)
+                       if (ip6_offset < 4)
                                tuple->ip.src_v6.s6_addr32[ip6_offset] = cpu_to_be32(val);
+                       else if (ip6_offset < 8)
+                               tuple->ip.dst_v6.s6_addr32[ip6_offset - 4] = cpu_to_be32(val);
                        else
                                return -EOPNOTSUPP;
                        break;
@@ -699,6 +701,7 @@ mlx5_tc_ct_entry_add_rule(struct mlx5_tc_ct_priv *ct_priv,
 err_rule:
        mlx5e_mod_hdr_detach(ct_priv->esw->dev,
                             &esw->offloads.mod_hdr, zone_rule->mh);
+       mapping_remove(ct_priv->labels_mapping, attr->ct_attr.ct_labels_id);
 err_mod_hdr:
        kfree(spec);
        return err;
@@ -958,12 +961,22 @@ mlx5_tc_ct_add_no_trk_match(struct mlx5e_priv *priv,
        return 0;
 }
 
+void mlx5_tc_ct_match_del(struct mlx5e_priv *priv, struct mlx5_ct_attr *ct_attr)
+{
+       struct mlx5_tc_ct_priv *ct_priv = mlx5_tc_ct_get_ct_priv(priv);
+
+       if (!ct_priv || !ct_attr->ct_labels_id)
+               return;
+
+       mapping_remove(ct_priv->labels_mapping, ct_attr->ct_labels_id);
+}
+
 int
-mlx5_tc_ct_parse_match(struct mlx5e_priv *priv,
-                      struct mlx5_flow_spec *spec,
-                      struct flow_cls_offload *f,
-                      struct mlx5_ct_attr *ct_attr,
-                      struct netlink_ext_ack *extack)
+mlx5_tc_ct_match_add(struct mlx5e_priv *priv,
+                    struct mlx5_flow_spec *spec,
+                    struct flow_cls_offload *f,
+                    struct mlx5_ct_attr *ct_attr,
+                    struct netlink_ext_ack *extack)
 {
        struct mlx5_tc_ct_priv *ct_priv = mlx5_tc_ct_get_ct_priv(priv);
        struct flow_rule *rule = flow_cls_offload_flow_rule(f);
index 3baef91..708c216 100644 (file)
@@ -87,12 +87,15 @@ mlx5_tc_ct_init(struct mlx5_rep_uplink_priv *uplink_priv);
 void
 mlx5_tc_ct_clean(struct mlx5_rep_uplink_priv *uplink_priv);
 
+void
+mlx5_tc_ct_match_del(struct mlx5e_priv *priv, struct mlx5_ct_attr *ct_attr);
+
 int
-mlx5_tc_ct_parse_match(struct mlx5e_priv *priv,
-                      struct mlx5_flow_spec *spec,
-                      struct flow_cls_offload *f,
-                      struct mlx5_ct_attr *ct_attr,
-                      struct netlink_ext_ack *extack);
+mlx5_tc_ct_match_add(struct mlx5e_priv *priv,
+                    struct mlx5_flow_spec *spec,
+                    struct flow_cls_offload *f,
+                    struct mlx5_ct_attr *ct_attr,
+                    struct netlink_ext_ack *extack);
 int
 mlx5_tc_ct_add_no_trk_match(struct mlx5e_priv *priv,
                            struct mlx5_flow_spec *spec);
@@ -130,12 +133,15 @@ mlx5_tc_ct_clean(struct mlx5_rep_uplink_priv *uplink_priv)
 {
 }
 
+static inline void
+mlx5_tc_ct_match_del(struct mlx5e_priv *priv, struct mlx5_ct_attr *ct_attr) {}
+
 static inline int
-mlx5_tc_ct_parse_match(struct mlx5e_priv *priv,
-                      struct mlx5_flow_spec *spec,
-                      struct flow_cls_offload *f,
-                      struct mlx5_ct_attr *ct_attr,
-                      struct netlink_ext_ack *extack)
+mlx5_tc_ct_match_add(struct mlx5e_priv *priv,
+                    struct mlx5_flow_spec *spec,
+                    struct flow_cls_offload *f,
+                    struct mlx5_ct_attr *ct_attr,
+                    struct netlink_ext_ack *extack)
 {
        struct flow_rule *rule = flow_cls_offload_flow_rule(f);
 
index 9334c9c..24336c6 100644 (file)
@@ -20,6 +20,11 @@ enum mlx5e_icosq_wqe_type {
 };
 
 /* General */
+static inline bool mlx5e_skb_is_multicast(struct sk_buff *skb)
+{
+       return skb->pkt_type == PACKET_MULTICAST || skb->pkt_type == PACKET_BROADCAST;
+}
+
 void mlx5e_trigger_irq(struct mlx5e_icosq *sq);
 void mlx5e_completion_event(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe);
 void mlx5e_cq_error_event(struct mlx5_core_cq *mcq, enum mlx5_event event);
index 0e6946f..b28df21 100644 (file)
@@ -122,7 +122,7 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq,
 bool mlx5e_xdp_handle(struct mlx5e_rq *rq, struct mlx5e_dma_info *di,
                      u32 *len, struct xdp_buff *xdp)
 {
-       struct bpf_prog *prog = READ_ONCE(rq->xdp_prog);
+       struct bpf_prog *prog = rcu_dereference(rq->xdp_prog);
        u32 act;
        int err;
 
index a33a1f7..40db27b 100644 (file)
@@ -31,7 +31,6 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,
 {
        struct xdp_buff *xdp = wi->umr.dma_info[page_idx].xsk;
        u32 cqe_bcnt32 = cqe_bcnt;
-       bool consumed;
 
        /* Check packet size. Note LRO doesn't use linear SKB */
        if (unlikely(cqe_bcnt > rq->hw_mtu)) {
@@ -51,10 +50,6 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,
        xsk_buff_dma_sync_for_cpu(xdp);
        prefetch(xdp->data);
 
-       rcu_read_lock();
-       consumed = mlx5e_xdp_handle(rq, NULL, &cqe_bcnt32, xdp);
-       rcu_read_unlock();
-
        /* Possible flows:
         * - XDP_REDIRECT to XSKMAP:
         *   The page is owned by the userspace from now.
@@ -70,7 +65,7 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,
         * allocated first from the Reuse Ring, so it has enough space.
         */
 
-       if (likely(consumed)) {
+       if (likely(mlx5e_xdp_handle(rq, NULL, &cqe_bcnt32, xdp))) {
                if (likely(__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)))
                        __set_bit(page_idx, wi->xdp_xmit_bitmap); /* non-atomic */
                return NULL; /* page/packet was consumed by XDP */
@@ -88,7 +83,6 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_linear(struct mlx5e_rq *rq,
                                              u32 cqe_bcnt)
 {
        struct xdp_buff *xdp = wi->di->xsk;
-       bool consumed;
 
        /* wi->offset is not used in this function, because xdp->data and the
         * DMA address point directly to the necessary place. Furthermore, the
@@ -107,11 +101,7 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_linear(struct mlx5e_rq *rq,
                return NULL;
        }
 
-       rcu_read_lock();
-       consumed = mlx5e_xdp_handle(rq, NULL, &cqe_bcnt, xdp);
-       rcu_read_unlock();
-
-       if (likely(consumed))
+       if (likely(mlx5e_xdp_handle(rq, NULL, &cqe_bcnt, xdp)))
                return NULL; /* page/packet was consumed by XDP */
 
        /* XDP_PASS: copy the data from the UMEM to a new SKB. The frame reuse
index dd9df51..55e65a4 100644 (file)
@@ -106,8 +106,7 @@ err_free_cparam:
 void mlx5e_close_xsk(struct mlx5e_channel *c)
 {
        clear_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
-       napi_synchronize(&c->napi);
-       synchronize_rcu(); /* Sync with the XSK wakeup. */
+       synchronize_rcu(); /* Sync with the XSK wakeup and with NAPI. */
 
        mlx5e_close_rq(&c->xskrq);
        mlx5e_close_cq(&c->xskrq.cq);
index acf6d80..6bbfcf1 100644 (file)
@@ -234,7 +234,7 @@ mlx5e_get_ktls_rx_priv_ctx(struct tls_context *tls_ctx)
 
 /* Re-sync */
 /* Runs in work context */
-static struct mlx5_wqe_ctrl_seg *
+static int
 resync_post_get_progress_params(struct mlx5e_icosq *sq,
                                struct mlx5e_ktls_offload_context_rx *priv_rx)
 {
@@ -258,15 +258,19 @@ resync_post_get_progress_params(struct mlx5e_icosq *sq,
                                       PROGRESS_PARAMS_PADDED_SIZE, DMA_FROM_DEVICE);
        if (unlikely(dma_mapping_error(pdev, buf->dma_addr))) {
                err = -ENOMEM;
-               goto err_out;
+               goto err_free;
        }
 
        buf->priv_rx = priv_rx;
 
        BUILD_BUG_ON(MLX5E_KTLS_GET_PROGRESS_WQEBBS != 1);
+
+       spin_lock(&sq->channel->async_icosq_lock);
+
        if (unlikely(!mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, 1))) {
+               spin_unlock(&sq->channel->async_icosq_lock);
                err = -ENOSPC;
-               goto err_out;
+               goto err_dma_unmap;
        }
 
        pi = mlx5e_icosq_get_next_pi(sq, 1);
@@ -294,12 +298,18 @@ resync_post_get_progress_params(struct mlx5e_icosq *sq,
        };
        icosq_fill_wi(sq, pi, &wi);
        sq->pc++;
+       mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, cseg);
+       spin_unlock(&sq->channel->async_icosq_lock);
 
-       return cseg;
+       return 0;
 
+err_dma_unmap:
+       dma_unmap_single(pdev, buf->dma_addr, PROGRESS_PARAMS_PADDED_SIZE, DMA_FROM_DEVICE);
+err_free:
+       kfree(buf);
 err_out:
        priv_rx->stats->tls_resync_req_skip++;
-       return ERR_PTR(err);
+       return err;
 }
 
 /* Function is called with elevated refcount.
@@ -309,10 +319,8 @@ static void resync_handle_work(struct work_struct *work)
 {
        struct mlx5e_ktls_offload_context_rx *priv_rx;
        struct mlx5e_ktls_rx_resync_ctx *resync;
-       struct mlx5_wqe_ctrl_seg *cseg;
        struct mlx5e_channel *c;
        struct mlx5e_icosq *sq;
-       struct mlx5_wq_cyc *wq;
 
        resync = container_of(work, struct mlx5e_ktls_rx_resync_ctx, work);
        priv_rx = container_of(resync, struct mlx5e_ktls_offload_context_rx, resync);
@@ -324,18 +332,9 @@ static void resync_handle_work(struct work_struct *work)
 
        c = resync->priv->channels.c[priv_rx->rxq];
        sq = &c->async_icosq;
-       wq = &sq->wq;
-
-       spin_lock(&c->async_icosq_lock);
 
-       cseg = resync_post_get_progress_params(sq, priv_rx);
-       if (IS_ERR(cseg)) {
+       if (resync_post_get_progress_params(sq, priv_rx))
                refcount_dec(&resync->refcnt);
-               goto unlock;
-       }
-       mlx5e_notify_hw(wq, sq->pc, sq->uar_map, cseg);
-unlock:
-       spin_unlock(&c->async_icosq_lock);
 }
 
 static void resync_init(struct mlx5e_ktls_rx_resync_ctx *resync,
@@ -386,16 +385,17 @@ void mlx5e_ktls_handle_get_psv_completion(struct mlx5e_icosq_wqe_info *wi,
        struct mlx5e_ktls_offload_context_rx *priv_rx;
        struct mlx5e_ktls_rx_resync_ctx *resync;
        u8 tracker_state, auth_state, *ctx;
+       struct device *dev;
        u32 hw_seq;
 
        priv_rx = buf->priv_rx;
        resync = &priv_rx->resync;
-
+       dev = resync->priv->mdev->device;
        if (unlikely(test_bit(MLX5E_PRIV_RX_FLAG_DELETING, priv_rx->flags)))
                goto out;
 
-       dma_sync_single_for_cpu(resync->priv->mdev->device, buf->dma_addr,
-                               PROGRESS_PARAMS_PADDED_SIZE, DMA_FROM_DEVICE);
+       dma_sync_single_for_cpu(dev, buf->dma_addr, PROGRESS_PARAMS_PADDED_SIZE,
+                               DMA_FROM_DEVICE);
 
        ctx = buf->progress.ctx;
        tracker_state = MLX5_GET(tls_progress_params, ctx, record_tracker_state);
@@ -411,6 +411,7 @@ void mlx5e_ktls_handle_get_psv_completion(struct mlx5e_icosq_wqe_info *wi,
        priv_rx->stats->tls_resync_req_end++;
 out:
        refcount_dec(&resync->refcnt);
+       dma_unmap_single(dev, buf->dma_addr, PROGRESS_PARAMS_PADDED_SIZE, DMA_FROM_DEVICE);
        kfree(buf);
 }
 
@@ -659,7 +660,7 @@ void mlx5e_ktls_del_rx(struct net_device *netdev, struct tls_context *tls_ctx)
        priv_rx = mlx5e_get_ktls_rx_priv_ctx(tls_ctx);
        set_bit(MLX5E_PRIV_RX_FLAG_DELETING, priv_rx->flags);
        mlx5e_set_ktls_rx_priv_ctx(tls_ctx, NULL);
-       napi_synchronize(&priv->channels.c[priv_rx->rxq]->napi);
+       synchronize_rcu(); /* Sync with NAPI */
        if (!cancel_work_sync(&priv_rx->rule.work))
                /* completion is needed, as the priv_rx in the add flow
                 * is maintained on the wqe info (wi), not on the socket.
index 01468ec..b949b9a 100644 (file)
@@ -35,7 +35,6 @@
 #include <net/sock.h>
 
 #include "en.h"
-#include "accel/tls.h"
 #include "fpga/sdk.h"
 #include "en_accel/tls.h"
 
@@ -51,9 +50,14 @@ static const struct counter_desc mlx5e_tls_sw_stats_desc[] = {
 
 #define NUM_TLS_SW_COUNTERS ARRAY_SIZE(mlx5e_tls_sw_stats_desc)
 
+static bool is_tls_atomic_stats(struct mlx5e_priv *priv)
+{
+       return priv->tls && !mlx5_accel_is_ktls_device(priv->mdev);
+}
+
 int mlx5e_tls_get_count(struct mlx5e_priv *priv)
 {
-       if (!priv->tls)
+       if (!is_tls_atomic_stats(priv))
                return 0;
 
        return NUM_TLS_SW_COUNTERS;
@@ -63,7 +67,7 @@ int mlx5e_tls_get_strings(struct mlx5e_priv *priv, uint8_t *data)
 {
        unsigned int i, idx = 0;
 
-       if (!priv->tls)
+       if (!is_tls_atomic_stats(priv))
                return 0;
 
        for (i = 0; i < NUM_TLS_SW_COUNTERS; i++)
@@ -77,7 +81,7 @@ int mlx5e_tls_get_stats(struct mlx5e_priv *priv, u64 *data)
 {
        int i, idx = 0;
 
-       if (!priv->tls)
+       if (!is_tls_atomic_stats(priv))
                return 0;
 
        for (i = 0; i < NUM_TLS_SW_COUNTERS; i++)
index 64d002d..1f48f99 100644 (file)
@@ -217,6 +217,9 @@ static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv,
                break;
        }
 
+       if (WARN_ONCE(*rule_p, "VLAN rule already exists type %d", rule_type))
+               return 0;
+
        *rule_p = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
 
        if (IS_ERR(*rule_p)) {
@@ -397,8 +400,7 @@ static void mlx5e_add_vlan_rules(struct mlx5e_priv *priv)
        for_each_set_bit(i, priv->fs.vlan.active_svlans, VLAN_N_VID)
                mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID, i);
 
-       if (priv->fs.vlan.cvlan_filter_disabled &&
-           !(priv->netdev->flags & IFF_PROMISC))
+       if (priv->fs.vlan.cvlan_filter_disabled)
                mlx5e_add_any_vid_rules(priv);
 }
 
@@ -415,8 +417,12 @@ static void mlx5e_del_vlan_rules(struct mlx5e_priv *priv)
        for_each_set_bit(i, priv->fs.vlan.active_svlans, VLAN_N_VID)
                mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_STAG_VID, i);
 
-       if (priv->fs.vlan.cvlan_filter_disabled &&
-           !(priv->netdev->flags & IFF_PROMISC))
+       WARN_ON_ONCE(!(test_bit(MLX5E_STATE_DESTROYING, &priv->state)));
+
+       /* must be called after DESTROY bit is set and
+        * set_rx_mode is called and flushed
+        */
+       if (priv->fs.vlan.cvlan_filter_disabled)
                mlx5e_del_any_vid_rules(priv);
 }
 
index aebcf73..42ec28e 100644 (file)
@@ -158,16 +158,6 @@ static void mlx5e_update_carrier_work(struct work_struct *work)
        mutex_unlock(&priv->state_lock);
 }
 
-void mlx5e_update_ndo_stats(struct mlx5e_priv *priv)
-{
-       int i;
-
-       for (i = mlx5e_nic_stats_grps_num(priv) - 1; i >= 0; i--)
-               if (mlx5e_nic_stats_grps[i]->update_stats_mask &
-                   MLX5E_NDO_UPDATE_STATS)
-                       mlx5e_nic_stats_grps[i]->update_stats(priv);
-}
-
 static void mlx5e_update_stats_work(struct work_struct *work)
 {
        struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv,
@@ -256,12 +246,17 @@ static int mlx5e_rq_alloc_mpwqe_info(struct mlx5e_rq *rq,
 
 static int mlx5e_create_umr_mkey(struct mlx5_core_dev *mdev,
                                 u64 npages, u8 page_shift,
-                                struct mlx5_core_mkey *umr_mkey)
+                                struct mlx5_core_mkey *umr_mkey,
+                                dma_addr_t filler_addr)
 {
-       int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
+       struct mlx5_mtt *mtt;
+       int inlen;
        void *mkc;
        u32 *in;
        int err;
+       int i;
+
+       inlen = MLX5_ST_SZ_BYTES(create_mkey_in) + sizeof(*mtt) * npages;
 
        in = kvzalloc(inlen, GFP_KERNEL);
        if (!in)
@@ -281,6 +276,18 @@ static int mlx5e_create_umr_mkey(struct mlx5_core_dev *mdev,
        MLX5_SET(mkc, mkc, translations_octword_size,
                 MLX5_MTT_OCTW(npages));
        MLX5_SET(mkc, mkc, log_page_size, page_shift);
+       MLX5_SET(create_mkey_in, in, translations_octword_actual_size,
+                MLX5_MTT_OCTW(npages));
+
+       /* Initialize the mkey with all MTTs pointing to a default
+        * page (filler_addr). When the channels are activated, UMR
+        * WQEs will redirect the RX WQEs to the actual memory from
+        * the RQ's pool, while the gaps (wqe_overflow) remain mapped
+        * to the default page.
+        */
+       mtt = MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
+       for (i = 0 ; i < npages ; i++)
+               mtt[i].ptag = cpu_to_be64(filler_addr);
 
        err = mlx5_core_create_mkey(mdev, umr_mkey, in, inlen);
 
@@ -292,7 +299,8 @@ static int mlx5e_create_rq_umr_mkey(struct mlx5_core_dev *mdev, struct mlx5e_rq
 {
        u64 num_mtts = MLX5E_REQUIRED_MTTS(mlx5_wq_ll_get_size(&rq->mpwqe.wq));
 
-       return mlx5e_create_umr_mkey(mdev, num_mtts, PAGE_SHIFT, &rq->umr_mkey);
+       return mlx5e_create_umr_mkey(mdev, num_mtts, PAGE_SHIFT, &rq->umr_mkey,
+                                    rq->wqe_overflow.addr);
 }
 
 static inline u64 mlx5e_get_mpwqe_offset(struct mlx5e_rq *rq, u16 wqe_ix)
@@ -360,6 +368,28 @@ static void mlx5e_rq_err_cqe_work(struct work_struct *recover_work)
        mlx5e_reporter_rq_cqe_err(rq);
 }
 
+static int mlx5e_alloc_mpwqe_rq_drop_page(struct mlx5e_rq *rq)
+{
+       rq->wqe_overflow.page = alloc_page(GFP_KERNEL);
+       if (!rq->wqe_overflow.page)
+               return -ENOMEM;
+
+       rq->wqe_overflow.addr = dma_map_page(rq->pdev, rq->wqe_overflow.page, 0,
+                                            PAGE_SIZE, rq->buff.map_dir);
+       if (dma_mapping_error(rq->pdev, rq->wqe_overflow.addr)) {
+               __free_page(rq->wqe_overflow.page);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void mlx5e_free_mpwqe_rq_drop_page(struct mlx5e_rq *rq)
+{
+        dma_unmap_page(rq->pdev, rq->wqe_overflow.addr, PAGE_SIZE,
+                       rq->buff.map_dir);
+        __free_page(rq->wqe_overflow.page);
+}
+
 static int mlx5e_alloc_rq(struct mlx5e_channel *c,
                          struct mlx5e_params *params,
                          struct mlx5e_xsk_param *xsk,
@@ -399,16 +429,16 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
 
        if (params->xdp_prog)
                bpf_prog_inc(params->xdp_prog);
-       rq->xdp_prog = params->xdp_prog;
+       RCU_INIT_POINTER(rq->xdp_prog, params->xdp_prog);
 
        rq_xdp_ix = rq->ix;
        if (xsk)
                rq_xdp_ix += params->num_channels * MLX5E_RQ_GROUP_XSK;
        err = xdp_rxq_info_reg(&rq->xdp_rxq, rq->netdev, rq_xdp_ix);
        if (err < 0)
-               goto err_rq_wq_destroy;
+               goto err_rq_xdp_prog;
 
-       rq->buff.map_dir = rq->xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
+       rq->buff.map_dir = params->xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
        rq->buff.headroom = mlx5e_get_rq_headroom(mdev, params, xsk);
        pool_size = 1 << params->log_rq_mtu_frames;
 
@@ -417,6 +447,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
                err = mlx5_wq_ll_create(mdev, &rqp->wq, rqc_wq, &rq->mpwqe.wq,
                                        &rq->wq_ctrl);
                if (err)
+                       goto err_rq_xdp;
+
+               err = mlx5e_alloc_mpwqe_rq_drop_page(rq);
+               if (err)
                        goto err_rq_wq_destroy;
 
                rq->mpwqe.wq.db = &rq->mpwqe.wq.db[MLX5_RCV_DBR];
@@ -434,18 +468,18 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
 
                err = mlx5e_create_rq_umr_mkey(mdev, rq);
                if (err)
-                       goto err_rq_wq_destroy;
+                       goto err_rq_drop_page;
                rq->mkey_be = cpu_to_be32(rq->umr_mkey.key);
 
                err = mlx5e_rq_alloc_mpwqe_info(rq, c);
                if (err)
-                       goto err_free;
+                       goto err_rq_mkey;
                break;
        default: /* MLX5_WQ_TYPE_CYCLIC */
                err = mlx5_wq_cyc_create(mdev, &rqp->wq, rqc_wq, &rq->wqe.wq,
                                         &rq->wq_ctrl);
                if (err)
-                       goto err_rq_wq_destroy;
+                       goto err_rq_xdp;
 
                rq->wqe.wq.db = &rq->wqe.wq.db[MLX5_RCV_DBR];
 
@@ -460,19 +494,19 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
                                      GFP_KERNEL, cpu_to_node(c->cpu));
                if (!rq->wqe.frags) {
                        err = -ENOMEM;
-                       goto err_free;
+                       goto err_rq_wq_destroy;
                }
 
                err = mlx5e_init_di_list(rq, wq_sz, c->cpu);
                if (err)
-                       goto err_free;
+                       goto err_rq_frags;
 
                rq->mkey_be = c->mkey_be;
        }
 
        err = mlx5e_rq_set_handlers(rq, params, xsk);
        if (err)
-               goto err_free;
+               goto err_free_by_rq_type;
 
        if (xsk) {
                err = xdp_rxq_info_reg_mem_model(&rq->xdp_rxq,
@@ -496,13 +530,13 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
                if (IS_ERR(rq->page_pool)) {
                        err = PTR_ERR(rq->page_pool);
                        rq->page_pool = NULL;
-                       goto err_free;
+                       goto err_free_by_rq_type;
                }
                err = xdp_rxq_info_reg_mem_model(&rq->xdp_rxq,
                                                 MEM_TYPE_PAGE_POOL, rq->page_pool);
        }
        if (err)
-               goto err_free;
+               goto err_free_by_rq_type;
 
        for (i = 0; i < wq_sz; i++) {
                if (rq->wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
@@ -552,38 +586,49 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
 
        return 0;
 
-err_free:
+err_free_by_rq_type:
        switch (rq->wq_type) {
        case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
                kvfree(rq->mpwqe.info);
+err_rq_mkey:
                mlx5_core_destroy_mkey(mdev, &rq->umr_mkey);
+err_rq_drop_page:
+               mlx5e_free_mpwqe_rq_drop_page(rq);
                break;
        default: /* MLX5_WQ_TYPE_CYCLIC */
-               kvfree(rq->wqe.frags);
                mlx5e_free_di_list(rq);
+err_rq_frags:
+               kvfree(rq->wqe.frags);
        }
-
 err_rq_wq_destroy:
-       if (rq->xdp_prog)
-               bpf_prog_put(rq->xdp_prog);
-       xdp_rxq_info_unreg(&rq->xdp_rxq);
-       page_pool_destroy(rq->page_pool);
        mlx5_wq_destroy(&rq->wq_ctrl);
+err_rq_xdp:
+       xdp_rxq_info_unreg(&rq->xdp_rxq);
+err_rq_xdp_prog:
+       if (params->xdp_prog)
+               bpf_prog_put(params->xdp_prog);
 
        return err;
 }
 
 static void mlx5e_free_rq(struct mlx5e_rq *rq)
 {
+       struct mlx5e_channel *c = rq->channel;
+       struct bpf_prog *old_prog = NULL;
        int i;
 
-       if (rq->xdp_prog)
-               bpf_prog_put(rq->xdp_prog);
+       /* drop_rq has neither channel nor xdp_prog. */
+       if (c)
+               old_prog = rcu_dereference_protected(rq->xdp_prog,
+                                                    lockdep_is_held(&c->priv->state_lock));
+       if (old_prog)
+               bpf_prog_put(old_prog);
 
        switch (rq->wq_type) {
        case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
                kvfree(rq->mpwqe.info);
                mlx5_core_destroy_mkey(rq->mdev, &rq->umr_mkey);
+               mlx5e_free_mpwqe_rq_drop_page(rq);
                break;
        default: /* MLX5_WQ_TYPE_CYCLIC */
                kvfree(rq->wqe.frags);
@@ -867,7 +912,7 @@ void mlx5e_activate_rq(struct mlx5e_rq *rq)
 void mlx5e_deactivate_rq(struct mlx5e_rq *rq)
 {
        clear_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
-       napi_synchronize(&rq->channel->napi); /* prevent mlx5e_post_rx_wqes */
+       synchronize_rcu(); /* Sync with NAPI to prevent mlx5e_post_rx_wqes. */
 }
 
 void mlx5e_close_rq(struct mlx5e_rq *rq)
@@ -1312,12 +1357,10 @@ void mlx5e_tx_disable_queue(struct netdev_queue *txq)
 
 static void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
 {
-       struct mlx5e_channel *c = sq->channel;
        struct mlx5_wq_cyc *wq = &sq->wq;
 
        clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
-       /* prevent netif_tx_wake_queue */
-       napi_synchronize(&c->napi);
+       synchronize_rcu(); /* Sync with NAPI to prevent netif_tx_wake_queue. */
 
        mlx5e_tx_disable_queue(sq->txq);
 
@@ -1392,10 +1435,8 @@ void mlx5e_activate_icosq(struct mlx5e_icosq *icosq)
 
 void mlx5e_deactivate_icosq(struct mlx5e_icosq *icosq)
 {
-       struct mlx5e_channel *c = icosq->channel;
-
        clear_bit(MLX5E_SQ_STATE_ENABLED, &icosq->state);
-       napi_synchronize(&c->napi);
+       synchronize_rcu(); /* Sync with NAPI. */
 }
 
 void mlx5e_close_icosq(struct mlx5e_icosq *sq)
@@ -1474,7 +1515,7 @@ void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq)
        struct mlx5e_channel *c = sq->channel;
 
        clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
-       napi_synchronize(&c->napi);
+       synchronize_rcu(); /* Sync with NAPI. */
 
        mlx5e_destroy_sq(c->mdev, sq->sqn);
        mlx5e_free_xdpsq_descs(sq);
@@ -3567,6 +3608,7 @@ void mlx5e_fold_sw_stats64(struct mlx5e_priv *priv, struct rtnl_link_stats64 *s)
 
                s->rx_packets   += rq_stats->packets + xskrq_stats->packets;
                s->rx_bytes     += rq_stats->bytes + xskrq_stats->bytes;
+               s->multicast    += rq_stats->mcast_packets + xskrq_stats->mcast_packets;
 
                for (j = 0; j < priv->max_opened_tc; j++) {
                        struct mlx5e_sq_stats *sq_stats = &channel_stats->sq[j];
@@ -3582,7 +3624,6 @@ void
 mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
-       struct mlx5e_vport_stats *vstats = &priv->stats.vport;
        struct mlx5e_pport_stats *pstats = &priv->stats.pport;
 
        /* In switchdev mode, monitor counters doesn't monitor
@@ -3617,12 +3658,6 @@ mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
        stats->rx_errors = stats->rx_length_errors + stats->rx_crc_errors +
                           stats->rx_frame_errors;
        stats->tx_errors = stats->tx_aborted_errors + stats->tx_carrier_errors;
-
-       /* vport multicast also counts packets that are dropped due to steering
-        * or rx out of buffer
-        */
-       stats->multicast =
-               VPORT_COUNTER_GET(vstats, received_eth_multicast.packets);
 }
 
 static void mlx5e_set_rx_mode(struct net_device *dev)
@@ -4191,6 +4226,21 @@ int mlx5e_get_vf_stats(struct net_device *dev,
 }
 #endif
 
+static bool mlx5e_gre_tunnel_inner_proto_offload_supported(struct mlx5_core_dev *mdev,
+                                                          struct sk_buff *skb)
+{
+       switch (skb->inner_protocol) {
+       case htons(ETH_P_IP):
+       case htons(ETH_P_IPV6):
+       case htons(ETH_P_TEB):
+               return true;
+       case htons(ETH_P_MPLS_UC):
+       case htons(ETH_P_MPLS_MC):
+               return MLX5_CAP_ETH(mdev, tunnel_stateless_mpls_over_gre);
+       }
+       return false;
+}
+
 static netdev_features_t mlx5e_tunnel_features_check(struct mlx5e_priv *priv,
                                                     struct sk_buff *skb,
                                                     netdev_features_t features)
@@ -4213,7 +4263,9 @@ static netdev_features_t mlx5e_tunnel_features_check(struct mlx5e_priv *priv,
 
        switch (proto) {
        case IPPROTO_GRE:
-               return features;
+               if (mlx5e_gre_tunnel_inner_proto_offload_supported(priv->mdev, skb))
+                       return features;
+               break;
        case IPPROTO_IPIP:
        case IPPROTO_IPV6:
                if (mlx5e_tunnel_proto_supported(priv->mdev, IPPROTO_IPIP))
@@ -4330,6 +4382,16 @@ static int mlx5e_xdp_allowed(struct mlx5e_priv *priv, struct bpf_prog *prog)
        return 0;
 }
 
+static void mlx5e_rq_replace_xdp_prog(struct mlx5e_rq *rq, struct bpf_prog *prog)
+{
+       struct bpf_prog *old_prog;
+
+       old_prog = rcu_replace_pointer(rq->xdp_prog, prog,
+                                      lockdep_is_held(&rq->channel->priv->state_lock));
+       if (old_prog)
+               bpf_prog_put(old_prog);
+}
+
 static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -4388,29 +4450,10 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog)
         */
        for (i = 0; i < priv->channels.num; i++) {
                struct mlx5e_channel *c = priv->channels.c[i];
-               bool xsk_open = test_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
-
-               clear_bit(MLX5E_RQ_STATE_ENABLED, &c->rq.state);
-               if (xsk_open)
-                       clear_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
-               napi_synchronize(&c->napi);
-               /* prevent mlx5e_poll_rx_cq from accessing rq->xdp_prog */
-
-               old_prog = xchg(&c->rq.xdp_prog, prog);
-               if (old_prog)
-                       bpf_prog_put(old_prog);
-
-               if (xsk_open) {
-                       old_prog = xchg(&c->xskrq.xdp_prog, prog);
-                       if (old_prog)
-                               bpf_prog_put(old_prog);
-               }
 
-               set_bit(MLX5E_RQ_STATE_ENABLED, &c->rq.state);
-               if (xsk_open)
-                       set_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
-               /* napi_schedule in case we have missed anything */
-               napi_schedule(&c->napi);
+               mlx5e_rq_replace_xdp_prog(&c->rq, prog);
+               if (test_bit(MLX5E_CHANNEL_STATE_XSK, c->state))
+                       mlx5e_rq_replace_xdp_prog(&c->xskrq, prog);
        }
 
 unlock:
@@ -5200,7 +5243,7 @@ static const struct mlx5e_profile mlx5e_nic_profile = {
        .enable            = mlx5e_nic_enable,
        .disable           = mlx5e_nic_disable,
        .update_rx         = mlx5e_update_nic_rx,
-       .update_stats      = mlx5e_update_ndo_stats,
+       .update_stats      = mlx5e_stats_update_ndo_stats,
        .update_carrier    = mlx5e_update_carrier,
        .rx_handlers       = &mlx5e_rx_handlers_nic,
        .max_tc            = MLX5E_MAX_NUM_TC,
index e13e5d1..e979bff 100644 (file)
@@ -1171,7 +1171,7 @@ static const struct mlx5e_profile mlx5e_rep_profile = {
        .cleanup_tx             = mlx5e_cleanup_rep_tx,
        .enable                 = mlx5e_rep_enable,
        .update_rx              = mlx5e_update_rep_rx,
-       .update_stats           = mlx5e_update_ndo_stats,
+       .update_stats           = mlx5e_stats_update_ndo_stats,
        .rx_handlers            = &mlx5e_rx_handlers_rep,
        .max_tc                 = 1,
        .rq_groups              = MLX5E_NUM_RQ_GROUPS(REGULAR),
@@ -1189,7 +1189,7 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
        .enable                 = mlx5e_uplink_rep_enable,
        .disable                = mlx5e_uplink_rep_disable,
        .update_rx              = mlx5e_update_rep_rx,
-       .update_stats           = mlx5e_update_ndo_stats,
+       .update_stats           = mlx5e_stats_update_ndo_stats,
        .update_carrier         = mlx5e_update_carrier,
        .rx_handlers            = &mlx5e_rx_handlers_rep,
        .max_tc                 = MLX5E_MAX_NUM_TC,
index 622c27a..0d1562e 100644 (file)
@@ -135,12 +135,6 @@ struct mlx5e_neigh_hash_entry {
        /* encap list sharing the same neigh */
        struct list_head encap_list;
 
-       /* valid only when the neigh reference is taken during
-        * neigh_update_work workqueue callback.
-        */
-       struct neighbour *n;
-       struct work_struct neigh_update_work;
-
        /* neigh hash entry can be deleted only when the refcount is zero.
         * refcount is needed to avoid neigh hash entry removal by TC, while
         * it's used by the neigh notification call.
index 65828af..64c8ac5 100644 (file)
@@ -53,6 +53,7 @@
 #include "en/xsk/rx.h"
 #include "en/health.h"
 #include "en/params.h"
+#include "en/txrx.h"
 
 static struct sk_buff *
 mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
@@ -1080,6 +1081,9 @@ static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
                mlx5e_enable_ecn(rq, skb);
 
        skb->protocol = eth_type_trans(skb, netdev);
+
+       if (unlikely(mlx5e_skb_is_multicast(skb)))
+               stats->mcast_packets++;
 }
 
 static inline void mlx5e_complete_rx_cqe(struct mlx5e_rq *rq,
@@ -1132,7 +1136,6 @@ mlx5e_skb_from_cqe_linear(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
        struct xdp_buff xdp;
        struct sk_buff *skb;
        void *va, *data;
-       bool consumed;
        u32 frag_size;
 
        va             = page_address(di->page) + wi->offset;
@@ -1144,11 +1147,8 @@ mlx5e_skb_from_cqe_linear(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
        prefetchw(va); /* xdp_frame data area */
        prefetch(data);
 
-       rcu_read_lock();
        mlx5e_fill_xdp_buff(rq, va, rx_headroom, cqe_bcnt, &xdp);
-       consumed = mlx5e_xdp_handle(rq, di, &cqe_bcnt, &xdp);
-       rcu_read_unlock();
-       if (consumed)
+       if (mlx5e_xdp_handle(rq, di, &cqe_bcnt, &xdp))
                return NULL; /* page/packet was consumed by XDP */
 
        rx_headroom = xdp.data - xdp.data_hard_start;
@@ -1438,7 +1438,6 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
        struct sk_buff *skb;
        void *va, *data;
        u32 frag_size;
-       bool consumed;
 
        /* Check packet size. Note LRO doesn't use linear SKB */
        if (unlikely(cqe_bcnt > rq->hw_mtu)) {
@@ -1455,11 +1454,8 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
        prefetchw(va); /* xdp_frame data area */
        prefetch(data);
 
-       rcu_read_lock();
        mlx5e_fill_xdp_buff(rq, va, rx_headroom, cqe_bcnt32, &xdp);
-       consumed = mlx5e_xdp_handle(rq, di, &cqe_bcnt32, &xdp);
-       rcu_read_unlock();
-       if (consumed) {
+       if (mlx5e_xdp_handle(rq, di, &cqe_bcnt32, &xdp)) {
                if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags))
                        __set_bit(page_idx, wi->xdp_xmit_bitmap); /* non-atomic */
                return NULL; /* page/packet was consumed by XDP */
index e3b2f59..f6383bc 100644 (file)
@@ -54,6 +54,18 @@ unsigned int mlx5e_stats_total_num(struct mlx5e_priv *priv)
        return total;
 }
 
+void mlx5e_stats_update_ndo_stats(struct mlx5e_priv *priv)
+{
+       mlx5e_stats_grp_t *stats_grps = priv->profile->stats_grps;
+       const unsigned int num_stats_grps = stats_grps_num(priv);
+       int i;
+
+       for (i = num_stats_grps - 1; i >= 0; i--)
+               if (stats_grps[i]->update_stats &&
+                   stats_grps[i]->update_stats_mask & MLX5E_NDO_UPDATE_STATS)
+                       stats_grps[i]->update_stats(priv);
+}
+
 void mlx5e_stats_update(struct mlx5e_priv *priv)
 {
        mlx5e_stats_grp_t *stats_grps = priv->profile->stats_grps;
index 2e1cca1..562263d 100644 (file)
@@ -103,6 +103,7 @@ unsigned int mlx5e_stats_total_num(struct mlx5e_priv *priv);
 void mlx5e_stats_update(struct mlx5e_priv *priv);
 void mlx5e_stats_fill(struct mlx5e_priv *priv, u64 *data, int idx);
 void mlx5e_stats_fill_strings(struct mlx5e_priv *priv, u8 *data);
+void mlx5e_stats_update_ndo_stats(struct mlx5e_priv *priv);
 
 /* Concrete NIC Stats */
 
@@ -119,6 +120,7 @@ struct mlx5e_sw_stats {
        u64 tx_nop;
        u64 rx_lro_packets;
        u64 rx_lro_bytes;
+       u64 rx_mcast_packets;
        u64 rx_ecn_mark;
        u64 rx_removed_vlan_packets;
        u64 rx_csum_unnecessary;
@@ -298,6 +300,7 @@ struct mlx5e_rq_stats {
        u64 csum_none;
        u64 lro_packets;
        u64 lro_bytes;
+       u64 mcast_packets;
        u64 ecn_mark;
        u64 removed_vlan_packets;
        u64 xdp_drop;
index fd53d10..1c93f92 100644 (file)
@@ -1290,11 +1290,8 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
 
        mlx5e_put_flow_tunnel_id(flow);
 
-       if (flow_flag_test(flow, NOT_READY)) {
+       if (flow_flag_test(flow, NOT_READY))
                remove_unready_flow(flow);
-               kvfree(attr->parse_attr);
-               return;
-       }
 
        if (mlx5e_is_offloaded_flow(flow)) {
                if (flow_flag_test(flow, SLOW))
@@ -1315,6 +1312,8 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
                }
        kvfree(attr->parse_attr);
 
+       mlx5_tc_ct_match_del(priv, &flow->esw_attr->ct_attr);
+
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
                mlx5e_detach_mod_hdr(priv, flow);
 
@@ -2625,6 +2624,22 @@ static struct mlx5_fields fields[] = {
        OFFLOAD(UDP_DPORT, 16, U16_MAX, udp.dest,   0, udp_dport),
 };
 
+static unsigned long mask_to_le(unsigned long mask, int size)
+{
+       __be32 mask_be32;
+       __be16 mask_be16;
+
+       if (size == 32) {
+               mask_be32 = (__force __be32)(mask);
+               mask = (__force unsigned long)cpu_to_le32(be32_to_cpu(mask_be32));
+       } else if (size == 16) {
+               mask_be32 = (__force __be32)(mask);
+               mask_be16 = *(__be16 *)&mask_be32;
+               mask = (__force unsigned long)cpu_to_le16(be16_to_cpu(mask_be16));
+       }
+
+       return mask;
+}
 static int offload_pedit_fields(struct mlx5e_priv *priv,
                                int namespace,
                                struct pedit_headers_action *hdrs,
@@ -2638,9 +2653,7 @@ static int offload_pedit_fields(struct mlx5e_priv *priv,
        u32 *s_masks_p, *a_masks_p, s_mask, a_mask;
        struct mlx5e_tc_mod_hdr_acts *mod_acts;
        struct mlx5_fields *f;
-       unsigned long mask;
-       __be32 mask_be32;
-       __be16 mask_be16;
+       unsigned long mask, field_mask;
        int err;
        u8 cmd;
 
@@ -2706,14 +2719,7 @@ static int offload_pedit_fields(struct mlx5e_priv *priv,
                if (skip)
                        continue;
 
-               if (f->field_bsize == 32) {
-                       mask_be32 = (__force __be32)(mask);
-                       mask = (__force unsigned long)cpu_to_le32(be32_to_cpu(mask_be32));
-               } else if (f->field_bsize == 16) {
-                       mask_be32 = (__force __be32)(mask);
-                       mask_be16 = *(__be16 *)&mask_be32;
-                       mask = (__force unsigned long)cpu_to_le16(be16_to_cpu(mask_be16));
-               }
+               mask = mask_to_le(mask, f->field_bsize);
 
                first = find_first_bit(&mask, f->field_bsize);
                next_z = find_next_zero_bit(&mask, f->field_bsize, first);
@@ -2744,9 +2750,10 @@ static int offload_pedit_fields(struct mlx5e_priv *priv,
                if (cmd == MLX5_ACTION_TYPE_SET) {
                        int start;
 
+                       field_mask = mask_to_le(f->field_mask, f->field_bsize);
+
                        /* if field is bit sized it can start not from first bit */
-                       start = find_first_bit((unsigned long *)&f->field_mask,
-                                              f->field_bsize);
+                       start = find_first_bit(&field_mask, f->field_bsize);
 
                        MLX5_SET(set_action_in, action, offset, first - start);
                        /* length is num of bits to be written, zero means length of 32 */
@@ -4402,8 +4409,8 @@ __mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
                goto err_free;
 
        /* actions validation depends on parsing the ct matches first */
-       err = mlx5_tc_ct_parse_match(priv, &parse_attr->spec, f,
-                                    &flow->esw_attr->ct_attr, extack);
+       err = mlx5_tc_ct_match_add(priv, &parse_attr->spec, f,
+                                  &flow->esw_attr->ct_attr, extack);
        if (err)
                goto err_free;
 
index de10b06..d586867 100644 (file)
@@ -121,13 +121,17 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
        struct mlx5e_xdpsq *xsksq = &c->xsksq;
        struct mlx5e_rq *xskrq = &c->xskrq;
        struct mlx5e_rq *rq = &c->rq;
-       bool xsk_open = test_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
        bool aff_change = false;
        bool busy_xsk = false;
        bool busy = false;
        int work_done = 0;
+       bool xsk_open;
        int i;
 
+       rcu_read_lock();
+
+       xsk_open = test_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
+
        ch_stats->poll++;
 
        for (i = 0; i < c->num_tc; i++)
@@ -167,8 +171,10 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
        busy |= busy_xsk;
 
        if (busy) {
-               if (likely(mlx5e_channel_no_affinity_change(c)))
-                       return budget;
+               if (likely(mlx5e_channel_no_affinity_change(c))) {
+                       work_done = budget;
+                       goto out;
+               }
                ch_stats->aff_change++;
                aff_change = true;
                if (budget && work_done == budget)
@@ -176,7 +182,7 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
        }
 
        if (unlikely(!napi_complete_done(napi, work_done)))
-               return work_done;
+               goto out;
 
        ch_stats->arm++;
 
@@ -203,6 +209,9 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
                ch_stats->force_irq++;
        }
 
+out:
+       rcu_read_unlock();
+
        return work_done;
 }
 
index 31ef9f8..22a19d3 100644 (file)
@@ -189,6 +189,29 @@ u32 mlx5_eq_poll_irq_disabled(struct mlx5_eq_comp *eq)
        return count_eqe;
 }
 
+static void mlx5_eq_async_int_lock(struct mlx5_eq_async *eq, unsigned long *flags)
+       __acquires(&eq->lock)
+{
+       if (in_irq())
+               spin_lock(&eq->lock);
+       else
+               spin_lock_irqsave(&eq->lock, *flags);
+}
+
+static void mlx5_eq_async_int_unlock(struct mlx5_eq_async *eq, unsigned long *flags)
+       __releases(&eq->lock)
+{
+       if (in_irq())
+               spin_unlock(&eq->lock);
+       else
+               spin_unlock_irqrestore(&eq->lock, *flags);
+}
+
+enum async_eq_nb_action {
+       ASYNC_EQ_IRQ_HANDLER = 0,
+       ASYNC_EQ_RECOVER = 1,
+};
+
 static int mlx5_eq_async_int(struct notifier_block *nb,
                             unsigned long action, void *data)
 {
@@ -198,11 +221,14 @@ static int mlx5_eq_async_int(struct notifier_block *nb,
        struct mlx5_eq_table *eqt;
        struct mlx5_core_dev *dev;
        struct mlx5_eqe *eqe;
+       unsigned long flags;
        int num_eqes = 0;
 
        dev = eq->dev;
        eqt = dev->priv.eq_table;
 
+       mlx5_eq_async_int_lock(eq_async, &flags);
+
        eqe = next_eqe_sw(eq);
        if (!eqe)
                goto out;
@@ -223,8 +249,19 @@ static int mlx5_eq_async_int(struct notifier_block *nb,
 
 out:
        eq_update_ci(eq, 1);
+       mlx5_eq_async_int_unlock(eq_async, &flags);
 
-       return 0;
+       return unlikely(action == ASYNC_EQ_RECOVER) ? num_eqes : 0;
+}
+
+void mlx5_cmd_eq_recover(struct mlx5_core_dev *dev)
+{
+       struct mlx5_eq_async *eq = &dev->priv.eq_table->cmd_eq;
+       int eqes;
+
+       eqes = mlx5_eq_async_int(&eq->irq_nb, ASYNC_EQ_RECOVER, NULL);
+       if (eqes)
+               mlx5_core_warn(dev, "Recovered %d EQEs on cmd_eq\n", eqes);
 }
 
 static void init_eq_buf(struct mlx5_eq *eq)
@@ -569,6 +606,7 @@ setup_async_eq(struct mlx5_core_dev *dev, struct mlx5_eq_async *eq,
        int err;
 
        eq->irq_nb.notifier_call = mlx5_eq_async_int;
+       spin_lock_init(&eq->lock);
 
        err = create_async_eq(dev, &eq->core, param);
        if (err) {
@@ -656,8 +694,10 @@ static void destroy_async_eqs(struct mlx5_core_dev *dev)
 
        cleanup_async_eq(dev, &table->pages_eq, "pages");
        cleanup_async_eq(dev, &table->async_eq, "async");
+       mlx5_cmd_allowed_opcode(dev, MLX5_CMD_OP_DESTROY_EQ);
        mlx5_cmd_use_polling(dev);
        cleanup_async_eq(dev, &table->cmd_eq, "cmd");
+       mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL);
        mlx5_eq_notifier_unregister(dev, &table->cq_err_nb);
 }
 
index d251692..1bcf260 100644 (file)
@@ -1219,35 +1219,37 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
        }
        esw->fdb_table.offloads.send_to_vport_grp = g;
 
-       /* create peer esw miss group */
-       memset(flow_group_in, 0, inlen);
+       if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
+               /* create peer esw miss group */
+               memset(flow_group_in, 0, inlen);
 
-       esw_set_flow_group_source_port(esw, flow_group_in);
+               esw_set_flow_group_source_port(esw, flow_group_in);
 
-       if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) {
-               match_criteria = MLX5_ADDR_OF(create_flow_group_in,
-                                             flow_group_in,
-                                             match_criteria);
+               if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+                       match_criteria = MLX5_ADDR_OF(create_flow_group_in,
+                                                     flow_group_in,
+                                                     match_criteria);
 
-               MLX5_SET_TO_ONES(fte_match_param, match_criteria,
-                                misc_parameters.source_eswitch_owner_vhca_id);
+                       MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+                                        misc_parameters.source_eswitch_owner_vhca_id);
 
-               MLX5_SET(create_flow_group_in, flow_group_in,
-                        source_eswitch_owner_vhca_id_valid, 1);
-       }
+                       MLX5_SET(create_flow_group_in, flow_group_in,
+                                source_eswitch_owner_vhca_id_valid, 1);
+               }
 
-       MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
-       MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
-                ix + esw->total_vports - 1);
-       ix += esw->total_vports;
+               MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
+               MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
+                        ix + esw->total_vports - 1);
+               ix += esw->total_vports;
 
-       g = mlx5_create_flow_group(fdb, flow_group_in);
-       if (IS_ERR(g)) {
-               err = PTR_ERR(g);
-               esw_warn(dev, "Failed to create peer miss flow group err(%d)\n", err);
-               goto peer_miss_err;
+               g = mlx5_create_flow_group(fdb, flow_group_in);
+               if (IS_ERR(g)) {
+                       err = PTR_ERR(g);
+                       esw_warn(dev, "Failed to create peer miss flow group err(%d)\n", err);
+                       goto peer_miss_err;
+               }
+               esw->fdb_table.offloads.peer_miss_grp = g;
        }
-       esw->fdb_table.offloads.peer_miss_grp = g;
 
        /* create miss group */
        memset(flow_group_in, 0, inlen);
@@ -1281,7 +1283,8 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
 miss_rule_err:
        mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
 miss_err:
-       mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
+       if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
+               mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
 peer_miss_err:
        mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
 send_vport_err:
@@ -1305,7 +1308,8 @@ static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
        mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
        mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
        mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
-       mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
+       if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
+               mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
        mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
 
        mlx5_esw_chains_destroy(esw);
index 9ccec5f..75fa44e 100644 (file)
@@ -654,7 +654,7 @@ static struct fs_fte *alloc_fte(struct mlx5_flow_table *ft,
        fte->action = *flow_act;
        fte->flow_context = spec->flow_context;
 
-       tree_init_node(&fte->node, NULL, del_sw_fte);
+       tree_init_node(&fte->node, del_hw_fte, del_sw_fte);
 
        return fte;
 }
@@ -1792,7 +1792,6 @@ skip_search:
                up_write_ref_node(&g->node, false);
                rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
                up_write_ref_node(&fte->node, false);
-               tree_put_node(&fte->node, false);
                return rule;
        }
        rule = ERR_PTR(-ENOENT);
@@ -1891,7 +1890,6 @@ search_again_locked:
        up_write_ref_node(&g->node, false);
        rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
        up_write_ref_node(&fte->node, false);
-       tree_put_node(&fte->node, false);
        tree_put_node(&g->node, false);
        return rule;
 
@@ -2001,7 +1999,9 @@ void mlx5_del_flow_rules(struct mlx5_flow_handle *handle)
                up_write_ref_node(&fte->node, false);
        } else {
                del_hw_fte(&fte->node);
-               up_write(&fte->node.lock);
+               /* Avoid double call to del_hw_fte */
+               fte->node.del_hw_func = NULL;
+               up_write_ref_node(&fte->node, false);
                tree_put_node(&fte->node, false);
        }
        kfree(handle);
index 4aaca74..5c681e3 100644 (file)
@@ -37,6 +37,7 @@ struct mlx5_eq {
 struct mlx5_eq_async {
        struct mlx5_eq          core;
        struct notifier_block   irq_nb;
+       spinlock_t              lock; /* To avoid irq EQ handle races with resiliency flows */
 };
 
 struct mlx5_eq_comp {
@@ -81,6 +82,7 @@ void mlx5_cq_tasklet_cb(unsigned long data);
 struct cpumask *mlx5_eq_comp_cpumask(struct mlx5_core_dev *dev, int ix);
 
 u32 mlx5_eq_poll_irq_disabled(struct mlx5_eq_comp *eq);
+void mlx5_cmd_eq_recover(struct mlx5_core_dev *dev);
 void mlx5_eq_synchronize_async_irq(struct mlx5_core_dev *dev);
 void mlx5_eq_synchronize_cmd_irq(struct mlx5_core_dev *dev);
 
index f9b798a..c0e18f2 100644 (file)
@@ -432,7 +432,7 @@ static int reclaim_pages_cmd(struct mlx5_core_dev *dev,
        u32 npages;
        u32 i = 0;
 
-       if (dev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR)
+       if (!mlx5_cmd_is_down(dev))
                return mlx5_cmd_exec(dev, in, in_size, out, out_size);
 
        /* No hard feelings, we want our pages back! */
index 373981a..6fd9749 100644 (file)
@@ -115,7 +115,7 @@ static int request_irqs(struct mlx5_core_dev *dev, int nvec)
        return 0;
 
 err_request_irq:
-       for (; i >= 0; i--) {
+       while (i--) {
                struct mlx5_irq *irq = mlx5_irq_get(dev, i);
                int irqn = pci_irq_vector(dev->pdev, i);
 
index 7a04c62..bcd1669 100644 (file)
@@ -72,7 +72,7 @@ static int mlxfw_fsm_state_err(struct mlxfw_dev *mlxfw_dev,
        case MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET:
                MLXFW_ERR_MSG(mlxfw_dev, extack, "pending reset", err);
                break;
-       case MLXFW_FSM_STATE_ERR_OK: /* fall through */
+       case MLXFW_FSM_STATE_ERR_OK:
        case MLXFW_FSM_STATE_ERR_MAX:
                MLXFW_ERR_MSG(mlxfw_dev, extack, "unknown error", err);
                break;
@@ -155,7 +155,7 @@ mlxfw_fsm_reactivate_err(struct mlxfw_dev *mlxfw_dev,
        case MLXFW_FSM_REACTIVATE_STATUS_FW_ALREADY_ACTIVATED:
                MLXFW_REACT_ERR("fw already activated", err);
                break;
-       case MLXFW_FSM_REACTIVATE_STATUS_OK: /* fall through */
+       case MLXFW_FSM_REACTIVATE_STATUS_OK:
        case MLXFW_FSM_REACTIVATE_STATUS_MAX:
                MLXFW_REACT_ERR("unexpected error", err);
                break;
index 08d1011..ec45a03 100644 (file)
@@ -2289,21 +2289,21 @@ int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module)
        /* Here we need to get the module width according to the module type. */
 
        switch (module_type) {
-       case MLXSW_REG_PMTM_MODULE_TYPE_C2C8X: /* fall through */
-       case MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD: /* fall through */
+       case MLXSW_REG_PMTM_MODULE_TYPE_C2C8X:
+       case MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD:
        case MLXSW_REG_PMTM_MODULE_TYPE_OSFP:
                return 8;
-       case MLXSW_REG_PMTM_MODULE_TYPE_C2C4X: /* fall through */
-       case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X: /* fall through */
+       case MLXSW_REG_PMTM_MODULE_TYPE_C2C4X:
+       case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X:
        case MLXSW_REG_PMTM_MODULE_TYPE_QSFP:
                return 4;
-       case MLXSW_REG_PMTM_MODULE_TYPE_C2C2X: /* fall through */
-       case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X: /* fall through */
-       case MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD: /* fall through */
+       case MLXSW_REG_PMTM_MODULE_TYPE_C2C2X:
+       case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X:
+       case MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD:
        case MLXSW_REG_PMTM_MODULE_TYPE_DSFP:
                return 2;
-       case MLXSW_REG_PMTM_MODULE_TYPE_C2C1X: /* fall through */
-       case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X: /* fall through */
+       case MLXSW_REG_PMTM_MODULE_TYPE_C2C1X:
+       case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X:
        case MLXSW_REG_PMTM_MODULE_TYPE_SFP:
                return 1;
        default:
index 44fa02c..056eeb8 100644 (file)
@@ -30,8 +30,8 @@ static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
        case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
                *qsfp = false;
                break;
-       case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: /* fall-through */
-       case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */
+       case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
+       case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS:
        case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
                *qsfp = true;
                break;
@@ -205,7 +205,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module,
                modinfo->type       = ETH_MODULE_SFF_8436;
                modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
                break;
-       case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */
+       case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS:
        case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
                if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 ||
                    module_rev_id >=
index 3fe878d..61719ec 100644 (file)
@@ -259,8 +259,8 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev,
                 */
                fault = 1;
                break;
-       case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
-       case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
+       case MLXSW_REG_MTBR_NO_CONN:
+       case MLXSW_REG_MTBR_NO_TEMP_SENS:
        case MLXSW_REG_MTBR_INDEX_NA:
        default:
                fault = 0;
index fdf9aa8..f3c0e24 100644 (file)
@@ -517,8 +517,8 @@ enum mlxsw_reg_spms_state mlxsw_sp_stp_spms_state(u8 state)
                return MLXSW_REG_SPMS_STATE_FORWARDING;
        case BR_STATE_LEARNING:
                return MLXSW_REG_SPMS_STATE_LEARNING;
-       case BR_STATE_LISTENING: /* fall-through */
-       case BR_STATE_DISABLED: /* fall-through */
+       case BR_STATE_LISTENING:
+       case BR_STATE_DISABLED:
        case BR_STATE_BLOCKING:
                return MLXSW_REG_SPMS_STATE_DISCARDING;
        default:
@@ -3690,13 +3690,13 @@ bool mlxsw_sp_port_dev_check(const struct net_device *dev)
        return dev->netdev_ops == &mlxsw_sp_port_netdev_ops;
 }
 
-static int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev, void *data)
+static int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev,
+                                  struct netdev_nested_priv *priv)
 {
-       struct mlxsw_sp_port **p_mlxsw_sp_port = data;
        int ret = 0;
 
        if (mlxsw_sp_port_dev_check(lower_dev)) {
-               *p_mlxsw_sp_port = netdev_priv(lower_dev);
+               priv->data = (void *)netdev_priv(lower_dev);
                ret = 1;
        }
 
@@ -3705,15 +3705,16 @@ static int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev, void *data)
 
 struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev)
 {
-       struct mlxsw_sp_port *mlxsw_sp_port;
+       struct netdev_nested_priv priv = {
+               .data = NULL,
+       };
 
        if (mlxsw_sp_port_dev_check(dev))
                return netdev_priv(dev);
 
-       mlxsw_sp_port = NULL;
-       netdev_walk_all_lower_dev(dev, mlxsw_sp_lower_dev_walk, &mlxsw_sp_port);
+       netdev_walk_all_lower_dev(dev, mlxsw_sp_lower_dev_walk, &priv);
 
-       return mlxsw_sp_port;
+       return (struct mlxsw_sp_port *)priv.data;
 }
 
 struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev)
@@ -3726,16 +3727,17 @@ struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev)
 
 struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev)
 {
-       struct mlxsw_sp_port *mlxsw_sp_port;
+       struct netdev_nested_priv priv = {
+               .data = NULL,
+       };
 
        if (mlxsw_sp_port_dev_check(dev))
                return netdev_priv(dev);
 
-       mlxsw_sp_port = NULL;
        netdev_walk_all_lower_dev_rcu(dev, mlxsw_sp_lower_dev_walk,
-                                     &mlxsw_sp_port);
+                                     &priv);
 
-       return mlxsw_sp_port;
+       return (struct mlxsw_sp_port *)priv.data;
 }
 
 struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev)
index f9ba596..5240bf1 100644 (file)
@@ -636,11 +636,11 @@ static inline unsigned int
 mlxsw_sp_kvdl_entry_size(enum mlxsw_sp_kvdl_entry_type type)
 {
        switch (type) {
-       case MLXSW_SP_KVDL_ENTRY_TYPE_ADJ: /* fall through */
-       case MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET: /* fall through */
-       case MLXSW_SP_KVDL_ENTRY_TYPE_PBS: /* fall through */
-       case MLXSW_SP_KVDL_ENTRY_TYPE_MCRIGR: /* fall through */
-       case MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT: /* fall through */
+       case MLXSW_SP_KVDL_ENTRY_TYPE_ADJ:
+       case MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET:
+       case MLXSW_SP_KVDL_ENTRY_TYPE_PBS:
+       case MLXSW_SP_KVDL_ENTRY_TYPE_MCRIGR:
+       case MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT:
        default:
                return 1;
        }
index 5c02040..7cccc41 100644 (file)
@@ -292,13 +292,14 @@ mlxsw_sp_acl_tcam_group_add(struct mlxsw_sp_acl_tcam *tcam,
        int err;
 
        group->tcam = tcam;
-       mutex_init(&group->lock);
        INIT_LIST_HEAD(&group->region_list);
 
        err = mlxsw_sp_acl_tcam_group_id_get(tcam, &group->id);
        if (err)
                return err;
 
+       mutex_init(&group->lock);
+
        return 0;
 }
 
index 0521e9d..460cb52 100644 (file)
@@ -1164,7 +1164,7 @@ mlxsw_sp_router_ip2me_fib_entry_find(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
                addr_len = 4;
                addr_prefix_len = 32;
                break;
-       case MLXSW_SP_L3_PROTO_IPV6: /* fall through */
+       case MLXSW_SP_L3_PROTO_IPV6:
        default:
                WARN_ON(1);
                return NULL;
@@ -4555,14 +4555,14 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
                        fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
                        return 0;
                }
-               /* fall through */
+               fallthrough;
        case RTN_BROADCAST:
                fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
                return 0;
        case RTN_BLACKHOLE:
                fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE;
                return 0;
-       case RTN_UNREACHABLE: /* fall through */
+       case RTN_UNREACHABLE:
        case RTN_PROHIBIT:
                /* Packets hitting these routes need to be trapped, but
                 * can do so with a lower priority than packets directed
@@ -5990,7 +5990,7 @@ static void mlxsw_sp_router_fib4_event_work(struct work_struct *work)
                mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info);
                fib_info_put(fib_work->fen_info.fi);
                break;
-       case FIB_EVENT_NH_ADD: /* fall through */
+       case FIB_EVENT_NH_ADD:
        case FIB_EVENT_NH_DEL:
                mlxsw_sp_nexthop4_event(mlxsw_sp, fib_work->event,
                                        fib_work->fnh_info.fib_nh);
@@ -6050,7 +6050,7 @@ static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work)
        rtnl_lock();
        mutex_lock(&mlxsw_sp->router->lock);
        switch (fib_work->event) {
-       case FIB_EVENT_ENTRY_REPLACE: /* fall through */
+       case FIB_EVENT_ENTRY_REPLACE:
        case FIB_EVENT_ENTRY_ADD:
                replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
 
@@ -6089,7 +6089,7 @@ static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work *fib_work,
        struct fib_nh_notifier_info *fnh_info;
 
        switch (fib_work->event) {
-       case FIB_EVENT_ENTRY_REPLACE: /* fall through */
+       case FIB_EVENT_ENTRY_REPLACE:
        case FIB_EVENT_ENTRY_DEL:
                fen_info = container_of(info, struct fib_entry_notifier_info,
                                        info);
@@ -6099,7 +6099,7 @@ static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work *fib_work,
                 */
                fib_info_hold(fib_work->fen_info.fi);
                break;
-       case FIB_EVENT_NH_ADD: /* fall through */
+       case FIB_EVENT_NH_ADD:
        case FIB_EVENT_NH_DEL:
                fnh_info = container_of(info, struct fib_nh_notifier_info,
                                        info);
@@ -6116,8 +6116,8 @@ static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
        int err;
 
        switch (fib_work->event) {
-       case FIB_EVENT_ENTRY_REPLACE: /* fall through */
-       case FIB_EVENT_ENTRY_APPEND: /* fall through */
+       case FIB_EVENT_ENTRY_REPLACE:
+       case FIB_EVENT_ENTRY_APPEND:
        case FIB_EVENT_ENTRY_DEL:
                fen6_info = container_of(info, struct fib6_entry_notifier_info,
                                         info);
@@ -6136,13 +6136,13 @@ mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event_work *fib_work,
                            struct fib_notifier_info *info)
 {
        switch (fib_work->event) {
-       case FIB_EVENT_ENTRY_REPLACE: /* fall through */
-       case FIB_EVENT_ENTRY_ADD: /* fall through */
+       case FIB_EVENT_ENTRY_REPLACE:
+       case FIB_EVENT_ENTRY_ADD:
        case FIB_EVENT_ENTRY_DEL:
                memcpy(&fib_work->men_info, info, sizeof(fib_work->men_info));
                mr_cache_hold(fib_work->men_info.mfc);
                break;
-       case FIB_EVENT_VIF_ADD: /* fall through */
+       case FIB_EVENT_VIF_ADD:
        case FIB_EVENT_VIF_DEL:
                memcpy(&fib_work->ven_info, info, sizeof(fib_work->ven_info));
                dev_hold(fib_work->ven_info.dev);
@@ -6215,13 +6215,13 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
        router = container_of(nb, struct mlxsw_sp_router, fib_nb);
 
        switch (event) {
-       case FIB_EVENT_RULE_ADD: /* fall through */
+       case FIB_EVENT_RULE_ADD:
        case FIB_EVENT_RULE_DEL:
                err = mlxsw_sp_router_fib_rule_event(event, info,
                                                     router->mlxsw_sp);
                return notifier_from_errno(err);
-       case FIB_EVENT_ENTRY_ADD: /* fall through */
-       case FIB_EVENT_ENTRY_REPLACE: /* fall through */
+       case FIB_EVENT_ENTRY_ADD:
+       case FIB_EVENT_ENTRY_REPLACE:
        case FIB_EVENT_ENTRY_APPEND:
                if (router->aborted) {
                        NL_SET_ERR_MSG_MOD(info->extack, "FIB offload was aborted. Not configuring route");
@@ -7277,7 +7277,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
                goto out;
 
        switch (event) {
-       case NETDEV_CHANGEMTU: /* fall through */
+       case NETDEV_CHANGEMTU:
        case NETDEV_CHANGEADDR:
                err = mlxsw_sp_router_port_change_event(mlxsw_sp, rif);
                break;
@@ -7351,9 +7351,10 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
        return err;
 }
 
-static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev, void *data)
+static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev,
+                                       struct netdev_nested_priv *priv)
 {
-       struct mlxsw_sp_rif *rif = data;
+       struct mlxsw_sp_rif *rif = (struct mlxsw_sp_rif *)priv->data;
 
        if (!netif_is_macvlan(dev))
                return 0;
@@ -7364,12 +7365,16 @@ static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev, void *data)
 
 static int mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif *rif)
 {
+       struct netdev_nested_priv priv = {
+               .data = (void *)rif,
+       };
+
        if (!netif_is_macvlan_port(rif->dev))
                return 0;
 
        netdev_warn(rif->dev, "Router interface is deleted. Upper macvlans will not work\n");
        return netdev_walk_all_upper_dev_rcu(rif->dev,
-                                            __mlxsw_sp_rif_macvlan_flush, rif);
+                                            __mlxsw_sp_rif_macvlan_flush, &priv);
 }
 
 static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif,
index 5c959a9..1d18e41 100644 (file)
@@ -1523,12 +1523,12 @@ mlxsw_sp_span_trigger_ops_set(struct mlxsw_sp_span_trigger_entry *trigger_entry)
        enum mlxsw_sp_span_trigger_type type;
 
        switch (trigger_entry->trigger) {
-       case MLXSW_SP_SPAN_TRIGGER_INGRESS: /* fall-through */
+       case MLXSW_SP_SPAN_TRIGGER_INGRESS:
        case MLXSW_SP_SPAN_TRIGGER_EGRESS:
                type = MLXSW_SP_SPAN_TRIGGER_TYPE_PORT;
                break;
-       case MLXSW_SP_SPAN_TRIGGER_TAIL_DROP: /* fall-through */
-       case MLXSW_SP_SPAN_TRIGGER_EARLY_DROP: /* fall-through */
+       case MLXSW_SP_SPAN_TRIGGER_TAIL_DROP:
+       case MLXSW_SP_SPAN_TRIGGER_EARLY_DROP:
        case MLXSW_SP_SPAN_TRIGGER_ECN:
                type = MLXSW_SP_SPAN_TRIGGER_TYPE_GLOBAL;
                break;
index a26162b..6501ce9 100644 (file)
@@ -136,9 +136,9 @@ bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp,
 }
 
 static int mlxsw_sp_bridge_device_upper_rif_destroy(struct net_device *dev,
-                                                   void *data)
+                                                   struct netdev_nested_priv *priv)
 {
-       struct mlxsw_sp *mlxsw_sp = data;
+       struct mlxsw_sp *mlxsw_sp = priv->data;
 
        mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev);
        return 0;
@@ -147,10 +147,14 @@ static int mlxsw_sp_bridge_device_upper_rif_destroy(struct net_device *dev,
 static void mlxsw_sp_bridge_device_rifs_destroy(struct mlxsw_sp *mlxsw_sp,
                                                struct net_device *dev)
 {
+       struct netdev_nested_priv priv = {
+               .data = (void *)mlxsw_sp,
+       };
+
        mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev);
        netdev_walk_all_upper_dev_rcu(dev,
                                      mlxsw_sp_bridge_device_upper_rif_destroy,
-                                     mlxsw_sp);
+                                     &priv);
 }
 
 static int mlxsw_sp_bridge_device_vxlan_init(struct mlxsw_sp_bridge *bridge,
@@ -1297,7 +1301,7 @@ static int mlxsw_sp_port_fdb_tunnel_uc_op(struct mlxsw_sp *mlxsw_sp,
                uip = be32_to_cpu(addr->addr4);
                sfd_proto = MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV4;
                break;
-       case MLXSW_SP_L3_PROTO_IPV6: /* fall through */
+       case MLXSW_SP_L3_PROTO_IPV6:
        default:
                WARN_ON(1);
                return -EOPNOTSUPP;
@@ -2870,7 +2874,7 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work)
                fdb_info = &switchdev_work->fdb_info;
                mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, false);
                break;
-       case SWITCHDEV_FDB_ADD_TO_BRIDGE: /* fall through */
+       case SWITCHDEV_FDB_ADD_TO_BRIDGE:
        case SWITCHDEV_FDB_DEL_TO_BRIDGE:
                /* These events are only used to potentially update an existing
                 * SPAN mirror.
@@ -3116,9 +3120,9 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
        switchdev_work->event = event;
 
        switch (event) {
-       case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */
-       case SWITCHDEV_FDB_DEL_TO_DEVICE: /* fall through */
-       case SWITCHDEV_FDB_ADD_TO_BRIDGE: /* fall through */
+       case SWITCHDEV_FDB_ADD_TO_DEVICE:
+       case SWITCHDEV_FDB_DEL_TO_DEVICE:
+       case SWITCHDEV_FDB_ADD_TO_BRIDGE:
        case SWITCHDEV_FDB_DEL_TO_BRIDGE:
                fdb_info = container_of(info,
                                        struct switchdev_notifier_fdb_info,
@@ -3138,7 +3142,7 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
                 */
                dev_hold(dev);
                break;
-       case SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE: /* fall through */
+       case SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE:
        case SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE:
                INIT_WORK(&switchdev_work->work,
                          mlxsw_sp_switchdev_vxlan_fdb_event_work);
index c533d06..dcde496 100644 (file)
@@ -548,7 +548,7 @@ static int lan743x_ethtool_get_rxnfc(struct net_device *netdev,
                case TCP_V4_FLOW:case UDP_V4_FLOW:
                case TCP_V6_FLOW:case UDP_V6_FLOW:
                        rxnfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
-                       /* fall through */
+                       fallthrough;
                case IPV4_FLOW: case IPV6_FLOW:
                        rxnfc->data |= RXH_IP_SRC | RXH_IP_DST;
                        return 0;
index 867c680..aa002db 100644 (file)
@@ -421,10 +421,15 @@ int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port,
 
        if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP &&
            ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
+               spin_lock(&ocelot_port->ts_id_lock);
+
                shinfo->tx_flags |= SKBTX_IN_PROGRESS;
                /* Store timestamp ID in cb[0] of sk_buff */
-               skb->cb[0] = ocelot_port->ts_id % 4;
+               skb->cb[0] = ocelot_port->ts_id;
+               ocelot_port->ts_id = (ocelot_port->ts_id + 1) % 4;
                skb_queue_tail(&ocelot_port->tx_skbs, skb);
+
+               spin_unlock(&ocelot_port->ts_id_lock);
                return 0;
        }
        return -ENODATA;
@@ -859,7 +864,7 @@ void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
        switch (state) {
        case BR_STATE_FORWARDING:
                ocelot->bridge_fwd_mask |= BIT(port);
-               /* Fallthrough */
+               fallthrough;
        case BR_STATE_LEARNING:
                port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA;
                break;
@@ -1248,7 +1253,7 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
        struct ocelot_port *ocelot_port = ocelot->ports[port];
        int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN;
        int pause_start, pause_stop;
-       int atop_wm;
+       int atop, atop_tot;
 
        if (port == ocelot->npi) {
                maxlen += OCELOT_TAG_LEN;
@@ -1269,12 +1274,12 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
        ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_STOP,
                            pause_stop);
 
-       /* Tail dropping watermark */
-       atop_wm = (ocelot->shared_queue_sz - 9 * maxlen) /
+       /* Tail dropping watermarks */
+       atop_tot = (ocelot->shared_queue_sz - 9 * maxlen) /
                   OCELOT_BUFFER_CELL_SZ;
-       ocelot_write_rix(ocelot, ocelot->ops->wm_enc(9 * maxlen),
-                        SYS_ATOP, port);
-       ocelot_write(ocelot, ocelot->ops->wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
+       atop = (9 * maxlen) / OCELOT_BUFFER_CELL_SZ;
+       ocelot_write_rix(ocelot, ocelot->ops->wm_enc(atop), SYS_ATOP, port);
+       ocelot_write(ocelot, ocelot->ops->wm_enc(atop_tot), SYS_ATOP_TOT_CFG);
 }
 EXPORT_SYMBOL(ocelot_port_set_maxlen);
 
@@ -1300,6 +1305,7 @@ void ocelot_init_port(struct ocelot *ocelot, int port)
        struct ocelot_port *ocelot_port = ocelot->ports[port];
 
        skb_queue_head_init(&ocelot_port->tx_skbs);
+       spin_lock_init(&ocelot_port->ts_id_lock);
 
        /* Basic L2 initialization */
 
@@ -1544,18 +1550,18 @@ EXPORT_SYMBOL(ocelot_init);
 
 void ocelot_deinit(struct ocelot *ocelot)
 {
-       struct ocelot_port *port;
-       int i;
-
        cancel_delayed_work(&ocelot->stats_work);
        destroy_workqueue(ocelot->stats_queue);
        mutex_destroy(&ocelot->stats_lock);
-
-       for (i = 0; i < ocelot->num_phys_ports; i++) {
-               port = ocelot->ports[i];
-               skb_queue_purge(&port->tx_skbs);
-       }
 }
 EXPORT_SYMBOL(ocelot_deinit);
 
+void ocelot_deinit_port(struct ocelot *ocelot, int port)
+{
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+
+       skb_queue_purge(&ocelot_port->tx_skbs);
+}
+EXPORT_SYMBOL(ocelot_deinit_port);
+
 MODULE_LICENSE("Dual MIT/GPL");
index 0668d23..8490e42 100644 (file)
@@ -330,6 +330,7 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
        u8 grp = 0; /* Send everything on CPU group 0 */
        unsigned int i, count, last;
        int port = priv->chip_port;
+       bool do_tstamp;
 
        val = ocelot_read(ocelot, QS_INJ_STATUS);
        if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp))) ||
@@ -344,10 +345,12 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
        info.vid = skb_vlan_tag_get(skb);
 
        /* Check if timestamping is needed */
+       do_tstamp = (ocelot_port_add_txtstamp_skb(ocelot_port, skb) == 0);
+
        if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP) {
                info.rew_op = ocelot_port->ptp_cmd;
                if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
-                       info.rew_op |= (ocelot_port->ts_id  % 4) << 3;
+                       info.rew_op |= skb->cb[0] << 3;
        }
 
        ocelot_gen_ifh(ifh, &info);
@@ -380,12 +383,9 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
 
-       if (!ocelot_port_add_txtstamp_skb(ocelot_port, skb)) {
-               ocelot_port->ts_id++;
-               return NETDEV_TX_OK;
-       }
+       if (!do_tstamp)
+               dev_kfree_skb_any(skb);
 
-       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
index 65408bc..8a69176 100644 (file)
@@ -745,6 +745,8 @@ static int ocelot_reset(struct ocelot *ocelot)
  */
 static u16 ocelot_wm_enc(u16 value)
 {
+       WARN_ON(value >= 16 * BIT(8));
+
        if (value >= BIT(8))
                return BIT(8) | (value / 16);
 
@@ -806,17 +808,17 @@ static const struct vcap_field vsc7514_vcap_is2_keys[] = {
        [VCAP_IS2_HK_DIP_EQ_SIP]                = {123,   1},
        /* IP4_TCP_UDP (TYPE=100) */
        [VCAP_IS2_HK_TCP]                       = {124,   1},
-       [VCAP_IS2_HK_L4_SPORT]                  = {125,  16},
-       [VCAP_IS2_HK_L4_DPORT]                  = {141,  16},
+       [VCAP_IS2_HK_L4_DPORT]                  = {125,  16},
+       [VCAP_IS2_HK_L4_SPORT]                  = {141,  16},
        [VCAP_IS2_HK_L4_RNG]                    = {157,   8},
        [VCAP_IS2_HK_L4_SPORT_EQ_DPORT]         = {165,   1},
        [VCAP_IS2_HK_L4_SEQUENCE_EQ0]           = {166,   1},
-       [VCAP_IS2_HK_L4_URG]                    = {167,   1},
-       [VCAP_IS2_HK_L4_ACK]                    = {168,   1},
-       [VCAP_IS2_HK_L4_PSH]                    = {169,   1},
-       [VCAP_IS2_HK_L4_RST]                    = {170,   1},
-       [VCAP_IS2_HK_L4_SYN]                    = {171,   1},
-       [VCAP_IS2_HK_L4_FIN]                    = {172,   1},
+       [VCAP_IS2_HK_L4_FIN]                    = {167,   1},
+       [VCAP_IS2_HK_L4_SYN]                    = {168,   1},
+       [VCAP_IS2_HK_L4_RST]                    = {169,   1},
+       [VCAP_IS2_HK_L4_PSH]                    = {170,   1},
+       [VCAP_IS2_HK_L4_ACK]                    = {171,   1},
+       [VCAP_IS2_HK_L4_URG]                    = {172,   1},
        [VCAP_IS2_HK_L4_1588_DOM]               = {173,   8},
        [VCAP_IS2_HK_L4_1588_VER]               = {181,   4},
        /* IP4_OTHER (TYPE=101) */
@@ -896,11 +898,137 @@ static struct ptp_clock_info ocelot_ptp_clock_info = {
        .enable         = ocelot_ptp_enable,
 };
 
+static void mscc_ocelot_release_ports(struct ocelot *ocelot)
+{
+       int port;
+
+       for (port = 0; port < ocelot->num_phys_ports; port++) {
+               struct ocelot_port_private *priv;
+               struct ocelot_port *ocelot_port;
+
+               ocelot_port = ocelot->ports[port];
+               if (!ocelot_port)
+                       continue;
+
+               ocelot_deinit_port(ocelot, port);
+
+               priv = container_of(ocelot_port, struct ocelot_port_private,
+                                   port);
+
+               unregister_netdev(priv->dev);
+               free_netdev(priv->dev);
+       }
+}
+
+static int mscc_ocelot_init_ports(struct platform_device *pdev,
+                                 struct device_node *ports)
+{
+       struct ocelot *ocelot = platform_get_drvdata(pdev);
+       struct device_node *portnp;
+       int err;
+
+       ocelot->ports = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
+                                    sizeof(struct ocelot_port *), GFP_KERNEL);
+       if (!ocelot->ports)
+               return -ENOMEM;
+
+       /* No NPI port */
+       ocelot_configure_cpu(ocelot, -1, OCELOT_TAG_PREFIX_NONE,
+                            OCELOT_TAG_PREFIX_NONE);
+
+       for_each_available_child_of_node(ports, portnp) {
+               struct ocelot_port_private *priv;
+               struct ocelot_port *ocelot_port;
+               struct device_node *phy_node;
+               phy_interface_t phy_mode;
+               struct phy_device *phy;
+               struct regmap *target;
+               struct resource *res;
+               struct phy *serdes;
+               char res_name[8];
+               u32 port;
+
+               if (of_property_read_u32(portnp, "reg", &port))
+                       continue;
+
+               snprintf(res_name, sizeof(res_name), "port%d", port);
+
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                                  res_name);
+               target = ocelot_regmap_init(ocelot, res);
+               if (IS_ERR(target))
+                       continue;
+
+               phy_node = of_parse_phandle(portnp, "phy-handle", 0);
+               if (!phy_node)
+                       continue;
+
+               phy = of_phy_find_device(phy_node);
+               of_node_put(phy_node);
+               if (!phy)
+                       continue;
+
+               err = ocelot_probe_port(ocelot, port, target, phy);
+               if (err) {
+                       of_node_put(portnp);
+                       return err;
+               }
+
+               ocelot_port = ocelot->ports[port];
+               priv = container_of(ocelot_port, struct ocelot_port_private,
+                                   port);
+
+               of_get_phy_mode(portnp, &phy_mode);
+
+               ocelot_port->phy_mode = phy_mode;
+
+               switch (ocelot_port->phy_mode) {
+               case PHY_INTERFACE_MODE_NA:
+                       continue;
+               case PHY_INTERFACE_MODE_SGMII:
+                       break;
+               case PHY_INTERFACE_MODE_QSGMII:
+                       /* Ensure clock signals and speed is set on all
+                        * QSGMII links
+                        */
+                       ocelot_port_writel(ocelot_port,
+                                          DEV_CLOCK_CFG_LINK_SPEED
+                                          (OCELOT_SPEED_1000),
+                                          DEV_CLOCK_CFG);
+                       break;
+               default:
+                       dev_err(ocelot->dev,
+                               "invalid phy mode for port%d, (Q)SGMII only\n",
+                               port);
+                       of_node_put(portnp);
+                       return -EINVAL;
+               }
+
+               serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
+               if (IS_ERR(serdes)) {
+                       err = PTR_ERR(serdes);
+                       if (err == -EPROBE_DEFER)
+                               dev_dbg(ocelot->dev, "deferring probe\n");
+                       else
+                               dev_err(ocelot->dev,
+                                       "missing SerDes phys for port%d\n",
+                                       port);
+
+                       of_node_put(portnp);
+                       return err;
+               }
+
+               priv->serdes = serdes;
+       }
+
+       return 0;
+}
+
 static int mscc_ocelot_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct device_node *ports, *portnp;
        int err, irq_xtr, irq_ptp_rdy;
+       struct device_node *ports;
        struct ocelot *ocelot;
        struct regmap *hsio;
        unsigned int i;
@@ -985,20 +1113,24 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
 
        ports = of_get_child_by_name(np, "ethernet-ports");
        if (!ports) {
-               dev_err(&pdev->dev, "no ethernet-ports child node found\n");
+               dev_err(ocelot->dev, "no ethernet-ports child node found\n");
                return -ENODEV;
        }
 
        ocelot->num_phys_ports = of_get_child_count(ports);
 
-       ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports,
-                                    sizeof(struct ocelot_port *), GFP_KERNEL);
-
        ocelot->vcap_is2_keys = vsc7514_vcap_is2_keys;
        ocelot->vcap_is2_actions = vsc7514_vcap_is2_actions;
        ocelot->vcap = vsc7514_vcap_props;
 
-       ocelot_init(ocelot);
+       err = ocelot_init(ocelot);
+       if (err)
+               goto out_put_ports;
+
+       err = mscc_ocelot_init_ports(pdev, ports);
+       if (err)
+               goto out_put_ports;
+
        if (ocelot->ptp) {
                err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info);
                if (err) {
@@ -1008,96 +1140,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
                }
        }
 
-       /* No NPI port */
-       ocelot_configure_cpu(ocelot, -1, OCELOT_TAG_PREFIX_NONE,
-                            OCELOT_TAG_PREFIX_NONE);
-
-       for_each_available_child_of_node(ports, portnp) {
-               struct ocelot_port_private *priv;
-               struct ocelot_port *ocelot_port;
-               struct device_node *phy_node;
-               phy_interface_t phy_mode;
-               struct phy_device *phy;
-               struct regmap *target;
-               struct resource *res;
-               struct phy *serdes;
-               char res_name[8];
-               u32 port;
-
-               if (of_property_read_u32(portnp, "reg", &port))
-                       continue;
-
-               snprintf(res_name, sizeof(res_name), "port%d", port);
-
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                                  res_name);
-               target = ocelot_regmap_init(ocelot, res);
-               if (IS_ERR(target))
-                       continue;
-
-               phy_node = of_parse_phandle(portnp, "phy-handle", 0);
-               if (!phy_node)
-                       continue;
-
-               phy = of_phy_find_device(phy_node);
-               of_node_put(phy_node);
-               if (!phy)
-                       continue;
-
-               err = ocelot_probe_port(ocelot, port, target, phy);
-               if (err) {
-                       of_node_put(portnp);
-                       goto out_put_ports;
-               }
-
-               ocelot_port = ocelot->ports[port];
-               priv = container_of(ocelot_port, struct ocelot_port_private,
-                                   port);
-
-               of_get_phy_mode(portnp, &phy_mode);
-
-               ocelot_port->phy_mode = phy_mode;
-
-               switch (ocelot_port->phy_mode) {
-               case PHY_INTERFACE_MODE_NA:
-                       continue;
-               case PHY_INTERFACE_MODE_SGMII:
-                       break;
-               case PHY_INTERFACE_MODE_QSGMII:
-                       /* Ensure clock signals and speed is set on all
-                        * QSGMII links
-                        */
-                       ocelot_port_writel(ocelot_port,
-                                          DEV_CLOCK_CFG_LINK_SPEED
-                                          (OCELOT_SPEED_1000),
-                                          DEV_CLOCK_CFG);
-                       break;
-               default:
-                       dev_err(ocelot->dev,
-                               "invalid phy mode for port%d, (Q)SGMII only\n",
-                               port);
-                       of_node_put(portnp);
-                       err = -EINVAL;
-                       goto out_put_ports;
-               }
-
-               serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
-               if (IS_ERR(serdes)) {
-                       err = PTR_ERR(serdes);
-                       if (err == -EPROBE_DEFER)
-                               dev_dbg(ocelot->dev, "deferring probe\n");
-                       else
-                               dev_err(ocelot->dev,
-                                       "missing SerDes phys for port%d\n",
-                                       port);
-
-                       of_node_put(portnp);
-                       goto out_put_ports;
-               }
-
-               priv->serdes = serdes;
-       }
-
        register_netdevice_notifier(&ocelot_netdevice_nb);
        register_switchdev_notifier(&ocelot_switchdev_nb);
        register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
@@ -1114,6 +1156,7 @@ static int mscc_ocelot_remove(struct platform_device *pdev)
        struct ocelot *ocelot = platform_get_drvdata(pdev);
 
        ocelot_deinit_timestamp(ocelot);
+       mscc_ocelot_release_ports(ocelot);
        ocelot_deinit(ocelot);
        unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
        unregister_switchdev_notifier(&ocelot_switchdev_nb);
index c2867fe..3de8430 100644 (file)
@@ -3081,7 +3081,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        switch(cmd) {
        case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
                data->phy_id = np->phy_addr_external;
-               /* Fall Through */
+               fallthrough;
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
                /* The phy_id is not enough to uniquely identify
index 4f1f90f..78eba10 100644 (file)
@@ -3768,20 +3768,20 @@ vxge_hw_rts_rth_data0_data1_get(u32 j, u64 *data0, u64 *data1,
                        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_ENTRY_EN |
                        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_DATA(
                        itable[j]);
-               /* fall through */
+               fallthrough;
        case 2:
                *data0 |=
                        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_NUM(j)|
                        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_ENTRY_EN |
                        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_DATA(
                        itable[j]);
-               /* fall through */
+               fallthrough;
        case 3:
                *data1 = VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_NUM(j)|
                        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_ENTRY_EN |
                        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_DATA(
                        itable[j]);
-               /* fall through */
+               fallthrough;
        case 4:
                *data1 |=
                        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_NUM(j)|
index 7c50e3d..76c51da 100644 (file)
@@ -296,7 +296,7 @@ nfp_net_tls_add(struct net_device *netdev, struct sock *sk,
                        break;
                }
 #endif
-               /* fall through */
+               fallthrough;
        case AF_INET:
                req_sz = sizeof(struct nfp_crypto_req_add_v4);
                ipv6 = false;
index ff844e5..1cbe2c9 100644 (file)
@@ -297,7 +297,7 @@ nfp_fl_get_tun_from_act(struct nfp_app *app,
        case htons(GENEVE_UDP_PORT):
                if (priv->flower_ext_feats & NFP_FL_FEATS_GENEVE)
                        return NFP_FL_TUNNEL_GENEVE;
-               /* FALLTHROUGH */
+               fallthrough;
        default:
                return NFP_FL_TUNNEL_NONE;
        }
index a050cb8..f21cf1f 100644 (file)
@@ -289,7 +289,7 @@ nfp_flower_cmsg_process_one_rx(struct nfp_app *app, struct sk_buff *skb)
                        skb_stored = nfp_flower_lag_unprocessed_msg(app, skb);
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
 err_default:
                nfp_flower_cmsg_warn(app, "Cannot handle invalid repr control type %u\n",
index 4651fe4..36356f9 100644 (file)
@@ -784,7 +784,7 @@ nfp_flower_copy_pre_actions(char *act_dst, char *act_src, int len,
                case NFP_FL_ACTION_OPCODE_PRE_TUNNEL:
                        if (tunnel_act)
                                *tunnel_act = true;
-                       /* fall through */
+                       fallthrough;
                case NFP_FL_ACTION_OPCODE_PRE_LAG:
                        memcpy(act_dst + act_off, act_src + act_off, act_len);
                        break;
index 2df3dee..7248d24 100644 (file)
@@ -61,6 +61,7 @@ struct nfp_tun_active_tuns {
  * @flags:             options part of the request
  * @tun_info.ipv6:             dest IPv6 address of active route
  * @tun_info.egress_port:      port the encapsulated packet egressed
+ * @tun_info.extra:            reserved for future use
  * @tun_info:          tunnels that have sent traffic in reported period
  */
 struct nfp_tun_active_tuns_v6 {
@@ -70,6 +71,7 @@ struct nfp_tun_active_tuns_v6 {
        struct route_ip_info_v6 {
                struct in6_addr ipv6;
                __be32 egress_port;
+               __be32 extra[2];
        } tun_info[];
 };
 
index b04b836..2643ea5 100644 (file)
@@ -137,7 +137,7 @@ static u16 nfp_swreg_to_unreg(swreg reg, bool is_dst)
                                val;
                case NN_LM_MOD_DEC:
                        lm_dec = true;
-                       /* fall through */
+                       fallthrough;
                case NN_LM_MOD_INC:
                        if (val) {
                                pr_err("LM offset in inc/dev mode\n");
index 39ee23e..21ea226 100644 (file)
@@ -1940,10 +1940,10 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
                                continue;
                        default:
                                bpf_warn_invalid_xdp_action(act);
-                               /* fall through */
+                               fallthrough;
                        case XDP_ABORTED:
                                trace_xdp_exception(dp->netdev, xdp_prog, act);
-                               /* fall through */
+                               fallthrough;
                        case XDP_DROP:
                                nfp_net_rx_give_one(dp, rx_ring, rxbuf->frag,
                                                    rxbuf->dma_addr);
index 6eb9fb9..9c9ae33 100644 (file)
@@ -829,8 +829,8 @@ nfp_port_get_fecparam(struct net_device *netdev,
        struct nfp_eth_table_port *eth_port;
        struct nfp_port *port;
 
-       param->active_fec = ETHTOOL_FEC_NONE_BIT;
-       param->fec = ETHTOOL_FEC_NONE_BIT;
+       param->active_fec = ETHTOOL_FEC_NONE;
+       param->fec = ETHTOOL_FEC_NONE;
 
        port = nfp_port_from_netdev(netdev);
        eth_port = nfp_port_get_eth_port(port);
index a486008..252fe06 100644 (file)
@@ -340,12 +340,12 @@ static int matching_bar(struct nfp_bar *bar, u32 tgt, u32 act, u32 tok,
        switch (maptype) {
        case NFP_PCIE_BAR_PCIE2CPP_MapType_TARGET:
                bartok = -1;
-               /* FALLTHROUGH */
+               fallthrough;
        case NFP_PCIE_BAR_PCIE2CPP_MapType_BULK:
                baract = NFP_CPP_ACTION_RW;
                if (act == 0)
                        act = NFP_CPP_ACTION_RW;
-               /* FALLTHROUGH */
+               fallthrough;
        case NFP_PCIE_BAR_PCIE2CPP_MapType_FIXED:
                break;
        default:
index 75f0124..2260c24 100644 (file)
@@ -213,7 +213,7 @@ u64 nfp_rtsym_size(const struct nfp_rtsym *sym)
                return 0;
        default:
                pr_warn("rtsym '%s': unknown type: %d\n", sym->name, sym->type);
-               /* fall through */
+               fallthrough;
        case NFP_RTSYM_TYPE_OBJECT:
        case NFP_RTSYM_TYPE_FUNCTION:
                return sym->size;
index a26966f..dceec80 100644 (file)
@@ -410,7 +410,7 @@ static void pch_gbe_check_copper_options(struct pch_gbe_adapter *adapter)
        case SPEED_1000 + HALF_DUPLEX:
                netdev_dbg(adapter->netdev,
                           "Half Duplex is not supported at 1000 Mbps\n");
-               /* fall through */
+               fallthrough;
        case SPEED_1000 + FULL_DUPLEX:
 full_duplex_only:
                netdev_dbg(adapter->netdev,
index 647a143..3da0753 100644 (file)
@@ -1356,7 +1356,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        switch(cmd) {
        case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
                data->phy_id = np->phys[0] & 0x1f;
-               /* Fall Through */
+               fallthrough;
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
                data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);
index 8107d32..def65fe 100644 (file)
@@ -496,9 +496,7 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget)
        struct ionic_cq *txcq;
        u32 rx_work_done = 0;
        u32 tx_work_done = 0;
-       u32 work_done = 0;
        u32 flags = 0;
-       bool unmask;
 
        lif = rxcq->bound_q->lif;
        idev = &lif->ionic->idev;
@@ -512,17 +510,12 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget)
        if (rx_work_done)
                ionic_rx_fill_cb(rxcq->bound_q);
 
-       unmask = (rx_work_done < budget) && (tx_work_done < lif->tx_budget);
-
-       if (unmask && napi_complete_done(napi, rx_work_done)) {
+       if (rx_work_done < budget && napi_complete_done(napi, rx_work_done)) {
                flags |= IONIC_INTR_CRED_UNMASK;
                DEBUG_STATS_INTR_REARM(rxcq->bound_intr);
-               work_done = rx_work_done;
-       } else {
-               work_done = budget;
        }
 
-       if (work_done || flags) {
+       if (rx_work_done || flags) {
                flags |= IONIC_INTR_CRED_RESET_COALESCE;
                ionic_intr_credits(idev->intr_ctrl, rxcq->bound_intr->index,
                                   tx_work_done + rx_work_done, flags);
@@ -531,7 +524,7 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget)
        DEBUG_STATS_NAPI_POLL(qcq, rx_work_done);
        DEBUG_STATS_NAPI_POLL(qcq, tx_work_done);
 
-       return work_done;
+       return rx_work_done;
 }
 
 static dma_addr_t ionic_tx_map_single(struct ionic_queue *q,
index 66f45fc..c3f50dd 100644 (file)
@@ -153,7 +153,7 @@ skip:
        case NETXEN_BRDTYPE_P3_4_GB_MM:
                supported |= SUPPORTED_Autoneg;
                advertising |= ADVERTISED_Autoneg;
-               /* fall through */
+               fallthrough;
        case NETXEN_BRDTYPE_P2_SB31_10G_CX4:
        case NETXEN_BRDTYPE_P3_10G_CX4:
        case NETXEN_BRDTYPE_P3_10G_CX4_LP:
@@ -182,7 +182,7 @@ skip:
                supported |= SUPPORTED_TP;
                check_sfp_module = netif_running(dev) &&
                        adapter->has_link_events;
-               /* fall through */
+               fallthrough;
        case NETXEN_BRDTYPE_P2_SB31_10G:
        case NETXEN_BRDTYPE_P3_10G_XFP:
                supported |= SUPPORTED_FIBRE;
index 876743a..0e4cd88 100644 (file)
@@ -2046,7 +2046,7 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 rdma_tasks)
                                               rdma_tasks);
                /* no need for break since RoCE coexist with Ethernet */
        }
-       /* fall through */
+               fallthrough;
        case QED_PCI_ETH:
        {
                struct qed_eth_pf_params *p_params =
index b3c9eba..3db181f 100644 (file)
@@ -3109,14 +3109,14 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
                                                p_hwfn->hw_info.hw_mode);
                        if (rc)
                                break;
-               /* Fall through */
+                       fallthrough;
                case FW_MSG_CODE_DRV_LOAD_PORT:
                        rc = qed_hw_init_port(p_hwfn, p_hwfn->p_main_ptt,
                                              p_hwfn->hw_info.hw_mode);
                        if (rc)
                                break;
 
-               /* Fall through */
+                       fallthrough;
                case FW_MSG_CODE_DRV_LOAD_FUNCTION:
                        rc = qed_hw_init_pf(p_hwfn, p_hwfn->p_main_ptt,
                                            p_params->p_tunn,
@@ -4253,7 +4253,8 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
                        cdev->mf_bits = BIT(QED_MF_LLH_MAC_CLSS) |
                                        BIT(QED_MF_LLH_PROTO_CLSS) |
                                        BIT(QED_MF_LL2_NON_UNICAST) |
-                                       BIT(QED_MF_INTER_PF_SWITCH);
+                                       BIT(QED_MF_INTER_PF_SWITCH) |
+                                       BIT(QED_MF_DISABLE_ARFS);
                        break;
                case NVM_CFG1_GLOB_MF_MODE_DEFAULT:
                        cdev->mf_bits = BIT(QED_MF_LLH_MAC_CLSS) |
@@ -4266,6 +4267,14 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
 
                DP_INFO(p_hwfn, "Multi function mode is 0x%lx\n",
                        cdev->mf_bits);
+
+               /* In CMT the PF is unknown when the GFS block processes the
+                * packet. Therefore cannot use searcher as it has a per PF
+                * database, and thus ARFS must be disabled.
+                *
+                */
+               if (QED_IS_CMT(cdev))
+                       cdev->mf_bits |= BIT(QED_MF_DISABLE_ARFS);
        }
 
        DP_INFO(p_hwfn, "Multi function mode is 0x%lx\n",
index 4c6ac88..07824bf 100644 (file)
@@ -1980,6 +1980,9 @@ void qed_arfs_mode_configure(struct qed_hwfn *p_hwfn,
                             struct qed_ptt *p_ptt,
                             struct qed_arfs_config_params *p_cfg_params)
 {
+       if (test_bit(QED_MF_DISABLE_ARFS, &p_hwfn->cdev->mf_bits))
+               return;
+
        if (p_cfg_params->mode != QED_FILTER_CONFIG_MODE_DISABLE) {
                qed_gft_config(p_hwfn, p_ptt, p_hwfn->rel_pf_id,
                               p_cfg_params->tcp,
index 2558cb6..50e5eb2 100644 (file)
@@ -444,6 +444,8 @@ int qed_fill_dev_info(struct qed_dev *cdev,
                dev_info->fw_eng = FW_ENGINEERING_VERSION;
                dev_info->b_inter_pf_switch = test_bit(QED_MF_INTER_PF_SWITCH,
                                                       &cdev->mf_bits);
+               if (!test_bit(QED_MF_DISABLE_ARFS, &cdev->mf_bits))
+                       dev_info->b_arfs_capable = true;
                dev_info->tx_switching = true;
 
                if (hw_info->b_wol_support == QED_WOL_SUPPORT_PME)
@@ -761,7 +763,7 @@ static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode)
                kfree(int_params->msix_table);
                if (force_mode)
                        goto out;
-               /* Fallthrough */
+               fallthrough;
 
        case QED_INT_MODE_MSI:
                if (cdev->num_hwfns == 1) {
@@ -775,7 +777,7 @@ static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode)
                        if (force_mode)
                                goto out;
                }
-               /* Fallthrough */
+               fallthrough;
 
        case QED_INT_MODE_INTA:
                        int_params->out.int_mode = QED_INT_MODE_INTA;
index 5be08f8..cd882c4 100644 (file)
@@ -1085,7 +1085,7 @@ int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
                DP_NOTICE(p_hwfn,
                          "Unknown WoL configuration %02x\n",
                          p_hwfn->cdev->wol_config);
-               /* Fallthrough */
+               fallthrough;
        case QED_OV_WOL_DEFAULT:
                wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP;
        }
@@ -1365,7 +1365,7 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
                break;
        case LINK_STATUS_SPEED_AND_DUPLEX_1000THD:
                p_link->full_duplex = false;
-       /* Fall-through */
+               fallthrough;
        case LINK_STATUS_SPEED_AND_DUPLEX_1000TFD:
                p_link->speed = 1000;
                break;
@@ -2451,7 +2451,7 @@ qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn,
                break;
        case FUNC_MF_CFG_PROTOCOL_ROCE:
                DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n");
-       /* Fallthrough */
+               fallthrough;
        default:
                rc = -EINVAL;
        }
@@ -3546,7 +3546,7 @@ qed_mcp_resc_allocation_msg(struct qed_hwfn *p_hwfn,
        switch (p_in_params->cmd) {
        case DRV_MSG_SET_RESOURCE_VALUE_MSG:
                mfw_resc_info.size = p_in_params->resc_max_val;
-               /* Fallthrough */
+               fallthrough;
        case DRV_MSG_GET_RESOURCE_ALLOC_MSG:
                break;
        default:
@@ -3823,7 +3823,7 @@ qed_mcp_resc_unlock(struct qed_hwfn *p_hwfn,
                DP_INFO(p_hwfn,
                        "Resource unlock request for an already released resource [%d]\n",
                        p_params->resource);
-               /* Fallthrough */
+               fallthrough;
        case RESOURCE_OPCODE_RELEASED:
                p_params->b_released = true;
                break;
index f1f75b6..b8dc5c4 100644 (file)
@@ -71,6 +71,7 @@ static int qed_sp_vf_start(struct qed_hwfn *p_hwfn, struct qed_vf_info *p_vf)
                p_ramrod->personality = PERSONALITY_ETH;
                break;
        case QED_PCI_ETH_ROCE:
+       case QED_PCI_ETH_IWARP:
                p_ramrod->personality = PERSONALITY_RDMA_AND_ETH;
                break;
        default:
index f961f65..c59b72c 100644 (file)
@@ -311,6 +311,9 @@ int qede_alloc_arfs(struct qede_dev *edev)
 {
        int i;
 
+       if (!edev->dev_info.common.b_arfs_capable)
+               return -EINVAL;
+
        edev->arfs = vzalloc(sizeof(*edev->arfs));
        if (!edev->arfs)
                return -ENOMEM;
index 140a392..9e1f41b 100644 (file)
@@ -804,7 +804,7 @@ static void qede_init_ndev(struct qede_dev *edev)
                      NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                      NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_TC;
 
-       if (!IS_VF(edev) && edev->dev_info.common.num_hwfns == 1)
+       if (edev->dev_info.common.b_arfs_capable)
                hw_features |= NETIF_F_NTUPLE;
 
        if (edev->dev_info.common.vxlan_enable ||
@@ -2274,7 +2274,7 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode,
        qede_vlan_mark_nonconfigured(edev);
        edev->ops->fastpath_stop(edev->cdev);
 
-       if (!IS_VF(edev) && edev->dev_info.common.num_hwfns == 1) {
+       if (edev->dev_info.common.b_arfs_capable) {
                qede_poll_for_freeing_arfs_filters(edev);
                qede_free_arfs(edev);
        }
@@ -2341,10 +2341,9 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode,
        if (rc)
                goto err2;
 
-       if (!IS_VF(edev) && edev->dev_info.common.num_hwfns == 1) {
-               rc = qede_alloc_arfs(edev);
-               if (rc)
-                       DP_NOTICE(edev, "aRFS memory allocation failed\n");
+       if (qede_alloc_arfs(edev)) {
+               edev->ndev->features &= ~NETIF_F_NTUPLE;
+               edev->dev_info.common.b_arfs_capable = false;
        }
 
        qede_napi_add_enable(edev);
index 0d0e38d..569e2a7 100644 (file)
@@ -1542,7 +1542,7 @@ static void ql_link_state_machine_work(struct work_struct *work)
                if (test_bit(QL_LINK_MASTER, &qdev->flags))
                        ql_port_start(qdev);
                qdev->port_link_state = LS_DOWN;
-               /* Fall Through */
+               fallthrough;
 
        case LS_DOWN:
                if (curr_link_state == LS_UP) {
index 5c2a3ac..b9894d5 100644 (file)
@@ -353,7 +353,7 @@ skip:
        case QLCNIC_BRDTYPE_P3P_4_GB_MM:
                supported |= SUPPORTED_Autoneg;
                advertising |= ADVERTISED_Autoneg;
-               /* fall through */
+               fallthrough;
        case QLCNIC_BRDTYPE_P3P_10G_CX4:
        case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
        case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
@@ -377,7 +377,7 @@ skip:
                supported |= SUPPORTED_TP;
                check_sfp_module = netif_running(adapter->netdev) &&
                                   ahw->has_link_events;
-               /* fall through */
+               fallthrough;
        case QLCNIC_BRDTYPE_P3P_10G_XFP:
                supported |= SUPPORTED_FIBRE;
                advertising |= ADVERTISED_FIBRE;
index d1da92a..11e6962 100644 (file)
@@ -2058,11 +2058,18 @@ static void rtl_release_firmware(struct rtl8169_private *tp)
 
 void r8169_apply_firmware(struct rtl8169_private *tp)
 {
+       int val;
+
        /* TODO: release firmware if rtl_fw_write_firmware signals failure. */
        if (tp->rtl_fw) {
                rtl_fw_write_firmware(tp, tp->rtl_fw);
                /* At least one firmware doesn't reset tp->ocp_base. */
                tp->ocp_base = OCP_STD_PHY_BASE;
+
+               /* PHY soft reset may still be in progress */
+               phy_read_poll_timeout(tp->phydev, MII_BMCR, val,
+                                     !(val & BMCR_RESET),
+                                     50000, 600000, true);
        }
 }
 
@@ -2239,14 +2246,10 @@ static void rtl_pll_power_down(struct rtl8169_private *tp)
        default:
                break;
        }
-
-       clk_disable_unprepare(tp->clk);
 }
 
 static void rtl_pll_power_up(struct rtl8169_private *tp)
 {
-       clk_prepare_enable(tp->clk);
-
        switch (tp->mac_version) {
        case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_33:
        case RTL_GIGA_MAC_VER_37:
@@ -2904,7 +2907,7 @@ static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
                { 0x08, 0x0001, 0x0002 },
                { 0x09, 0x0000, 0x0080 },
                { 0x19, 0x0000, 0x0224 },
-               { 0x00, 0x0000, 0x0004 },
+               { 0x00, 0x0000, 0x0008 },
                { 0x0c, 0x3df0, 0x0200 },
        };
 
@@ -2921,7 +2924,7 @@ static void rtl_hw_start_8411(struct rtl8169_private *tp)
                { 0x06, 0x00c0, 0x0020 },
                { 0x0f, 0xffff, 0x5200 },
                { 0x19, 0x0000, 0x0224 },
-               { 0x00, 0x0000, 0x0004 },
+               { 0x00, 0x0000, 0x0008 },
                { 0x0c, 0x3df0, 0x0200 },
        };
 
@@ -4826,29 +4829,43 @@ static void rtl8169_net_suspend(struct rtl8169_private *tp)
 
 #ifdef CONFIG_PM
 
+static int rtl8169_net_resume(struct rtl8169_private *tp)
+{
+       rtl_rar_set(tp, tp->dev->dev_addr);
+
+       if (tp->TxDescArray)
+               rtl8169_up(tp);
+
+       netif_device_attach(tp->dev);
+
+       return 0;
+}
+
 static int __maybe_unused rtl8169_suspend(struct device *device)
 {
        struct rtl8169_private *tp = dev_get_drvdata(device);
 
        rtnl_lock();
        rtl8169_net_suspend(tp);
+       if (!device_may_wakeup(tp_to_dev(tp)))
+               clk_disable_unprepare(tp->clk);
        rtnl_unlock();
 
        return 0;
 }
 
-static int rtl8169_resume(struct device *device)
+static int __maybe_unused rtl8169_resume(struct device *device)
 {
        struct rtl8169_private *tp = dev_get_drvdata(device);
 
-       rtl_rar_set(tp, tp->dev->dev_addr);
+       if (!device_may_wakeup(tp_to_dev(tp)))
+               clk_prepare_enable(tp->clk);
 
-       if (tp->TxDescArray)
-               rtl8169_up(tp);
+       /* Reportedly at least Asus X453MA truncates packets otherwise */
+       if (tp->mac_version == RTL_GIGA_MAC_VER_37)
+               rtl_init_rxcfg(tp);
 
-       netif_device_attach(tp->dev);
-
-       return 0;
+       return rtl8169_net_resume(tp);
 }
 
 static int rtl8169_runtime_suspend(struct device *device)
@@ -4874,7 +4891,7 @@ static int rtl8169_runtime_resume(struct device *device)
 
        __rtl8169_set_wol(tp, tp->saved_wolopts);
 
-       return rtl8169_resume(device);
+       return rtl8169_net_resume(tp);
 }
 
 static int rtl8169_runtime_idle(struct device *device)
@@ -4994,7 +5011,7 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
                rtl_unlock_config_regs(tp);
                RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable);
                rtl_lock_config_regs(tp);
-               /* fall through */
+               fallthrough;
        case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_17:
                flags = PCI_IRQ_LEGACY;
                break;
@@ -5137,7 +5154,7 @@ static void rtl_hw_initialize(struct rtl8169_private *tp)
        switch (tp->mac_version) {
        case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52:
                rtl8168ep_stop_cmac(tp);
-               /* fall through */
+               fallthrough;
        case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48:
                rtl_hw_init_8168g(tp);
                break;
index fc99e71..9cc31f7 100644 (file)
@@ -2169,7 +2169,7 @@ static void rocker_router_fib_event_work(struct work_struct *work)
                rocker_world_fib4_del(rocker, &fib_work->fen_info);
                fib_info_put(fib_work->fen_info.fi);
                break;
-       case FIB_EVENT_RULE_ADD: /* fall through */
+       case FIB_EVENT_RULE_ADD:
        case FIB_EVENT_RULE_DEL:
                rule = fib_work->fr_info.rule;
                if (!fib4_rule_default(rule))
@@ -2201,7 +2201,7 @@ static int rocker_router_fib_event(struct notifier_block *nb,
        fib_work->event = event;
 
        switch (event) {
-       case FIB_EVENT_ENTRY_REPLACE: /* fall through */
+       case FIB_EVENT_ENTRY_REPLACE:
        case FIB_EVENT_ENTRY_DEL:
                if (info->family == AF_INET) {
                        struct fib_entry_notifier_info *fen_info = ptr;
@@ -2224,7 +2224,7 @@ static int rocker_router_fib_event(struct notifier_block *nb,
                 */
                fib_info_hold(fib_work->fen_info.fi);
                break;
-       case FIB_EVENT_RULE_ADD: /* fall through */
+       case FIB_EVENT_RULE_ADD:
        case FIB_EVENT_RULE_DEL:
                memcpy(&fib_work->fr_info, ptr, sizeof(fib_work->fr_info));
                fib_rule_get(fib_work->fr_info.rule);
@@ -2811,7 +2811,7 @@ static int rocker_switchdev_event(struct notifier_block *unused,
        switchdev_work->event = event;
 
        switch (event) {
-       case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */
+       case SWITCHDEV_FDB_ADD_TO_DEVICE:
        case SWITCHDEV_FDB_DEL_TO_DEVICE:
                memcpy(&switchdev_work->fdb_info, ptr,
                       sizeof(switchdev_work->fdb_info));
@@ -3099,9 +3099,10 @@ struct rocker_walk_data {
        struct rocker_port *port;
 };
 
-static int rocker_lower_dev_walk(struct net_device *lower_dev, void *_data)
+static int rocker_lower_dev_walk(struct net_device *lower_dev,
+                                struct netdev_nested_priv *priv)
 {
-       struct rocker_walk_data *data = _data;
+       struct rocker_walk_data *data = (struct rocker_walk_data *)priv->data;
        int ret = 0;
 
        if (rocker_port_dev_check_under(lower_dev, data->rocker)) {
@@ -3115,6 +3116,7 @@ static int rocker_lower_dev_walk(struct net_device *lower_dev, void *_data)
 struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev,
                                               struct rocker *rocker)
 {
+       struct netdev_nested_priv priv;
        struct rocker_walk_data data;
 
        if (rocker_port_dev_check_under(dev, rocker))
@@ -3122,7 +3124,8 @@ struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev,
 
        data.rocker = rocker;
        data.port = NULL;
-       netdev_walk_all_lower_dev(dev, rocker_lower_dev_walk, &data);
+       priv.data = (void *)&data;
+       netdev_walk_all_lower_dev(dev, rocker_lower_dev_walk, &priv);
 
        return data.port;
 }
index 21465cb..7f8b10c 100644 (file)
@@ -316,7 +316,7 @@ static int sxgbe_get_rss_hash_opts(struct sxgbe_priv_data *priv,
        case TCP_V4_FLOW:
        case UDP_V4_FLOW:
                cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
-               /* Fall through */
+               fallthrough;
        case SCTP_V4_FLOW:
        case AH_ESP_V4_FLOW:
        case AH_V4_FLOW:
@@ -327,7 +327,7 @@ static int sxgbe_get_rss_hash_opts(struct sxgbe_priv_data *priv,
        case TCP_V6_FLOW:
        case UDP_V6_FLOW:
                cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
-               /* Fall through */
+               fallthrough;
        case SCTP_V6_FLOW:
        case AH_ESP_V6_FLOW:
        case AH_V6_FLOW:
index c54b7f8..ffdb367 100644 (file)
@@ -490,6 +490,7 @@ static int ef100_pci_probe(struct pci_dev *pci_dev,
        if (fcw.offset > pci_resource_len(efx->pci_dev, fcw.bar) - ESE_GZ_FCW_LEN) {
                netif_err(efx, probe, efx->net_dev,
                          "Func control window overruns BAR\n");
+               rc = -EIO;
                goto fail;
        }
 
index 012925e..85207ac 100644 (file)
@@ -36,7 +36,7 @@ bool ef100_rx_buf_hash_valid(const u8 *prefix)
        return PREFIX_FIELD(prefix, RSS_HASH_VALID);
 }
 
-static bool check_fcs(struct efx_channel *channel, u32 *prefix)
+static bool ef100_has_fcs_error(struct efx_channel *channel, u32 *prefix)
 {
        u16 rxclass;
        u8 l2status;
@@ -46,11 +46,11 @@ static bool check_fcs(struct efx_channel *channel, u32 *prefix)
 
        if (likely(l2status == ESE_GZ_RH_HCLASS_L2_STATUS_OK))
                /* Everything is ok */
-               return 0;
+               return false;
 
        if (l2status == ESE_GZ_RH_HCLASS_L2_STATUS_FCS_ERR)
                channel->n_rx_eth_crc_err++;
-       return 1;
+       return true;
 }
 
 void __ef100_rx_packet(struct efx_channel *channel)
@@ -63,7 +63,7 @@ void __ef100_rx_packet(struct efx_channel *channel)
 
        prefix = (u32 *)(eh - ESE_GZ_RX_PKT_PREFIX_LEN);
 
-       if (check_fcs(channel, prefix) &&
+       if (ef100_has_fcs_error(channel, prefix) &&
            unlikely(!(efx->net_dev->features & NETIF_F_RXALL)))
                goto out;
 
index db90d94..a6bae6a 100644 (file)
@@ -957,7 +957,7 @@ ef4_ethtool_get_rxnfc(struct net_device *net_dev,
                switch (info->flow_type) {
                case TCP_V4_FLOW:
                        info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
-                       /* Fall through */
+                       fallthrough;
                case UDP_V4_FLOW:
                case SCTP_V4_FLOW:
                case AH_ESP_V4_FLOW:
index 3321832..fa1ade8 100644 (file)
@@ -1049,10 +1049,10 @@ ef4_farch_handle_rx_event(struct ef4_channel *channel, const ef4_qword_t *event)
                switch (rx_ev_hdr_type) {
                case FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP:
                        flags |= EF4_RX_PKT_TCP;
-                       /* fall through */
+                       fallthrough;
                case FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP:
                        flags |= EF4_RX_PKT_CSUMMED;
-                       /* fall through */
+                       fallthrough;
                case FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_OTHER:
                case FSE_AZ_RX_EV_HDR_TYPE_OTHER:
                        break;
@@ -1310,7 +1310,7 @@ int ef4_farch_ev_process(struct ef4_channel *channel, int budget)
                        if (efx->type->handle_global_event &&
                            efx->type->handle_global_event(channel, &event))
                                break;
-                       /* else fall through */
+                       fallthrough;
                default:
                        netif_err(channel->efx, hw, channel->efx->net_dev,
                                  "channel %d unknown event type %d (data "
@@ -1983,7 +1983,7 @@ ef4_farch_filter_from_gen_spec(struct ef4_farch_filter_spec *spec,
              EF4_FILTER_MATCH_LOC_HOST | EF4_FILTER_MATCH_LOC_PORT |
              EF4_FILTER_MATCH_REM_HOST | EF4_FILTER_MATCH_REM_PORT):
                is_full = true;
-               /* fall through */
+               fallthrough;
        case (EF4_FILTER_MATCH_ETHER_TYPE | EF4_FILTER_MATCH_IP_PROTO |
              EF4_FILTER_MATCH_LOC_HOST | EF4_FILTER_MATCH_LOC_PORT): {
                __be32 rhost, host1, host2;
@@ -2034,7 +2034,7 @@ ef4_farch_filter_from_gen_spec(struct ef4_farch_filter_spec *spec,
 
        case EF4_FILTER_MATCH_LOC_MAC | EF4_FILTER_MATCH_OUTER_VID:
                is_full = true;
-               /* fall through */
+               fallthrough;
        case EF4_FILTER_MATCH_LOC_MAC:
                spec->type = (is_full ? EF4_FARCH_FILTER_MAC_FULL :
                              EF4_FARCH_FILTER_MAC_WILD);
@@ -2081,7 +2081,7 @@ ef4_farch_filter_to_gen_spec(struct ef4_filter_spec *gen_spec,
        case EF4_FARCH_FILTER_TCP_FULL:
        case EF4_FARCH_FILTER_UDP_FULL:
                is_full = true;
-               /* fall through */
+               fallthrough;
        case EF4_FARCH_FILTER_TCP_WILD:
        case EF4_FARCH_FILTER_UDP_WILD: {
                __be32 host1, host2;
@@ -2125,7 +2125,7 @@ ef4_farch_filter_to_gen_spec(struct ef4_filter_spec *gen_spec,
 
        case EF4_FARCH_FILTER_MAC_FULL:
                is_full = true;
-               /* fall through */
+               fallthrough;
        case EF4_FARCH_FILTER_MAC_WILD:
                gen_spec->match_flags = EF4_FILTER_MATCH_LOC_MAC;
                if (is_full)
index d07eeaa..4002f9a 100644 (file)
@@ -1038,10 +1038,10 @@ efx_farch_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
                switch (rx_ev_hdr_type) {
                case FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP:
                        flags |= EFX_RX_PKT_TCP;
-                       /* fall through */
+                       fallthrough;
                case FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP:
                        flags |= EFX_RX_PKT_CSUMMED;
-                       /* fall through */
+                       fallthrough;
                case FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_OTHER:
                case FSE_AZ_RX_EV_HDR_TYPE_OTHER:
                        break;
@@ -1316,7 +1316,7 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget)
                        if (efx->type->handle_global_event &&
                            efx->type->handle_global_event(channel, &event))
                                break;
-                       /* else fall through */
+                       fallthrough;
                default:
                        netif_err(channel->efx, hw, channel->efx->net_dev,
                                  "channel %d unknown event type %d (data "
@@ -2043,7 +2043,7 @@ efx_farch_filter_from_gen_spec(struct efx_farch_filter_spec *spec,
              EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
              EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT):
                is_full = true;
-               /* fall through */
+               fallthrough;
        case (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
              EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT): {
                __be32 rhost, host1, host2;
@@ -2094,7 +2094,7 @@ efx_farch_filter_from_gen_spec(struct efx_farch_filter_spec *spec,
 
        case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
                is_full = true;
-               /* fall through */
+               fallthrough;
        case EFX_FILTER_MATCH_LOC_MAC:
                spec->type = (is_full ? EFX_FARCH_FILTER_MAC_FULL :
                              EFX_FARCH_FILTER_MAC_WILD);
@@ -2141,7 +2141,7 @@ efx_farch_filter_to_gen_spec(struct efx_filter_spec *gen_spec,
        case EFX_FARCH_FILTER_TCP_FULL:
        case EFX_FARCH_FILTER_UDP_FULL:
                is_full = true;
-               /* fall through */
+               fallthrough;
        case EFX_FARCH_FILTER_TCP_WILD:
        case EFX_FARCH_FILTER_UDP_WILD: {
                __be32 host1, host2;
@@ -2185,7 +2185,7 @@ efx_farch_filter_to_gen_spec(struct efx_filter_spec *gen_spec,
 
        case EFX_FARCH_FILTER_MAC_FULL:
                is_full = true;
-               /* fall through */
+               fallthrough;
        case EFX_FARCH_FILTER_MAC_WILD:
                gen_spec->match_flags = EFX_FILTER_MATCH_LOC_MAC;
                if (is_full)
index 5a74d88..1523be7 100644 (file)
@@ -140,7 +140,7 @@ efx_mcdi_filter_push_prep_set_match_fields(struct efx_nic *efx,
                switch (encap_type & EFX_ENCAP_TYPES_MASK) {
                case EFX_ENCAP_TYPE_VXLAN:
                        vni_type = MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN;
-                       /* fallthrough */
+                       fallthrough;
                case EFX_ENCAP_TYPE_GENEVE:
                        COPY_VALUE(ether_type, ETHER_TYPE);
                        outer_ip_proto = IPPROTO_UDP;
index 56af8b5..714d7f9 100644 (file)
@@ -282,7 +282,7 @@ void efx_mcdi_phy_decode_link(struct efx_nic *efx,
                break;
        default:
                WARN_ON(1);
-               /* Fall through */
+               fallthrough;
        case MC_CMD_FCNTL_OFF:
                link_state->fc = 0;
                break;
index 59a43d5..aaa1128 100644 (file)
@@ -358,7 +358,7 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel,
 
        case XDP_ABORTED:
                trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act);
-               /* Fall through */
+               fallthrough;
        case XDP_DROP:
                efx_free_rx_buffers(rx_queue, rx_buf, 1);
                channel->n_rx_xdp_drops++;
index 336105f..cfa460c 100644 (file)
@@ -2228,7 +2228,7 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
        switch(cmd) {
        case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
                data->phy_id = sis_priv->mii->phy_addr;
-               /* Fall Through */
+               fallthrough;
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
                data->val_out = mdio_read(net_dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
index 186c0bd..01069df 100644 (file)
@@ -712,7 +712,7 @@ static void smc911x_phy_detect(struct net_device *dev)
                                        /* Found an external PHY */
                                        break;
                        }
-                       /* Else, fall through */
+                       fallthrough;
                default:
                        /* Internal media only */
                        SMC_GET_PHY_ID1(lp, 1, id1);
index 25db667..806eb65 100644 (file)
@@ -919,10 +919,10 @@ static u32 netsec_run_xdp(struct netsec_priv *priv, struct bpf_prog *prog,
                break;
        default:
                bpf_warn_invalid_xdp_action(act);
-               /* fall through */
+               fallthrough;
        case XDP_ABORTED:
                trace_xdp_exception(priv->ndev, prog, act);
-               /* fall through -- handle aborts by dropping packet */
+               fallthrough;    /* handle aborts by dropping packet */
        case XDP_DROP:
                ret = NETSEC_XDP_CONSUMED;
                page = virt_to_head_page(xdp->data);
index d0d2d0f..08c7663 100644 (file)
@@ -84,9 +84,10 @@ static struct anarion_gmac *anarion_config_dt(struct platform_device *pdev)
                return ERR_PTR(err);
 
        switch (phy_mode) {
-       case PHY_INTERFACE_MODE_RGMII:          /* Fall through */
-       case PHY_INTERFACE_MODE_RGMII_ID        /* Fall through */:
-       case PHY_INTERFACE_MODE_RGMII_RXID:     /* Fall through */
+       case PHY_INTERFACE_MODE_RGMII:
+               fallthrough;
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
        case PHY_INTERFACE_MODE_RGMII_TXID:
                gmac->phy_intf_sel = GMAC_CONFIG_INTF_RGMII;
                break;
index 2ac9dfb..9e6d60e 100644 (file)
@@ -653,7 +653,6 @@ static void intel_eth_pci_remove(struct pci_dev *pdev)
 
        pci_free_irq_vectors(pdev);
 
-       clk_disable_unprepare(priv->plat->stmmac_clk);
        clk_unregister_fixed_rate(priv->plat->stmmac_clk);
 
        pcim_iounmap_regions(pdev, BIT(0));
index 9c02fc7..5456969 100644 (file)
@@ -203,6 +203,8 @@ struct stmmac_priv {
        int eee_enabled;
        int eee_active;
        int tx_lpi_timer;
+       int tx_lpi_enabled;
+       int eee_tw_timer;
        unsigned int mode;
        unsigned int chain_mode;
        int extend_desc;
index ac5e8cc..814879f 100644 (file)
@@ -665,6 +665,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev,
        edata->eee_enabled = priv->eee_enabled;
        edata->eee_active = priv->eee_active;
        edata->tx_lpi_timer = priv->tx_lpi_timer;
+       edata->tx_lpi_enabled = priv->tx_lpi_enabled;
 
        return phylink_ethtool_get_eee(priv->phylink, edata);
 }
@@ -675,24 +676,26 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
        struct stmmac_priv *priv = netdev_priv(dev);
        int ret;
 
-       if (!edata->eee_enabled) {
+       if (!priv->dma_cap.eee)
+               return -EOPNOTSUPP;
+
+       if (priv->tx_lpi_enabled != edata->tx_lpi_enabled)
+               netdev_warn(priv->dev,
+                           "Setting EEE tx-lpi is not supported\n");
+
+       if (!edata->eee_enabled)
                stmmac_disable_eee_mode(priv);
-       } else {
-               /* We are asking for enabling the EEE but it is safe
-                * to verify all by invoking the eee_init function.
-                * In case of failure it will return an error.
-                */
-               edata->eee_enabled = stmmac_eee_init(priv);
-               if (!edata->eee_enabled)
-                       return -EOPNOTSUPP;
-       }
 
        ret = phylink_ethtool_set_eee(priv->phylink, edata);
        if (ret)
                return ret;
 
-       priv->eee_enabled = edata->eee_enabled;
-       priv->tx_lpi_timer = edata->tx_lpi_timer;
+       if (edata->eee_enabled &&
+           priv->tx_lpi_timer != edata->tx_lpi_timer) {
+               priv->tx_lpi_timer = edata->tx_lpi_timer;
+               stmmac_eee_init(priv);
+       }
+
        return 0;
 }
 
index 89b2b34..b56b13d 100644 (file)
@@ -94,7 +94,7 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
 static int eee_timer = STMMAC_DEFAULT_LPI_TIMER;
 module_param(eee_timer, int, 0644);
 MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
-#define STMMAC_LPI_T(x) (jiffies + msecs_to_jiffies(x))
+#define STMMAC_LPI_T(x) (jiffies + usecs_to_jiffies(x))
 
 /* By default the driver will use the ring mode to manage tx and rx descriptors,
  * but allow user to force to use the chain instead of the ring
@@ -370,7 +370,7 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
        struct stmmac_priv *priv = from_timer(priv, t, eee_ctrl_timer);
 
        stmmac_enable_eee_mode(priv);
-       mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
+       mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
 }
 
 /**
@@ -383,7 +383,7 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
  */
 bool stmmac_eee_init(struct stmmac_priv *priv)
 {
-       int tx_lpi_timer = priv->tx_lpi_timer;
+       int eee_tw_timer = priv->eee_tw_timer;
 
        /* Using PCS we cannot dial with the phy registers at this stage
         * so we do not support extra feature like EEE.
@@ -403,7 +403,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
                if (priv->eee_enabled) {
                        netdev_dbg(priv->dev, "disable EEE\n");
                        del_timer_sync(&priv->eee_ctrl_timer);
-                       stmmac_set_eee_timer(priv, priv->hw, 0, tx_lpi_timer);
+                       stmmac_set_eee_timer(priv, priv->hw, 0, eee_tw_timer);
                }
                mutex_unlock(&priv->lock);
                return false;
@@ -411,11 +411,12 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
 
        if (priv->eee_active && !priv->eee_enabled) {
                timer_setup(&priv->eee_ctrl_timer, stmmac_eee_ctrl_timer, 0);
-               mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
                stmmac_set_eee_timer(priv, priv->hw, STMMAC_DEFAULT_LIT_LS,
-                                    tx_lpi_timer);
+                                    eee_tw_timer);
        }
 
+       mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
+
        mutex_unlock(&priv->lock);
        netdev_dbg(priv->dev, "Energy-Efficient Ethernet initialized\n");
        return true;
@@ -930,6 +931,7 @@ static void stmmac_mac_link_down(struct phylink_config *config,
 
        stmmac_mac_set(priv, priv->ioaddr, false);
        priv->eee_active = false;
+       priv->tx_lpi_enabled = false;
        stmmac_eee_init(priv);
        stmmac_set_eee_pls(priv, priv->hw, false);
 }
@@ -1027,6 +1029,7 @@ static void stmmac_mac_link_up(struct phylink_config *config,
        if (phy && priv->dma_cap.eee) {
                priv->eee_active = phy_init_eee(phy, 1) >= 0;
                priv->eee_enabled = stmmac_eee_init(priv);
+               priv->tx_lpi_enabled = priv->eee_enabled;
                stmmac_set_eee_pls(priv, priv->hw, true);
        }
 }
@@ -2061,7 +2064,7 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
 
        if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) {
                stmmac_enable_eee_mode(priv);
-               mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
+               mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
        }
 
        /* We still have pending packets, let's call for a new scheduling */
@@ -2694,7 +2697,11 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
                        netdev_warn(priv->dev, "PTP init failed\n");
        }
 
-       priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
+       priv->eee_tw_timer = STMMAC_DEFAULT_TWT_LS;
+
+       /* Convert the timer from msec to usec */
+       if (!priv->tx_lpi_timer)
+               priv->tx_lpi_timer = eee_timer * 1000;
 
        if (priv->use_riwt) {
                if (!priv->rx_riwt)
index e113b13..bf195ad 100644 (file)
@@ -1985,7 +1985,7 @@ void stmmac_selftest_run(struct net_device *dev,
                                ret = phy_loopback(dev->phydev, true);
                        if (!ret)
                                break;
-                       /* Fallthrough */
+                       fallthrough;
                case STMMAC_LOOPBACK_MAC:
                        ret = stmmac_set_mac_loopback(priv, priv->ioaddr, true);
                        break;
@@ -2018,7 +2018,7 @@ void stmmac_selftest_run(struct net_device *dev,
                                ret = phy_loopback(dev->phydev, false);
                        if (!ret)
                                break;
-                       /* Fallthrough */
+                       fallthrough;
                case STMMAC_LOOPBACK_MAC:
                        stmmac_set_mac_loopback(priv, priv->ioaddr, false);
                        break;
index 3d74784..cc27d66 100644 (file)
@@ -228,7 +228,7 @@ static int tc_setup_cls_u32(struct stmmac_priv *priv,
        switch (cls->command) {
        case TC_CLSU32_REPLACE_KNODE:
                tc_unfill_entry(priv, cls);
-               /* Fall through */
+               fallthrough;
        case TC_CLSU32_NEW_KNODE:
                return tc_config_knode(priv, cls);
        case TC_CLSU32_DELETE_KNODE:
index e2bc7a2..b624e17 100644 (file)
@@ -4759,7 +4759,7 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        switch (cmd) {
        case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
                data->phy_id = cp->phy_addr;
-               /* Fallthrough... */
+               fallthrough;
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
                spin_lock_irqsave(&cp->lock, flags);
index 9b5effb..68695d4 100644 (file)
@@ -8835,7 +8835,7 @@ static int walk_phys(struct niu *np, struct niu_parent *parent)
                        else
                                goto unknown_vg_1g_port;
 
-                       /* fallthru */
+                       fallthrough;
                case 0x22:
                        val = (phy_encode(PORT_TYPE_10G, 0) |
                               phy_encode(PORT_TYPE_10G, 1) |
@@ -8860,7 +8860,7 @@ static int walk_phys(struct niu *np, struct niu_parent *parent)
                        else
                                goto unknown_vg_1g_port;
 
-                       /* fallthru */
+                       fallthrough;
                case 0x13:
                        if ((lowest_10g & 0x7) == 0)
                                val = (phy_encode(PORT_TYPE_10G, 0) |
index eeb8518..8deb943 100644 (file)
@@ -2712,7 +2712,7 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        switch (cmd) {
        case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
                data->phy_id = gp->mii_phy_addr;
-               /* Fallthrough... */
+               fallthrough;
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
                data->val_out = __sungem_phy_read(gp, data->phy_id & 0x1f,
index 8dc6c9f..80fde5f 100644 (file)
@@ -1168,7 +1168,7 @@ static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, int ncookies)
                        *(__sum16 *)(skb->data + offset) = 0;
                        csum = skb_copy_and_csum_bits(skb, start,
                                                      nskb->data + start,
-                                                     skb->len - start, 0);
+                                                     skb->len - start);
 
                        /* add in the header checksums */
                        if (skb->protocol == htons(ETH_P_IP)) {
index cb994f6..9baf3f3 100644 (file)
@@ -174,6 +174,8 @@ void am65_cpsw_nuss_adjust_link(struct net_device *ndev)
                if (phy->speed == 10 && phy_interface_is_rgmii(phy))
                        /* Can be used with in band mode only */
                        mac_control |= CPSW_SL_CTL_EXT_EN;
+               if (phy->speed == 100 && phy->interface == PHY_INTERFACE_MODE_RMII)
+                       mac_control |= CPSW_SL_CTL_IFCTL_A;
                if (phy->duplex)
                        mac_control |= CPSW_SL_CTL_FULLDUPLEX;
 
index 4e184ee..6e72ecb 100644 (file)
@@ -67,7 +67,7 @@ static void cpsw_gmii_sel_am3352(struct cpsw_phy_sel_priv *priv,
                dev_warn(priv->dev,
                         "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
                        phy_modes(phy_mode));
-               /* fallthrough */
+               fallthrough;
        case PHY_INTERFACE_MODE_MII:
                mode = AM33XX_GMII_SEL_MODE_MII;
                break;
@@ -122,7 +122,7 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv,
                dev_warn(priv->dev,
                         "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
                        phy_modes(phy_mode));
-               /* fallthrough */
+               fallthrough;
        case PHY_INTERFACE_MODE_MII:
                mode = AM33XX_GMII_SEL_MODE_MII;
                break;
index 9b17bbb..4a65edc 100644 (file)
@@ -1116,7 +1116,7 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
                                  HOST_PORT_NUM, ALE_VLAN, vid);
        ret |= cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast,
                                  0, ALE_VLAN, vid);
-       ret |= cpsw_ale_flush_multicast(cpsw->ale, 0, vid);
+       ret |= cpsw_ale_flush_multicast(cpsw->ale, ALE_PORT_HOST, vid);
 err:
        pm_runtime_put(cpsw->dev);
        return ret;
index 1247d35..15672d0 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/phy.h>
 #include <linux/phy/phy.h>
 #include <linux/delay.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/gpio/consumer.h>
 #include <linux/of.h>
@@ -1032,19 +1033,34 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
                return ret;
        }
 
+       /* reset the return code as pm_runtime_get_sync() can return
+        * non zero values as well.
+        */
+       ret = 0;
        for (i = 0; i < cpsw->data.slaves; i++) {
                if (cpsw->slaves[i].ndev &&
-                   vid == cpsw->slaves[i].port_vlan)
+                   vid == cpsw->slaves[i].port_vlan) {
+                       ret = -EINVAL;
                        goto err;
+               }
        }
 
        dev_dbg(priv->dev, "removing vlanid %d from vlan filter\n", vid);
-       cpsw_ale_del_vlan(cpsw->ale, vid, 0);
-       cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr,
-                          HOST_PORT_NUM, ALE_VLAN, vid);
-       cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast,
-                          0, ALE_VLAN, vid);
-       cpsw_ale_flush_multicast(cpsw->ale, 0, vid);
+       ret = cpsw_ale_del_vlan(cpsw->ale, vid, 0);
+       if (ret)
+               dev_err(priv->dev, "cpsw_ale_del_vlan() failed: ret %d\n", ret);
+       ret = cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr,
+                                HOST_PORT_NUM, ALE_VLAN, vid);
+       if (ret)
+               dev_err(priv->dev, "cpsw_ale_del_ucast() failed: ret %d\n",
+                       ret);
+       ret = cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast,
+                                0, ALE_VLAN, vid);
+       if (ret)
+               dev_err(priv->dev, "cpsw_ale_del_mcast failed. ret %d\n",
+                       ret);
+       cpsw_ale_flush_multicast(cpsw->ale, ALE_PORT_HOST, vid);
+       ret = 0;
 err:
        pm_runtime_put(cpsw->dev);
        return ret;
@@ -2055,9 +2071,61 @@ static int cpsw_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int __maybe_unused cpsw_suspend(struct device *dev)
+{
+       struct cpsw_common *cpsw = dev_get_drvdata(dev);
+       int i;
+
+       rtnl_lock();
+
+       for (i = 0; i < cpsw->data.slaves; i++) {
+               struct net_device *ndev = cpsw->slaves[i].ndev;
+
+               if (!(ndev && netif_running(ndev)))
+                       continue;
+
+               cpsw_ndo_stop(ndev);
+       }
+
+       rtnl_unlock();
+
+       /* Select sleep pin state */
+       pinctrl_pm_select_sleep_state(dev);
+
+       return 0;
+}
+
+static int __maybe_unused cpsw_resume(struct device *dev)
+{
+       struct cpsw_common *cpsw = dev_get_drvdata(dev);
+       int i;
+
+       /* Select default pin state */
+       pinctrl_pm_select_default_state(dev);
+
+       /* shut up ASSERT_RTNL() warning in netif_set_real_num_tx/rx_queues */
+       rtnl_lock();
+
+       for (i = 0; i < cpsw->data.slaves; i++) {
+               struct net_device *ndev = cpsw->slaves[i].ndev;
+
+               if (!(ndev && netif_running(ndev)))
+                       continue;
+
+               cpsw_ndo_open(ndev);
+       }
+
+       rtnl_unlock();
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cpsw_pm_ops, cpsw_suspend, cpsw_resume);
+
 static struct platform_driver cpsw_driver = {
        .driver = {
                .name    = "cpsw-switch",
+               .pm      = &cpsw_pm_ops,
                .of_match_table = cpsw_of_mtable,
        },
        .probe = cpsw_probe,
index d6d7a7d..482a1a4 100644 (file)
@@ -1371,10 +1371,10 @@ int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp,
                break;
        default:
                bpf_warn_invalid_xdp_action(act);
-               /* fall through */
+               fallthrough;
        case XDP_ABORTED:
                trace_xdp_exception(ndev, prog, act);
-               /* fall through -- handle aborts by dropping packet */
+               fallthrough;    /* handle aborts by dropping packet */
        case XDP_DROP:
                goto drop;
        }
index 58623e9..76a342e 100644 (file)
@@ -948,7 +948,7 @@ static int tlan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        switch (cmd) {
        case SIOCGMIIPHY:               /* get address of MII PHY in use. */
                data->phy_id = phy;
-               /* fall through */
+               fallthrough;
 
 
        case SIOCGMIIREG:               /* read MII PHY register. */
index 2db546b..dc14a66 100644 (file)
@@ -877,7 +877,7 @@ static int gelic_wl_set_auth(struct net_device *netdev,
        case IW_AUTH_KEY_MGMT:
                if (param->value & IW_AUTH_KEY_MGMT_PSK)
                        break;
-               /* intentionally fall through */
+               fallthrough;
        default:
                ret = -EOPNOTSUPP;
                break;
index 0738970..5f5b33e 100644 (file)
@@ -786,7 +786,7 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
                        /* fallthrough, if we release the descriptors
                         * brutally (then we don't care about
                         * SPIDER_NET_DESCR_CARDOWNED) */
-                       /* Fall through */
+                       fallthrough;
 
                case SPIDER_NET_DESCR_RESPONSE_ERROR:
                case SPIDER_NET_DESCR_PROTECTION_ERROR:
@@ -1397,9 +1397,9 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg,
                show_error = 0;
                break;
 
-       case SPIDER_NET_GDDDEN0INT: /* fallthrough */
-       case SPIDER_NET_GDCDEN0INT: /* fallthrough */
-       case SPIDER_NET_GDBDEN0INT: /* fallthrough */
+       case SPIDER_NET_GDDDEN0INT:
+       case SPIDER_NET_GDCDEN0INT:
+       case SPIDER_NET_GDBDEN0INT:
        case SPIDER_NET_GDADEN0INT:
                /* someone has set RX_DMA_EN to 0 */
                show_error = 0;
@@ -1449,10 +1449,10 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg,
                 * Logging is not needed. */
                show_error = 0;
                break;
-       case SPIDER_NET_GRFDFLLINT: /* fallthrough */
-       case SPIDER_NET_GRFCFLLINT: /* fallthrough */
-       case SPIDER_NET_GRFBFLLINT: /* fallthrough */
-       case SPIDER_NET_GRFAFLLINT: /* fallthrough */
+       case SPIDER_NET_GRFDFLLINT:
+       case SPIDER_NET_GRFCFLLINT:
+       case SPIDER_NET_GRFBFLLINT:
+       case SPIDER_NET_GRFAFLLINT:
        case SPIDER_NET_GRMFLLINT:
                /* Could happen when rx chain is full */
                if (card->ignore_rx_ramfull == 0) {
@@ -1473,9 +1473,9 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg,
                break;
 
        /* chain end */
-       case SPIDER_NET_GDDDCEINT: /* fallthrough */
-       case SPIDER_NET_GDCDCEINT: /* fallthrough */
-       case SPIDER_NET_GDBDCEINT: /* fallthrough */
+       case SPIDER_NET_GDDDCEINT:
+       case SPIDER_NET_GDCDCEINT:
+       case SPIDER_NET_GDBDCEINT:
        case SPIDER_NET_GDADCEINT:
                spider_net_resync_head_ptr(card);
                spider_net_refill_rx_chain(card);
@@ -1486,9 +1486,9 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg,
                break;
 
        /* invalid descriptor */
-       case SPIDER_NET_GDDINVDINT: /* fallthrough */
-       case SPIDER_NET_GDCINVDINT: /* fallthrough */
-       case SPIDER_NET_GDBINVDINT: /* fallthrough */
+       case SPIDER_NET_GDDINVDINT:
+       case SPIDER_NET_GDCINVDINT:
+       case SPIDER_NET_GDBINVDINT:
        case SPIDER_NET_GDAINVDINT:
                /* Could happen when rx chain is full */
                spider_net_resync_head_ptr(card);
index 803247d..55b0dda 100644 (file)
@@ -2,7 +2,7 @@
 /*
        Written 1998-2001 by Donald Becker.
 
-       Current Maintainer: Roger Luethi <rl@hellgate.ch>
+       Current Maintainer: Kevin Brace <kevinbrace@bracecomputerlab.com>
 
        This software may be used and distributed according to the terms of
        the GNU General Public License (GPL), incorporated herein by reference.
@@ -32,8 +32,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #define DRV_NAME       "via-rhine"
-#define DRV_VERSION    "1.5.1"
-#define DRV_RELDATE    "2010-10-09"
 
 #include <linux/types.h>
 
@@ -117,10 +115,6 @@ static const int multicast_filter_limit = 32;
 #include <linux/uaccess.h>
 #include <linux/dmi.h>
 
-/* These identify the driver base version and may not be removed. */
-static const char version[] =
-       "v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker";
-
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
 MODULE_LICENSE("GPL");
@@ -243,7 +237,7 @@ enum rhine_revs {
        VT8233          = 0x60, /* Integrated MAC */
        VT8235          = 0x74, /* Integrated MAC */
        VT8237          = 0x78, /* Integrated MAC */
-       VTunknown1      = 0x7C,
+       VT8251          = 0x7C, /* Integrated MAC */
        VT6105          = 0x80,
        VT6105_B0       = 0x83,
        VT6105L         = 0x8A,
@@ -1051,11 +1045,6 @@ static int rhine_init_one_pci(struct pci_dev *pdev,
        u32 quirks = 0;
 #endif
 
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
-       pr_info_once("%s\n", version);
-#endif
-
        rc = pci_enable_device(pdev);
        if (rc)
                goto err_out;
@@ -1706,6 +1695,8 @@ static int rhine_open(struct net_device *dev)
                goto out_free_ring;
 
        alloc_tbufs(dev);
+       enable_mmio(rp->pioaddr, rp->quirks);
+       rhine_power_init(dev);
        rhine_chip_reset(dev);
        rhine_task_enable(rp);
        init_registers(dev);
@@ -2294,7 +2285,6 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
        struct device *hwdev = dev->dev.parent;
 
        strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
-       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
        strlcpy(info->bus_info, dev_name(hwdev), sizeof(info->bus_info));
 }
 
@@ -2616,9 +2606,6 @@ static int __init rhine_init(void)
        int ret_pci, ret_platform;
 
 /* when a module, this is printed whether or not devices are found in probe */
-#ifdef MODULE
-       pr_info("%s\n", version);
-#endif
        if (dmi_check_system(rhine_dmi_table)) {
                /* these BIOSes fail at PXE boot if chip is in D3 */
                avoid_D3 = true;
index 3e3883a..3e33714 100644 (file)
@@ -1434,7 +1434,7 @@ do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
     switch(cmd) {
       case SIOCGMIIPHY:                /* Get the address of the PHY in use. */
        data->phy_id = 0;       /* we have only this address */
-       /* fall through */
+       fallthrough;
       case SIOCGMIIREG:                /* Read the specified MII register. */
        data->val_out = mii_rd(ioaddr, data->phy_id & 0x1f,
                               data->reg_num & 0x1f);
index 1be0395..554cde8 100644 (file)
@@ -847,7 +847,7 @@ static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd)
 
        case ACTIONS(PC5_SIGNAL) :
                ACTIONS_DONE() ;
-               /* fall through */
+               fallthrough;
        case PC5_SIGNAL :
                if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT))
                        break ;
@@ -946,7 +946,7 @@ static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd)
                SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
                ACTIONS_DONE() ;
                cmd = 0 ;
-               /* fall thru */
+               fallthrough;
        case PC6_JOIN :
                switch (plc->p_state) {
                case PS_ACTIVE:
index 8c810ed..4666226 100644 (file)
@@ -974,7 +974,7 @@ static void fjes_stop_req_irq(struct fjes_adapter *adapter, int src_epid)
                                FJES_RX_STOP_REQ_DONE;
                spin_unlock_irqrestore(&hw->rx_status_lock, flags);
                clear_bit(src_epid, &hw->txrx_stop_req_bit);
-               /* fall through */
+               fallthrough;
        case EP_PARTNER_UNSHARE:
        case EP_PARTNER_COMPLETE:
        default:
index c71f994..974a244 100644 (file)
@@ -777,7 +777,8 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
                                       struct net_device *dev,
                                       struct geneve_sock *gs4,
                                       struct flowi4 *fl4,
-                                      const struct ip_tunnel_info *info)
+                                      const struct ip_tunnel_info *info,
+                                      __be16 dport, __be16 sport)
 {
        bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
        struct geneve_dev *geneve = netdev_priv(dev);
@@ -793,6 +794,8 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
        fl4->flowi4_proto = IPPROTO_UDP;
        fl4->daddr = info->key.u.ipv4.dst;
        fl4->saddr = info->key.u.ipv4.src;
+       fl4->fl4_dport = dport;
+       fl4->fl4_sport = sport;
 
        tos = info->key.tos;
        if ((tos == 1) && !geneve->cfg.collect_md) {
@@ -827,7 +830,8 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
                                           struct net_device *dev,
                                           struct geneve_sock *gs6,
                                           struct flowi6 *fl6,
-                                          const struct ip_tunnel_info *info)
+                                          const struct ip_tunnel_info *info,
+                                          __be16 dport, __be16 sport)
 {
        bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
        struct geneve_dev *geneve = netdev_priv(dev);
@@ -843,6 +847,9 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
        fl6->flowi6_proto = IPPROTO_UDP;
        fl6->daddr = info->key.u.ipv6.dst;
        fl6->saddr = info->key.u.ipv6.src;
+       fl6->fl6_dport = dport;
+       fl6->fl6_sport = sport;
+
        prio = info->key.tos;
        if ((prio == 1) && !geneve->cfg.collect_md) {
                prio = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
@@ -889,7 +896,9 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        __be16 sport;
        int err;
 
-       rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info);
+       sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
+       rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
+                             geneve->cfg.info.key.tp_dst, sport);
        if (IS_ERR(rt))
                return PTR_ERR(rt);
 
@@ -919,7 +928,6 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                return -EMSGSIZE;
        }
 
-       sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
        if (geneve->cfg.collect_md) {
                tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
                ttl = key->ttl;
@@ -974,7 +982,9 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        __be16 sport;
        int err;
 
-       dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info);
+       sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
+       dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
+                               geneve->cfg.info.key.tp_dst, sport);
        if (IS_ERR(dst))
                return PTR_ERR(dst);
 
@@ -1003,7 +1013,6 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                return -EMSGSIZE;
        }
 
-       sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
        if (geneve->cfg.collect_md) {
                prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
                ttl = key->ttl;
@@ -1085,13 +1094,18 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 {
        struct ip_tunnel_info *info = skb_tunnel_info(skb);
        struct geneve_dev *geneve = netdev_priv(dev);
+       __be16 sport;
 
        if (ip_tunnel_info_af(info) == AF_INET) {
                struct rtable *rt;
                struct flowi4 fl4;
+
                struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
+               sport = udp_flow_src_port(geneve->net, skb,
+                                         1, USHRT_MAX, true);
 
-               rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info);
+               rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
+                                     geneve->cfg.info.key.tp_dst, sport);
                if (IS_ERR(rt))
                        return PTR_ERR(rt);
 
@@ -1101,9 +1115,13 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
        } else if (ip_tunnel_info_af(info) == AF_INET6) {
                struct dst_entry *dst;
                struct flowi6 fl6;
+
                struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
+               sport = udp_flow_src_port(geneve->net, skb,
+                                         1, USHRT_MAX, true);
 
-               dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info);
+               dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
+                                       geneve->cfg.info.key.tp_dst, sport);
                if (IS_ERR(dst))
                        return PTR_ERR(dst);
 
@@ -1114,8 +1132,7 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
                return -EINVAL;
        }
 
-       info->key.tp_src = udp_flow_src_port(geneve->net, skb,
-                                            1, USHRT_MAX, true);
+       info->key.tp_src = sport;
        info->key.tp_dst = geneve->cfg.info.key.tp_dst;
        return 0;
 }
index 21640a0..8e47d01 100644 (file)
@@ -1179,6 +1179,7 @@ static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq,
                goto nlmsg_failure;
 
        if (nla_put_u32(skb, GTPA_VERSION, pctx->gtp_version) ||
+           nla_put_u32(skb, GTPA_LINK, pctx->dev->ifindex) ||
            nla_put_be32(skb, GTPA_PEER_ADDRESS, pctx->peer_addr_ip4.s_addr) ||
            nla_put_be32(skb, GTPA_MS_ADDRESS, pctx->ms_addr_ip4.s_addr))
                goto nla_put_failure;
index 4476491..e4e4981 100644 (file)
@@ -500,7 +500,7 @@ static int transmit(struct baycom_state *bc, int cnt, unsigned char stat)
                                }
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
 
                default:
                        if (bc->hdlctx.calibrate <= 0)
index deef142..17be2bb 100644 (file)
@@ -482,7 +482,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
                case CRC_MODE_SMACK_TEST:
                        ax->crcmode  = CRC_MODE_FLEX_TEST;
                        printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name);
-                       // fall through
+                       fallthrough;
                case CRC_MODE_SMACK:
                        *p |= 0x80;
                        crc = swab16(crc16(0, p, len));
@@ -491,7 +491,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
                case CRC_MODE_FLEX_TEST:
                        ax->crcmode = CRC_MODE_NONE;
                        printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name);
-                       // fall through
+                       fallthrough;
                case CRC_MODE_FLEX:
                        *p |= 0x20;
                        crc = calc_crc_flex(p, len);
@@ -744,7 +744,6 @@ static int mkiss_open(struct tty_struct *tty)
                       ax->dev->name);
                break;
        case 0:
-               /* fall through */
        default:
                crc_force = 0;
                printk(KERN_INFO "mkiss: %s: crc mode is auto.\n",
index 2181d45..a0f338c 100644 (file)
@@ -847,6 +847,10 @@ struct nvsp_message {
 
 #define NETVSC_XDP_HDRM 256
 
+#define NETVSC_XFER_HEADER_SIZE(rng_cnt) \
+               (offsetof(struct vmtransfer_page_packet_header, ranges) + \
+               (rng_cnt) * sizeof(struct vmtransfer_page_range))
+
 struct multi_send_data {
        struct sk_buff *skb; /* skb containing the pkt */
        struct hv_netvsc_packet *pkt; /* netvsc pkt pending */
@@ -974,6 +978,9 @@ struct net_device_context {
        /* Serial number of the VF to team with */
        u32 vf_serial;
 
+       /* Is the current data path through the VF NIC? */
+       bool  data_path_is_vf;
+
        /* Used to temporarily save the config info across hibernation */
        struct netvsc_device_info *saved_netvsc_dev_info;
 };
index 41f5cf0..5a57d19 100644 (file)
@@ -388,6 +388,15 @@ static int netvsc_init_buf(struct hv_device *device,
        net_device->recv_section_size = resp->sections[0].sub_alloc_size;
        net_device->recv_section_cnt = resp->sections[0].num_sub_allocs;
 
+       /* Ensure buffer will not overflow */
+       if (net_device->recv_section_size < NETVSC_MTU_MIN || (u64)net_device->recv_section_size *
+           (u64)net_device->recv_section_cnt > (u64)buf_size) {
+               netdev_err(ndev, "invalid recv_section_size %u\n",
+                          net_device->recv_section_size);
+               ret = -EINVAL;
+               goto cleanup;
+       }
+
        /* Setup receive completion ring.
         * Add 1 to the recv_section_cnt because at least one entry in a
         * ring buffer has to be empty.
@@ -460,6 +469,12 @@ static int netvsc_init_buf(struct hv_device *device,
        /* Parse the response */
        net_device->send_section_size = init_packet->msg.
                                v1_msg.send_send_buf_complete.section_size;
+       if (net_device->send_section_size < NETVSC_MTU_MIN) {
+               netdev_err(ndev, "invalid send_section_size %u\n",
+                          net_device->send_section_size);
+               ret = -EINVAL;
+               goto cleanup;
+       }
 
        /* Section count is simply the size divided by the section size. */
        net_device->send_section_cnt = buf_size / net_device->send_section_size;
@@ -731,12 +746,49 @@ static void netvsc_send_completion(struct net_device *ndev,
                                   int budget)
 {
        const struct nvsp_message *nvsp_packet = hv_pkt_data(desc);
+       u32 msglen = hv_pkt_datalen(desc);
+
+       /* Ensure packet is big enough to read header fields */
+       if (msglen < sizeof(struct nvsp_message_header)) {
+               netdev_err(ndev, "nvsp_message length too small: %u\n", msglen);
+               return;
+       }
 
        switch (nvsp_packet->hdr.msg_type) {
        case NVSP_MSG_TYPE_INIT_COMPLETE:
+               if (msglen < sizeof(struct nvsp_message_header) +
+                               sizeof(struct nvsp_message_init_complete)) {
+                       netdev_err(ndev, "nvsp_msg length too small: %u\n",
+                                  msglen);
+                       return;
+               }
+               fallthrough;
+
        case NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE:
+               if (msglen < sizeof(struct nvsp_message_header) +
+                               sizeof(struct nvsp_1_message_send_receive_buffer_complete)) {
+                       netdev_err(ndev, "nvsp_msg1 length too small: %u\n",
+                                  msglen);
+                       return;
+               }
+               fallthrough;
+
        case NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE:
+               if (msglen < sizeof(struct nvsp_message_header) +
+                               sizeof(struct nvsp_1_message_send_send_buffer_complete)) {
+                       netdev_err(ndev, "nvsp_msg1 length too small: %u\n",
+                                  msglen);
+                       return;
+               }
+               fallthrough;
+
        case NVSP_MSG5_TYPE_SUBCHANNEL:
+               if (msglen < sizeof(struct nvsp_message_header) +
+                               sizeof(struct nvsp_5_subchannel_complete)) {
+                       netdev_err(ndev, "nvsp_msg5 length too small: %u\n",
+                                  msglen);
+                       return;
+               }
                /* Copy the response back */
                memcpy(&net_device->channel_init_pkt, nvsp_packet,
                       sizeof(struct nvsp_message));
@@ -1117,19 +1169,28 @@ static void enq_receive_complete(struct net_device *ndev,
 static int netvsc_receive(struct net_device *ndev,
                          struct netvsc_device *net_device,
                          struct netvsc_channel *nvchan,
-                         const struct vmpacket_descriptor *desc,
-                         const struct nvsp_message *nvsp)
+                         const struct vmpacket_descriptor *desc)
 {
        struct net_device_context *net_device_ctx = netdev_priv(ndev);
        struct vmbus_channel *channel = nvchan->channel;
        const struct vmtransfer_page_packet_header *vmxferpage_packet
                = container_of(desc, const struct vmtransfer_page_packet_header, d);
+       const struct nvsp_message *nvsp = hv_pkt_data(desc);
+       u32 msglen = hv_pkt_datalen(desc);
        u16 q_idx = channel->offermsg.offer.sub_channel_index;
        char *recv_buf = net_device->recv_buf;
        u32 status = NVSP_STAT_SUCCESS;
        int i;
        int count = 0;
 
+       /* Ensure packet is big enough to read header fields */
+       if (msglen < sizeof(struct nvsp_message_header)) {
+               netif_err(net_device_ctx, rx_err, ndev,
+                         "invalid nvsp header, length too small: %u\n",
+                         msglen);
+               return 0;
+       }
+
        /* Make sure this is a valid nvsp packet */
        if (unlikely(nvsp->hdr.msg_type != NVSP_MSG1_TYPE_SEND_RNDIS_PKT)) {
                netif_err(net_device_ctx, rx_err, ndev,
@@ -1138,6 +1199,14 @@ static int netvsc_receive(struct net_device *ndev,
                return 0;
        }
 
+       /* Validate xfer page pkt header */
+       if ((desc->offset8 << 3) < sizeof(struct vmtransfer_page_packet_header)) {
+               netif_err(net_device_ctx, rx_err, ndev,
+                         "Invalid xfer page pkt, offset too small: %u\n",
+                         desc->offset8 << 3);
+               return 0;
+       }
+
        if (unlikely(vmxferpage_packet->xfer_pageset_id != NETVSC_RECEIVE_BUFFER_ID)) {
                netif_err(net_device_ctx, rx_err, ndev,
                          "Invalid xfer page set id - expecting %x got %x\n",
@@ -1148,6 +1217,14 @@ static int netvsc_receive(struct net_device *ndev,
 
        count = vmxferpage_packet->range_cnt;
 
+       /* Check count for a valid value */
+       if (NETVSC_XFER_HEADER_SIZE(count) > desc->offset8 << 3) {
+               netif_err(net_device_ctx, rx_err, ndev,
+                         "Range count is not valid: %d\n",
+                         count);
+               return 0;
+       }
+
        /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
        for (i = 0; i < count; i++) {
                u32 offset = vmxferpage_packet->ranges[i].byte_offset;
@@ -1155,7 +1232,8 @@ static int netvsc_receive(struct net_device *ndev,
                void *data;
                int ret;
 
-               if (unlikely(offset + buflen > net_device->recv_buf_size)) {
+               if (unlikely(offset > net_device->recv_buf_size ||
+                            buflen > net_device->recv_buf_size - offset)) {
                        nvchan->rsc.cnt = 0;
                        status = NVSP_STAT_FAIL;
                        netif_err(net_device_ctx, rx_err, ndev,
@@ -1194,6 +1272,13 @@ static void netvsc_send_table(struct net_device *ndev,
        u32 count, offset, *tab;
        int i;
 
+       /* Ensure packet is big enough to read send_table fields */
+       if (msglen < sizeof(struct nvsp_message_header) +
+                    sizeof(struct nvsp_5_send_indirect_table)) {
+               netdev_err(ndev, "nvsp_v5_msg length too small: %u\n", msglen);
+               return;
+       }
+
        count = nvmsg->msg.v5_msg.send_table.count;
        offset = nvmsg->msg.v5_msg.send_table.offset;
 
@@ -1225,10 +1310,18 @@ static void netvsc_send_table(struct net_device *ndev,
 }
 
 static void netvsc_send_vf(struct net_device *ndev,
-                          const struct nvsp_message *nvmsg)
+                          const struct nvsp_message *nvmsg,
+                          u32 msglen)
 {
        struct net_device_context *net_device_ctx = netdev_priv(ndev);
 
+       /* Ensure packet is big enough to read its fields */
+       if (msglen < sizeof(struct nvsp_message_header) +
+                    sizeof(struct nvsp_4_send_vf_association)) {
+               netdev_err(ndev, "nvsp_v4_msg length too small: %u\n", msglen);
+               return;
+       }
+
        net_device_ctx->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated;
        net_device_ctx->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial;
        netdev_info(ndev, "VF slot %u %s\n",
@@ -1238,16 +1331,24 @@ static void netvsc_send_vf(struct net_device *ndev,
 
 static void netvsc_receive_inband(struct net_device *ndev,
                                  struct netvsc_device *nvscdev,
-                                 const struct nvsp_message *nvmsg,
-                                 u32 msglen)
+                                 const struct vmpacket_descriptor *desc)
 {
+       const struct nvsp_message *nvmsg = hv_pkt_data(desc);
+       u32 msglen = hv_pkt_datalen(desc);
+
+       /* Ensure packet is big enough to read header fields */
+       if (msglen < sizeof(struct nvsp_message_header)) {
+               netdev_err(ndev, "inband nvsp_message length too small: %u\n", msglen);
+               return;
+       }
+
        switch (nvmsg->hdr.msg_type) {
        case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE:
                netvsc_send_table(ndev, nvscdev, nvmsg, msglen);
                break;
 
        case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION:
-               netvsc_send_vf(ndev, nvmsg);
+               netvsc_send_vf(ndev, nvmsg, msglen);
                break;
        }
 }
@@ -1261,23 +1362,20 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
 {
        struct vmbus_channel *channel = nvchan->channel;
        const struct nvsp_message *nvmsg = hv_pkt_data(desc);
-       u32 msglen = hv_pkt_datalen(desc);
 
        trace_nvsp_recv(ndev, channel, nvmsg);
 
        switch (desc->type) {
        case VM_PKT_COMP:
-               netvsc_send_completion(ndev, net_device, channel,
-                                      desc, budget);
+               netvsc_send_completion(ndev, net_device, channel, desc, budget);
                break;
 
        case VM_PKT_DATA_USING_XFER_PAGES:
-               return netvsc_receive(ndev, net_device, nvchan,
-                                     desc, nvmsg);
+               return netvsc_receive(ndev, net_device, nvchan, desc);
                break;
 
        case VM_PKT_DATA_INBAND:
-               netvsc_receive_inband(ndev, net_device, nvmsg, msglen);
+               netvsc_receive_inband(ndev, net_device, desc);
                break;
 
        default:
index 64b0a74..9869e39 100644 (file)
@@ -748,6 +748,13 @@ void netvsc_linkstatus_callback(struct net_device *net,
        struct netvsc_reconfig *event;
        unsigned long flags;
 
+       /* Ensure the packet is big enough to access its fields */
+       if (resp->msg_len - RNDIS_HEADER_SIZE < sizeof(struct rndis_indicate_status)) {
+               netdev_err(net, "invalid rndis_indicate_status packet, len: %u\n",
+                          resp->msg_len);
+               return;
+       }
+
        /* Update the physical link speed when changing to another vSwitch */
        if (indicate->status == RNDIS_STATUS_LINK_SPEED_CHANGE) {
                u32 speed;
@@ -2366,7 +2373,16 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
        return NOTIFY_OK;
 }
 
-/* VF up/down change detected, schedule to change data path */
+/* Change the data path when VF UP/DOWN/CHANGE are detected.
+ *
+ * Typically a UP or DOWN event is followed by a CHANGE event, so
+ * net_device_ctx->data_path_is_vf is used to cache the current data path
+ * to avoid the duplicate call of netvsc_switch_datapath() and the duplicate
+ * message.
+ *
+ * During hibernation, if a VF NIC driver (e.g. mlx5) preserves the network
+ * interface, there is only the CHANGE event and no UP or DOWN event.
+ */
 static int netvsc_vf_changed(struct net_device *vf_netdev)
 {
        struct net_device_context *net_device_ctx;
@@ -2383,6 +2399,10 @@ static int netvsc_vf_changed(struct net_device *vf_netdev)
        if (!netvsc_dev)
                return NOTIFY_DONE;
 
+       if (net_device_ctx->data_path_is_vf == vf_is_up)
+               return NOTIFY_OK;
+       net_device_ctx->data_path_is_vf = vf_is_up;
+
        netvsc_switch_datapath(ndev, vf_is_up);
        netdev_info(ndev, "Data path switched %s VF: %s\n",
                    vf_is_up ? "to" : "from", vf_netdev->name);
@@ -2587,8 +2607,8 @@ static int netvsc_remove(struct hv_device *dev)
 static int netvsc_suspend(struct hv_device *dev)
 {
        struct net_device_context *ndev_ctx;
-       struct net_device *vf_netdev, *net;
        struct netvsc_device *nvdev;
+       struct net_device *net;
        int ret;
 
        net = hv_get_drvdata(dev);
@@ -2604,10 +2624,6 @@ static int netvsc_suspend(struct hv_device *dev)
                goto out;
        }
 
-       vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev);
-       if (vf_netdev)
-               netvsc_unregister_vf(vf_netdev);
-
        /* Save the current config info */
        ndev_ctx->saved_netvsc_dev_info = netvsc_devinfo_get(nvdev);
 
@@ -2628,6 +2644,12 @@ static int netvsc_resume(struct hv_device *dev)
        rtnl_lock();
 
        net_device_ctx = netdev_priv(net);
+
+       /* Reset the data path to the netvsc NIC before re-opening the vmbus
+        * channel. Later netvsc_netdev_event() will switch the data path to
+        * the VF upon the UP or CHANGE event.
+        */
+       net_device_ctx->data_path_is_vf = false;
        device_info = net_device_ctx->saved_netvsc_dev_info;
 
        ret = netvsc_attach(net, device_info);
@@ -2695,6 +2717,7 @@ static int netvsc_netdev_event(struct notifier_block *this,
                return netvsc_unregister_vf(event_dev);
        case NETDEV_UP:
        case NETDEV_DOWN:
+       case NETDEV_CHANGE:
                return netvsc_vf_changed(event_dev);
        default:
                return NOTIFY_DONE;
index b81ceba..12ad471 100644 (file)
@@ -275,6 +275,16 @@ static void rndis_filter_receive_response(struct net_device *ndev,
                return;
        }
 
+       /* Ensure the packet is big enough to read req_id. Req_id is the 1st
+        * field in any request/response message, so the payload should have at
+        * least sizeof(u32) bytes
+        */
+       if (resp->msg_len - RNDIS_HEADER_SIZE < sizeof(u32)) {
+               netdev_err(ndev, "rndis msg_len too small: %u\n",
+                          resp->msg_len);
+               return;
+       }
+
        spin_lock_irqsave(&dev->request_lock, flags);
        list_for_each_entry(request, &dev->req_list, list_ent) {
                /*
@@ -331,8 +341,9 @@ static void rndis_filter_receive_response(struct net_device *ndev,
  * Get the Per-Packet-Info with the specified type
  * return NULL if not found.
  */
-static inline void *rndis_get_ppi(struct rndis_packet *rpkt,
-                                 u32 type, u8 internal)
+static inline void *rndis_get_ppi(struct net_device *ndev,
+                                 struct rndis_packet *rpkt,
+                                 u32 rpkt_len, u32 type, u8 internal)
 {
        struct rndis_per_packet_info *ppi;
        int len;
@@ -340,11 +351,36 @@ static inline void *rndis_get_ppi(struct rndis_packet *rpkt,
        if (rpkt->per_pkt_info_offset == 0)
                return NULL;
 
+       /* Validate info_offset and info_len */
+       if (rpkt->per_pkt_info_offset < sizeof(struct rndis_packet) ||
+           rpkt->per_pkt_info_offset > rpkt_len) {
+               netdev_err(ndev, "Invalid per_pkt_info_offset: %u\n",
+                          rpkt->per_pkt_info_offset);
+               return NULL;
+       }
+
+       if (rpkt->per_pkt_info_len > rpkt_len - rpkt->per_pkt_info_offset) {
+               netdev_err(ndev, "Invalid per_pkt_info_len: %u\n",
+                          rpkt->per_pkt_info_len);
+               return NULL;
+       }
+
        ppi = (struct rndis_per_packet_info *)((ulong)rpkt +
                rpkt->per_pkt_info_offset);
        len = rpkt->per_pkt_info_len;
 
        while (len > 0) {
+               /* Validate ppi_offset and ppi_size */
+               if (ppi->size > len) {
+                       netdev_err(ndev, "Invalid ppi size: %u\n", ppi->size);
+                       continue;
+               }
+
+               if (ppi->ppi_offset >= ppi->size) {
+                       netdev_err(ndev, "Invalid ppi_offset: %u\n", ppi->ppi_offset);
+                       continue;
+               }
+
                if (ppi->type == type && ppi->internal == internal)
                        return (void *)((ulong)ppi + ppi->ppi_offset);
                len -= ppi->size;
@@ -388,14 +424,29 @@ static int rndis_filter_receive_data(struct net_device *ndev,
        const struct ndis_pkt_8021q_info *vlan;
        const struct rndis_pktinfo_id *pktinfo_id;
        const u32 *hash_info;
-       u32 data_offset;
+       u32 data_offset, rpkt_len;
        void *data;
        bool rsc_more = false;
        int ret;
 
+       /* Ensure data_buflen is big enough to read header fields */
+       if (data_buflen < RNDIS_HEADER_SIZE + sizeof(struct rndis_packet)) {
+               netdev_err(ndev, "invalid rndis pkt, data_buflen too small: %u\n",
+                          data_buflen);
+               return NVSP_STAT_FAIL;
+       }
+
+       /* Validate rndis_pkt offset */
+       if (rndis_pkt->data_offset >= data_buflen - RNDIS_HEADER_SIZE) {
+               netdev_err(ndev, "invalid rndis packet offset: %u\n",
+                          rndis_pkt->data_offset);
+               return NVSP_STAT_FAIL;
+       }
+
        /* Remove the rndis header and pass it back up the stack */
        data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
 
+       rpkt_len = data_buflen - RNDIS_HEADER_SIZE;
        data_buflen -= data_offset;
 
        /*
@@ -410,13 +461,13 @@ static int rndis_filter_receive_data(struct net_device *ndev,
                return NVSP_STAT_FAIL;
        }
 
-       vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO, 0);
+       vlan = rndis_get_ppi(ndev, rndis_pkt, rpkt_len, IEEE_8021Q_INFO, 0);
 
-       csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO, 0);
+       csum_info = rndis_get_ppi(ndev, rndis_pkt, rpkt_len, TCPIP_CHKSUM_PKTINFO, 0);
 
-       hash_info = rndis_get_ppi(rndis_pkt, NBL_HASH_VALUE, 0);
+       hash_info = rndis_get_ppi(ndev, rndis_pkt, rpkt_len, NBL_HASH_VALUE, 0);
 
-       pktinfo_id = rndis_get_ppi(rndis_pkt, RNDIS_PKTINFO_ID, 1);
+       pktinfo_id = rndis_get_ppi(ndev, rndis_pkt, rpkt_len, RNDIS_PKTINFO_ID, 1);
 
        data = (void *)msg + data_offset;
 
@@ -474,6 +525,14 @@ int rndis_filter_receive(struct net_device *ndev,
        if (netif_msg_rx_status(net_device_ctx))
                dump_rndis_message(ndev, rndis_msg);
 
+       /* Validate incoming rndis_message packet */
+       if (buflen < RNDIS_HEADER_SIZE || rndis_msg->msg_len < RNDIS_HEADER_SIZE ||
+           buflen < rndis_msg->msg_len) {
+               netdev_err(ndev, "Invalid rndis_msg (buflen: %u, msg_len: %u)\n",
+                          buflen, rndis_msg->msg_len);
+               return NVSP_STAT_FAIL;
+       }
+
        switch (rndis_msg->ndis_msg_type) {
        case RNDIS_MSG_PACKET:
                return rndis_filter_receive_data(ndev, net_dev, nvchan,
index c11f32f..7db9cbd 100644 (file)
@@ -882,7 +882,9 @@ static int adf7242_rx(struct adf7242_local *lp)
        int ret;
        u8 lqi, len_u8, *data;
 
-       adf7242_read_reg(lp, 0, &len_u8);
+       ret = adf7242_read_reg(lp, 0, &len_u8);
+       if (ret)
+               return ret;
 
        len = len_u8;
 
index e04c3b6..4eb6470 100644 (file)
@@ -2925,6 +2925,7 @@ static int ca8210_dev_com_init(struct ca8210_priv *priv)
        );
        if (!priv->irq_workqueue) {
                dev_crit(&priv->spi->dev, "alloc of irq_workqueue failed!\n");
+               destroy_workqueue(priv->mlme_workqueue);
                return -ENOMEM;
        }
 
index 2098ca2..b3790aa 100644 (file)
@@ -521,7 +521,7 @@ static void ipa_filter_tuple_zero(struct ipa_endpoint *endpoint)
        val = ioread32(endpoint->ipa->reg_virt + offset);
 
        /* Zero all filter-related fields, preserving the rest */
-       u32_replace_bits(val, 0, IPA_REG_ENDP_FILTER_HASH_MSK_ALL);
+       u32p_replace_bits(&val, 0, IPA_REG_ENDP_FILTER_HASH_MSK_ALL);
 
        iowrite32(val, endpoint->ipa->reg_virt + offset);
 }
@@ -573,7 +573,7 @@ static void ipa_route_tuple_zero(struct ipa *ipa, u32 route_id)
        val = ioread32(ipa->reg_virt + offset);
 
        /* Zero all route-related fields, preserving the rest */
-       u32_replace_bits(val, 0, IPA_REG_ENDP_ROUTER_HASH_MSK_ALL);
+       u32p_replace_bits(&val, 0, IPA_REG_ENDP_ROUTER_HASH_MSK_ALL);
 
        iowrite32(val, ipa->reg_virt + offset);
 }
index 9159846..787ac2c 100644 (file)
@@ -1077,6 +1077,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
        struct macsec_rx_sa *rx_sa;
        struct macsec_rxh_data *rxd;
        struct macsec_dev *macsec;
+       unsigned int len;
        sci_t sci;
        u32 hdr_pn;
        bool cbit;
@@ -1232,9 +1233,10 @@ deliver:
        macsec_rxsc_put(rx_sc);
 
        skb_orphan(skb);
+       len = skb->len;
        ret = gro_cells_receive(&macsec->gro_cells, skb);
        if (ret == NET_RX_SUCCESS)
-               count_rx(dev, skb->len);
+               count_rx(dev, len);
        else
                macsec->secy.netdev->stats.rx_dropped++;
 
index 5da04e9..c8d803d 100644 (file)
@@ -842,7 +842,7 @@ static int macvlan_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCSHWTSTAMP:
                if (!net_eq(dev_net(dev), &init_net))
                        break;
-               /* fall through */
+               fallthrough;
        case SIOCGHWTSTAMP:
                if (netif_device_present(real_dev) && ops->ndo_do_ioctl)
                        err = ops->ndo_do_ioctl(real_dev, &ifrr, cmd);
index 4461212..f6a97c8 100644 (file)
@@ -597,7 +597,7 @@ int generic_mii_ioctl(struct mii_if_info *mii_if,
        switch(cmd) {
        case SIOCGMIIPHY:
                mii_data->phy_id = mii_if->phy_id;
-               /* fall through */
+               fallthrough;
 
        case SIOCGMIIREG:
                mii_data->val_out =
index 7971dc4..0e95116 100644 (file)
@@ -193,7 +193,7 @@ new_device_store(struct bus_type *bus, const char *buf, size_t count)
        switch (err) {
        case 1:
                port_count = 1;
-               /* fall through */
+               fallthrough;
        case 2:
                if (id > INT_MAX) {
                        pr_err("Value of \"id\" is too big.\n");
index f32d56a..deea17a 100644 (file)
@@ -760,14 +760,14 @@ static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event,
        spin_lock_bh(&data->fib_lock);
 
        switch (event) {
-       case FIB_EVENT_RULE_ADD: /* fall through */
+       case FIB_EVENT_RULE_ADD:
        case FIB_EVENT_RULE_DEL:
                err = nsim_fib_rule_event(data, info,
                                          event == FIB_EVENT_RULE_ADD);
                break;
 
-       case FIB_EVENT_ENTRY_REPLACE:  /* fall through */
-       case FIB_EVENT_ENTRY_APPEND:  /* fall through */
+       case FIB_EVENT_ENTRY_REPLACE:
+       case FIB_EVENT_ENTRY_APPEND:
        case FIB_EVENT_ENTRY_DEL:
                err = nsim_fib_event(data, info, event);
                break;
index 726e4b2..1c5a10b 100644 (file)
@@ -222,6 +222,7 @@ config MDIO_THUNDER
        depends on 64BIT
        depends on PCI
        select MDIO_CAVIUM
+       select MDIO_DEVRES
        help
          This driver supports the MDIO interfaces found on Cavium
          ThunderX SoCs when the MDIO bus device appears as a PCI
index 7471a8b..307f0ac 100644 (file)
@@ -366,10 +366,10 @@ static int adin_set_edpd(struct phy_device *phydev, u16 tx_interval)
 
        switch (tx_interval) {
        case 1000: /* 1 second */
-               /* fallthrough */
+               fallthrough;
        case ETHTOOL_PHY_EDPD_DFLT_TX_MSECS:
                val |= ADIN1300_NRG_PD_TX_EN;
-               /* fallthrough */
+               fallthrough;
        case ETHTOOL_PHY_EDPD_NO_TX:
                break;
        default:
index 50fb7d1..79e67f2 100644 (file)
@@ -766,13 +766,13 @@ static int decode_evnt(struct dp83640_private *dp83640,
        switch (words) {
        case 3:
                dp83640->edata.sec_hi = phy_txts->sec_hi;
-               /* fall through */
+               fallthrough;
        case 2:
                dp83640->edata.sec_lo = phy_txts->sec_lo;
-               /* fall through */
+               fallthrough;
        case 1:
                dp83640->edata.ns_hi = phy_txts->ns_hi;
-               /* fall through */
+               fallthrough;
        case 0:
                dp83640->edata.ns_lo = phy_txts->ns_lo;
        }
@@ -1409,7 +1409,7 @@ static void dp83640_txtstamp(struct mii_timestamper *mii_ts,
                        kfree_skb(skb);
                        return;
                }
-               /* fall through */
+               fallthrough;
        case HWTSTAMP_TX_ON:
                skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
                skb_info->tmo = jiffies + SKB_TIMESTAMP_TIMEOUT;
index f3c0498..cd70326 100644 (file)
@@ -215,9 +215,9 @@ static int dp83867_set_wol(struct phy_device *phydev,
                if (wol->wolopts & WAKE_MAGICSECURE) {
                        phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1,
                                      (wol->sopass[1] << 8) | wol->sopass[0]);
-                       phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1,
+                       phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP2,
                                      (wol->sopass[3] << 8) | wol->sopass[2]);
-                       phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1,
+                       phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP3,
                                      (wol->sopass[5] << 8) | wol->sopass[4]);
 
                        val_rxcfg |= DP83867_WOL_SEC_EN;
index 5810315..6b98d74 100644 (file)
@@ -427,18 +427,18 @@ static int dp83869_config_init(struct phy_device *phydev)
                        return ret;
 
                val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIICTL);
-               val &= ~(DP83869_RGMII_TX_CLK_DELAY_EN |
-                        DP83869_RGMII_RX_CLK_DELAY_EN);
+               val |= (DP83869_RGMII_TX_CLK_DELAY_EN |
+                       DP83869_RGMII_RX_CLK_DELAY_EN);
 
                if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
-                       val |= (DP83869_RGMII_TX_CLK_DELAY_EN |
-                               DP83869_RGMII_RX_CLK_DELAY_EN);
+                       val &= ~(DP83869_RGMII_TX_CLK_DELAY_EN |
+                                DP83869_RGMII_RX_CLK_DELAY_EN);
 
                if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
-                       val |= DP83869_RGMII_TX_CLK_DELAY_EN;
+                       val &= ~DP83869_RGMII_TX_CLK_DELAY_EN;
 
                if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
-                       val |= DP83869_RGMII_RX_CLK_DELAY_EN;
+                       val &= ~DP83869_RGMII_RX_CLK_DELAY_EN;
 
                ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIICTL,
                                    val);
index c4641b1..18d81f4 100644 (file)
@@ -279,13 +279,13 @@ static struct phy_device *__fixed_phy_register(unsigned int irq,
                                 phy->supported);
                linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
                                 phy->supported);
-               /* fall through */
+               fallthrough;
        case SPEED_100:
                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
                                 phy->supported);
                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
                                 phy->supported);
-               /* fall through */
+               fallthrough;
        case SPEED_10:
        default:
                linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
index 79b4f35..8947d58 100644 (file)
@@ -355,7 +355,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
        switch (cmd) {
        case SIOCGMIIPHY:
                mii_data->phy_id = phydev->mdio.addr;
-               /* fall through */
+               fallthrough;
 
        case SIOCGMIIREG:
                if (mdio_phy_id_is_c45(mii_data->phy_id)) {
@@ -433,7 +433,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
        case SIOCSHWTSTAMP:
                if (phydev->mii_ts && phydev->mii_ts->hwtstamp)
                        return phydev->mii_ts->hwtstamp(phydev->mii_ts, ifr);
-               /* fall through */
+               fallthrough;
 
        default:
                return -EOPNOTSUPP;
@@ -996,7 +996,7 @@ void phy_stop(struct phy_device *phydev)
 {
        struct net_device *dev = phydev->attached_dev;
 
-       if (!phy_is_started(phydev)) {
+       if (!phy_is_started(phydev) && phydev->state != PHY_DOWN) {
                WARN(1, "called from state %s\n",
                     phy_state_to_str(phydev->state));
                return;
index 57d4464..5dab6be 100644 (file)
@@ -1143,10 +1143,6 @@ int phy_init_hw(struct phy_device *phydev)
        if (ret < 0)
                return ret;
 
-       ret = phy_disable_interrupts(phydev);
-       if (ret)
-               return ret;
-
        if (phydev->drv->config_init)
                ret = phydev->drv->config_init(phydev);
 
@@ -1423,6 +1419,10 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
        if (err)
                goto error;
 
+       err = phy_disable_interrupts(phydev);
+       if (err)
+               return err;
+
        phy_resume(phydev);
        phy_led_triggers_register(phydev);
 
@@ -1682,7 +1682,8 @@ void phy_detach(struct phy_device *phydev)
 
        phy_led_triggers_unregister(phydev);
 
-       module_put(phydev->mdio.dev.driver->owner);
+       if (phydev->mdio.dev.driver)
+               module_put(phydev->mdio.dev.driver->owner);
 
        /* If the device had no specific driver before (i.e. - it
         * was using the generic driver), we unbind the device
@@ -1979,7 +1980,7 @@ static int genphy_setup_master_slave(struct phy_device *phydev)
                break;
        case MASTER_SLAVE_CFG_MASTER_FORCE:
                ctl |= CTL1000_AS_MASTER;
-               /* fallthrough */
+               fallthrough;
        case MASTER_SLAVE_CFG_SLAVE_FORCE:
                ctl |= CTL1000_ENABLE_MASTER;
                break;
index 32b4bd6..32f4e8e 100644 (file)
@@ -1905,7 +1905,7 @@ int phylink_mii_ioctl(struct phylink *pl, struct ifreq *ifr, int cmd)
                switch (cmd) {
                case SIOCGMIIPHY:
                        mii->phy_id = pl->phydev->mdio.addr;
-                       /* fall through */
+                       fallthrough;
 
                case SIOCGMIIREG:
                        ret = phylink_phy_read(pl, mii->phy_id, mii->reg_num);
@@ -1928,7 +1928,7 @@ int phylink_mii_ioctl(struct phylink *pl, struct ifreq *ifr, int cmd)
                switch (cmd) {
                case SIOCGMIIPHY:
                        mii->phy_id = 0;
-                       /* fall through */
+                       fallthrough;
 
                case SIOCGMIIREG:
                        ret = phylink_mii_read(pl, mii->phy_id, mii->reg_num);
index 95dbe5e..0f09609 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0+
-/*
- * drivers/net/phy/realtek.c
+/* drivers/net/phy/realtek.c
  *
  * Driver for Realtek PHYs
  *
@@ -32,9 +31,9 @@
 #define RTL8211F_TX_DELAY                      BIT(8)
 #define RTL8211F_RX_DELAY                      BIT(3)
 
-#define RTL8211E_TX_DELAY                      BIT(1)
-#define RTL8211E_RX_DELAY                      BIT(2)
-#define RTL8211E_MODE_MII_GMII                 BIT(3)
+#define RTL8211E_CTRL_DELAY                    BIT(13)
+#define RTL8211E_TX_DELAY                      BIT(12)
+#define RTL8211E_RX_DELAY                      BIT(11)
 
 #define RTL8201F_ISR                           0x1e
 #define RTL8201F_IER                           0x13
@@ -246,16 +245,16 @@ static int rtl8211e_config_init(struct phy_device *phydev)
        /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
        switch (phydev->interface) {
        case PHY_INTERFACE_MODE_RGMII:
-               val = 0;
+               val = RTL8211E_CTRL_DELAY | 0;
                break;
        case PHY_INTERFACE_MODE_RGMII_ID:
-               val = RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
+               val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
                break;
        case PHY_INTERFACE_MODE_RGMII_RXID:
-               val = RTL8211E_RX_DELAY;
+               val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY;
                break;
        case PHY_INTERFACE_MODE_RGMII_TXID:
-               val = RTL8211E_TX_DELAY;
+               val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY;
                break;
        default: /* the rest of the modes imply leaving delays as is. */
                return 0;
@@ -263,11 +262,12 @@ static int rtl8211e_config_init(struct phy_device *phydev)
 
        /* According to a sample driver there is a 0x1c config register on the
         * 0xa4 extension page (0x7) layout. It can be used to disable/enable
-        * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. It can
-        * also be used to customize the whole configuration register:
-        * 8:6 = PHY Address, 5:4 = Auto-Negotiation, 3 = Interface Mode Select,
-        * 2 = RX Delay, 1 = TX Delay, 0 = SELRGV (see original PHY datasheet
-        * for details).
+        * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins.
+        * The configuration register definition:
+        * 14 = reserved
+        * 13 = Force Tx RX Delay controlled by bit12 bit11,
+        * 12 = RX Delay, 11 = TX Delay
+        * 10:0 = Test && debug settings reserved by realtek
         */
        oldpage = phy_select_page(phydev, 0x7);
        if (oldpage < 0)
@@ -277,7 +277,8 @@ static int rtl8211e_config_init(struct phy_device *phydev)
        if (ret)
                goto err_restore_page;
 
-       ret = __phy_modify(phydev, 0x1c, RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
+       ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY
+                          | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
                           val);
 
 err_restore_page:
index 6900c68..58014fe 100644 (file)
@@ -149,7 +149,7 @@ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
                        port = PORT_TP;
                        break;
                }
-               /* fallthrough */
+               fallthrough;
        case SFF8024_CONNECTOR_SG: /* guess */
        case SFF8024_CONNECTOR_HSSDC_II:
        case SFF8024_CONNECTOR_NOSEPARATE:
@@ -301,7 +301,7 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
                break;
        case SFF8024_ECC_100GBASE_CR4:
                phylink_set(modes, 100000baseCR4_Full);
-               /* fallthrough */
+               fallthrough;
        case SFF8024_ECC_25GBASE_CR_S:
        case SFF8024_ECC_25GBASE_CR_N:
                phylink_set(modes, 25000baseCR_Full);
index c24b0e8..cf83314 100644 (file)
@@ -552,7 +552,7 @@ static umode_t sfp_hwmon_is_visible(const void *data,
                case hwmon_temp_crit:
                        if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN))
                                return 0;
-                       /* fall through */
+                       fallthrough;
                case hwmon_temp_input:
                case hwmon_temp_label:
                        return 0444;
@@ -571,7 +571,7 @@ static umode_t sfp_hwmon_is_visible(const void *data,
                case hwmon_in_crit:
                        if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN))
                                return 0;
-                       /* fall through */
+                       fallthrough;
                case hwmon_in_input:
                case hwmon_in_label:
                        return 0444;
@@ -590,7 +590,7 @@ static umode_t sfp_hwmon_is_visible(const void *data,
                case hwmon_curr_crit:
                        if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN))
                                return 0;
-                       /* fall through */
+                       fallthrough;
                case hwmon_curr_input:
                case hwmon_curr_label:
                        return 0444;
@@ -618,7 +618,7 @@ static umode_t sfp_hwmon_is_visible(const void *data,
                case hwmon_power_crit:
                        if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_ALARMWARN))
                                return 0;
-                       /* fall through */
+                       fallthrough;
                case hwmon_power_input:
                case hwmon_power_label:
                        return 0444;
@@ -1872,7 +1872,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
                        dev_warn(sfp->dev, "hwmon probe failed: %d\n", err);
 
                sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0);
-               /* fall through */
+               fallthrough;
        case SFP_MOD_WAITDEV:
                /* Ensure that the device is attached before proceeding */
                if (sfp->sm_dev_state < SFP_DEV_DOWN)
@@ -1890,7 +1890,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
                        goto insert;
 
                sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, 0);
-               /* fall through */
+               fallthrough;
        case SFP_MOD_HPOWER:
                /* Enable high power mode */
                err = sfp_sm_mod_hpower(sfp, true);
index d82016d..4406b35 100644 (file)
@@ -498,7 +498,7 @@ plip_receive(unsigned short nibble_timeout, struct net_device *dev,
                *data_p = (c0 >> 3) & 0x0f;
                write_data (dev, 0x10); /* send ACK */
                *ns_p = PLIP_NB_1;
-               /* fall through */
+               fallthrough;
 
        case PLIP_NB_1:
                cx = nibble_timeout;
@@ -594,7 +594,7 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
                        printk(KERN_DEBUG "%s: receive start\n", dev->name);
                rcv->state = PLIP_PK_LENGTH_LSB;
                rcv->nibble = PLIP_NB_BEGIN;
-               /* fall through */
+               fallthrough;
 
        case PLIP_PK_LENGTH_LSB:
                if (snd->state != PLIP_PK_DONE) {
@@ -615,7 +615,7 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
                                return TIMEOUT;
                }
                rcv->state = PLIP_PK_LENGTH_MSB;
-               /* fall through */
+               fallthrough;
 
        case PLIP_PK_LENGTH_MSB:
                if (plip_receive(nibble_timeout, dev,
@@ -638,7 +638,7 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
                rcv->state = PLIP_PK_DATA;
                rcv->byte = 0;
                rcv->checksum = 0;
-               /* fall through */
+               fallthrough;
 
        case PLIP_PK_DATA:
                lbuf = rcv->skb->data;
@@ -651,7 +651,7 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
                        rcv->checksum += lbuf[--rcv->byte];
                } while (rcv->byte);
                rcv->state = PLIP_PK_CHECKSUM;
-               /* fall through */
+               fallthrough;
 
        case PLIP_PK_CHECKSUM:
                if (plip_receive(nibble_timeout, dev,
@@ -664,7 +664,7 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
                        return ERROR;
                }
                rcv->state = PLIP_PK_DONE;
-               /* fall through */
+               fallthrough;
 
        case PLIP_PK_DONE:
                /* Inform the upper layer for the arrival of a packet. */
@@ -710,7 +710,7 @@ plip_send(unsigned short nibble_timeout, struct net_device *dev,
        case PLIP_NB_BEGIN:
                write_data (dev, data & 0x0f);
                *ns_p = PLIP_NB_1;
-               /* fall through */
+               fallthrough;
 
        case PLIP_NB_1:
                write_data (dev, 0x10 | (data & 0x0f));
@@ -725,7 +725,7 @@ plip_send(unsigned short nibble_timeout, struct net_device *dev,
                }
                write_data (dev, 0x10 | (data >> 4));
                *ns_p = PLIP_NB_2;
-               /* fall through */
+               fallthrough;
 
        case PLIP_NB_2:
                write_data (dev, (data >> 4));
@@ -814,7 +814,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
                              &snd->nibble, snd->length.b.lsb))
                        return TIMEOUT;
                snd->state = PLIP_PK_LENGTH_MSB;
-               /* fall through */
+               fallthrough;
 
        case PLIP_PK_LENGTH_MSB:
                if (plip_send(nibble_timeout, dev,
@@ -823,7 +823,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
                snd->state = PLIP_PK_DATA;
                snd->byte = 0;
                snd->checksum = 0;
-               /* fall through */
+               fallthrough;
 
        case PLIP_PK_DATA:
                do {
@@ -835,7 +835,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
                        snd->checksum += lbuf[--snd->byte];
                } while (snd->byte);
                snd->state = PLIP_PK_CHECKSUM;
-               /* fall through */
+               fallthrough;
 
        case PLIP_PK_CHECKSUM:
                if (plip_send(nibble_timeout, dev,
@@ -846,7 +846,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
                dev_kfree_skb(snd->skb);
                dev->stats.tx_packets++;
                snd->state = PLIP_PK_DONE;
-               /* fall through */
+               fallthrough;
 
        case PLIP_PK_DONE:
                /* Close the connection */
@@ -935,7 +935,7 @@ plip_interrupt(void *dev_id)
        switch (nl->connection) {
        case PLIP_CN_CLOSING:
                netif_wake_queue (dev);
-               /* fall through */
+               fallthrough;
        case PLIP_CN_NONE:
        case PLIP_CN_SEND:
                rcv->state = PLIP_PK_TRIGGER;
index 8c1e027..bcc4a4c 100644 (file)
@@ -287,7 +287,7 @@ inst_rollback:
        for (i--; i >= 0; i--)
                __team_option_inst_del_option(team, dst_opts[i]);
 
-       i = option_count - 1;
+       i = option_count;
 alloc_rollback:
        for (i--; i >= 0; i--)
                kfree(dst_opts[i]);
@@ -2112,6 +2112,7 @@ static void team_setup_by_port(struct net_device *dev,
        dev->header_ops = port_dev->header_ops;
        dev->type = port_dev->type;
        dev->hard_header_len = port_dev->hard_header_len;
+       dev->needed_headroom = port_dev->needed_headroom;
        dev->addr_len = port_dev->addr_len;
        dev->mtu = port_dev->mtu;
        memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len);
index 3c11a77..7959b5c 100644 (file)
@@ -1590,10 +1590,10 @@ static int tun_xdp_act(struct tun_struct *tun, struct bpf_prog *xdp_prog,
                break;
        default:
                bpf_warn_invalid_xdp_action(act);
-               /* fall through */
+               fallthrough;
        case XDP_ABORTED:
                trace_xdp_exception(tun->dev, xdp_prog, act);
-               /* fall through */
+               fallthrough;
        case XDP_DROP:
                this_cpu_inc(tun->pcpu_stats->rx_dropped);
                break;
@@ -2417,7 +2417,7 @@ static int tun_xdp_one(struct tun_struct *tun,
                switch (err) {
                case XDP_REDIRECT:
                        *flush = true;
-                       /* fall through */
+                       fallthrough;
                case XDP_TX:
                        return 0;
                case XDP_PASS:
index a7fbc3c..c7bcfca 100644 (file)
@@ -252,6 +252,7 @@ config USB_NET_CDC_EEM
 config USB_NET_CDC_NCM
        tristate "CDC NCM support"
        depends on USB_USBNET
+       select USB_NET_CDCETHER
        default y
        help
          This driver provides support for CDC NCM (Network Control Model
index 7e44110..0717c18 100644 (file)
@@ -333,13 +333,13 @@ static void aqc111_set_phy_speed(struct usbnet *dev, u8 autoneg, u16 speed)
                switch (speed) {
                case SPEED_5000:
                        aqc111_data->phy_cfg |= AQ_ADV_5G;
-                       /* fall-through */
+                       fallthrough;
                case SPEED_2500:
                        aqc111_data->phy_cfg |= AQ_ADV_2G5;
-                       /* fall-through */
+                       fallthrough;
                case SPEED_1000:
                        aqc111_data->phy_cfg |= AQ_ADV_1G;
-                       /* fall-through */
+                       fallthrough;
                case SPEED_100:
                        aqc111_data->phy_cfg |= AQ_ADV_100M;
                        /* fall-through */
index e39f41e..7bc6e8f 100644 (file)
@@ -296,7 +296,7 @@ int asix_read_phy_addr(struct usbnet *dev, int internal)
 
        netdev_dbg(dev->net, "asix_get_phy_addr()\n");
 
-       if (ret < 0) {
+       if (ret < 2) {
                netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
                goto out;
        }
index a38e868..5541f3f 100644 (file)
@@ -1823,6 +1823,33 @@ static const struct driver_info belkin_info = {
        .status = ax88179_status,
        .link_reset = ax88179_link_reset,
        .reset  = ax88179_reset,
+       .stop   = ax88179_stop,
+       .flags  = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+};
+
+static const struct driver_info toshiba_info = {
+       .description = "Toshiba USB Ethernet Adapter",
+       .bind   = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset  = ax88179_reset,
+       .stop = ax88179_stop,
+       .flags  = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+};
+
+static const struct driver_info mct_info = {
+       .description = "MCT USB 3.0 Gigabit Ethernet Adapter",
+       .bind   = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset  = ax88179_reset,
+       .stop   = ax88179_stop,
        .flags  = FLAG_ETHER | FLAG_FRAMING_AX,
        .rx_fixup = ax88179_rx_fixup,
        .tx_fixup = ax88179_tx_fixup,
@@ -1861,6 +1888,14 @@ static const struct usb_device_id products[] = {
        /* Belkin B2B128 USB 3.0 Hub + Gigabit Ethernet Adapter */
        USB_DEVICE(0x050d, 0x0128),
        .driver_info = (unsigned long)&belkin_info,
+}, {
+       /* Toshiba USB 3.0 GBit Ethernet Adapter */
+       USB_DEVICE(0x0930, 0x0a13),
+       .driver_info = (unsigned long)&toshiba_info,
+}, {
+       /* Magic Control Technology U3-A9003 USB 3.0 Gigabit Ethernet Adapter */
+       USB_DEVICE(0x0711, 0x0179),
+       .driver_info = (unsigned long)&mct_info,
 },
        { },
 };
index d387bc7..97ba670 100644 (file)
@@ -858,7 +858,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
                default:
                        dev_warn(&intf->dev,
                                 "Couldn't detect memory size, assuming 32k\n");
-                       /* fall through */
+                       fallthrough;
                case 0x87654321:
                        catc_set_reg(catc, TxBufCount, 4);
                        catc_set_reg(catc, RxBufCount, 16);
index 9bdbd7b..dba847f 100644 (file)
@@ -97,7 +97,7 @@ static void tx_complete(struct urb *req)
        case -ECONNRESET:
        case -ESHUTDOWN:
                dev->stats.tx_aborted_errors++;
-               /* fall through */
+               fallthrough;
        default:
                dev->stats.tx_errors++;
                dev_dbg(&dev->dev, "TX error (%d)\n", status);
index b91f92e..915ac75 100644 (file)
@@ -625,6 +625,10 @@ static const struct usb_device_id products[] = {
         USB_DEVICE(0x0a46, 0x1269),    /* DM9621A USB to Fast Ethernet Adapter */
         .driver_info = (unsigned long)&dm9601_info,
        },
+       {
+        USB_DEVICE(0x0586, 0x3427),    /* ZyXEL Keenetic Plus DSL xDSL modem */
+        .driver_info = (unsigned long)&dm9601_info,
+       },
        {},                     // END
 };
 
index 442507f..65b315b 100644 (file)
@@ -3192,7 +3192,7 @@ static void rx_complete(struct urb *urb)
        case -EPIPE:
                dev->net->stats.rx_errors++;
                lan78xx_defer_kevent(dev, EVENT_RX_HALT);
-               /* FALLTHROUGH */
+               fallthrough;
        case -ECONNRESET:                               /* async unlink */
        case -ESHUTDOWN:                                /* hardware gone */
                netif_dbg(dev, ifdown, dev->net,
@@ -3213,7 +3213,7 @@ static void rx_complete(struct urb *urb)
        /* data overrun ... flush fifo? */
        case -EOVERFLOW:
                dev->net->stats.rx_over_errors++;
-               /* FALLTHROUGH */
+               fallthrough;
 
        default:
                state = rx_cleanup;
index 0ef7e1f..060a8a0 100644 (file)
@@ -360,28 +360,47 @@ fail:
 }
 #endif                         /* PEGASUS_WRITE_EEPROM */
 
-static inline void get_node_id(pegasus_t *pegasus, __u8 *id)
+static inline int get_node_id(pegasus_t *pegasus, u8 *id)
 {
-       int i;
-       __u16 w16;
+       int i, ret;
+       u16 w16;
 
        for (i = 0; i < 3; i++) {
-               read_eprom_word(pegasus, i, &w16);
+               ret = read_eprom_word(pegasus, i, &w16);
+               if (ret < 0)
+                       return ret;
                ((__le16 *) id)[i] = cpu_to_le16(w16);
        }
+
+       return 0;
 }
 
 static void set_ethernet_addr(pegasus_t *pegasus)
 {
-       __u8 node_id[6];
+       int ret;
+       u8 node_id[6];
 
        if (pegasus->features & PEGASUS_II) {
-               get_registers(pegasus, 0x10, sizeof(node_id), node_id);
+               ret = get_registers(pegasus, 0x10, sizeof(node_id), node_id);
+               if (ret < 0)
+                       goto err;
        } else {
-               get_node_id(pegasus, node_id);
-               set_registers(pegasus, EthID, sizeof(node_id), node_id);
+               ret = get_node_id(pegasus, node_id);
+               if (ret < 0)
+                       goto err;
+               ret = set_registers(pegasus, EthID, sizeof(node_id), node_id);
+               if (ret < 0)
+                       goto err;
        }
+
        memcpy(pegasus->net->dev_addr, node_id, sizeof(node_id));
+
+       return;
+err:
+       eth_hw_addr_random(pegasus->net);
+       dev_info(&pegasus->intf->dev, "software assigned MAC address.\n");
+
+       return;
 }
 
 static inline int reset_mac(pegasus_t *pegasus)
@@ -629,7 +648,7 @@ static void write_bulk_callback(struct urb *urb)
                return;
        default:
                netif_info(pegasus, tx_err, net, "TX status %d\n", status);
-               /* FALL THROUGH */
+               fallthrough;
        case 0:
                break;
        }
@@ -1009,7 +1028,7 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
        switch (cmd) {
        case SIOCDEVPRIVATE:
                data[0] = pegasus->phy;
-               /* fall through */
+               fallthrough;
        case SIOCDEVPRIVATE + 1:
                read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]);
                res = 0;
index 07c42c0..5ca1356 100644 (file)
@@ -1375,6 +1375,7 @@ static const struct usb_device_id products[] = {
        {QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */
        {QMI_FIXED_INTF(0x0489, 0xe0b4, 0)},    /* Foxconn T77W968 LTE */
        {QMI_FIXED_INTF(0x0489, 0xe0b5, 0)},    /* Foxconn T77W968 LTE with eSIM support*/
+       {QMI_FIXED_INTF(0x2692, 0x9025, 4)},    /* Cellient MPL200 (rebranded Qualcomm 05c6:9025) */
 
        /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
index 2b02fef..b177048 100644 (file)
@@ -1682,7 +1682,7 @@ static void intr_callback(struct urb *urb)
        case -ECONNRESET:       /* unlink */
        case -ESHUTDOWN:
                netif_device_detach(tp->netdev);
-               /* fall through */
+               fallthrough;
        case -ENOENT:
        case -EPROTO:
                netif_info(tp, intr, tp->netdev,
@@ -3251,7 +3251,7 @@ static void r8153b_ups_en(struct r8152 *tp, bool enable)
                        r8152_mdio_write(tp, MII_BMCR, data);
 
                        data = r8153_phy_status(tp, PHY_STAT_LAN_ON);
-                       /* fall through */
+                       fallthrough;
 
                default:
                        if (data != PHY_STAT_LAN_ON)
@@ -4849,7 +4849,7 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
                                tp->ups_info.speed_duplex = NWAY_1000M_FULL;
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
                default:
                        ret = -EINVAL;
                        goto out;
index bd9c078..6fa7a00 100644 (file)
@@ -201,7 +201,7 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
                        dev_dbg(&info->control->dev,
                                "rndis response error, code %d\n", retval);
                }
-               msleep(20);
+               msleep(40);
        }
        dev_dbg(&info->control->dev, "rndis response timeout\n");
        return -ETIMEDOUT;
index e7c630d..9d079dc 100644 (file)
@@ -274,12 +274,20 @@ static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
                return 1;
 }
 
-static inline void set_ethernet_addr(rtl8150_t * dev)
+static void set_ethernet_addr(rtl8150_t *dev)
 {
-       u8 node_id[6];
+       u8 node_id[ETH_ALEN];
+       int ret;
+
+       ret = get_registers(dev, IDR, sizeof(node_id), node_id);
 
-       get_registers(dev, IDR, sizeof(node_id), node_id);
-       memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
+       if (ret == sizeof(node_id)) {
+               ether_addr_copy(dev->netdev->dev_addr, node_id);
+       } else {
+               eth_hw_addr_random(dev->netdev);
+               netdev_notice(dev->netdev, "Assigned a random MAC address: %pM\n",
+                             dev->netdev->dev_addr);
+       }
 }
 
 static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
@@ -843,7 +851,7 @@ static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
        switch (cmd) {
        case SIOCDEVPRIVATE:
                data[0] = dev->phy;
-               /* fall through */
+               fallthrough;
        case SIOCDEVPRIVATE + 1:
                read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
                break;
index e45935a..2b2a841 100644 (file)
@@ -110,7 +110,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
                                if (!usb_endpoint_dir_in(&e->desc))
                                        continue;
                                intr = 1;
-                               /* FALLTHROUGH */
+                               fallthrough;
                        case USB_ENDPOINT_XFER_BULK:
                                break;
                        default:
@@ -628,7 +628,7 @@ block:
        /* data overrun ... flush fifo? */
        case -EOVERFLOW:
                dev->net->stats.rx_over_errors++;
-               // FALLTHROUGH
+               fallthrough;
 
        default:
                state = rx_cleanup;
@@ -1530,7 +1530,7 @@ static void usbnet_bh (struct timer_list *t)
                        continue;
                case tx_done:
                        kfree(entry->urb->sg);
-                       /* fall through */
+                       fallthrough;
                case rx_cleanup:
                        usb_free_urb (entry->urb);
                        dev_kfree_skb (skb);
index e56cd56..a475f48 100644 (file)
@@ -610,10 +610,10 @@ static struct sk_buff *veth_xdp_rcv_one(struct veth_rq *rq,
                        goto xdp_xmit;
                default:
                        bpf_warn_invalid_xdp_action(act);
-                       /* fall through */
+                       fallthrough;
                case XDP_ABORTED:
                        trace_xdp_exception(rq->dev, xdp_prog, act);
-                       /* fall through */
+                       fallthrough;
                case XDP_DROP:
                        stats->xdp_drops++;
                        goto err_xdp;
@@ -745,10 +745,10 @@ static struct sk_buff *veth_xdp_rcv_skb(struct veth_rq *rq,
                goto xdp_xmit;
        default:
                bpf_warn_invalid_xdp_action(act);
-               /* fall through */
+               fallthrough;
        case XDP_ABORTED:
                trace_xdp_exception(rq->dev, xdp_prog, act);
-               /* fall through */
+               fallthrough;
        case XDP_DROP:
                stats->xdp_drops++;
                goto xdp_drop;
index 0ada48e..668685c 100644 (file)
@@ -63,6 +63,11 @@ static const unsigned long guest_offloads[] = {
        VIRTIO_NET_F_GUEST_CSUM
 };
 
+#define GUEST_OFFLOAD_LRO_MASK ((1ULL << VIRTIO_NET_F_GUEST_TSO4) | \
+                               (1ULL << VIRTIO_NET_F_GUEST_TSO6) | \
+                               (1ULL << VIRTIO_NET_F_GUEST_ECN)  | \
+                               (1ULL << VIRTIO_NET_F_GUEST_UFO))
+
 struct virtnet_stat_desc {
        char desc[ETH_GSTRING_LEN];
        size_t offset;
@@ -724,7 +729,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
                        goto xdp_xmit;
                default:
                        bpf_warn_invalid_xdp_action(act);
-                       /* fall through */
+                       fallthrough;
                case XDP_ABORTED:
                        trace_xdp_exception(vi->dev, xdp_prog, act);
                case XDP_DROP:
@@ -922,10 +927,10 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
                        goto xdp_xmit;
                default:
                        bpf_warn_invalid_xdp_action(act);
-                       /* fall through */
+                       fallthrough;
                case XDP_ABORTED:
                        trace_xdp_exception(vi->dev, xdp_prog, act);
-                       /* fall through */
+                       fallthrough;
                case XDP_DROP:
                        if (unlikely(xdp_page != page))
                                __free_pages(xdp_page, 0);
@@ -2531,7 +2536,8 @@ static int virtnet_set_features(struct net_device *dev,
                if (features & NETIF_F_LRO)
                        offloads = vi->guest_offloads_capable;
                else
-                       offloads = 0;
+                       offloads = vi->guest_offloads_capable &
+                                  ~GUEST_OFFLOAD_LRO_MASK;
 
                err = virtnet_set_guest_offloads(vi, offloads);
                if (err)
index 2818015..336504b 100644 (file)
@@ -1032,7 +1032,6 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
        /* Use temporary descriptor to avoid touching bits multiple times */
        union Vmxnet3_GenericDesc tempTxDesc;
 #endif
-       struct udphdr *udph;
 
        count = txd_estimate(skb);
 
@@ -1135,8 +1134,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                        gdesc->txd.om = VMXNET3_OM_ENCAP;
                        gdesc->txd.msscof = ctx.mss;
 
-                       udph = udp_hdr(skb);
-                       if (udph->check)
+                       if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)
                                gdesc->txd.oco = 1;
                } else {
                        gdesc->txd.hlen = ctx.l4_offset + ctx.l4_hdr_size;
@@ -3371,6 +3369,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
                .ndo_change_mtu = vmxnet3_change_mtu,
                .ndo_fix_features = vmxnet3_fix_features,
                .ndo_set_features = vmxnet3_set_features,
+               .ndo_features_check = vmxnet3_features_check,
                .ndo_get_stats64 = vmxnet3_get_stats64,
                .ndo_tx_timeout = vmxnet3_tx_timeout,
                .ndo_set_rx_mode = vmxnet3_set_mc,
index def27af..7ec8652 100644 (file)
@@ -267,6 +267,34 @@ netdev_features_t vmxnet3_fix_features(struct net_device *netdev,
        return features;
 }
 
+netdev_features_t vmxnet3_features_check(struct sk_buff *skb,
+                                        struct net_device *netdev,
+                                        netdev_features_t features)
+{
+       struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
+       /* Validate if the tunneled packet is being offloaded by the device */
+       if (VMXNET3_VERSION_GE_4(adapter) &&
+           skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL) {
+               u8 l4_proto = 0;
+
+               switch (vlan_get_protocol(skb)) {
+               case htons(ETH_P_IP):
+                       l4_proto = ip_hdr(skb)->protocol;
+                       break;
+               case htons(ETH_P_IPV6):
+                       l4_proto = ipv6_hdr(skb)->nexthdr;
+                       break;
+               default:
+                       return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
+               }
+
+               if (l4_proto != IPPROTO_UDP)
+                       return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
+       }
+       return features;
+}
+
 static void vmxnet3_enable_encap_offloads(struct net_device *netdev)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
@@ -743,7 +771,7 @@ vmxnet3_get_rss_hash_opts(struct vmxnet3_adapter *adapter,
        case ESP_V4_FLOW:
                if (rss_fields & VMXNET3_RSS_FIELDS_ESPIP4)
                        info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
-                       /* fallthrough */
+               fallthrough;
        case SCTP_V4_FLOW:
        case IPV4_FLOW:
                info->data |= RXH_IP_SRC | RXH_IP_DST;
index 5d2b062..d958b92 100644 (file)
@@ -470,6 +470,10 @@ vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter);
 netdev_features_t
 vmxnet3_fix_features(struct net_device *netdev, netdev_features_t features);
 
+netdev_features_t
+vmxnet3_features_check(struct sk_buff *skb,
+                      struct net_device *netdev, netdev_features_t features);
+
 int
 vmxnet3_set_features(struct net_device *netdev, netdev_features_t features);
 
index 386ed2a..9b00708 100644 (file)
@@ -229,7 +229,7 @@ static void hdlc_setup_dev(struct net_device *dev)
        dev->min_mtu             = 68;
        dev->max_mtu             = HDLC_MAX_MTU;
        dev->type                = ARPHRD_RAWHDLC;
-       dev->hard_header_len     = 16;
+       dev->hard_header_len     = 0;
        dev->needed_headroom     = 0;
        dev->addr_len            = 0;
        dev->header_ops          = &hdlc_null_ops;
index d8cba36..cb5898f 100644 (file)
@@ -118,6 +118,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
        skb_put(skb, sizeof(struct cisco_packet));
        skb->priority = TC_PRIO_CONTROL;
        skb->dev = dev;
+       skb->protocol = htons(ETH_P_HDLC);
        skb_reset_network_header(skb);
 
        dev_queue_xmit(skb);
@@ -370,6 +371,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
                memcpy(&state(hdlc)->settings, &new_settings, size);
                spin_lock_init(&state(hdlc)->lock);
                dev->header_ops = &cisco_header_ops;
+               dev->hard_header_len = sizeof(struct hdlc_header);
                dev->type = ARPHRD_CISCO;
                call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev);
                netif_dormant_on(dev);
index 9acad65..d6cfd51 100644 (file)
@@ -433,6 +433,8 @@ static netdev_tx_t pvc_xmit(struct sk_buff *skb, struct net_device *dev)
                        if (pvc->state.fecn) /* TX Congestion counter */
                                dev->stats.tx_compressed++;
                        skb->dev = pvc->frad;
+                       skb->protocol = htons(ETH_P_HDLC);
+                       skb_reset_network_header(skb);
                        dev_queue_xmit(skb);
                        return NETDEV_TX_OK;
                }
@@ -555,6 +557,7 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
        skb_put(skb, i);
        skb->priority = TC_PRIO_CONTROL;
        skb->dev = dev;
+       skb->protocol = htons(ETH_P_HDLC);
        skb_reset_network_header(skb);
 
        dev_queue_xmit(skb);
@@ -1041,7 +1044,7 @@ static void pvc_setup(struct net_device *dev)
 {
        dev->type = ARPHRD_DLCI;
        dev->flags = IFF_POINTOPOINT;
-       dev->hard_header_len = 10;
+       dev->hard_header_len = 0;
        dev->addr_len = 2;
        netif_keep_dst(dev);
 }
@@ -1093,6 +1096,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
        dev->mtu = HDLC_MAX_MTU;
        dev->min_mtu = 68;
        dev->max_mtu = HDLC_MAX_MTU;
+       dev->needed_headroom = 10;
        dev->priv_flags |= IFF_NO_QUEUE;
        dev->ml_priv = pvc;
 
index 48ced39..64f8556 100644 (file)
@@ -251,6 +251,7 @@ static void ppp_tx_cp(struct net_device *dev, u16 pid, u8 code,
 
        skb->priority = TC_PRIO_CONTROL;
        skb->dev = dev;
+       skb->protocol = htons(ETH_P_HDLC);
        skb_reset_network_header(skb);
        skb_queue_tail(&tx_queue, skb);
 }
@@ -383,11 +384,8 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id,
        }
 
        for (opt = data; len; len -= opt[1], opt += opt[1]) {
-               if (len < 2 || len < opt[1]) {
-                       dev->stats.rx_errors++;
-                       kfree(out);
-                       return; /* bad packet, drop silently */
-               }
+               if (len < 2 || opt[1] < 2 || len < opt[1])
+                       goto err_out;
 
                if (pid == PID_LCP)
                        switch (opt[0]) {
@@ -395,6 +393,8 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id,
                                continue; /* MRU always OK and > 1500 bytes? */
 
                        case LCP_OPTION_ACCM: /* async control character map */
+                               if (opt[1] < sizeof(valid_accm))
+                                       goto err_out;
                                if (!memcmp(opt, valid_accm,
                                            sizeof(valid_accm)))
                                        continue;
@@ -406,6 +406,8 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id,
                                }
                                break;
                        case LCP_OPTION_MAGIC:
+                               if (len < 6)
+                                       goto err_out;
                                if (opt[1] != 6 || (!opt[2] && !opt[3] &&
                                                    !opt[4] && !opt[5]))
                                        break; /* reject invalid magic number */
@@ -424,6 +426,11 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id,
                ppp_cp_event(dev, pid, RCR_GOOD, CP_CONF_ACK, id, req_len, data);
 
        kfree(out);
+       return;
+
+err_out:
+       dev->stats.rx_errors++;
+       kfree(out);
 }
 
 static int ppp_rx(struct sk_buff *skb)
index 1ea15f2..b6be245 100644 (file)
@@ -173,7 +173,7 @@ static netdev_tx_t lapbeth_xmit(struct sk_buff *skb,
        case X25_IFACE_DISCONNECT:
                if ((err = lapb_disconnect_request(dev)) != LAPB_OK)
                        pr_err("lapb_disconnect_request err: %d\n", err);
-               /* Fall thru */
+               fallthrough;
        default:
                goto drop;
        }
@@ -198,8 +198,6 @@ static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
        struct net_device *dev;
        int size = skb->len;
 
-       skb->protocol = htons(ETH_P_X25);
-
        ptr = skb_push(skb, 2);
 
        *ptr++ = size % 256;
@@ -210,6 +208,10 @@ static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
 
        skb->dev = dev = lapbeth->ethdev;
 
+       skb->protocol = htons(ETH_P_DEC);
+
+       skb_reset_network_header(skb);
+
        dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
 
        dev_queue_xmit(skb);
@@ -340,6 +342,7 @@ static int lapbeth_new_device(struct net_device *dev)
         */
        ndev->needed_headroom = -1 + 3 + 2 + dev->hard_header_len
                                           + dev->needed_headroom;
+       ndev->needed_tailroom = dev->needed_tailroom;
 
        lapbeth = netdev_priv(ndev);
        lapbeth->axdev = ndev;
index 77ccf36..bc2c1c7 100644 (file)
@@ -413,7 +413,7 @@ static void sdla_errors(struct net_device *dev, int cmd, int dlci, int ret, int
                case SDLA_RET_NO_BUFS:
                        if (cmd == SDLA_INFORMATION_WRITE)
                                break;
-                       /* Else, fall through */
+                       fallthrough;
 
                default: 
                        netdev_dbg(dev, "Cmd 0x%02X generated return code 0x%02X\n",
index de79844..c418767 100644 (file)
@@ -330,7 +330,7 @@ static netdev_tx_t x25_asy_xmit(struct sk_buff *skb,
                if (err != LAPB_OK)
                        netdev_err(dev, "lapb_disconnect_request error: %d\n",
                                   err);
-               /* fall through */
+               fallthrough;
        default:
                kfree_skb(skb);
                return NETDEV_TX_OK;
@@ -464,7 +464,6 @@ static int x25_asy_open(struct net_device *dev)
 {
        struct x25_asy *sl = netdev_priv(dev);
        unsigned long len;
-       int err;
 
        if (sl->tty == NULL)
                return -ENODEV;
@@ -490,14 +489,7 @@ static int x25_asy_open(struct net_device *dev)
        sl->xleft    = 0;
        sl->flags   &= (1 << SLF_INUSE);      /* Clear ESCAPE & ERROR flags */
 
-       netif_start_queue(dev);
-
-       /*
-        *      Now attach LAPB
-        */
-       err = lapb_register(dev, &x25_asy_callbacks);
-       if (err == LAPB_OK)
-               return 0;
+       return 0;
 
        /* Cleanup */
        kfree(sl->xbuff);
@@ -519,7 +511,6 @@ static int x25_asy_close(struct net_device *dev)
        if (sl->tty)
                clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
 
-       netif_stop_queue(dev);
        sl->rcount = 0;
        sl->xleft  = 0;
        spin_unlock(&sl->lock);
@@ -604,7 +595,6 @@ static int x25_asy_open_tty(struct tty_struct *tty)
 static void x25_asy_close_tty(struct tty_struct *tty)
 {
        struct x25_asy *sl = tty->disc_data;
-       int err;
 
        /* First make sure we're connected. */
        if (!sl || sl->magic != X25_ASY_MAGIC)
@@ -615,11 +605,6 @@ static void x25_asy_close_tty(struct tty_struct *tty)
                dev_close(sl->dev);
        rtnl_unlock();
 
-       err = lapb_unregister(sl->dev);
-       if (err != LAPB_OK)
-               pr_err("%s: lapb_unregister error: %d\n",
-                      __func__, err);
-
        tty->disc_data = NULL;
        sl->tty = NULL;
        x25_asy_free(sl);
@@ -722,15 +707,39 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
 
 static int x25_asy_open_dev(struct net_device *dev)
 {
+       int err;
        struct x25_asy *sl = netdev_priv(dev);
        if (sl->tty == NULL)
                return -ENODEV;
+
+       err = lapb_register(dev, &x25_asy_callbacks);
+       if (err != LAPB_OK)
+               return -ENOMEM;
+
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+static int x25_asy_close_dev(struct net_device *dev)
+{
+       int err;
+
+       netif_stop_queue(dev);
+
+       err = lapb_unregister(dev);
+       if (err != LAPB_OK)
+               pr_err("%s: lapb_unregister error: %d\n",
+                      __func__, err);
+
+       x25_asy_close(dev);
+
        return 0;
 }
 
 static const struct net_device_ops x25_asy_netdev_ops = {
        .ndo_open       = x25_asy_open_dev,
-       .ndo_stop       = x25_asy_close,
+       .ndo_stop       = x25_asy_close_dev,
        .ndo_start_xmit = x25_asy_xmit,
        .ndo_tx_timeout = x25_asy_timeout,
        .ndo_change_mtu = x25_asy_change_mtu,
index 4fe7c7e..9afed3b 100644 (file)
@@ -352,7 +352,7 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
 
        case I2400M_SS_IDLE:
                d_printf(1, dev, "entering BS-negotiated idle mode\n");
-               /* Fall through */
+               fallthrough;
        case I2400M_SS_DISCONNECTING:
        case I2400M_SS_DATA_PATH_CONNECTED:
                wimax_state_change(wimax_dev, WIMAX_ST_CONNECTED);
index 1f7709d..27ab233 100644 (file)
@@ -135,7 +135,7 @@ retry:
                        msleep(10);     /* give the device some time */
                        goto retry;
                }
-               /* fall through */
+               fallthrough;
        case -EINVAL:                   /* while removing driver */
        case -ENODEV:                   /* dev disconnect ... */
        case -ENOENT:                   /* just ignore it */
index 3a0e722..3ba9d70 100644 (file)
@@ -136,7 +136,7 @@ retry:
                        msleep(10);     /* give the device some time */
                        goto retry;
                }
-               /* fall through */
+               fallthrough;
        case -EINVAL:                   /* while removing driver */
        case -ENODEV:                   /* dev disconnect ... */
        case -ENOENT:                   /* just ignore it */
index 9659f9e..b684e97 100644 (file)
@@ -195,7 +195,7 @@ retry:
                        msleep(10);     /* give the device some time */
                        goto retry;
                }
-               /* fall through */
+               fallthrough;
        case -EINVAL:                   /* while removing driver */
        case -ENODEV:                   /* dev disconnect ... */
        case -ENOENT:                   /* just ignore it */
index 3dd3b76..c0cfd9b 100644 (file)
@@ -87,15 +87,12 @@ static void handshake_zero(struct noise_handshake *handshake)
 
 void wg_noise_handshake_clear(struct noise_handshake *handshake)
 {
+       down_write(&handshake->lock);
        wg_index_hashtable_remove(
                        handshake->entry.peer->device->index_hashtable,
                        &handshake->entry);
-       down_write(&handshake->lock);
        handshake_zero(handshake);
        up_write(&handshake->lock);
-       wg_index_hashtable_remove(
-                       handshake->entry.peer->device->index_hashtable,
-                       &handshake->entry);
 }
 
 static struct noise_keypair *keypair_create(struct wg_peer *peer)
index e4deb33..f2783aa 100644 (file)
@@ -167,9 +167,13 @@ bool wg_index_hashtable_replace(struct index_hashtable *table,
                                struct index_hashtable_entry *old,
                                struct index_hashtable_entry *new)
 {
-       if (unlikely(hlist_unhashed(&old->index_hash)))
-               return false;
+       bool ret;
+
        spin_lock_bh(&table->lock);
+       ret = !hlist_unhashed(&old->index_hash);
+       if (unlikely(!ret))
+               goto out;
+
        new->index = old->index;
        hlist_replace_rcu(&old->index_hash, &new->index_hash);
 
@@ -180,8 +184,9 @@ bool wg_index_hashtable_replace(struct index_hashtable *table,
         * simply gets dropped, which isn't terrible.
         */
        INIT_HLIST_NODE(&old->index_hash);
+out:
        spin_unlock_bh(&table->lock);
-       return true;
+       return ret;
 }
 
 void wg_index_hashtable_remove(struct index_hashtable *table,
index e8712ad..3c07d1b 100644 (file)
@@ -664,9 +664,15 @@ static void pkt_align(struct sk_buff *p, int len, int align)
 /* To check if there's window offered */
 static bool data_ok(struct brcmf_sdio *bus)
 {
-       /* Reserve TXCTL_CREDITS credits for txctl */
-       return (bus->tx_max - bus->tx_seq) > TXCTL_CREDITS &&
-              ((bus->tx_max - bus->tx_seq) & 0x80) == 0;
+       u8 tx_rsv = 0;
+
+       /* Reserve TXCTL_CREDITS credits for txctl when it is ready to send */
+       if (bus->ctrl_frame_stat)
+               tx_rsv = TXCTL_CREDITS;
+
+       return (bus->tx_max - bus->tx_seq - tx_rsv) != 0 &&
+              ((bus->tx_max - bus->tx_seq - tx_rsv) & 0x80) == 0;
+
 }
 
 /* To check if there's window offered */
index b1e7b44..1650d58 100644 (file)
@@ -160,11 +160,7 @@ config LIBIPW
        select WIRELESS_EXT
        select WEXT_SPY
        select CRYPTO
-       select CRYPTO_ARC4
-       select CRYPTO_ECB
-       select CRYPTO_AES
        select CRYPTO_MICHAEL_MIC
-       select CRYPTO_ECB
        select CRC32
        select LIB80211
        select LIB80211_CRYPT_WEP
index 6ad8829..c865d31 100644 (file)
@@ -5,11 +5,7 @@ config HOSTAP
        select WEXT_SPY
        select WEXT_PRIV
        select CRYPTO
-       select CRYPTO_ARC4
-       select CRYPTO_ECB
-       select CRYPTO_AES
        select CRYPTO_MICHAEL_MIC
-       select CRYPTO_ECB
        select CRC32
        select LIB80211
        select LIB80211_CRYPT_WEP
index 8047e30..d9f8bdb 100644 (file)
@@ -954,7 +954,7 @@ struct mwifiex_tkip_param {
 struct mwifiex_aes_param {
        u8 pn[WPA_PN_SIZE];
        __le16 key_len;
-       u8 key[WLAN_KEY_LEN_CCMP];
+       u8 key[WLAN_KEY_LEN_CCMP_256];
 } __packed;
 
 struct mwifiex_wapi_param {
index 962d8bf..119ccac 100644 (file)
@@ -619,7 +619,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv,
        key_v2 = &resp->params.key_material_v2;
 
        len = le16_to_cpu(key_v2->key_param_set.key_params.aes.key_len);
-       if (len > WLAN_KEY_LEN_CCMP)
+       if (len > sizeof(key_v2->key_param_set.key_params.aes.key))
                return -EINVAL;
 
        if (le16_to_cpu(key_v2->action) == HostCmd_ACT_GEN_SET) {
@@ -635,7 +635,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv,
                return 0;
 
        memset(priv->aes_key_v2.key_param_set.key_params.aes.key, 0,
-              WLAN_KEY_LEN_CCMP);
+              sizeof(key_v2->key_param_set.key_params.aes.key));
        priv->aes_key_v2.key_param_set.key_params.aes.key_len =
                                cpu_to_le16(len);
        memcpy(priv->aes_key_v2.key_param_set.key_params.aes.key,
index fc1ebab..1f57b43 100644 (file)
@@ -460,7 +460,7 @@ void mt7615_init_device(struct mt7615_dev *dev)
        dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
        dev->mphy.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
        dev->mphy.sband_5g.sband.vht_cap.cap |=
-                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
                        IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
        mt7615_cap_dbdc_disable(dev);
        dev->phy.dfs_state = -1;
index d0cbb28..bd316db 100644 (file)
@@ -2128,7 +2128,8 @@ static int mt7615_load_n9(struct mt7615_dev *dev, const char *name)
                 sizeof(dev->mt76.hw->wiphy->fw_version),
                 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
 
-       if (!strncmp(hdr->fw_ver, "2.0", sizeof(hdr->fw_ver))) {
+       if (!is_mt7615(&dev->mt76) &&
+           !strncmp(hdr->fw_ver, "2.0", sizeof(hdr->fw_ver))) {
                dev->fw_ver = MT7615_FIRMWARE_V2;
                dev->mcu_ops = &sta_update_ops;
        } else {
index e90d008..8d6ceb3 100644 (file)
@@ -699,8 +699,12 @@ void mt7915_unregister_device(struct mt7915_dev *dev)
        spin_lock_bh(&dev->token_lock);
        idr_for_each_entry(&dev->token, txwi, id) {
                mt7915_txp_skb_unmap(&dev->mt76, txwi);
-               if (txwi->skb)
-                       dev_kfree_skb_any(txwi->skb);
+               if (txwi->skb) {
+                       struct ieee80211_hw *hw;
+
+                       hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb);
+                       ieee80211_free_txskb(hw, txwi->skb);
+               }
                mt76_put_txwi(&dev->mt76, txwi);
        }
        spin_unlock_bh(&dev->token_lock);
index 6825afc..036207f 100644 (file)
@@ -841,7 +841,7 @@ mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
        if (sta || !(info->flags & IEEE80211_TX_CTL_NO_ACK))
                mt7915_tx_status(sta, hw, info, NULL);
 
-       dev_kfree_skb(skb);
+       ieee80211_free_txskb(hw, skb);
 }
 
 void mt7915_txp_skb_unmap(struct mt76_dev *dev,
index 6aafff9..e013ebe 100644 (file)
@@ -671,9 +671,10 @@ bool qtnf_netdev_is_qtn(const struct net_device *ndev)
        return ndev->netdev_ops == &qtnf_netdev_ops;
 }
 
-static int qtnf_check_br_ports(struct net_device *dev, void *data)
+static int qtnf_check_br_ports(struct net_device *dev,
+                              struct netdev_nested_priv *priv)
 {
-       struct net_device *ndev = data;
+       struct net_device *ndev = (struct net_device *)priv->data;
 
        if (dev != ndev && netdev_port_same_parent_id(dev, ndev))
                return -ENOTSUPP;
@@ -686,6 +687,9 @@ static int qtnf_core_netdevice_event(struct notifier_block *nb,
 {
        struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
        const struct netdev_notifier_changeupper_info *info;
+       struct netdev_nested_priv priv = {
+               .data = (void *)ndev,
+       };
        struct net_device *brdev;
        struct qtnf_vif *vif;
        struct qtnf_bus *bus;
@@ -725,7 +729,7 @@ static int qtnf_core_netdevice_event(struct notifier_block *nb,
                } else {
                        ret = netdev_walk_all_lower_dev(brdev,
                                                        qtnf_check_br_ports,
-                                                       ndev);
+                                                       &priv);
                }
 
                break;
index 9acd8a4..f2609d5 100644 (file)
@@ -458,7 +458,6 @@ enum wl1271_cmd_key_type {
        KEY_TKIP = 2,
        KEY_AES  = 3,
        KEY_GEM  = 4,
-       KEY_IGTK  = 5,
 };
 
 struct wl1271_cmd_set_keys {
index 821ad1a..d2bbd51 100644 (file)
@@ -3559,9 +3559,6 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
        case WL1271_CIPHER_SUITE_GEM:
                key_type = KEY_GEM;
                break;
-       case WLAN_CIPHER_SUITE_AES_CMAC:
-               key_type = KEY_IGTK;
-               break;
        default:
                wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
 
@@ -6231,7 +6228,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
                WLAN_CIPHER_SUITE_TKIP,
                WLAN_CIPHER_SUITE_CCMP,
                WL1271_CIPHER_SUITE_GEM,
-               WLAN_CIPHER_SUITE_AES_CMAC,
        };
 
        /* The tx descriptor buffer */
index 6b7532f..ff96f22 100644 (file)
@@ -393,7 +393,7 @@ void xenvif_dump_hash_info(struct xenvif *vif, struct seq_file *m)
 
        case XEN_NETIF_CTRL_HASH_ALGORITHM_NONE:
                seq_puts(m, "Hash Algorithm: NONE\n");
-               /* FALLTHRU */
+               fallthrough;
        default:
                return;
        }
index 7e62a6e..f1c1624 100644 (file)
@@ -448,7 +448,7 @@ static void frontend_changed(struct xenbus_device *dev,
                set_backend_state(be, XenbusStateClosed);
                if (xenbus_dev_is_online(dev))
                        break;
-               /* fall through - if not online */
+               fallthrough;    /* if not online */
        case XenbusStateUnknown:
                set_backend_state(be, XenbusStateClosed);
                device_unregister(&dev->dev);
index 458be68..3e9895b 100644 (file)
@@ -2341,7 +2341,7 @@ static void netback_changed(struct xenbus_device *dev,
        case XenbusStateClosed:
                if (dev->state == XenbusStateClosed)
                        break;
-               /* Fall through - Missed the backend's CLOSING state. */
+               fallthrough;    /* Missed the backend's CLOSING state */
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;
index 346e084..f7464bd 100644 (file)
@@ -2321,7 +2321,7 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
 
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                /* jumbo frame ? */
                if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
@@ -2448,7 +2448,7 @@ static void pn533_wq_mi_recv(struct work_struct *work)
 
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                skb_put_u8(skb, 1); /*TG*/
 
index 0b9ca6d..8874d60 100644 (file)
@@ -611,7 +611,7 @@ static void st21nfca_im_recv_dep_res_cb(void *context, struct sk_buff *skb,
                switch (ST21NFCA_NFC_DEP_PFB_TYPE(dep_res->pfb)) {
                case ST21NFCA_NFC_DEP_PFB_ACK_NACK_PDU:
                        pr_err("Received a ACK/NACK PDU\n");
-                       /* fall through */
+                       fallthrough;
                case ST21NFCA_NFC_DEP_PFB_I_PDU:
                        info->dep_info.curr_nfc_dep_pni =
                            ST21NFCA_NFC_DEP_PFB_PNI(dep_res->pfb + 1);
index 9642971..4578547 100644 (file)
@@ -966,7 +966,7 @@ static int st95hf_in_send_cmd(struct nfc_digital_dev *ddev,
        rc = down_killable(&stcontext->exchange_lock);
        if (rc) {
                WARN(1, "Semaphore is not found up in st95hf_in_send_cmd\n");
-               return rc;
+               goto free_skb_resp;
        }
 
        rc = st95hf_spi_send(&stcontext->spicontext, skb->data,
index e46adaa..3bd97c7 100644 (file)
@@ -1153,7 +1153,7 @@ static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on)
                        dev_err(trf->dev, "%s - Invalid request: %d %d\n",
                                __func__, trf->state, on);
                        ret = -EINVAL;
-                       /* FALLTHROUGH */
+                       fallthrough;
                case TRF7970A_ST_IDLE:
                case TRF7970A_ST_IDLE_RX_BLOCKED:
                case TRF7970A_ST_WAIT_FOR_RX_DATA:
@@ -1960,7 +1960,7 @@ static void trf7970a_shutdown(struct trf7970a *trf)
        case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
        case TRF7970A_ST_LISTENING:
                trf7970a_send_err_upstream(trf, -ECANCELED);
-               /* FALLTHROUGH */
+               fallthrough;
        case TRF7970A_ST_IDLE:
        case TRF7970A_ST_IDLE_RX_BLOCKED:
                trf7970a_switch_rf_off(trf);
index e6d1f5b..4a02561 100644 (file)
@@ -1483,7 +1483,7 @@ static void ntb_rx_copy_callback(void *data,
                case DMA_TRANS_READ_FAILED:
                case DMA_TRANS_WRITE_FAILED:
                        entry->errors++;
-                       /* fall through */
+                       fallthrough;
                case DMA_TRANS_ABORTED:
                {
                        struct ntb_transport_qp *qp = entry->qp;
@@ -1739,7 +1739,7 @@ static void ntb_tx_copy_callback(void *data,
                case DMA_TRANS_READ_FAILED:
                case DMA_TRANS_WRITE_FAILED:
                        entry->errors++;
-                       /* fall through */
+                       fallthrough;
                case DMA_TRANS_ABORTED:
                {
                        void __iomem *offset =
index 45964ac..22d865b 100644 (file)
@@ -268,7 +268,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
        if (rw == READ) {
                if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align)))
                        return -EIO;
-               if (memcpy_mcsafe(buf, nsio->addr + offset, size) != 0)
+               if (copy_mc_to_kernel(buf, nsio->addr + offset, size) != 0)
                        return -EIO;
                return 0;
        }
index 61374de..b59032e 100644 (file)
@@ -529,6 +529,7 @@ static DEVICE_ATTR_ADMIN_RW(activate);
 static struct attribute *nvdimm_firmware_attributes[] = {
        &dev_attr_activate.attr,
        &dev_attr_result.attr,
+       NULL,
 };
 
 static umode_t nvdimm_firmware_visible(struct kobject *kobj, struct attribute *a, int n)
index fab29b5..5c6939e 100644 (file)
@@ -125,7 +125,7 @@ static blk_status_t read_pmem(struct page *page, unsigned int off,
        while (len) {
                mem = kmap_atomic(page);
                chunk = min_t(unsigned int, len, PAGE_SIZE - off);
-               rem = memcpy_mcsafe(mem + off, pmem_addr, chunk);
+               rem = copy_mc_to_kernel(mem + off, pmem_addr, chunk);
                kunmap_atomic(mem);
                if (rem)
                        return BLK_STS_IOERR;
@@ -304,7 +304,7 @@ static long pmem_dax_direct_access(struct dax_device *dax_dev,
 
 /*
  * Use the 'no check' versions of copy_from_iter_flushcache() and
- * copy_to_iter_mcsafe() to bypass HARDENED_USERCOPY overhead. Bounds
+ * copy_mc_to_iter() to bypass HARDENED_USERCOPY overhead. Bounds
  * checking, both file offset and device offset, is handled by
  * dax_iomap_actor()
  */
@@ -317,7 +317,7 @@ static size_t pmem_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff,
 static size_t pmem_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff,
                void *addr, size_t bytes, struct iov_iter *i)
 {
-       return _copy_to_iter_mcsafe(addr, bytes, i);
+       return _copy_mc_to_iter(addr, bytes, i);
 }
 
 static const struct dax_operations pmem_dax_ops = {
index 3ed9786..a44d49d 100644 (file)
@@ -73,6 +73,7 @@ config NVME_TCP
        depends on INET
        depends on BLK_DEV_NVME
        select NVME_FABRICS
+       select CRYPTO
        select CRYPTO_CRC32C
        help
          This provides support for the NVMe over Fabrics protocol using
index 88cff30..893e296 100644 (file)
@@ -241,17 +241,6 @@ static blk_status_t nvme_error_status(u16 status)
        }
 }
 
-static inline bool nvme_req_needs_retry(struct request *req)
-{
-       if (blk_noretry_request(req))
-               return false;
-       if (nvme_req(req)->status & NVME_SC_DNR)
-               return false;
-       if (nvme_req(req)->retries >= nvme_max_retries)
-               return false;
-       return true;
-}
-
 static void nvme_retry_req(struct request *req)
 {
        struct nvme_ns *ns = req->q->queuedata;
@@ -268,34 +257,67 @@ static void nvme_retry_req(struct request *req)
        blk_mq_delay_kick_requeue_list(req->q, delay);
 }
 
-void nvme_complete_rq(struct request *req)
+enum nvme_disposition {
+       COMPLETE,
+       RETRY,
+       FAILOVER,
+};
+
+static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
 {
-       blk_status_t status = nvme_error_status(nvme_req(req)->status);
+       if (likely(nvme_req(req)->status == 0))
+               return COMPLETE;
 
-       trace_nvme_complete_rq(req);
+       if (blk_noretry_request(req) ||
+           (nvme_req(req)->status & NVME_SC_DNR) ||
+           nvme_req(req)->retries >= nvme_max_retries)
+               return COMPLETE;
 
-       nvme_cleanup_cmd(req);
+       if (req->cmd_flags & REQ_NVME_MPATH) {
+               if (nvme_is_path_error(nvme_req(req)->status) ||
+                   blk_queue_dying(req->q))
+                       return FAILOVER;
+       } else {
+               if (blk_queue_dying(req->q))
+                       return COMPLETE;
+       }
 
-       if (nvme_req(req)->ctrl->kas)
-               nvme_req(req)->ctrl->comp_seen = true;
+       return RETRY;
+}
 
-       if (unlikely(status != BLK_STS_OK && nvme_req_needs_retry(req))) {
-               if ((req->cmd_flags & REQ_NVME_MPATH) && nvme_failover_req(req))
-                       return;
+static inline void nvme_end_req(struct request *req)
+{
+       blk_status_t status = nvme_error_status(nvme_req(req)->status);
 
-               if (!blk_queue_dying(req->q)) {
-                       nvme_retry_req(req);
-                       return;
-               }
-       } else if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
-                  req_op(req) == REQ_OP_ZONE_APPEND) {
+       if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
+           req_op(req) == REQ_OP_ZONE_APPEND)
                req->__sector = nvme_lba_to_sect(req->q->queuedata,
                        le64_to_cpu(nvme_req(req)->result.u64));
-       }
 
        nvme_trace_bio_complete(req, status);
        blk_mq_end_request(req, status);
 }
+
+void nvme_complete_rq(struct request *req)
+{
+       trace_nvme_complete_rq(req);
+       nvme_cleanup_cmd(req);
+
+       if (nvme_req(req)->ctrl->kas)
+               nvme_req(req)->ctrl->comp_seen = true;
+
+       switch (nvme_decide_disposition(req)) {
+       case COMPLETE:
+               nvme_end_req(req);
+               return;
+       case RETRY:
+               nvme_retry_req(req);
+               return;
+       case FAILOVER:
+               nvme_failover_req(req);
+               return;
+       }
+}
 EXPORT_SYMBOL_GPL(nvme_complete_rq);
 
 bool nvme_cancel_request(struct request *req, void *data, bool reserved)
@@ -330,7 +352,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                case NVME_CTRL_RESETTING:
                case NVME_CTRL_CONNECTING:
                        changed = true;
-                       /* FALLTHRU */
+                       fallthrough;
                default:
                        break;
                }
@@ -340,7 +362,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                case NVME_CTRL_NEW:
                case NVME_CTRL_LIVE:
                        changed = true;
-                       /* FALLTHRU */
+                       fallthrough;
                default:
                        break;
                }
@@ -350,7 +372,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                case NVME_CTRL_NEW:
                case NVME_CTRL_RESETTING:
                        changed = true;
-                       /* FALLTHRU */
+                       fallthrough;
                default:
                        break;
                }
@@ -361,7 +383,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                case NVME_CTRL_RESETTING:
                case NVME_CTRL_CONNECTING:
                        changed = true;
-                       /* FALLTHRU */
+                       fallthrough;
                default:
                        break;
                }
@@ -371,7 +393,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                case NVME_CTRL_DELETING:
                case NVME_CTRL_DEAD:
                        changed = true;
-                       /* FALLTHRU */
+                       fallthrough;
                default:
                        break;
                }
@@ -380,7 +402,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                switch (old_state) {
                case NVME_CTRL_DELETING:
                        changed = true;
-                       /* FALLTHRU */
+                       fallthrough;
                default:
                        break;
                }
@@ -2004,13 +2026,49 @@ static void nvme_update_disk_info(struct gendisk *disk,
        blk_mq_unfreeze_queue(disk->queue);
 }
 
+static inline bool nvme_first_scan(struct gendisk *disk)
+{
+       /* nvme_alloc_ns() scans the disk prior to adding it */
+       return !(disk->flags & GENHD_FL_UP);
+}
+
+static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)
+{
+       struct nvme_ctrl *ctrl = ns->ctrl;
+       u32 iob;
+
+       if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) &&
+           is_power_of_2(ctrl->max_hw_sectors))
+               iob = ctrl->max_hw_sectors;
+       else
+               iob = nvme_lba_to_sect(ns, le16_to_cpu(id->noiob));
+
+       if (!iob)
+               return;
+
+       if (!is_power_of_2(iob)) {
+               if (nvme_first_scan(ns->disk))
+                       pr_warn("%s: ignoring unaligned IO boundary:%u\n",
+                               ns->disk->disk_name, iob);
+               return;
+       }
+
+       if (blk_queue_is_zoned(ns->disk->queue)) {
+               if (nvme_first_scan(ns->disk))
+                       pr_warn("%s: ignoring zoned namespace IO boundary\n",
+                               ns->disk->disk_name);
+               return;
+       }
+
+       blk_queue_chunk_sectors(ns->queue, iob);
+}
+
 static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
 {
        unsigned lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
        struct nvme_ns *ns = disk->private_data;
        struct nvme_ctrl *ctrl = ns->ctrl;
        int ret;
-       u32 iob;
 
        /*
         * If identify namespace failed, use default 512 byte block size so
@@ -2038,12 +2096,6 @@ static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
                return -ENODEV;
        }
 
-       if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) &&
-           is_power_of_2(ctrl->max_hw_sectors))
-               iob = ctrl->max_hw_sectors;
-       else
-               iob = nvme_lba_to_sect(ns, le16_to_cpu(id->noiob));
-
        ns->features = 0;
        ns->ms = le16_to_cpu(id->lbaf[lbaf].ms);
        /* the PI implementation requires metadata equal t10 pi tuple size */
@@ -2075,8 +2127,7 @@ static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
                }
        }
 
-       if (iob)
-               blk_queue_chunk_sectors(ns->queue, rounddown_pow_of_two(iob));
+       nvme_set_chunk_sectors(ns, id);
        nvme_update_disk_info(disk, ns, id);
 #ifdef CONFIG_NVME_MULTIPATH
        if (ns->head->disk) {
@@ -2965,14 +3016,14 @@ static struct nvme_cel *nvme_find_cel(struct nvme_ctrl *ctrl, u8 csi)
 {
        struct nvme_cel *cel, *ret = NULL;
 
-       spin_lock(&ctrl->lock);
+       spin_lock_irq(&ctrl->lock);
        list_for_each_entry(cel, &ctrl->cels, entry) {
                if (cel->csi == csi) {
                        ret = cel;
                        break;
                }
        }
-       spin_unlock(&ctrl->lock);
+       spin_unlock_irq(&ctrl->lock);
 
        return ret;
 }
@@ -2990,7 +3041,7 @@ static int nvme_get_effects_log(struct nvme_ctrl *ctrl, u8 csi,
        if (!cel)
                return -ENOMEM;
 
-       ret = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_CMD_EFFECTS, 0, csi,
+       ret = nvme_get_log(ctrl, 0x00, NVME_LOG_CMD_EFFECTS, 0, csi,
                        &cel->log, sizeof(cel->log), 0);
        if (ret) {
                kfree(cel);
@@ -2999,9 +3050,9 @@ static int nvme_get_effects_log(struct nvme_ctrl *ctrl, u8 csi,
 
        cel->csi = csi;
 
-       spin_lock(&ctrl->lock);
+       spin_lock_irq(&ctrl->lock);
        list_add_tail(&cel->entry, &ctrl->cels);
-       spin_unlock(&ctrl->lock);
+       spin_unlock_irq(&ctrl->lock);
 out:
        *log = &cel->log;
        return 0;
@@ -3185,8 +3236,11 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
        if (ret < 0)
                return ret;
 
-       if (!ctrl->identified)
-               nvme_hwmon_init(ctrl);
+       if (!ctrl->identified) {
+               ret = nvme_hwmon_init(ctrl);
+               if (ret < 0)
+                       return ret;
+       }
 
        ctrl->identified = true;
 
@@ -3210,10 +3264,26 @@ static int nvme_dev_open(struct inode *inode, struct file *file)
                return -EWOULDBLOCK;
        }
 
+       nvme_get_ctrl(ctrl);
+       if (!try_module_get(ctrl->ops->module)) {
+               nvme_put_ctrl(ctrl);
+               return -EINVAL;
+       }
+
        file->private_data = ctrl;
        return 0;
 }
 
+static int nvme_dev_release(struct inode *inode, struct file *file)
+{
+       struct nvme_ctrl *ctrl =
+               container_of(inode->i_cdev, struct nvme_ctrl, cdev);
+
+       module_put(ctrl->ops->module);
+       nvme_put_ctrl(ctrl);
+       return 0;
+}
+
 static int nvme_dev_user_cmd(struct nvme_ctrl *ctrl, void __user *argp)
 {
        struct nvme_ns *ns;
@@ -3276,6 +3346,7 @@ static long nvme_dev_ioctl(struct file *file, unsigned int cmd,
 static const struct file_operations nvme_dev_fops = {
        .owner          = THIS_MODULE,
        .open           = nvme_dev_open,
+       .release        = nvme_dev_release,
        .unlocked_ioctl = nvme_dev_ioctl,
        .compat_ioctl   = compat_ptr_ioctl,
 };
@@ -3474,10 +3545,6 @@ static ssize_t nvme_sysfs_delete(struct device *dev,
 {
        struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
 
-       /* Can't delete non-created controllers */
-       if (!ctrl->created)
-               return -EBUSY;
-
        if (device_remove_file_self(dev, attr))
                nvme_delete_ctrl_sync(ctrl);
        return count;
@@ -3654,6 +3721,10 @@ static umode_t nvme_dev_attrs_are_visible(struct kobject *kobj,
                return 0;
        if (a == &dev_attr_hostid.attr && !ctrl->opts)
                return 0;
+       if (a == &dev_attr_ctrl_loss_tmo.attr && !ctrl->opts)
+               return 0;
+       if (a == &dev_attr_reconnect_delay.attr && !ctrl->opts)
+               return 0;
 
        return a->mode;
 }
@@ -4348,7 +4419,6 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl)
                nvme_queue_scan(ctrl);
                nvme_start_queues(ctrl);
        }
-       ctrl->created = true;
 }
 EXPORT_SYMBOL_GPL(nvme_start_ctrl);
 
@@ -4368,7 +4438,7 @@ static void nvme_free_ctrl(struct device *dev)
        struct nvme_subsystem *subsys = ctrl->subsys;
        struct nvme_cel *cel, *next;
 
-       if (subsys && ctrl->instance != subsys->instance)
+       if (!subsys || ctrl->instance != subsys->instance)
                ida_simple_remove(&nvme_instance_ida, ctrl->instance);
 
        list_for_each_entry_safe(cel, next, &ctrl->cels, entry) {
@@ -4512,7 +4582,7 @@ void nvme_unfreeze(struct nvme_ctrl *ctrl)
 }
 EXPORT_SYMBOL_GPL(nvme_unfreeze);
 
-void nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout)
+int nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout)
 {
        struct nvme_ns *ns;
 
@@ -4523,6 +4593,7 @@ void nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout)
                        break;
        }
        up_read(&ctrl->namespaces_rwsem);
+       return timeout;
 }
 EXPORT_SYMBOL_GPL(nvme_wait_freeze_timeout);
 
index 4ec4829..8575724 100644 (file)
@@ -565,10 +565,14 @@ bool __nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
        struct nvme_request *req = nvme_req(rq);
 
        /*
-        * If we are in some state of setup or teardown only allow
-        * internally generated commands.
+        * currently we have a problem sending passthru commands
+        * on the admin_q if the controller is not LIVE because we can't
+        * make sure that they are going out after the admin connect,
+        * controller enable and/or other commands in the initialization
+        * sequence. until the controller will be LIVE, fail with
+        * BLK_STS_RESOURCE so that they will be rescheduled.
         */
-       if (!blk_rq_is_passthrough(rq) || (req->flags & NVME_REQ_USERCMD))
+       if (rq->q == ctrl->admin_q && (req->flags & NVME_REQ_USERCMD))
                return false;
 
        /*
@@ -576,9 +580,8 @@ bool __nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
         * which is require to set the queue live in the appropinquate states.
         */
        switch (ctrl->state) {
-       case NVME_CTRL_NEW:
        case NVME_CTRL_CONNECTING:
-               if (nvme_is_fabrics(req->cmd) &&
+               if (blk_rq_is_passthrough(rq) && nvme_is_fabrics(req->cmd) &&
                    req->cmd->fabrics.fctype == nvme_fabrics_type_connect)
                        return true;
                break;
index eae43bb..e2e09e2 100644 (file)
@@ -2035,7 +2035,7 @@ done:
        }
 
        __nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate);
-       if (!nvme_end_request(rq, status, result))
+       if (!nvme_try_complete_req(rq, status, result))
                nvme_fc_complete_rq(rq);
 
 check_error:
@@ -2078,7 +2078,7 @@ __nvme_fc_init_request(struct nvme_fc_ctrl *ctrl,
        if (fc_dma_mapping_error(ctrl->lport->dev, op->fcp_req.cmddma)) {
                dev_err(ctrl->dev,
                        "FCP Op failed - cmdiu dma mapping failed.\n");
-               ret = EFAULT;
+               ret = -EFAULT;
                goto out_on_error;
        }
 
@@ -2088,7 +2088,7 @@ __nvme_fc_init_request(struct nvme_fc_ctrl *ctrl,
        if (fc_dma_mapping_error(ctrl->lport->dev, op->fcp_req.rspdma)) {
                dev_err(ctrl->dev,
                        "FCP Op failed - rspiu dma mapping failed.\n");
-               ret = EFAULT;
+               ret = -EFAULT;
        }
 
        atomic_set(&op->state, FCPOP_STATE_IDLE);
@@ -2160,6 +2160,7 @@ nvme_fc_term_aen_ops(struct nvme_fc_ctrl *ctrl)
        struct nvme_fc_fcp_op *aen_op;
        int i;
 
+       cancel_work_sync(&ctrl->ctrl.async_event_work);
        aen_op = ctrl->aen_ops;
        for (i = 0; i < NVME_NR_AEN_COMMANDS; i++, aen_op++) {
                __nvme_fc_exit_request(ctrl, aen_op);
@@ -3670,12 +3671,14 @@ nvme_fc_create_ctrl(struct device *dev, struct nvmf_ctrl_options *opts)
        spin_lock_irqsave(&nvme_fc_lock, flags);
        list_for_each_entry(lport, &nvme_fc_lport_list, port_list) {
                if (lport->localport.node_name != laddr.nn ||
-                   lport->localport.port_name != laddr.pn)
+                   lport->localport.port_name != laddr.pn ||
+                   lport->localport.port_state != FC_OBJSTATE_ONLINE)
                        continue;
 
                list_for_each_entry(rport, &lport->endp_list, endp_list) {
                        if (rport->remoteport.node_name != raddr.nn ||
-                           rport->remoteport.port_name != raddr.pn)
+                           rport->remoteport.port_name != raddr.pn ||
+                           rport->remoteport.port_state != FC_OBJSTATE_ONLINE)
                                continue;
 
                        /* if fail to get reference fall through. Will error */
index 412a6c9..552dbc0 100644 (file)
@@ -59,12 +59,8 @@ static int nvme_set_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under,
 
 static int nvme_hwmon_get_smart_log(struct nvme_hwmon_data *data)
 {
-       int ret;
-
-       ret = nvme_get_log(data->ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0,
+       return nvme_get_log(data->ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0,
                           NVME_CSI_NVM, &data->log, sizeof(data->log), 0);
-
-       return ret <= 0 ? ret : -EIO;
 }
 
 static int nvme_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
@@ -225,7 +221,7 @@ static const struct hwmon_chip_info nvme_hwmon_chip_info = {
        .info   = nvme_hwmon_info,
 };
 
-void nvme_hwmon_init(struct nvme_ctrl *ctrl)
+int nvme_hwmon_init(struct nvme_ctrl *ctrl)
 {
        struct device *dev = ctrl->dev;
        struct nvme_hwmon_data *data;
@@ -234,7 +230,7 @@ void nvme_hwmon_init(struct nvme_ctrl *ctrl)
 
        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
-               return;
+               return 0;
 
        data->ctrl = ctrl;
        mutex_init(&data->read_lock);
@@ -244,7 +240,7 @@ void nvme_hwmon_init(struct nvme_ctrl *ctrl)
                dev_warn(ctrl->device,
                        "Failed to read smart log (error %d)\n", err);
                devm_kfree(dev, data);
-               return;
+               return err;
        }
 
        hwmon = devm_hwmon_device_register_with_info(dev, "nvme", data,
@@ -254,4 +250,6 @@ void nvme_hwmon_init(struct nvme_ctrl *ctrl)
                dev_warn(dev, "Failed to instantiate hwmon device\n");
                devm_kfree(dev, data);
        }
+
+       return 0;
 }
index 3ded54d..d4ba736 100644 (file)
@@ -65,51 +65,30 @@ void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
        }
 }
 
-bool nvme_failover_req(struct request *req)
+void nvme_failover_req(struct request *req)
 {
        struct nvme_ns *ns = req->q->queuedata;
-       u16 status = nvme_req(req)->status;
+       u16 status = nvme_req(req)->status & 0x7ff;
        unsigned long flags;
 
-       switch (status & 0x7ff) {
-       case NVME_SC_ANA_TRANSITION:
-       case NVME_SC_ANA_INACCESSIBLE:
-       case NVME_SC_ANA_PERSISTENT_LOSS:
-               /*
-                * If we got back an ANA error we know the controller is alive,
-                * but not ready to serve this namespaces.  The spec suggests
-                * we should update our general state here, but due to the fact
-                * that the admin and I/O queues are not serialized that is
-                * fundamentally racy.  So instead just clear the current path,
-                * mark the the path as pending and kick of a re-read of the ANA
-                * log page ASAP.
-                */
-               nvme_mpath_clear_current_path(ns);
-               if (ns->ctrl->ana_log_buf) {
-                       set_bit(NVME_NS_ANA_PENDING, &ns->flags);
-                       queue_work(nvme_wq, &ns->ctrl->ana_work);
-               }
-               break;
-       case NVME_SC_HOST_PATH_ERROR:
-       case NVME_SC_HOST_ABORTED_CMD:
-               /*
-                * Temporary transport disruption in talking to the controller.
-                * Try to send on a new path.
-                */
-               nvme_mpath_clear_current_path(ns);
-               break;
-       default:
-               /* This was a non-ANA error so follow the normal error path. */
-               return false;
+       nvme_mpath_clear_current_path(ns);
+
+       /*
+        * If we got back an ANA error, we know the controller is alive but not
+        * ready to serve this namespace.  Kick of a re-read of the ANA
+        * information page, and just try any other available path for now.
+        */
+       if (nvme_is_ana_error(status) && ns->ctrl->ana_log_buf) {
+               set_bit(NVME_NS_ANA_PENDING, &ns->flags);
+               queue_work(nvme_wq, &ns->ctrl->ana_work);
        }
 
        spin_lock_irqsave(&ns->head->requeue_lock, flags);
        blk_steal_bios(&ns->head->requeue_list, req);
        spin_unlock_irqrestore(&ns->head->requeue_lock, flags);
-       blk_mq_end_request(req, 0);
 
+       blk_mq_end_request(req, 0);
        kblockd_schedule_work(&ns->head->requeue_work);
-       return true;
 }
 
 void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
@@ -233,7 +212,7 @@ static struct nvme_ns *nvme_next_ns(struct nvme_ns_head *head,
 static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
                int node, struct nvme_ns *old)
 {
-       struct nvme_ns *ns, *found, *fallback = NULL;
+       struct nvme_ns *ns, *found = NULL;
 
        if (list_is_singular(&head->list)) {
                if (nvme_path_is_disabled(old))
@@ -252,18 +231,22 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
                        goto out;
                }
                if (ns->ana_state == NVME_ANA_NONOPTIMIZED)
-                       fallback = ns;
+                       found = ns;
        }
 
-       /* No optimized path found, re-check the current path */
+       /*
+        * The loop above skips the current path for round-robin semantics.
+        * Fall back to the current path if either:
+        *  - no other optimized path found and current is optimized,
+        *  - no other usable path found and current is usable.
+        */
        if (!nvme_path_is_disabled(old) &&
-           old->ana_state == NVME_ANA_OPTIMIZED) {
-               found = old;
-               goto out;
-       }
-       if (!fallback)
+           (old->ana_state == NVME_ANA_OPTIMIZED ||
+            (!found && old->ana_state == NVME_ANA_NONOPTIMIZED)))
+               return old;
+
+       if (!found)
                return NULL;
-       found = fallback;
 out:
        rcu_assign_pointer(head->current_path[node], found);
        return found;
index ebb8c3e..2aaedfa 100644 (file)
@@ -307,7 +307,6 @@ struct nvme_ctrl {
        struct nvme_command ka_cmd;
        struct work_struct fw_act_work;
        unsigned long events;
-       bool created;
 
 #ifdef CONFIG_NVME_MULTIPATH
        /* asymmetric namespace access: */
@@ -523,7 +522,31 @@ static inline u32 nvme_bytes_to_numd(size_t len)
        return (len >> 2) - 1;
 }
 
-static inline bool nvme_end_request(struct request *req, __le16 status,
+static inline bool nvme_is_ana_error(u16 status)
+{
+       switch (status & 0x7ff) {
+       case NVME_SC_ANA_TRANSITION:
+       case NVME_SC_ANA_INACCESSIBLE:
+       case NVME_SC_ANA_PERSISTENT_LOSS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static inline bool nvme_is_path_error(u16 status)
+{
+       /* check for a status code type of 'path related status' */
+       return (status & 0x700) == 0x300;
+}
+
+/*
+ * Fill in the status and result information from the CQE, and then figure out
+ * if blk-mq will need to use IPI magic to complete the request, and if yes do
+ * so.  If not let the caller complete the request without an indirect function
+ * call.
+ */
+static inline bool nvme_try_complete_req(struct request *req, __le16 status,
                union nvme_result result)
 {
        struct nvme_request *rq = nvme_req(req);
@@ -581,7 +604,7 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl);
 void nvme_sync_queues(struct nvme_ctrl *ctrl);
 void nvme_unfreeze(struct nvme_ctrl *ctrl);
 void nvme_wait_freeze(struct nvme_ctrl *ctrl);
-void nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout);
+int nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout);
 void nvme_start_freeze(struct nvme_ctrl *ctrl);
 
 #define NVME_QID_ANY -1
@@ -629,7 +652,7 @@ void nvme_mpath_wait_freeze(struct nvme_subsystem *subsys);
 void nvme_mpath_start_freeze(struct nvme_subsystem *subsys);
 void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
                        struct nvme_ctrl *ctrl, int *flags);
-bool nvme_failover_req(struct request *req);
+void nvme_failover_req(struct request *req);
 void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl);
 int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head);
 void nvme_mpath_add_disk(struct nvme_ns *ns, struct nvme_id_ns *id);
@@ -688,9 +711,8 @@ static inline void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
        sprintf(disk_name, "nvme%dn%d", ctrl->instance, ns->head->instance);
 }
 
-static inline bool nvme_failover_req(struct request *req)
+static inline void nvme_failover_req(struct request *req)
 {
-       return false;
 }
 static inline void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
 {
@@ -805,9 +827,12 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
 }
 
 #ifdef CONFIG_NVME_HWMON
-void nvme_hwmon_init(struct nvme_ctrl *ctrl);
+int nvme_hwmon_init(struct nvme_ctrl *ctrl);
 #else
-static inline void nvme_hwmon_init(struct nvme_ctrl *ctrl) { }
+static inline int nvme_hwmon_init(struct nvme_ctrl *ctrl)
+{
+       return 0;
+}
 #endif
 
 u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
index ba725ae..8984796 100644 (file)
@@ -120,7 +120,7 @@ struct nvme_dev {
        unsigned max_qid;
        unsigned io_queues[HCTX_MAX_TYPES];
        unsigned int num_vecs;
-       u16 q_depth;
+       u32 q_depth;
        int io_sqes;
        u32 db_stride;
        void __iomem *bar;
@@ -157,13 +157,13 @@ struct nvme_dev {
 static int io_queue_depth_set(const char *val, const struct kernel_param *kp)
 {
        int ret;
-       u16 n;
+       u32 n;
 
-       ret = kstrtou16(val, 10, &n);
+       ret = kstrtou32(val, 10, &n);
        if (ret != 0 || n < 2)
                return -EINVAL;
 
-       return param_set_ushort(val, kp);
+       return param_set_uint(val, kp);
 }
 
 static inline unsigned int sq_idx(unsigned int qid, u32 stride)
@@ -195,7 +195,7 @@ struct nvme_queue {
        dma_addr_t sq_dma_addr;
        dma_addr_t cq_dma_addr;
        u32 __iomem *q_db;
-       u16 q_depth;
+       u32 q_depth;
        u16 cq_vector;
        u16 sq_tail;
        u16 cq_head;
@@ -940,13 +940,6 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx)
        struct nvme_completion *cqe = &nvmeq->cqes[idx];
        struct request *req;
 
-       if (unlikely(cqe->command_id >= nvmeq->q_depth)) {
-               dev_warn(nvmeq->dev->ctrl.device,
-                       "invalid id %d completed on queue %d\n",
-                       cqe->command_id, le16_to_cpu(cqe->sq_id));
-               return;
-       }
-
        /*
         * AEN requests are special as they don't time out and can
         * survive any kind of queue freeze and often don't respond to
@@ -960,8 +953,15 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx)
        }
 
        req = blk_mq_tag_to_rq(nvme_queue_tagset(nvmeq), cqe->command_id);
+       if (unlikely(!req)) {
+               dev_warn(nvmeq->dev->ctrl.device,
+                       "invalid id %d completed on queue %d\n",
+                       cqe->command_id, le16_to_cpu(cqe->sq_id));
+               return;
+       }
+
        trace_nvme_sq(req, cqe->sq_head, nvmeq->sq_tail);
-       if (!nvme_end_request(req, cqe->status, cqe->result))
+       if (!nvme_try_complete_req(req, cqe->status, cqe->result))
                nvme_pci_complete_rq(req);
 }
 
@@ -1244,13 +1244,13 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
        switch (dev->ctrl.state) {
        case NVME_CTRL_CONNECTING:
                nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING);
-               /* fall through */
+               fallthrough;
        case NVME_CTRL_DELETING:
                dev_warn_ratelimited(dev->ctrl.device,
                         "I/O %d QID %d timeout, disable controller\n",
                         req->tag, nvmeq->qid);
-               nvme_dev_disable(dev, true);
                nvme_req(req)->flags |= NVME_REQ_CANCELLED;
+               nvme_dev_disable(dev, true);
                return BLK_EH_DONE;
        case NVME_CTRL_RESETTING:
                return BLK_EH_RESET_TIMER;
@@ -1267,10 +1267,10 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
                dev_warn(dev->ctrl.device,
                         "I/O %d QID %d timeout, reset controller\n",
                         req->tag, nvmeq->qid);
+               nvme_req(req)->flags |= NVME_REQ_CANCELLED;
                nvme_dev_disable(dev, false);
                nvme_reset_ctrl(&dev->ctrl);
 
-               nvme_req(req)->flags |= NVME_REQ_CANCELLED;
                return BLK_EH_DONE;
        }
 
@@ -2320,7 +2320,7 @@ static int nvme_pci_enable(struct nvme_dev *dev)
 
        dev->ctrl.cap = lo_hi_readq(dev->bar + NVME_REG_CAP);
 
-       dev->q_depth = min_t(u16, NVME_CAP_MQES(dev->ctrl.cap) + 1,
+       dev->q_depth = min_t(u32, NVME_CAP_MQES(dev->ctrl.cap) + 1,
                                io_queue_depth);
        dev->ctrl.sqsize = dev->q_depth - 1; /* 0's based queue depth */
        dev->db_stride = 1 << NVME_CAP_STRIDE(dev->ctrl.cap);
@@ -2460,7 +2460,8 @@ static int nvme_disable_prepare_reset(struct nvme_dev *dev, bool shutdown)
 static int nvme_setup_prp_pools(struct nvme_dev *dev)
 {
        dev->prp_page_pool = dma_pool_create("prp list page", dev->dev,
-                                               PAGE_SIZE, PAGE_SIZE, 0);
+                                               NVME_CTRL_PAGE_SIZE,
+                                               NVME_CTRL_PAGE_SIZE, 0);
        if (!dev->prp_page_pool)
                return -ENOMEM;
 
@@ -3152,7 +3153,8 @@ static const struct pci_device_id nvme_id_table[] = {
        { PCI_VDEVICE(INTEL, 0xf1a5),   /* Intel 600P/P3100 */
                .driver_data = NVME_QUIRK_NO_DEEPEST_PS |
                                NVME_QUIRK_MEDIUM_PRIO_SQ |
-                               NVME_QUIRK_NO_TEMP_THRESH_CHANGE },
+                               NVME_QUIRK_NO_TEMP_THRESH_CHANGE |
+                               NVME_QUIRK_DISABLE_WRITE_ZEROES, },
        { PCI_VDEVICE(INTEL, 0xf1a6),   /* Intel 760p/Pro 7600p */
                .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, },
        { PCI_VDEVICE(INTEL, 0x5845),   /* Qemu emulated controller */
index 44c76ff..9e378d0 100644 (file)
@@ -122,6 +122,7 @@ struct nvme_rdma_ctrl {
        struct sockaddr_storage src_addr;
 
        struct nvme_ctrl        ctrl;
+       struct mutex            teardown_lock;
        bool                    use_inline_data;
        u32                     io_queues[HCTX_MAX_TYPES];
 };
@@ -834,6 +835,7 @@ static void nvme_rdma_destroy_admin_queue(struct nvme_rdma_ctrl *ctrl,
                blk_mq_free_tag_set(ctrl->ctrl.admin_tagset);
        }
        if (ctrl->async_event_sqe.data) {
+               cancel_work_sync(&ctrl->ctrl.async_event_work);
                nvme_rdma_free_qe(ctrl->device->dev, &ctrl->async_event_sqe,
                                sizeof(struct nvme_command), DMA_TO_DEVICE);
                ctrl->async_event_sqe.data = NULL;
@@ -975,7 +977,15 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new)
 
        if (!new) {
                nvme_start_queues(&ctrl->ctrl);
-               nvme_wait_freeze(&ctrl->ctrl);
+               if (!nvme_wait_freeze_timeout(&ctrl->ctrl, NVME_IO_TIMEOUT)) {
+                       /*
+                        * If we timed out waiting for freeze we are likely to
+                        * be stuck.  Fail the controller initialization just
+                        * to be safe.
+                        */
+                       ret = -ENODEV;
+                       goto out_wait_freeze_timed_out;
+               }
                blk_mq_update_nr_hw_queues(ctrl->ctrl.tagset,
                        ctrl->ctrl.queue_count - 1);
                nvme_unfreeze(&ctrl->ctrl);
@@ -983,6 +993,9 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new)
 
        return 0;
 
+out_wait_freeze_timed_out:
+       nvme_stop_queues(&ctrl->ctrl);
+       nvme_rdma_stop_io_queues(ctrl);
 out_cleanup_connect_q:
        if (new)
                blk_cleanup_queue(ctrl->ctrl.connect_q);
@@ -997,6 +1010,7 @@ out_free_io_queues:
 static void nvme_rdma_teardown_admin_queue(struct nvme_rdma_ctrl *ctrl,
                bool remove)
 {
+       mutex_lock(&ctrl->teardown_lock);
        blk_mq_quiesce_queue(ctrl->ctrl.admin_q);
        nvme_rdma_stop_queue(&ctrl->queues[0]);
        if (ctrl->ctrl.admin_tagset) {
@@ -1007,11 +1021,13 @@ static void nvme_rdma_teardown_admin_queue(struct nvme_rdma_ctrl *ctrl,
        if (remove)
                blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);
        nvme_rdma_destroy_admin_queue(ctrl, remove);
+       mutex_unlock(&ctrl->teardown_lock);
 }
 
 static void nvme_rdma_teardown_io_queues(struct nvme_rdma_ctrl *ctrl,
                bool remove)
 {
+       mutex_lock(&ctrl->teardown_lock);
        if (ctrl->ctrl.queue_count > 1) {
                nvme_start_freeze(&ctrl->ctrl);
                nvme_stop_queues(&ctrl->ctrl);
@@ -1025,6 +1041,7 @@ static void nvme_rdma_teardown_io_queues(struct nvme_rdma_ctrl *ctrl,
                        nvme_start_queues(&ctrl->ctrl);
                nvme_rdma_destroy_io_queues(ctrl, remove);
        }
+       mutex_unlock(&ctrl->teardown_lock);
 }
 
 static void nvme_rdma_free_ctrl(struct nvme_ctrl *nctrl)
@@ -1180,6 +1197,7 @@ static void nvme_rdma_error_recovery(struct nvme_rdma_ctrl *ctrl)
        if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RESETTING))
                return;
 
+       dev_warn(ctrl->ctrl.device, "starting error recovery\n");
        queue_work(nvme_reset_wq, &ctrl->err_work);
 }
 
@@ -1189,7 +1207,7 @@ static void nvme_rdma_end_request(struct nvme_rdma_request *req)
 
        if (!refcount_dec_and_test(&req->ref))
                return;
-       if (!nvme_end_request(rq, req->status, req->result))
+       if (!nvme_try_complete_req(rq, req->status, req->result))
                nvme_rdma_complete_rq(rq);
 }
 
@@ -1915,7 +1933,7 @@ static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id,
        case RDMA_CM_EVENT_CONNECT_ERROR:
        case RDMA_CM_EVENT_UNREACHABLE:
                nvme_rdma_destroy_queue_ib(queue);
-               /* fall through */
+               fallthrough;
        case RDMA_CM_EVENT_ADDR_ERROR:
                dev_dbg(queue->ctrl->ctrl.device,
                        "CM error event %d\n", ev->event);
@@ -1946,6 +1964,22 @@ static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id,
        return 0;
 }
 
+static void nvme_rdma_complete_timed_out(struct request *rq)
+{
+       struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
+       struct nvme_rdma_queue *queue = req->queue;
+       struct nvme_rdma_ctrl *ctrl = queue->ctrl;
+
+       /* fence other contexts that may complete the command */
+       mutex_lock(&ctrl->teardown_lock);
+       nvme_rdma_stop_queue(queue);
+       if (!blk_mq_request_completed(rq)) {
+               nvme_req(rq)->status = NVME_SC_HOST_ABORTED_CMD;
+               blk_mq_complete_request(rq);
+       }
+       mutex_unlock(&ctrl->teardown_lock);
+}
+
 static enum blk_eh_timer_return
 nvme_rdma_timeout(struct request *rq, bool reserved)
 {
@@ -1956,29 +1990,29 @@ nvme_rdma_timeout(struct request *rq, bool reserved)
        dev_warn(ctrl->ctrl.device, "I/O %d QID %d timeout\n",
                 rq->tag, nvme_rdma_queue_idx(queue));
 
-       /*
-        * Restart the timer if a controller reset is already scheduled. Any
-        * timed out commands would be handled before entering the connecting
-        * state.
-        */
-       if (ctrl->ctrl.state == NVME_CTRL_RESETTING)
-               return BLK_EH_RESET_TIMER;
-
        if (ctrl->ctrl.state != NVME_CTRL_LIVE) {
                /*
-                * Teardown immediately if controller times out while starting
-                * or we are already started error recovery. all outstanding
-                * requests are completed on shutdown, so we return BLK_EH_DONE.
+                * If we are resetting, connecting or deleting we should
+                * complete immediately because we may block controller
+                * teardown or setup sequence
+                * - ctrl disable/shutdown fabrics requests
+                * - connect requests
+                * - initialization admin requests
+                * - I/O requests that entered after unquiescing and
+                *   the controller stopped responding
+                *
+                * All other requests should be cancelled by the error
+                * recovery work, so it's fine that we fail it here.
                 */
-               flush_work(&ctrl->err_work);
-               nvme_rdma_teardown_io_queues(ctrl, false);
-               nvme_rdma_teardown_admin_queue(ctrl, false);
+               nvme_rdma_complete_timed_out(rq);
                return BLK_EH_DONE;
        }
 
-       dev_warn(ctrl->ctrl.device, "starting error recovery\n");
+       /*
+        * LIVE state should trigger the normal error recovery which will
+        * handle completing this request.
+        */
        nvme_rdma_error_recovery(ctrl);
-
        return BLK_EH_RESET_TIMER;
 }
 
@@ -2278,6 +2312,7 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
                return ERR_PTR(-ENOMEM);
        ctrl->ctrl.opts = opts;
        INIT_LIST_HEAD(&ctrl->list);
+       mutex_init(&ctrl->teardown_lock);
 
        if (!(opts->mask & NVMF_OPT_TRSVCID)) {
                opts->trsvcid =
index 62fbaec..d6a3e14 100644 (file)
@@ -124,6 +124,7 @@ struct nvme_tcp_ctrl {
        struct sockaddr_storage src_addr;
        struct nvme_ctrl        ctrl;
 
+       struct mutex            teardown_lock;
        struct work_struct      err_work;
        struct delayed_work     connect_work;
        struct nvme_tcp_request async_req;
@@ -464,6 +465,7 @@ static void nvme_tcp_error_recovery(struct nvme_ctrl *ctrl)
        if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING))
                return;
 
+       dev_warn(ctrl->device, "starting error recovery\n");
        queue_work(nvme_reset_wq, &to_tcp_ctrl(ctrl)->err_work);
 }
 
@@ -481,7 +483,7 @@ static int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue,
                return -EINVAL;
        }
 
-       if (!nvme_end_request(rq, cqe->status, cqe->result))
+       if (!nvme_try_complete_req(rq, cqe->status, cqe->result))
                nvme_complete_rq(rq);
        queue->nr_cqe++;
 
@@ -672,7 +674,7 @@ static inline void nvme_tcp_end_request(struct request *rq, u16 status)
 {
        union nvme_result res = {};
 
-       if (!nvme_end_request(rq, cpu_to_le16(status << 1), res))
+       if (!nvme_try_complete_req(rq, cpu_to_le16(status << 1), res))
                nvme_complete_rq(rq);
 }
 
@@ -866,7 +868,6 @@ static void nvme_tcp_state_change(struct sock *sk)
        case TCP_LAST_ACK:
        case TCP_FIN_WAIT1:
        case TCP_FIN_WAIT2:
-               /* fallthrough */
                nvme_tcp_error_recovery(&queue->ctrl->ctrl);
                break;
        default:
@@ -912,12 +913,11 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
                else
                        flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST;
 
-               /* can't zcopy slab pages */
-               if (unlikely(PageSlab(page))) {
-                       ret = sock_no_sendpage(queue->sock, page, offset, len,
+               if (sendpage_ok(page)) {
+                       ret = kernel_sendpage(queue->sock, page, offset, len,
                                        flags);
                } else {
-                       ret = kernel_sendpage(queue->sock, page, offset, len,
+                       ret = sock_no_sendpage(queue->sock, page, offset, len,
                                        flags);
                }
                if (ret <= 0)
@@ -1527,7 +1527,6 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
 
        if (!test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
                return;
-
        __nvme_tcp_stop_queue(queue);
 }
 
@@ -1596,6 +1595,7 @@ static struct blk_mq_tag_set *nvme_tcp_alloc_tagset(struct nvme_ctrl *nctrl,
 static void nvme_tcp_free_admin_queue(struct nvme_ctrl *ctrl)
 {
        if (to_tcp_ctrl(ctrl)->async_req.pdu) {
+               cancel_work_sync(&ctrl->async_event_work);
                nvme_tcp_free_async_req(to_tcp_ctrl(ctrl));
                to_tcp_ctrl(ctrl)->async_req.pdu = NULL;
        }
@@ -1782,7 +1782,15 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
 
        if (!new) {
                nvme_start_queues(ctrl);
-               nvme_wait_freeze(ctrl);
+               if (!nvme_wait_freeze_timeout(ctrl, NVME_IO_TIMEOUT)) {
+                       /*
+                        * If we timed out waiting for freeze we are likely to
+                        * be stuck.  Fail the controller initialization just
+                        * to be safe.
+                        */
+                       ret = -ENODEV;
+                       goto out_wait_freeze_timed_out;
+               }
                blk_mq_update_nr_hw_queues(ctrl->tagset,
                        ctrl->queue_count - 1);
                nvme_unfreeze(ctrl);
@@ -1790,6 +1798,9 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
 
        return 0;
 
+out_wait_freeze_timed_out:
+       nvme_stop_queues(ctrl);
+       nvme_tcp_stop_io_queues(ctrl);
 out_cleanup_connect_q:
        if (new)
                blk_cleanup_queue(ctrl->connect_q);
@@ -1875,6 +1886,7 @@ out_free_queue:
 static void nvme_tcp_teardown_admin_queue(struct nvme_ctrl *ctrl,
                bool remove)
 {
+       mutex_lock(&to_tcp_ctrl(ctrl)->teardown_lock);
        blk_mq_quiesce_queue(ctrl->admin_q);
        nvme_tcp_stop_queue(ctrl, 0);
        if (ctrl->admin_tagset) {
@@ -1885,13 +1897,16 @@ static void nvme_tcp_teardown_admin_queue(struct nvme_ctrl *ctrl,
        if (remove)
                blk_mq_unquiesce_queue(ctrl->admin_q);
        nvme_tcp_destroy_admin_queue(ctrl, remove);
+       mutex_unlock(&to_tcp_ctrl(ctrl)->teardown_lock);
 }
 
 static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl,
                bool remove)
 {
+       mutex_lock(&to_tcp_ctrl(ctrl)->teardown_lock);
        if (ctrl->queue_count <= 1)
-               return;
+               goto out;
+       blk_mq_quiesce_queue(ctrl->admin_q);
        nvme_start_freeze(ctrl);
        nvme_stop_queues(ctrl);
        nvme_tcp_stop_io_queues(ctrl);
@@ -1903,6 +1918,8 @@ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl,
        if (remove)
                nvme_start_queues(ctrl);
        nvme_tcp_destroy_io_queues(ctrl, remove);
+out:
+       mutex_unlock(&to_tcp_ctrl(ctrl)->teardown_lock);
 }
 
 static void nvme_tcp_reconnect_or_remove(struct nvme_ctrl *ctrl)
@@ -2149,40 +2166,55 @@ static void nvme_tcp_submit_async_event(struct nvme_ctrl *arg)
        nvme_tcp_queue_request(&ctrl->async_req, true, true);
 }
 
+static void nvme_tcp_complete_timed_out(struct request *rq)
+{
+       struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
+       struct nvme_ctrl *ctrl = &req->queue->ctrl->ctrl;
+
+       /* fence other contexts that may complete the command */
+       mutex_lock(&to_tcp_ctrl(ctrl)->teardown_lock);
+       nvme_tcp_stop_queue(ctrl, nvme_tcp_queue_id(req->queue));
+       if (!blk_mq_request_completed(rq)) {
+               nvme_req(rq)->status = NVME_SC_HOST_ABORTED_CMD;
+               blk_mq_complete_request(rq);
+       }
+       mutex_unlock(&to_tcp_ctrl(ctrl)->teardown_lock);
+}
+
 static enum blk_eh_timer_return
 nvme_tcp_timeout(struct request *rq, bool reserved)
 {
        struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
-       struct nvme_tcp_ctrl *ctrl = req->queue->ctrl;
+       struct nvme_ctrl *ctrl = &req->queue->ctrl->ctrl;
        struct nvme_tcp_cmd_pdu *pdu = req->pdu;
 
-       /*
-        * Restart the timer if a controller reset is already scheduled. Any
-        * timed out commands would be handled before entering the connecting
-        * state.
-        */
-       if (ctrl->ctrl.state == NVME_CTRL_RESETTING)
-               return BLK_EH_RESET_TIMER;
-
-       dev_warn(ctrl->ctrl.device,
+       dev_warn(ctrl->device,
                "queue %d: timeout request %#x type %d\n",
                nvme_tcp_queue_id(req->queue), rq->tag, pdu->hdr.type);
 
-       if (ctrl->ctrl.state != NVME_CTRL_LIVE) {
+       if (ctrl->state != NVME_CTRL_LIVE) {
                /*
-                * Teardown immediately if controller times out while starting
-                * or we are already started error recovery. all outstanding
-                * requests are completed on shutdown, so we return BLK_EH_DONE.
+                * If we are resetting, connecting or deleting we should
+                * complete immediately because we may block controller
+                * teardown or setup sequence
+                * - ctrl disable/shutdown fabrics requests
+                * - connect requests
+                * - initialization admin requests
+                * - I/O requests that entered after unquiescing and
+                *   the controller stopped responding
+                *
+                * All other requests should be cancelled by the error
+                * recovery work, so it's fine that we fail it here.
                 */
-               flush_work(&ctrl->err_work);
-               nvme_tcp_teardown_io_queues(&ctrl->ctrl, false);
-               nvme_tcp_teardown_admin_queue(&ctrl->ctrl, false);
+               nvme_tcp_complete_timed_out(rq);
                return BLK_EH_DONE;
        }
 
-       dev_warn(ctrl->ctrl.device, "starting error recovery\n");
-       nvme_tcp_error_recovery(&ctrl->ctrl);
-
+       /*
+        * LIVE state should trigger the normal error recovery which will
+        * handle completing this request.
+        */
+       nvme_tcp_error_recovery(ctrl);
        return BLK_EH_RESET_TIMER;
 }
 
@@ -2423,6 +2455,7 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
                        nvme_tcp_reconnect_ctrl_work);
        INIT_WORK(&ctrl->err_work, nvme_tcp_error_recovery_work);
        INIT_WORK(&ctrl->ctrl.reset_work, nvme_reset_ctrl_work);
+       mutex_init(&ctrl->teardown_lock);
 
        if (!(opts->mask & NVMF_OPT_TRSVCID)) {
                opts->trsvcid =
index 74b2b61..37e1d77 100644 (file)
@@ -1136,6 +1136,7 @@ static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
        up_write(&nvmet_config_sem);
 
        kfree_rcu(new_model, rcuhead);
+       kfree(new_model_number);
 
        return count;
 }
index b92f45f..b7b6333 100644 (file)
@@ -73,7 +73,7 @@ inline u16 errno_to_nvme_status(struct nvmet_req *req, int errno)
                status = NVME_SC_ACCESS_DENIED;
                break;
        case -EIO:
-               /* FALLTHRU */
+               fallthrough;
        default:
                req->error_loc = offsetof(struct nvme_common_command, opcode);
                status = NVME_SC_INTERNAL | NVME_SC_DNR;
@@ -397,6 +397,9 @@ static void nvmet_keep_alive_timer(struct work_struct *work)
 
 static void nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl)
 {
+       if (unlikely(ctrl->kato == 0))
+               return;
+
        pr_debug("ctrl %d start keep-alive timer for %d secs\n",
                ctrl->cntlid, ctrl->kato);
 
@@ -406,6 +409,9 @@ static void nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl)
 
 static void nvmet_stop_keep_alive_timer(struct nvmet_ctrl *ctrl)
 {
+       if (unlikely(ctrl->kato == 0))
+               return;
+
        pr_debug("ctrl %d stop keep-alive\n", ctrl->cntlid);
 
        cancel_delayed_work_sync(&ctrl->ka_work);
index 55bafd5..e6861cc 100644 (file)
@@ -2342,9 +2342,9 @@ nvmet_fc_fod_op_done(struct nvmet_fc_fcp_iod *fod)
                        return;
                if (fcpreq->fcp_error ||
                    fcpreq->transferred_length != fcpreq->transfer_length) {
-                       spin_lock(&fod->flock);
+                       spin_lock_irqsave(&fod->flock, flags);
                        fod->abort = true;
-                       spin_unlock(&fod->flock);
+                       spin_unlock_irqrestore(&fod->flock, flags);
 
                        nvmet_req_complete(&fod->req, NVME_SC_INTERNAL);
                        return;
index c97e60b..3da067a 100644 (file)
@@ -812,7 +812,7 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport,
                        break;
 
                /* Fall-Thru to RSP handling */
-               /* FALLTHRU */
+               fallthrough;
 
        case NVMET_FCOP_RSP:
                if (fcpreq) {
index 3dd6f56..125dde3 100644 (file)
@@ -139,7 +139,6 @@ static u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
                req->error_loc = offsetof(struct nvme_rw_command, nsid);
                break;
        case BLK_STS_IOERR:
-               /* fallthru */
        default:
                status = NVME_SC_INTERNAL | NVME_SC_DNR;
                req->error_loc = offsetof(struct nvme_common_command, opcode);
index 4884ef1..0d6008c 100644 (file)
@@ -115,7 +115,7 @@ static void nvme_loop_queue_response(struct nvmet_req *req)
                        return;
                }
 
-               if (!nvme_end_request(rq, cqe->status, cqe->result))
+               if (!nvme_try_complete_req(rq, cqe->status, cqe->result))
                        nvme_loop_complete_rq(rq);
        }
 }
index 89d91dc..dacfa74 100644 (file)
@@ -165,7 +165,7 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
 
        req->cqe->result = nvme_req(rq)->result;
        nvmet_req_complete(req, status);
-       blk_put_request(rq);
+       blk_mq_free_request(rq);
 }
 
 static void nvmet_passthru_req_done(struct request *rq,
@@ -175,7 +175,7 @@ static void nvmet_passthru_req_done(struct request *rq,
 
        req->cqe->result = nvme_req(rq)->result;
        nvmet_req_complete(req, nvme_req(rq)->status);
-       blk_put_request(rq);
+       blk_mq_free_request(rq);
 }
 
 static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)
@@ -230,7 +230,7 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
                if (unlikely(!ns)) {
                        pr_err("failed to get passthru ns nsid:%u\n", nsid);
                        status = NVME_SC_INVALID_NS | NVME_SC_DNR;
-                       goto fail_out;
+                       goto out;
                }
 
                q = ns->queue;
@@ -238,16 +238,15 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
 
        rq = nvme_alloc_request(q, req->cmd, BLK_MQ_REQ_NOWAIT, NVME_QID_ANY);
        if (IS_ERR(rq)) {
-               rq = NULL;
                status = NVME_SC_INTERNAL;
-               goto fail_out;
+               goto out_put_ns;
        }
 
        if (req->sg_cnt) {
                ret = nvmet_passthru_map_sg(req, rq);
                if (unlikely(ret)) {
                        status = NVME_SC_INTERNAL;
-                       goto fail_out;
+                       goto out_put_req;
                }
        }
 
@@ -274,11 +273,13 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
 
        return;
 
-fail_out:
+out_put_req:
+       blk_mq_free_request(rq);
+out_put_ns:
        if (ns)
                nvme_put_ns(ns);
+out:
        nvmet_req_complete(req, status);
-       blk_put_request(rq);
 }
 
 /*
@@ -326,6 +327,10 @@ static u16 nvmet_setup_passthru_command(struct nvmet_req *req)
 
 u16 nvmet_parse_passthru_io_cmd(struct nvmet_req *req)
 {
+       /* Reject any commands with non-sgl flags set (ie. fused commands) */
+       if (req->cmd->common.flags & ~NVME_CMD_SGL_ALL)
+               return NVME_SC_INVALID_FIELD;
+
        switch (req->cmd->common.opcode) {
        case nvme_cmd_resv_register:
        case nvme_cmd_resv_report:
@@ -396,6 +401,10 @@ static u16 nvmet_passthru_get_set_features(struct nvmet_req *req)
 
 u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req)
 {
+       /* Reject any commands with non-sgl flags set (ie. fused commands) */
+       if (req->cmd->common.flags & ~NVME_CMD_SGL_ALL)
+               return NVME_SC_INVALID_FIELD;
+
        /*
         * Passthru all vendor specific commands
         */
@@ -508,6 +517,7 @@ int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys)
                subsys->ver = NVME_VS(1, 2, 1);
        }
 
+       __module_get(subsys->passthru_ctrl->ops->module);
        mutex_unlock(&subsys->lock);
        return 0;
 
@@ -522,6 +532,7 @@ static void __nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys)
 {
        if (subsys->passthru_ctrl) {
                xa_erase(&passthru_subsystems, subsys->passthru_ctrl->cntlid);
+               module_put(subsys->passthru_ctrl->ops->module);
                nvme_put_ctrl(subsys->passthru_ctrl);
        }
        subsys->passthru_ctrl = NULL;
index 3ccb592..ae66204 100644 (file)
@@ -1758,7 +1758,7 @@ static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id,
                        schedule_delayed_work(&port->repair_work, 0);
                        break;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case RDMA_CM_EVENT_DISCONNECTED:
        case RDMA_CM_EVENT_TIMEWAIT_EXIT:
                nvmet_rdma_queue_disconnect(queue);
@@ -1769,7 +1769,7 @@ static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id,
        case RDMA_CM_EVENT_REJECTED:
                pr_debug("Connection rejected: %s\n",
                         rdma_reject_msg(cm_id, event->status));
-               /* FALLTHROUGH */
+               fallthrough;
        case RDMA_CM_EVENT_UNREACHABLE:
        case RDMA_CM_EVENT_CONNECT_ERROR:
                nvmet_rdma_queue_connect_fail(cm_id, queue);
index 9eda911..8e0d766 100644 (file)
@@ -160,6 +160,11 @@ static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd);
 static inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue,
                struct nvmet_tcp_cmd *cmd)
 {
+       if (unlikely(!queue->nr_cmds)) {
+               /* We didn't allocate cmds yet, send 0xffff */
+               return USHRT_MAX;
+       }
+
        return cmd - queue->cmds;
 }
 
@@ -866,7 +871,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue)
        struct nvme_tcp_data_pdu *data = &queue->pdu.data;
        struct nvmet_tcp_cmd *cmd;
 
-       cmd = &queue->cmds[data->ttag];
+       if (likely(queue->nr_cmds))
+               cmd = &queue->cmds[data->ttag];
+       else
+               cmd = &queue->connect;
 
        if (le32_to_cpu(data->data_offset) != cmd->rbytes_done) {
                pr_err("ttag %u unexpected data offset %u (expected %u)\n",
index 9668ea0..3ca7543 100644 (file)
@@ -1296,13 +1296,19 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
 
-void _opp_remove_all_static(struct opp_table *opp_table)
+bool _opp_remove_all_static(struct opp_table *opp_table)
 {
        struct dev_pm_opp *opp, *tmp;
+       bool ret = true;
 
        mutex_lock(&opp_table->lock);
 
-       if (!opp_table->parsed_static_opps || --opp_table->parsed_static_opps)
+       if (!opp_table->parsed_static_opps) {
+               ret = false;
+               goto unlock;
+       }
+
+       if (--opp_table->parsed_static_opps)
                goto unlock;
 
        list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
@@ -1312,6 +1318,8 @@ void _opp_remove_all_static(struct opp_table *opp_table)
 
 unlock:
        mutex_unlock(&opp_table->lock);
+
+       return ret;
 }
 
 /**
@@ -2414,13 +2422,15 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev)
                return;
        }
 
-       _opp_remove_all_static(opp_table);
+       /*
+        * Drop the extra reference only if the OPP table was successfully added
+        * with dev_pm_opp_of_add_table() earlier.
+        **/
+       if (_opp_remove_all_static(opp_table))
+               dev_pm_opp_put_opp_table(opp_table);
 
        /* Drop reference taken by _find_opp_table() */
        dev_pm_opp_put_opp_table(opp_table);
-
-       /* Drop reference taken while the OPP table was added */
-       dev_pm_opp_put_opp_table(opp_table);
 }
 
 /**
index e51646f..c3fcd57 100644 (file)
@@ -212,7 +212,7 @@ struct opp_table {
 
 /* Routines internal to opp core */
 void dev_pm_opp_get(struct dev_pm_opp *opp);
-void _opp_remove_all_static(struct opp_table *opp_table);
+bool _opp_remove_all_static(struct opp_table *opp_table);
 void _get_opp_table_kref(struct opp_table *opp_table);
 int _get_opp_count(struct opp_table *opp_table);
 struct opp_table *_find_opp_table(struct device *dev);
index 4d76952..cc91786 100644 (file)
@@ -116,7 +116,7 @@ module_load_notify(struct notifier_block *self, unsigned long val, void *data)
 {
 #ifdef CONFIG_MODULES
        if (val != MODULE_STATE_COMING)
-               return 0;
+               return NOTIFY_DONE;
 
        /* FIXME: should we process all CPU buffers ? */
        mutex_lock(&buffer_mutex);
@@ -124,7 +124,7 @@ module_load_notify(struct notifier_block *self, unsigned long val, void *data)
        add_event_entry(MODULE_LOADED_CODE);
        mutex_unlock(&buffer_mutex);
 #endif
-       return 0;
+       return NOTIFY_OK;
 }
 
 
index f28d6a3..4547ac4 100644 (file)
@@ -260,7 +260,7 @@ static void parport_ieee1284_terminate (struct parport *port)
                        port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
                }
 
-               /* fall through */
+               fallthrough;
 
        default:
                /* Terminate from all other modes. */
@@ -598,7 +598,7 @@ ssize_t parport_write (struct parport *port, const void *buffer, size_t len)
        case IEEE1284_MODE_NIBBLE:
        case IEEE1284_MODE_BYTE:
                parport_negotiate (port, IEEE1284_MODE_COMPAT);
-               /* fall through */
+               fallthrough;
        case IEEE1284_MODE_COMPAT:
                pr_debug("%s: Using compatibility mode\n", port->name);
                fn = port->ops->compat_write_data;
@@ -702,7 +702,7 @@ ssize_t parport_read (struct parport *port, void *buffer, size_t len)
                if (parport_negotiate (port, IEEE1284_MODE_NIBBLE)) {
                        return -EIO;
                }
-               /* fall through - to NIBBLE */
+               fallthrough;    /* to NIBBLE */
        case IEEE1284_MODE_NIBBLE:
                pr_debug("%s: Using nibble mode\n", port->name);
                fn = port->ops->nibble_read_data;
index 77e37e3..eda4ded 100644 (file)
@@ -1647,7 +1647,7 @@ static int parport_ECP_supported(struct parport *pb)
                break;
        default:
                pr_warn("0x%lx: Unknown implementation ID\n", pb->base);
-               /* Fall through - Assume 1 */
+               fallthrough;    /* Assume 1 */
        case 1:
                pword = 1;
        }
index 4bef5c2..438a792 100644 (file)
@@ -56,6 +56,9 @@ config PCI_MSI_IRQ_DOMAIN
        depends on PCI_MSI
        select GENERIC_MSI_IRQ_DOMAIN
 
+config PCI_MSI_ARCH_FALLBACKS
+       bool
+
 config PCI_QUIRKS
        default y
        bool "Enable PCI quirk workarounds" if EXPERT
index f18c372..4a7afbe 100644 (file)
@@ -41,6 +41,7 @@ config PCI_TEGRA
        bool "NVIDIA Tegra PCIe controller"
        depends on ARCH_TEGRA || COMPILE_TEST
        depends on PCI_MSI_IRQ_DOMAIN
+       select PCI_MSI_ARCH_FALLBACKS
        help
          Say Y here if you want support for the PCIe host controller found
          on NVIDIA Tegra SoCs.
@@ -67,6 +68,7 @@ config PCIE_RCAR_HOST
        bool "Renesas R-Car PCIe host controller"
        depends on ARCH_RENESAS || COMPILE_TEST
        depends on PCI_MSI_IRQ_DOMAIN
+       select PCI_MSI_ARCH_FALLBACKS
        help
          Say Y here if you want PCIe controller support on R-Car SoCs in host
          mode.
@@ -95,6 +97,7 @@ config PCI_HOST_GENERIC
 config PCIE_XILINX
        bool "Xilinx AXI PCIe host bridge support"
        depends on OF || COMPILE_TEST
+       select PCI_MSI_ARCH_FALLBACKS
        help
          Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
          Host Bridge driver.
index 90df28c..5fef261 100644 (file)
@@ -439,7 +439,7 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
                regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
                                   IMX6SX_GPR12_PCIE_TEST_POWERDOWN, 0);
                break;
-       case IMX6QP:            /* FALLTHROUGH */
+       case IMX6QP:
        case IMX6Q:
                /* power up core phy and enable ref clock */
                regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
@@ -642,7 +642,7 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
                regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
                                   IMX6SX_GPR12_PCIE_RX_EQ_MASK,
                                   IMX6SX_GPR12_PCIE_RX_EQ_2);
-               /* FALLTHROUGH */
+               fallthrough;
        default:
                regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
                                   IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
@@ -1105,7 +1105,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
                        dev_err(dev, "pcie_aux clock source missing or invalid\n");
                        return PTR_ERR(imx6_pcie->pcie_aux);
                }
-               /* fall through */
+               fallthrough;
        case IMX7D:
                if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
                        imx6_pcie->controller_id = 1;
index fc4c3a1..25b4c90 100644 (file)
@@ -1531,16 +1531,8 @@ static struct irq_chip hv_msi_irq_chip = {
        .irq_unmask             = hv_irq_unmask,
 };
 
-static irq_hw_number_t hv_msi_domain_ops_get_hwirq(struct msi_domain_info *info,
-                                                  msi_alloc_info_t *arg)
-{
-       return arg->msi_hwirq;
-}
-
 static struct msi_domain_ops hv_msi_ops = {
-       .get_hwirq      = hv_msi_domain_ops_get_hwirq,
        .msi_prepare    = pci_msi_prepare,
-       .set_desc       = pci_msi_set_desc,
        .msi_free       = hv_msi_free,
 };
 
index c953003..afde4aa 100644 (file)
@@ -223,7 +223,7 @@ static void rcar_pci_setup(struct rcar_pci_priv *priv)
                pr_warn("unknown window size %ld - defaulting to 256M\n",
                        window_size);
                window_size = SZ_256M;
-               /* fall-through */
+               fallthrough;
        case SZ_256M:
                val |= RCAR_USBCTR_PCIAHB_WIN1_256M;
                break;
index 0bb2fb3..9705059 100644 (file)
@@ -71,16 +71,13 @@ static void rockchip_pcie_update_txcredit_mui(struct rockchip_pcie *rockchip)
 static int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip,
                                      struct pci_bus *bus, int dev)
 {
-       /* access only one slot on each root port */
-       if (pci_is_root_bus(bus) && dev > 0)
-               return 0;
-
        /*
-        * do not read more than one device on the bus directly attached
+        * Access only one slot on each root port.
+        * Do not read more than one device on the bus directly attached
         * to RC's downstream side.
         */
-       if (pci_is_root_bus(bus->parent) && dev > 0)
-               return 0;
+       if (pci_is_root_bus(bus) || pci_is_root_bus(bus->parent))
+               return dev == 0;
 
        return 1;
 }
index f69ef8c..aa1b12b 100644 (file)
@@ -573,12 +573,19 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
                return -ENODEV;
 
        vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info,
-                                                   x86_vector_domain);
+                                                   NULL);
+
        if (!vmd->irq_domain) {
                irq_domain_free_fwnode(fn);
                return -ENODEV;
        }
 
+       /*
+        * Override the irq domain bus token so the domain can be distinguished
+        * from a regular PCI/MSI domain.
+        */
+       irq_domain_update_bus_token(vmd->irq_domain, DOMAIN_BUS_VMD_MSI);
+
        pci_add_resource(&resources, &vmd->resources[0]);
        pci_add_resource_offset(&resources, &vmd->resources[1], offset[0]);
        pci_add_resource_offset(&resources, &vmd->resources[2], offset[1]);
index 5c93aa1..ae9acc7 100644 (file)
@@ -1941,7 +1941,7 @@ static int __init update_bridge_ranges(struct bus_node **bus)
                                                break;
                                        case PCI_HEADER_TYPE_BRIDGE:
                                                function = 0x8;
-                                               /* fall through */
+                                               fallthrough;
                                        case PCI_HEADER_TYPE_MULTIBRIDGE:
                                                /* We assume here that only 1 bus behind the bridge
                                                   TO DO: add functionality for several:
index 6503d15..9f85815 100644 (file)
@@ -236,7 +236,7 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
        switch (ctrl->state) {
        case BLINKINGOFF_STATE:
                cancel_delayed_work(&ctrl->button_work);
-               /* fall through */
+               fallthrough;
        case ON_STATE:
                ctrl->state = POWEROFF_STATE;
                mutex_unlock(&ctrl->state_lock);
@@ -265,7 +265,7 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
        switch (ctrl->state) {
        case BLINKINGON_STATE:
                cancel_delayed_work(&ctrl->button_work);
-               /* fall through */
+               fallthrough;
        case OFF_STATE:
                ctrl->state = POWERON_STATE;
                mutex_unlock(&ctrl->state_lock);
index afdc52d..65502e3 100644 (file)
@@ -642,7 +642,7 @@ int shpchp_sysfs_enable_slot(struct slot *p_slot)
        switch (p_slot->state) {
        case BLINKINGON_STATE:
                cancel_delayed_work(&p_slot->work);
-               /* fall through */
+               fallthrough;
        case STATIC_STATE:
                p_slot->state = POWERON_STATE;
                mutex_unlock(&p_slot->lock);
@@ -678,7 +678,7 @@ int shpchp_sysfs_disable_slot(struct slot *p_slot)
        switch (p_slot->state) {
        case BLINKINGOFF_STATE:
                cancel_delayed_work(&p_slot->work);
-               /* fall through */
+               fallthrough;
        case STATIC_STATE:
                p_slot->state = POWEROFF_STATE;
                mutex_unlock(&p_slot->lock);
index 30ae4ff..d52d118 100644 (file)
@@ -58,8 +58,8 @@ static void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
 #define pci_msi_teardown_msi_irqs      arch_teardown_msi_irqs
 #endif
 
+#ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS
 /* Arch hooks */
-
 int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
        struct msi_controller *chip = dev->bus->msi;
@@ -132,6 +132,7 @@ void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
 {
        return default_teardown_msi_irqs(dev);
 }
+#endif /* CONFIG_PCI_MSI_ARCH_FALLBACKS */
 
 static void default_restore_msi_irq(struct pci_dev *dev, int irq)
 {
@@ -1346,14 +1347,14 @@ void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
 
 /**
  * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source
- * @dev:       Pointer to the PCI device
  * @desc:      Pointer to the MSI descriptor
  *
  * The ID number is only used within the irqdomain.
  */
-irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
-                                         struct msi_desc *desc)
+static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc)
 {
+       struct pci_dev *dev = msi_desc_to_pci_dev(desc);
+
        return (irq_hw_number_t)desc->msi_attrib.entry_nr |
                pci_dev_id(dev) << 11 |
                (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
@@ -1401,17 +1402,12 @@ static int pci_msi_domain_handle_error(struct irq_domain *domain,
        return error;
 }
 
-#ifdef GENERIC_MSI_DOMAIN_OPS
 static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
                                    struct msi_desc *desc)
 {
        arg->desc = desc;
-       arg->hwirq = pci_msi_domain_calc_hwirq(msi_desc_to_pci_dev(desc),
-                                              desc);
+       arg->hwirq = pci_msi_domain_calc_hwirq(desc);
 }
-#else
-#define pci_msi_domain_set_desc                NULL
-#endif
 
 static struct msi_domain_ops pci_msi_domain_ops_default = {
        .set_desc       = pci_msi_domain_set_desc,
@@ -1558,4 +1554,26 @@ struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
                                             DOMAIN_BUS_PCI_MSI);
        return dom;
 }
+
+/**
+ * pci_dev_has_special_msi_domain - Check whether the device is handled by
+ *                                 a non-standard PCI-MSI domain
+ * @pdev:      The PCI device to check.
+ *
+ * Returns: True if the device irqdomain or the bus irqdomain is
+ * non-standard PCI/MSI.
+ */
+bool pci_dev_has_special_msi_domain(struct pci_dev *pdev)
+{
+       struct irq_domain *dom = dev_get_msi_domain(&pdev->dev);
+
+       if (!dom)
+               dom = dev_get_msi_domain(&pdev->bus->dev);
+
+       if (!dom)
+               return true;
+
+       return dom->bus_token != DOMAIN_BUS_PCI_MSI;
+}
+
 #endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
index a458c46..e39c549 100644 (file)
@@ -1049,7 +1049,7 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
                if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
                 && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
                        need_restore = true;
-               /* Fall-through - force to D0 */
+               fallthrough;    /* force to D0 */
        default:
                pmcsr = 0;
                break;
@@ -2541,7 +2541,7 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
                case PCI_D2:
                        if (pci_no_d1d2(dev))
                                break;
-                       /* else, fall through */
+                       fallthrough;
                default:
                        target_state = state;
                }
index bd2b691..d35186b 100644 (file)
@@ -231,7 +231,7 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
                }
                /* If arch decided it can't, fall through... */
 #endif /* HAVE_PCI_MMAP */
-               /* fall through */
+               fallthrough;
        default:
                ret = -EINVAL;
                break;
index bdf9b52..2a589b6 100644 (file)
@@ -1730,7 +1730,7 @@ static void quirk_jmicron_ata(struct pci_dev *pdev)
        case PCI_DEVICE_ID_JMICRON_JMB366:
                /* Redirect IDE second PATA port to the right spot */
                conf5 |= (1 << 24);
-               /* Fall through */
+               fallthrough;
        case PCI_DEVICE_ID_JMICRON_JMB361:
        case PCI_DEVICE_ID_JMICRON_JMB363:
        case PCI_DEVICE_ID_JMICRON_JMB369:
@@ -2224,7 +2224,7 @@ static void quirk_netmos(struct pci_dev *dev)
                if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
                                dev->subsystem_device == 0x0299)
                        return;
-               /* else, fall through */
+               fallthrough;
        case PCI_DEVICE_ID_NETMOS_9735:
        case PCI_DEVICE_ID_NETMOS_9745:
        case PCI_DEVICE_ID_NETMOS_9845:
index 3951e02..2ce6369 100644 (file)
@@ -1253,7 +1253,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                        additional_mmio_size = pci_hotplug_mmio_size;
                        additional_mmio_pref_size = pci_hotplug_mmio_pref_size;
                }
-               /* Fall through */
+               fallthrough;
        default:
                pbus_size_io(bus, realloc_head ? 0 : additional_io_size,
                             additional_io_size, realloc_head);
index fab267e..c0e85be 100644 (file)
@@ -1096,7 +1096,7 @@ static void __ref pcifront_backend_changed(struct xenbus_device *xdev,
        case XenbusStateClosed:
                if (xdev->state == XenbusStateClosed)
                        break;
-               /* fall through - Missed the backend's CLOSING state. */
+               fallthrough;    /* Missed the backend's CLOSING state */
        case XenbusStateClosing:
                dev_warn(&xdev->dev, "backend going away!\n");
                pcifront_try_disconnect(pdev);
index 590e594..a7c7c7c 100644 (file)
@@ -255,10 +255,10 @@ static int db1x_pcmcia_configure(struct pcmcia_socket *skt,
        switch (state->Vcc) {
        case 50:
                ++v;
-               /* fall through */
+               fallthrough;
        case 33:
                ++v;
-               /* fall through */
+               fallthrough;
        case 0:
                break;
        default:
@@ -269,11 +269,11 @@ static int db1x_pcmcia_configure(struct pcmcia_socket *skt,
        switch (state->Vpp) {
        case 12:
                ++p;
-               /* fall through */
+               fallthrough;
        case 33:
        case 50:
                ++p;
-               /* fall through */
+               fallthrough;
        case 0:
                break;
        default:
index 7305d57..130327f 100644 (file)
@@ -41,6 +41,13 @@ config ARM_CCN
          PMU (perf) driver supporting the ARM CCN (Cache Coherent Network)
          interconnect.
 
+config ARM_CMN
+       tristate "Arm CMN-600 PMU support"
+       depends on ARM64 || (COMPILE_TEST && 64BIT)
+       help
+         Support for PMU events monitoring on the Arm CMN-600 Coherent Mesh
+         Network interconnect.
+
 config ARM_PMU
        depends on ARM || ARM64
        bool "ARM PMU framework"
index 2ebb4de..5365fd5 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_ARM_CCI_PMU) += arm-cci.o
 obj-$(CONFIG_ARM_CCN) += arm-ccn.o
+obj-$(CONFIG_ARM_CMN) += arm-cmn.o
 obj-$(CONFIG_ARM_DSU_PMU) += arm_dsu_pmu.o
 obj-$(CONFIG_ARM_PMU) += arm_pmu.o arm_pmu_platform.o
 obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o
index 7b7d23f..a0a71c1 100644 (file)
@@ -1404,7 +1404,7 @@ static int arm_ccn_init_nodes(struct arm_ccn *ccn, int region,
                break;
        case CCN_TYPE_SBAS:
                ccn->sbas_present = 1;
-               /* Fall-through */
+               fallthrough;
        default:
                component = &ccn->node[id];
                break;
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
new file mode 100644 (file)
index 0000000..a76ff59
--- /dev/null
@@ -0,0 +1,1641 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2016-2020 Arm Limited
+// CMN-600 Coherent Mesh Network PMU driver
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+
+/* Common register stuff */
+#define CMN_NODE_INFO                  0x0000
+#define CMN_NI_NODE_TYPE               GENMASK_ULL(15, 0)
+#define CMN_NI_NODE_ID                 GENMASK_ULL(31, 16)
+#define CMN_NI_LOGICAL_ID              GENMASK_ULL(47, 32)
+
+#define CMN_NODEID_DEVID(reg)          ((reg) & 3)
+#define CMN_NODEID_PID(reg)            (((reg) >> 2) & 1)
+#define CMN_NODEID_X(reg, bits)                ((reg) >> (3 + (bits)))
+#define CMN_NODEID_Y(reg, bits)                (((reg) >> 3) & ((1U << (bits)) - 1))
+
+#define CMN_CHILD_INFO                 0x0080
+#define CMN_CI_CHILD_COUNT             GENMASK_ULL(15, 0)
+#define CMN_CI_CHILD_PTR_OFFSET                GENMASK_ULL(31, 16)
+
+#define CMN_CHILD_NODE_ADDR            GENMASK(27,0)
+#define CMN_CHILD_NODE_EXTERNAL                BIT(31)
+
+#define CMN_ADDR_NODE_PTR              GENMASK(27, 14)
+
+#define CMN_NODE_PTR_DEVID(ptr)                (((ptr) >> 2) & 3)
+#define CMN_NODE_PTR_PID(ptr)          ((ptr) & 1)
+#define CMN_NODE_PTR_X(ptr, bits)      ((ptr) >> (6 + (bits)))
+#define CMN_NODE_PTR_Y(ptr, bits)      (((ptr) >> 6) & ((1U << (bits)) - 1))
+
+#define CMN_MAX_XPS                    (8 * 8)
+
+/* The CFG node has one other useful purpose */
+#define CMN_CFGM_PERIPH_ID_2           0x0010
+#define CMN_CFGM_PID2_REVISION         GENMASK(7, 4)
+
+/* PMU registers occupy the 3rd 4KB page of each node's 16KB space */
+#define CMN_PMU_OFFSET                 0x2000
+
+/* For most nodes, this is all there is */
+#define CMN_PMU_EVENT_SEL              0x000
+#define CMN_PMU_EVENTn_ID_SHIFT(n)     ((n) * 8)
+
+/* DTMs live in the PMU space of XP registers */
+#define CMN_DTM_WPn(n)                 (0x1A0 + (n) * 0x18)
+#define CMN_DTM_WPn_CONFIG(n)          (CMN_DTM_WPn(n) + 0x00)
+#define CMN_DTM_WPn_CONFIG_WP_COMBINE  BIT(6)
+#define CMN_DTM_WPn_CONFIG_WP_EXCLUSIVE        BIT(5)
+#define CMN_DTM_WPn_CONFIG_WP_GRP      BIT(4)
+#define CMN_DTM_WPn_CONFIG_WP_CHN_SEL  GENMASK_ULL(3, 1)
+#define CMN_DTM_WPn_CONFIG_WP_DEV_SEL  BIT(0)
+#define CMN_DTM_WPn_VAL(n)             (CMN_DTM_WPn(n) + 0x08)
+#define CMN_DTM_WPn_MASK(n)            (CMN_DTM_WPn(n) + 0x10)
+
+#define CMN_DTM_PMU_CONFIG             0x210
+#define CMN__PMEVCNT0_INPUT_SEL                GENMASK_ULL(37, 32)
+#define CMN__PMEVCNT0_INPUT_SEL_WP     0x00
+#define CMN__PMEVCNT0_INPUT_SEL_XP     0x04
+#define CMN__PMEVCNT0_INPUT_SEL_DEV    0x10
+#define CMN__PMEVCNT0_GLOBAL_NUM       GENMASK_ULL(18, 16)
+#define CMN__PMEVCNTn_GLOBAL_NUM_SHIFT(n)      ((n) * 4)
+#define CMN__PMEVCNT_PAIRED(n)         BIT(4 + (n))
+#define CMN__PMEVCNT23_COMBINED                BIT(2)
+#define CMN__PMEVCNT01_COMBINED                BIT(1)
+#define CMN_DTM_PMU_CONFIG_PMU_EN      BIT(0)
+
+#define CMN_DTM_PMEVCNT                        0x220
+
+#define CMN_DTM_PMEVCNTSR              0x240
+
+#define CMN_DTM_NUM_COUNTERS           4
+
+/* The DTC node is where the magic happens */
+#define CMN_DT_DTC_CTL                 0x0a00
+#define CMN_DT_DTC_CTL_DT_EN           BIT(0)
+
+/* DTC counters are paired in 64-bit registers on a 16-byte stride. Yuck */
+#define _CMN_DT_CNT_REG(n)             ((((n) / 2) * 4 + (n) % 2) * 4)
+#define CMN_DT_PMEVCNT(n)              (CMN_PMU_OFFSET + _CMN_DT_CNT_REG(n))
+#define CMN_DT_PMCCNTR                 (CMN_PMU_OFFSET + 0x40)
+
+#define CMN_DT_PMEVCNTSR(n)            (CMN_PMU_OFFSET + 0x50 + _CMN_DT_CNT_REG(n))
+#define CMN_DT_PMCCNTRSR               (CMN_PMU_OFFSET + 0x90)
+
+#define CMN_DT_PMCR                    (CMN_PMU_OFFSET + 0x100)
+#define CMN_DT_PMCR_PMU_EN             BIT(0)
+#define CMN_DT_PMCR_CNTR_RST           BIT(5)
+#define CMN_DT_PMCR_OVFL_INTR_EN       BIT(6)
+
+#define CMN_DT_PMOVSR                  (CMN_PMU_OFFSET + 0x118)
+#define CMN_DT_PMOVSR_CLR              (CMN_PMU_OFFSET + 0x120)
+
+#define CMN_DT_PMSSR                   (CMN_PMU_OFFSET + 0x128)
+#define CMN_DT_PMSSR_SS_STATUS(n)      BIT(n)
+
+#define CMN_DT_PMSRR                   (CMN_PMU_OFFSET + 0x130)
+#define CMN_DT_PMSRR_SS_REQ            BIT(0)
+
+#define CMN_DT_NUM_COUNTERS            8
+#define CMN_MAX_DTCS                   4
+
+/*
+ * Even in the worst case a DTC counter can't wrap in fewer than 2^42 cycles,
+ * so throwing away one bit to make overflow handling easy is no big deal.
+ */
+#define CMN_COUNTER_INIT               0x80000000
+/* Similarly for the 40-bit cycle counter */
+#define CMN_CC_INIT                    0x8000000000ULL
+
+
+/* Event attributes */
+#define CMN_CONFIG_TYPE                        GENMASK(15, 0)
+#define CMN_CONFIG_EVENTID             GENMASK(23, 16)
+#define CMN_CONFIG_OCCUPID             GENMASK(27, 24)
+#define CMN_CONFIG_BYNODEID            BIT(31)
+#define CMN_CONFIG_NODEID              GENMASK(47, 32)
+
+#define CMN_EVENT_TYPE(event)          FIELD_GET(CMN_CONFIG_TYPE, (event)->attr.config)
+#define CMN_EVENT_EVENTID(event)       FIELD_GET(CMN_CONFIG_EVENTID, (event)->attr.config)
+#define CMN_EVENT_OCCUPID(event)       FIELD_GET(CMN_CONFIG_OCCUPID, (event)->attr.config)
+#define CMN_EVENT_BYNODEID(event)      FIELD_GET(CMN_CONFIG_BYNODEID, (event)->attr.config)
+#define CMN_EVENT_NODEID(event)                FIELD_GET(CMN_CONFIG_NODEID, (event)->attr.config)
+
+#define CMN_CONFIG_WP_COMBINE          GENMASK(27, 24)
+#define CMN_CONFIG_WP_DEV_SEL          BIT(48)
+#define CMN_CONFIG_WP_CHN_SEL          GENMASK(50, 49)
+#define CMN_CONFIG_WP_GRP              BIT(52)
+#define CMN_CONFIG_WP_EXCLUSIVE                BIT(53)
+#define CMN_CONFIG1_WP_VAL             GENMASK(63, 0)
+#define CMN_CONFIG2_WP_MASK            GENMASK(63, 0)
+
+#define CMN_EVENT_WP_COMBINE(event)    FIELD_GET(CMN_CONFIG_WP_COMBINE, (event)->attr.config)
+#define CMN_EVENT_WP_DEV_SEL(event)    FIELD_GET(CMN_CONFIG_WP_DEV_SEL, (event)->attr.config)
+#define CMN_EVENT_WP_CHN_SEL(event)    FIELD_GET(CMN_CONFIG_WP_CHN_SEL, (event)->attr.config)
+#define CMN_EVENT_WP_GRP(event)                FIELD_GET(CMN_CONFIG_WP_GRP, (event)->attr.config)
+#define CMN_EVENT_WP_EXCLUSIVE(event)  FIELD_GET(CMN_CONFIG_WP_EXCLUSIVE, (event)->attr.config)
+#define CMN_EVENT_WP_VAL(event)                FIELD_GET(CMN_CONFIG1_WP_VAL, (event)->attr.config1)
+#define CMN_EVENT_WP_MASK(event)       FIELD_GET(CMN_CONFIG2_WP_MASK, (event)->attr.config2)
+
+/* Made-up event IDs for watchpoint direction */
+#define CMN_WP_UP                      0
+#define CMN_WP_DOWN                    2
+
+
+/* r0px probably don't exist in silicon, thankfully */
+enum cmn_revision {
+       CMN600_R1P0,
+       CMN600_R1P1,
+       CMN600_R1P2,
+       CMN600_R1P3,
+       CMN600_R2P0,
+       CMN600_R3P0,
+};
+
+enum cmn_node_type {
+       CMN_TYPE_INVALID,
+       CMN_TYPE_DVM,
+       CMN_TYPE_CFG,
+       CMN_TYPE_DTC,
+       CMN_TYPE_HNI,
+       CMN_TYPE_HNF,
+       CMN_TYPE_XP,
+       CMN_TYPE_SBSX,
+       CMN_TYPE_RNI = 0xa,
+       CMN_TYPE_RND = 0xd,
+       CMN_TYPE_RNSAM = 0xf,
+       CMN_TYPE_CXRA = 0x100,
+       CMN_TYPE_CXHA = 0x101,
+       CMN_TYPE_CXLA = 0x102,
+       /* Not a real node type */
+       CMN_TYPE_WP = 0x7770
+};
+
+struct arm_cmn_node {
+       void __iomem *pmu_base;
+       u16 id, logid;
+       enum cmn_node_type type;
+
+       union {
+               /* Device node */
+               struct {
+                       int to_xp;
+                       /* DN/HN-F/CXHA */
+                       unsigned int occupid_val;
+                       unsigned int occupid_count;
+               };
+               /* XP */
+               struct {
+                       int dtc;
+                       u32 pmu_config_low;
+                       union {
+                               u8 input_sel[4];
+                               __le32 pmu_config_high;
+                       };
+                       s8 wp_event[4];
+               };
+       };
+
+       union {
+               u8 event[4];
+               __le32 event_sel;
+       };
+};
+
+struct arm_cmn_dtc {
+       void __iomem *base;
+       int irq;
+       int irq_friend;
+       bool cc_active;
+
+       struct perf_event *counters[CMN_DT_NUM_COUNTERS];
+       struct perf_event *cycles;
+};
+
+#define CMN_STATE_DISABLED     BIT(0)
+#define CMN_STATE_TXN          BIT(1)
+
+struct arm_cmn {
+       struct device *dev;
+       void __iomem *base;
+
+       enum cmn_revision rev;
+       u8 mesh_x;
+       u8 mesh_y;
+       u16 num_xps;
+       u16 num_dns;
+       struct arm_cmn_node *xps;
+       struct arm_cmn_node *dns;
+
+       struct arm_cmn_dtc *dtc;
+       unsigned int num_dtcs;
+
+       int cpu;
+       struct hlist_node cpuhp_node;
+
+       unsigned int state;
+       struct pmu pmu;
+};
+
+#define to_cmn(p)      container_of(p, struct arm_cmn, pmu)
+
+static int arm_cmn_hp_state;
+
+struct arm_cmn_hw_event {
+       struct arm_cmn_node *dn;
+       u64 dtm_idx[2];
+       unsigned int dtc_idx;
+       u8 dtcs_used;
+       u8 num_dns;
+};
+
+#define for_each_hw_dn(hw, dn, i) \
+       for (i = 0, dn = hw->dn; i < hw->num_dns; i++, dn++)
+
+static struct arm_cmn_hw_event *to_cmn_hw(struct perf_event *event)
+{
+       BUILD_BUG_ON(sizeof(struct arm_cmn_hw_event) > offsetof(struct hw_perf_event, target));
+       return (struct arm_cmn_hw_event *)&event->hw;
+}
+
+static void arm_cmn_set_index(u64 x[], unsigned int pos, unsigned int val)
+{
+       x[pos / 32] |= (u64)val << ((pos % 32) * 2);
+}
+
+static unsigned int arm_cmn_get_index(u64 x[], unsigned int pos)
+{
+       return (x[pos / 32] >> ((pos % 32) * 2)) & 3;
+}
+
+struct arm_cmn_event_attr {
+       struct device_attribute attr;
+       enum cmn_node_type type;
+       u8 eventid;
+       u8 occupid;
+};
+
+struct arm_cmn_format_attr {
+       struct device_attribute attr;
+       u64 field;
+       int config;
+};
+
+static int arm_cmn_xyidbits(const struct arm_cmn *cmn)
+{
+       return cmn->mesh_x > 4 || cmn->mesh_y > 4 ? 3 : 2;
+}
+
+static void arm_cmn_init_node_to_xp(const struct arm_cmn *cmn,
+                                   struct arm_cmn_node *dn)
+{
+       int bits = arm_cmn_xyidbits(cmn);
+       int x = CMN_NODEID_X(dn->id, bits);
+       int y = CMN_NODEID_Y(dn->id, bits);
+       int xp_idx = cmn->mesh_x * y + x;
+
+       dn->to_xp = (cmn->xps + xp_idx) - dn;
+}
+
+static struct arm_cmn_node *arm_cmn_node_to_xp(struct arm_cmn_node *dn)
+{
+       return dn->type == CMN_TYPE_XP ? dn : dn + dn->to_xp;
+}
+
+static struct arm_cmn_node *arm_cmn_node(const struct arm_cmn *cmn,
+                                        enum cmn_node_type type)
+{
+       int i;
+
+       for (i = 0; i < cmn->num_dns; i++)
+               if (cmn->dns[i].type == type)
+                       return &cmn->dns[i];
+       return NULL;
+}
+
+#define CMN_EVENT_ATTR(_name, _type, _eventid, _occupid)               \
+       (&((struct arm_cmn_event_attr[]) {{                             \
+               .attr = __ATTR(_name, 0444, arm_cmn_event_show, NULL),  \
+               .type = _type,                                          \
+               .eventid = _eventid,                                    \
+               .occupid = _occupid,                                    \
+       }})[0].attr.attr)
+
+static bool arm_cmn_is_occup_event(enum cmn_node_type type, unsigned int id)
+{
+       return (type == CMN_TYPE_DVM && id == 0x05) ||
+              (type == CMN_TYPE_HNF && id == 0x0f);
+}
+
+static ssize_t arm_cmn_event_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct arm_cmn_event_attr *eattr;
+
+       eattr = container_of(attr, typeof(*eattr), attr);
+
+       if (eattr->type == CMN_TYPE_DTC)
+               return snprintf(buf, PAGE_SIZE, "type=0x%x\n", eattr->type);
+
+       if (eattr->type == CMN_TYPE_WP)
+               return snprintf(buf, PAGE_SIZE,
+                               "type=0x%x,eventid=0x%x,wp_dev_sel=?,wp_chn_sel=?,wp_grp=?,wp_val=?,wp_mask=?\n",
+                               eattr->type, eattr->eventid);
+
+       if (arm_cmn_is_occup_event(eattr->type, eattr->eventid))
+               return snprintf(buf, PAGE_SIZE, "type=0x%x,eventid=0x%x,occupid=0x%x\n",
+                               eattr->type, eattr->eventid, eattr->occupid);
+
+       return snprintf(buf, PAGE_SIZE, "type=0x%x,eventid=0x%x\n",
+                       eattr->type, eattr->eventid);
+}
+
+static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
+                                            struct attribute *attr,
+                                            int unused)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct arm_cmn *cmn = to_cmn(dev_get_drvdata(dev));
+       struct arm_cmn_event_attr *eattr;
+       enum cmn_node_type type;
+
+       eattr = container_of(attr, typeof(*eattr), attr.attr);
+       type = eattr->type;
+
+       /* Watchpoints aren't nodes */
+       if (type == CMN_TYPE_WP)
+               type = CMN_TYPE_XP;
+
+       /* Revision-specific differences */
+       if (cmn->rev < CMN600_R1P2) {
+               if (type == CMN_TYPE_HNF && eattr->eventid == 0x1b)
+                       return 0;
+       }
+
+       if (!arm_cmn_node(cmn, type))
+               return 0;
+
+       return attr->mode;
+}
+
+#define _CMN_EVENT_DVM(_name, _event, _occup)                  \
+       CMN_EVENT_ATTR(dn_##_name, CMN_TYPE_DVM, _event, _occup)
+#define CMN_EVENT_DTC(_name)                                   \
+       CMN_EVENT_ATTR(dtc_##_name, CMN_TYPE_DTC, 0, 0)
+#define _CMN_EVENT_HNF(_name, _event, _occup)                  \
+       CMN_EVENT_ATTR(hnf_##_name, CMN_TYPE_HNF, _event, _occup)
+#define CMN_EVENT_HNI(_name, _event)                           \
+       CMN_EVENT_ATTR(hni_##_name, CMN_TYPE_HNI, _event, 0)
+#define __CMN_EVENT_XP(_name, _event)                          \
+       CMN_EVENT_ATTR(mxp_##_name, CMN_TYPE_XP, _event, 0)
+#define CMN_EVENT_SBSX(_name, _event)                          \
+       CMN_EVENT_ATTR(sbsx_##_name, CMN_TYPE_SBSX, _event, 0)
+#define CMN_EVENT_RNID(_name, _event)                          \
+       CMN_EVENT_ATTR(rnid_##_name, CMN_TYPE_RNI, _event, 0)
+
+#define CMN_EVENT_DVM(_name, _event)                           \
+       _CMN_EVENT_DVM(_name, _event, 0)
+#define CMN_EVENT_HNF(_name, _event)                           \
+       _CMN_EVENT_HNF(_name, _event, 0)
+#define _CMN_EVENT_XP(_name, _event)                           \
+       __CMN_EVENT_XP(e_##_name, (_event) | (0 << 2)),         \
+       __CMN_EVENT_XP(w_##_name, (_event) | (1 << 2)),         \
+       __CMN_EVENT_XP(n_##_name, (_event) | (2 << 2)),         \
+       __CMN_EVENT_XP(s_##_name, (_event) | (3 << 2)),         \
+       __CMN_EVENT_XP(p0_##_name, (_event) | (4 << 2)),        \
+       __CMN_EVENT_XP(p1_##_name, (_event) | (5 << 2))
+
+/* Good thing there are only 3 fundamental XP events... */
+#define CMN_EVENT_XP(_name, _event)                            \
+       _CMN_EVENT_XP(req_##_name, (_event) | (0 << 5)),        \
+       _CMN_EVENT_XP(rsp_##_name, (_event) | (1 << 5)),        \
+       _CMN_EVENT_XP(snp_##_name, (_event) | (2 << 5)),        \
+       _CMN_EVENT_XP(dat_##_name, (_event) | (3 << 5))
+
+
+static struct attribute *arm_cmn_event_attrs[] = {
+       CMN_EVENT_DTC(cycles),
+
+       /*
+        * DVM node events conflict with HN-I events in the equivalent PMU
+        * slot, but our lazy short-cut of using the DTM counter index for
+        * the PMU index as well happens to avoid that by construction.
+        */
+       CMN_EVENT_DVM(rxreq_dvmop,      0x01),
+       CMN_EVENT_DVM(rxreq_dvmsync,    0x02),
+       CMN_EVENT_DVM(rxreq_dvmop_vmid_filtered, 0x03),
+       CMN_EVENT_DVM(rxreq_retried,    0x04),
+       _CMN_EVENT_DVM(rxreq_trk_occupancy_all, 0x05, 0),
+       _CMN_EVENT_DVM(rxreq_trk_occupancy_dvmop, 0x05, 1),
+       _CMN_EVENT_DVM(rxreq_trk_occupancy_dvmsync, 0x05, 2),
+
+       CMN_EVENT_HNF(cache_miss,       0x01),
+       CMN_EVENT_HNF(slc_sf_cache_access, 0x02),
+       CMN_EVENT_HNF(cache_fill,       0x03),
+       CMN_EVENT_HNF(pocq_retry,       0x04),
+       CMN_EVENT_HNF(pocq_reqs_recvd,  0x05),
+       CMN_EVENT_HNF(sf_hit,           0x06),
+       CMN_EVENT_HNF(sf_evictions,     0x07),
+       CMN_EVENT_HNF(dir_snoops_sent,  0x08),
+       CMN_EVENT_HNF(brd_snoops_sent,  0x09),
+       CMN_EVENT_HNF(slc_eviction,     0x0a),
+       CMN_EVENT_HNF(slc_fill_invalid_way, 0x0b),
+       CMN_EVENT_HNF(mc_retries,       0x0c),
+       CMN_EVENT_HNF(mc_reqs,          0x0d),
+       CMN_EVENT_HNF(qos_hh_retry,     0x0e),
+       _CMN_EVENT_HNF(qos_pocq_occupancy_all, 0x0f, 0),
+       _CMN_EVENT_HNF(qos_pocq_occupancy_read, 0x0f, 1),
+       _CMN_EVENT_HNF(qos_pocq_occupancy_write, 0x0f, 2),
+       _CMN_EVENT_HNF(qos_pocq_occupancy_atomic, 0x0f, 3),
+       _CMN_EVENT_HNF(qos_pocq_occupancy_stash, 0x0f, 4),
+       CMN_EVENT_HNF(pocq_addrhaz,     0x10),
+       CMN_EVENT_HNF(pocq_atomic_addrhaz, 0x11),
+       CMN_EVENT_HNF(ld_st_swp_adq_full, 0x12),
+       CMN_EVENT_HNF(cmp_adq_full,     0x13),
+       CMN_EVENT_HNF(txdat_stall,      0x14),
+       CMN_EVENT_HNF(txrsp_stall,      0x15),
+       CMN_EVENT_HNF(seq_full,         0x16),
+       CMN_EVENT_HNF(seq_hit,          0x17),
+       CMN_EVENT_HNF(snp_sent,         0x18),
+       CMN_EVENT_HNF(sfbi_dir_snp_sent, 0x19),
+       CMN_EVENT_HNF(sfbi_brd_snp_sent, 0x1a),
+       CMN_EVENT_HNF(snp_sent_untrk,   0x1b),
+       CMN_EVENT_HNF(intv_dirty,       0x1c),
+       CMN_EVENT_HNF(stash_snp_sent,   0x1d),
+       CMN_EVENT_HNF(stash_data_pull,  0x1e),
+       CMN_EVENT_HNF(snp_fwded,        0x1f),
+
+       CMN_EVENT_HNI(rrt_rd_occ_cnt_ovfl, 0x20),
+       CMN_EVENT_HNI(rrt_wr_occ_cnt_ovfl, 0x21),
+       CMN_EVENT_HNI(rdt_rd_occ_cnt_ovfl, 0x22),
+       CMN_EVENT_HNI(rdt_wr_occ_cnt_ovfl, 0x23),
+       CMN_EVENT_HNI(wdb_occ_cnt_ovfl, 0x24),
+       CMN_EVENT_HNI(rrt_rd_alloc,     0x25),
+       CMN_EVENT_HNI(rrt_wr_alloc,     0x26),
+       CMN_EVENT_HNI(rdt_rd_alloc,     0x27),
+       CMN_EVENT_HNI(rdt_wr_alloc,     0x28),
+       CMN_EVENT_HNI(wdb_alloc,        0x29),
+       CMN_EVENT_HNI(txrsp_retryack,   0x2a),
+       CMN_EVENT_HNI(arvalid_no_arready, 0x2b),
+       CMN_EVENT_HNI(arready_no_arvalid, 0x2c),
+       CMN_EVENT_HNI(awvalid_no_awready, 0x2d),
+       CMN_EVENT_HNI(awready_no_awvalid, 0x2e),
+       CMN_EVENT_HNI(wvalid_no_wready, 0x2f),
+       CMN_EVENT_HNI(txdat_stall,      0x30),
+       CMN_EVENT_HNI(nonpcie_serialization, 0x31),
+       CMN_EVENT_HNI(pcie_serialization, 0x32),
+
+       CMN_EVENT_XP(txflit_valid,      0x01),
+       CMN_EVENT_XP(txflit_stall,      0x02),
+       CMN_EVENT_XP(partial_dat_flit,  0x03),
+       /* We treat watchpoints as a special made-up class of XP events */
+       CMN_EVENT_ATTR(watchpoint_up, CMN_TYPE_WP, 0, 0),
+       CMN_EVENT_ATTR(watchpoint_down, CMN_TYPE_WP, 2, 0),
+
+       CMN_EVENT_SBSX(rd_req,          0x01),
+       CMN_EVENT_SBSX(wr_req,          0x02),
+       CMN_EVENT_SBSX(cmo_req,         0x03),
+       CMN_EVENT_SBSX(txrsp_retryack,  0x04),
+       CMN_EVENT_SBSX(txdat_flitv,     0x05),
+       CMN_EVENT_SBSX(txrsp_flitv,     0x06),
+       CMN_EVENT_SBSX(rd_req_trkr_occ_cnt_ovfl, 0x11),
+       CMN_EVENT_SBSX(wr_req_trkr_occ_cnt_ovfl, 0x12),
+       CMN_EVENT_SBSX(cmo_req_trkr_occ_cnt_ovfl, 0x13),
+       CMN_EVENT_SBSX(wdb_occ_cnt_ovfl, 0x14),
+       CMN_EVENT_SBSX(rd_axi_trkr_occ_cnt_ovfl, 0x15),
+       CMN_EVENT_SBSX(cmo_axi_trkr_occ_cnt_ovfl, 0x16),
+       CMN_EVENT_SBSX(arvalid_no_arready, 0x21),
+       CMN_EVENT_SBSX(awvalid_no_awready, 0x22),
+       CMN_EVENT_SBSX(wvalid_no_wready, 0x23),
+       CMN_EVENT_SBSX(txdat_stall,     0x24),
+       CMN_EVENT_SBSX(txrsp_stall,     0x25),
+
+       CMN_EVENT_RNID(s0_rdata_beats,  0x01),
+       CMN_EVENT_RNID(s1_rdata_beats,  0x02),
+       CMN_EVENT_RNID(s2_rdata_beats,  0x03),
+       CMN_EVENT_RNID(rxdat_flits,     0x04),
+       CMN_EVENT_RNID(txdat_flits,     0x05),
+       CMN_EVENT_RNID(txreq_flits_total, 0x06),
+       CMN_EVENT_RNID(txreq_flits_retried, 0x07),
+       CMN_EVENT_RNID(rrt_occ_ovfl,    0x08),
+       CMN_EVENT_RNID(wrt_occ_ovfl,    0x09),
+       CMN_EVENT_RNID(txreq_flits_replayed, 0x0a),
+       CMN_EVENT_RNID(wrcancel_sent,   0x0b),
+       CMN_EVENT_RNID(s0_wdata_beats,  0x0c),
+       CMN_EVENT_RNID(s1_wdata_beats,  0x0d),
+       CMN_EVENT_RNID(s2_wdata_beats,  0x0e),
+       CMN_EVENT_RNID(rrt_alloc,       0x0f),
+       CMN_EVENT_RNID(wrt_alloc,       0x10),
+       CMN_EVENT_RNID(rdb_unord,       0x11),
+       CMN_EVENT_RNID(rdb_replay,      0x12),
+       CMN_EVENT_RNID(rdb_hybrid,      0x13),
+       CMN_EVENT_RNID(rdb_ord,         0x14),
+
+       NULL
+};
+
+static const struct attribute_group arm_cmn_event_attrs_group = {
+       .name = "events",
+       .attrs = arm_cmn_event_attrs,
+       .is_visible = arm_cmn_event_attr_is_visible,
+};
+
+static ssize_t arm_cmn_format_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct arm_cmn_format_attr *fmt = container_of(attr, typeof(*fmt), attr);
+       int lo = __ffs(fmt->field), hi = __fls(fmt->field);
+
+       if (lo == hi)
+               return snprintf(buf, PAGE_SIZE, "config:%d\n", lo);
+
+       if (!fmt->config)
+               return snprintf(buf, PAGE_SIZE, "config:%d-%d\n", lo, hi);
+
+       return snprintf(buf, PAGE_SIZE, "config%d:%d-%d\n", fmt->config, lo, hi);
+}
+
+#define _CMN_FORMAT_ATTR(_name, _cfg, _fld)                            \
+       (&((struct arm_cmn_format_attr[]) {{                            \
+               .attr = __ATTR(_name, 0444, arm_cmn_format_show, NULL), \
+               .config = _cfg,                                         \
+               .field = _fld,                                          \
+       }})[0].attr.attr)
+#define CMN_FORMAT_ATTR(_name, _fld)   _CMN_FORMAT_ATTR(_name, 0, _fld)
+
+static struct attribute *arm_cmn_format_attrs[] = {
+       CMN_FORMAT_ATTR(type, CMN_CONFIG_TYPE),
+       CMN_FORMAT_ATTR(eventid, CMN_CONFIG_EVENTID),
+       CMN_FORMAT_ATTR(occupid, CMN_CONFIG_OCCUPID),
+       CMN_FORMAT_ATTR(bynodeid, CMN_CONFIG_BYNODEID),
+       CMN_FORMAT_ATTR(nodeid, CMN_CONFIG_NODEID),
+
+       CMN_FORMAT_ATTR(wp_dev_sel, CMN_CONFIG_WP_DEV_SEL),
+       CMN_FORMAT_ATTR(wp_chn_sel, CMN_CONFIG_WP_CHN_SEL),
+       CMN_FORMAT_ATTR(wp_grp, CMN_CONFIG_WP_GRP),
+       CMN_FORMAT_ATTR(wp_exclusive, CMN_CONFIG_WP_EXCLUSIVE),
+       CMN_FORMAT_ATTR(wp_combine, CMN_CONFIG_WP_COMBINE),
+
+       _CMN_FORMAT_ATTR(wp_val, 1, CMN_CONFIG1_WP_VAL),
+       _CMN_FORMAT_ATTR(wp_mask, 2, CMN_CONFIG2_WP_MASK),
+
+       NULL
+};
+
+static const struct attribute_group arm_cmn_format_attrs_group = {
+       .name = "format",
+       .attrs = arm_cmn_format_attrs,
+};
+
+static ssize_t arm_cmn_cpumask_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct arm_cmn *cmn = to_cmn(dev_get_drvdata(dev));
+
+       return cpumap_print_to_pagebuf(true, buf, cpumask_of(cmn->cpu));
+}
+
+static struct device_attribute arm_cmn_cpumask_attr =
+               __ATTR(cpumask, 0444, arm_cmn_cpumask_show, NULL);
+
+static struct attribute *arm_cmn_cpumask_attrs[] = {
+       &arm_cmn_cpumask_attr.attr,
+       NULL,
+};
+
+static struct attribute_group arm_cmn_cpumask_attr_group = {
+       .attrs = arm_cmn_cpumask_attrs,
+};
+
+static const struct attribute_group *arm_cmn_attr_groups[] = {
+       &arm_cmn_event_attrs_group,
+       &arm_cmn_format_attrs_group,
+       &arm_cmn_cpumask_attr_group,
+       NULL
+};
+
+static int arm_cmn_wp_idx(struct perf_event *event)
+{
+       return CMN_EVENT_EVENTID(event) + CMN_EVENT_WP_GRP(event);
+}
+
+static u32 arm_cmn_wp_config(struct perf_event *event)
+{
+       u32 config;
+       u32 dev = CMN_EVENT_WP_DEV_SEL(event);
+       u32 chn = CMN_EVENT_WP_CHN_SEL(event);
+       u32 grp = CMN_EVENT_WP_GRP(event);
+       u32 exc = CMN_EVENT_WP_EXCLUSIVE(event);
+       u32 combine = CMN_EVENT_WP_COMBINE(event);
+
+       config = FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_DEV_SEL, dev) |
+                FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_CHN_SEL, chn) |
+                FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_GRP, grp) |
+                FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_EXCLUSIVE, exc);
+       if (combine && !grp)
+               config |= CMN_DTM_WPn_CONFIG_WP_COMBINE;
+
+       return config;
+}
+
+static void arm_cmn_set_state(struct arm_cmn *cmn, u32 state)
+{
+       if (!cmn->state)
+               writel_relaxed(0, cmn->dtc[0].base + CMN_DT_PMCR);
+       cmn->state |= state;
+}
+
+static void arm_cmn_clear_state(struct arm_cmn *cmn, u32 state)
+{
+       cmn->state &= ~state;
+       if (!cmn->state)
+               writel_relaxed(CMN_DT_PMCR_PMU_EN | CMN_DT_PMCR_OVFL_INTR_EN,
+                              cmn->dtc[0].base + CMN_DT_PMCR);
+}
+
+static void arm_cmn_pmu_enable(struct pmu *pmu)
+{
+       arm_cmn_clear_state(to_cmn(pmu), CMN_STATE_DISABLED);
+}
+
+static void arm_cmn_pmu_disable(struct pmu *pmu)
+{
+       arm_cmn_set_state(to_cmn(pmu), CMN_STATE_DISABLED);
+}
+
+static u64 arm_cmn_read_dtm(struct arm_cmn *cmn, struct arm_cmn_hw_event *hw,
+                           bool snapshot)
+{
+       struct arm_cmn_node *dn;
+       unsigned int i, offset;
+       u64 count = 0;
+
+       offset = snapshot ? CMN_DTM_PMEVCNTSR : CMN_DTM_PMEVCNT;
+       for_each_hw_dn(hw, dn, i) {
+               struct arm_cmn_node *xp = arm_cmn_node_to_xp(dn);
+               int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
+               u64 reg = readq_relaxed(xp->pmu_base + offset);
+               u16 dtm_count = reg >> (dtm_idx * 16);
+
+               count += dtm_count;
+       }
+       return count;
+}
+
+static u64 arm_cmn_read_cc(struct arm_cmn_dtc *dtc)
+{
+       u64 val = readq_relaxed(dtc->base + CMN_DT_PMCCNTR);
+
+       writeq_relaxed(CMN_CC_INIT, dtc->base + CMN_DT_PMCCNTR);
+       return (val - CMN_CC_INIT) & ((CMN_CC_INIT << 1) - 1);
+}
+
+static u32 arm_cmn_read_counter(struct arm_cmn_dtc *dtc, int idx)
+{
+       u32 val, pmevcnt = CMN_DT_PMEVCNT(idx);
+
+       val = readl_relaxed(dtc->base + pmevcnt);
+       writel_relaxed(CMN_COUNTER_INIT, dtc->base + pmevcnt);
+       return val - CMN_COUNTER_INIT;
+}
+
+static void arm_cmn_init_counter(struct perf_event *event)
+{
+       struct arm_cmn *cmn = to_cmn(event->pmu);
+       struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+       unsigned int i, pmevcnt = CMN_DT_PMEVCNT(hw->dtc_idx);
+       u64 count;
+
+       for (i = 0; hw->dtcs_used & (1U << i); i++) {
+               writel_relaxed(CMN_COUNTER_INIT, cmn->dtc[i].base + pmevcnt);
+               cmn->dtc[i].counters[hw->dtc_idx] = event;
+       }
+
+       count = arm_cmn_read_dtm(cmn, hw, false);
+       local64_set(&event->hw.prev_count, count);
+}
+
+static void arm_cmn_event_read(struct perf_event *event)
+{
+       struct arm_cmn *cmn = to_cmn(event->pmu);
+       struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+       u64 delta, new, prev;
+       unsigned long flags;
+       unsigned int i;
+
+       if (hw->dtc_idx == CMN_DT_NUM_COUNTERS) {
+               i = __ffs(hw->dtcs_used);
+               delta = arm_cmn_read_cc(cmn->dtc + i);
+               local64_add(delta, &event->count);
+               return;
+       }
+       new = arm_cmn_read_dtm(cmn, hw, false);
+       prev = local64_xchg(&event->hw.prev_count, new);
+
+       delta = new - prev;
+
+       local_irq_save(flags);
+       for (i = 0; hw->dtcs_used & (1U << i); i++) {
+               new = arm_cmn_read_counter(cmn->dtc + i, hw->dtc_idx);
+               delta += new << 16;
+       }
+       local_irq_restore(flags);
+       local64_add(delta, &event->count);
+}
+
+static void arm_cmn_event_start(struct perf_event *event, int flags)
+{
+       struct arm_cmn *cmn = to_cmn(event->pmu);
+       struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+       struct arm_cmn_node *dn;
+       enum cmn_node_type type = CMN_EVENT_TYPE(event);
+       int i;
+
+       if (type == CMN_TYPE_DTC) {
+               i = __ffs(hw->dtcs_used);
+               writeq_relaxed(CMN_CC_INIT, cmn->dtc[i].base + CMN_DT_PMCCNTR);
+               cmn->dtc[i].cc_active = true;
+       } else if (type == CMN_TYPE_WP) {
+               int wp_idx = arm_cmn_wp_idx(event);
+               u64 val = CMN_EVENT_WP_VAL(event);
+               u64 mask = CMN_EVENT_WP_MASK(event);
+
+               for_each_hw_dn(hw, dn, i) {
+                       writeq_relaxed(val, dn->pmu_base + CMN_DTM_WPn_VAL(wp_idx));
+                       writeq_relaxed(mask, dn->pmu_base + CMN_DTM_WPn_MASK(wp_idx));
+               }
+       } else for_each_hw_dn(hw, dn, i) {
+               int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
+
+               dn->event[dtm_idx] = CMN_EVENT_EVENTID(event);
+               writel_relaxed(le32_to_cpu(dn->event_sel), dn->pmu_base + CMN_PMU_EVENT_SEL);
+       }
+}
+
+static void arm_cmn_event_stop(struct perf_event *event, int flags)
+{
+       struct arm_cmn *cmn = to_cmn(event->pmu);
+       struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+       struct arm_cmn_node *dn;
+       enum cmn_node_type type = CMN_EVENT_TYPE(event);
+       int i;
+
+       if (type == CMN_TYPE_DTC) {
+               i = __ffs(hw->dtcs_used);
+               cmn->dtc[i].cc_active = false;
+       } else if (type == CMN_TYPE_WP) {
+               int wp_idx = arm_cmn_wp_idx(event);
+
+               for_each_hw_dn(hw, dn, i) {
+                       writeq_relaxed(0, dn->pmu_base + CMN_DTM_WPn_MASK(wp_idx));
+                       writeq_relaxed(~0ULL, dn->pmu_base + CMN_DTM_WPn_VAL(wp_idx));
+               }
+       } else for_each_hw_dn(hw, dn, i) {
+               int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
+
+               dn->event[dtm_idx] = 0;
+               writel_relaxed(le32_to_cpu(dn->event_sel), dn->pmu_base + CMN_PMU_EVENT_SEL);
+       }
+
+       arm_cmn_event_read(event);
+}
+
+struct arm_cmn_val {
+       u8 dtm_count[CMN_MAX_XPS];
+       u8 occupid[CMN_MAX_XPS];
+       u8 wp[CMN_MAX_XPS][4];
+       int dtc_count;
+       bool cycles;
+};
+
+static void arm_cmn_val_add_event(struct arm_cmn_val *val, struct perf_event *event)
+{
+       struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+       struct arm_cmn_node *dn;
+       enum cmn_node_type type;
+       int i;
+       u8 occupid;
+
+       if (is_software_event(event))
+               return;
+
+       type = CMN_EVENT_TYPE(event);
+       if (type == CMN_TYPE_DTC) {
+               val->cycles = true;
+               return;
+       }
+
+       val->dtc_count++;
+       if (arm_cmn_is_occup_event(type, CMN_EVENT_EVENTID(event)))
+               occupid = CMN_EVENT_OCCUPID(event) + 1;
+       else
+               occupid = 0;
+
+       for_each_hw_dn(hw, dn, i) {
+               int wp_idx, xp = arm_cmn_node_to_xp(dn)->logid;
+
+               val->dtm_count[xp]++;
+               val->occupid[xp] = occupid;
+
+               if (type != CMN_TYPE_WP)
+                       continue;
+
+               wp_idx = arm_cmn_wp_idx(event);
+               val->wp[xp][wp_idx] = CMN_EVENT_WP_COMBINE(event) + 1;
+       }
+}
+
+static int arm_cmn_validate_group(struct perf_event *event)
+{
+       struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+       struct arm_cmn_node *dn;
+       struct perf_event *sibling, *leader = event->group_leader;
+       enum cmn_node_type type;
+       struct arm_cmn_val val;
+       int i;
+       u8 occupid;
+
+       if (leader == event)
+               return 0;
+
+       if (event->pmu != leader->pmu && !is_software_event(leader))
+               return -EINVAL;
+
+       memset(&val, 0, sizeof(val));
+
+       arm_cmn_val_add_event(&val, leader);
+       for_each_sibling_event(sibling, leader)
+               arm_cmn_val_add_event(&val, sibling);
+
+       type = CMN_EVENT_TYPE(event);
+       if (type == CMN_TYPE_DTC)
+               return val.cycles ? -EINVAL : 0;
+
+       if (val.dtc_count == CMN_DT_NUM_COUNTERS)
+               return -EINVAL;
+
+       if (arm_cmn_is_occup_event(type, CMN_EVENT_EVENTID(event)))
+               occupid = CMN_EVENT_OCCUPID(event) + 1;
+       else
+               occupid = 0;
+
+       for_each_hw_dn(hw, dn, i) {
+               int wp_idx, wp_cmb, xp = arm_cmn_node_to_xp(dn)->logid;
+
+               if (val.dtm_count[xp] == CMN_DTM_NUM_COUNTERS)
+                       return -EINVAL;
+
+               if (occupid && val.occupid[xp] && occupid != val.occupid[xp])
+                       return -EINVAL;
+
+               if (type != CMN_TYPE_WP)
+                       continue;
+
+               wp_idx = arm_cmn_wp_idx(event);
+               if (val.wp[xp][wp_idx])
+                       return -EINVAL;
+
+               wp_cmb = val.wp[xp][wp_idx ^ 1];
+               if (wp_cmb && wp_cmb != CMN_EVENT_WP_COMBINE(event) + 1)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int arm_cmn_event_init(struct perf_event *event)
+{
+       struct arm_cmn *cmn = to_cmn(event->pmu);
+       struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+       enum cmn_node_type type;
+       unsigned int i;
+       bool bynodeid;
+       u16 nodeid, eventid;
+
+       if (event->attr.type != event->pmu->type)
+               return -ENOENT;
+
+       if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+               return -EINVAL;
+
+       event->cpu = cmn->cpu;
+       if (event->cpu < 0)
+               return -EINVAL;
+
+       type = CMN_EVENT_TYPE(event);
+       /* DTC events (i.e. cycles) already have everything they need */
+       if (type == CMN_TYPE_DTC)
+               return 0;
+
+       /* For watchpoints we need the actual XP node here */
+       if (type == CMN_TYPE_WP) {
+               type = CMN_TYPE_XP;
+               /* ...and we need a "real" direction */
+               eventid = CMN_EVENT_EVENTID(event);
+               if (eventid != CMN_WP_UP && eventid != CMN_WP_DOWN)
+                       return -EINVAL;
+       }
+
+       bynodeid = CMN_EVENT_BYNODEID(event);
+       nodeid = CMN_EVENT_NODEID(event);
+
+       hw->dn = arm_cmn_node(cmn, type);
+       for (i = hw->dn - cmn->dns; i < cmn->num_dns && cmn->dns[i].type == type; i++) {
+               if (!bynodeid) {
+                       hw->num_dns++;
+               } else if (cmn->dns[i].id != nodeid) {
+                       hw->dn++;
+               } else {
+                       hw->num_dns = 1;
+                       break;
+               }
+       }
+
+       if (!hw->num_dns) {
+               int bits = arm_cmn_xyidbits(cmn);
+
+               dev_dbg(cmn->dev, "invalid node 0x%x (%d,%d,%d,%d) type 0x%x\n",
+                       nodeid, CMN_NODEID_X(nodeid, bits), CMN_NODEID_Y(nodeid, bits),
+                       CMN_NODEID_PID(nodeid), CMN_NODEID_DEVID(nodeid), type);
+               return -EINVAL;
+       }
+       /*
+        * By assuming events count in all DTC domains, we cunningly avoid
+        * needing to know anything about how XPs are assigned to domains.
+        */
+       hw->dtcs_used = (1U << cmn->num_dtcs) - 1;
+
+       return arm_cmn_validate_group(event);
+}
+
+static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
+                               int i)
+{
+       struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+       enum cmn_node_type type = CMN_EVENT_TYPE(event);
+
+       while (i--) {
+               struct arm_cmn_node *xp = arm_cmn_node_to_xp(hw->dn + i);
+               unsigned int dtm_idx = arm_cmn_get_index(hw->dtm_idx, i);
+
+               if (type == CMN_TYPE_WP)
+                       hw->dn[i].wp_event[arm_cmn_wp_idx(event)] = -1;
+
+               if (arm_cmn_is_occup_event(type, CMN_EVENT_EVENTID(event)))
+                       hw->dn[i].occupid_count--;
+
+               xp->pmu_config_low &= ~CMN__PMEVCNT_PAIRED(dtm_idx);
+               writel_relaxed(xp->pmu_config_low, xp->pmu_base + CMN_DTM_PMU_CONFIG);
+       }
+       memset(hw->dtm_idx, 0, sizeof(hw->dtm_idx));
+
+       for (i = 0; hw->dtcs_used & (1U << i); i++)
+               cmn->dtc[i].counters[hw->dtc_idx] = NULL;
+}
+
+static int arm_cmn_event_add(struct perf_event *event, int flags)
+{
+       struct arm_cmn *cmn = to_cmn(event->pmu);
+       struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+       struct arm_cmn_dtc *dtc = &cmn->dtc[0];
+       struct arm_cmn_node *dn;
+       enum cmn_node_type type = CMN_EVENT_TYPE(event);
+       unsigned int i, dtc_idx, input_sel;
+
+       if (type == CMN_TYPE_DTC) {
+               i = 0;
+               while (cmn->dtc[i].cycles)
+                       if (++i == cmn->num_dtcs)
+                               return -ENOSPC;
+
+               cmn->dtc[i].cycles = event;
+               hw->dtc_idx = CMN_DT_NUM_COUNTERS;
+               hw->dtcs_used = 1U << i;
+
+               if (flags & PERF_EF_START)
+                       arm_cmn_event_start(event, 0);
+               return 0;
+       }
+
+       /* Grab a free global counter first... */
+       dtc_idx = 0;
+       while (dtc->counters[dtc_idx])
+               if (++dtc_idx == CMN_DT_NUM_COUNTERS)
+                       return -ENOSPC;
+
+       hw->dtc_idx = dtc_idx;
+
+       /* ...then the local counters to feed it. */
+       for_each_hw_dn(hw, dn, i) {
+               struct arm_cmn_node *xp = arm_cmn_node_to_xp(dn);
+               unsigned int dtm_idx, shift;
+               u64 reg;
+
+               dtm_idx = 0;
+               while (xp->pmu_config_low & CMN__PMEVCNT_PAIRED(dtm_idx))
+                       if (++dtm_idx == CMN_DTM_NUM_COUNTERS)
+                               goto free_dtms;
+
+               if (type == CMN_TYPE_XP) {
+                       input_sel = CMN__PMEVCNT0_INPUT_SEL_XP + dtm_idx;
+               } else if (type == CMN_TYPE_WP) {
+                       int tmp, wp_idx = arm_cmn_wp_idx(event);
+                       u32 cfg = arm_cmn_wp_config(event);
+
+                       if (dn->wp_event[wp_idx] >= 0)
+                               goto free_dtms;
+
+                       tmp = dn->wp_event[wp_idx ^ 1];
+                       if (tmp >= 0 && CMN_EVENT_WP_COMBINE(event) !=
+                                       CMN_EVENT_WP_COMBINE(dtc->counters[tmp]))
+                               goto free_dtms;
+
+                       input_sel = CMN__PMEVCNT0_INPUT_SEL_WP + wp_idx;
+                       dn->wp_event[wp_idx] = dtc_idx;
+                       writel_relaxed(cfg, dn->pmu_base + CMN_DTM_WPn_CONFIG(wp_idx));
+               } else {
+                       unsigned int port = CMN_NODEID_PID(dn->id);
+                       unsigned int dev = CMN_NODEID_DEVID(dn->id);
+
+                       input_sel = CMN__PMEVCNT0_INPUT_SEL_DEV + dtm_idx +
+                                   (port << 4) + (dev << 2);
+
+                       if (arm_cmn_is_occup_event(type, CMN_EVENT_EVENTID(event))) {
+                               int occupid = CMN_EVENT_OCCUPID(event);
+
+                               if (dn->occupid_count == 0) {
+                                       dn->occupid_val = occupid;
+                                       writel_relaxed(occupid,
+                                                      dn->pmu_base + CMN_PMU_EVENT_SEL + 4);
+                               } else if (dn->occupid_val != occupid) {
+                                       goto free_dtms;
+                               }
+                               dn->occupid_count++;
+                       }
+               }
+
+               arm_cmn_set_index(hw->dtm_idx, i, dtm_idx);
+
+               xp->input_sel[dtm_idx] = input_sel;
+               shift = CMN__PMEVCNTn_GLOBAL_NUM_SHIFT(dtm_idx);
+               xp->pmu_config_low &= ~(CMN__PMEVCNT0_GLOBAL_NUM << shift);
+               xp->pmu_config_low |= FIELD_PREP(CMN__PMEVCNT0_GLOBAL_NUM, dtc_idx) << shift;
+               xp->pmu_config_low |= CMN__PMEVCNT_PAIRED(dtm_idx);
+               reg = (u64)le32_to_cpu(xp->pmu_config_high) << 32 | xp->pmu_config_low;
+               writeq_relaxed(reg, xp->pmu_base + CMN_DTM_PMU_CONFIG);
+       }
+
+       /* Go go go! */
+       arm_cmn_init_counter(event);
+
+       if (flags & PERF_EF_START)
+               arm_cmn_event_start(event, 0);
+
+       return 0;
+
+free_dtms:
+       arm_cmn_event_clear(cmn, event, i);
+       return -ENOSPC;
+}
+
+static void arm_cmn_event_del(struct perf_event *event, int flags)
+{
+       struct arm_cmn *cmn = to_cmn(event->pmu);
+       struct arm_cmn_hw_event *hw = to_cmn_hw(event);
+       enum cmn_node_type type = CMN_EVENT_TYPE(event);
+
+       arm_cmn_event_stop(event, PERF_EF_UPDATE);
+
+       if (type == CMN_TYPE_DTC)
+               cmn->dtc[__ffs(hw->dtcs_used)].cycles = NULL;
+       else
+               arm_cmn_event_clear(cmn, event, hw->num_dns);
+}
+
+/*
+ * We stop the PMU for both add and read, to avoid skew across DTM counters.
+ * In theory we could use snapshots to read without stopping, but then it
+ * becomes a lot trickier to deal with overlow and racing against interrupts,
+ * plus it seems they don't work properly on some hardware anyway :(
+ */
+static void arm_cmn_start_txn(struct pmu *pmu, unsigned int flags)
+{
+       arm_cmn_set_state(to_cmn(pmu), CMN_STATE_TXN);
+}
+
+static void arm_cmn_end_txn(struct pmu *pmu)
+{
+       arm_cmn_clear_state(to_cmn(pmu), CMN_STATE_TXN);
+}
+
+static int arm_cmn_commit_txn(struct pmu *pmu)
+{
+       arm_cmn_end_txn(pmu);
+       return 0;
+}
+
+static int arm_cmn_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
+{
+       struct arm_cmn *cmn;
+       unsigned int target;
+
+       cmn = hlist_entry_safe(node, struct arm_cmn, cpuhp_node);
+       if (cpu != cmn->cpu)
+               return 0;
+
+       target = cpumask_any_but(cpu_online_mask, cpu);
+       if (target >= nr_cpu_ids)
+               return 0;
+
+       perf_pmu_migrate_context(&cmn->pmu, cpu, target);
+       cmn->cpu = target;
+       return 0;
+}
+
+static irqreturn_t arm_cmn_handle_irq(int irq, void *dev_id)
+{
+       struct arm_cmn_dtc *dtc = dev_id;
+       irqreturn_t ret = IRQ_NONE;
+
+       for (;;) {
+               u32 status = readl_relaxed(dtc->base + CMN_DT_PMOVSR);
+               u64 delta;
+               int i;
+
+               for (i = 0; i < CMN_DTM_NUM_COUNTERS; i++) {
+                       if (status & (1U << i)) {
+                               ret = IRQ_HANDLED;
+                               if (WARN_ON(!dtc->counters[i]))
+                                       continue;
+                               delta = (u64)arm_cmn_read_counter(dtc, i) << 16;
+                               local64_add(delta, &dtc->counters[i]->count);
+                       }
+               }
+
+               if (status & (1U << CMN_DT_NUM_COUNTERS)) {
+                       ret = IRQ_HANDLED;
+                       if (dtc->cc_active && !WARN_ON(!dtc->cycles)) {
+                               delta = arm_cmn_read_cc(dtc);
+                               local64_add(delta, &dtc->cycles->count);
+                       }
+               }
+
+               writel_relaxed(status, dtc->base + CMN_DT_PMOVSR_CLR);
+
+               if (!dtc->irq_friend)
+                       return ret;
+               dtc += dtc->irq_friend;
+       }
+}
+
+/* We can reasonably accommodate DTCs of the same CMN sharing IRQs */
+static int arm_cmn_init_irqs(struct arm_cmn *cmn)
+{
+       int i, j, irq, err;
+
+       for (i = 0; i < cmn->num_dtcs; i++) {
+               irq = cmn->dtc[i].irq;
+               for (j = i; j--; ) {
+                       if (cmn->dtc[j].irq == irq) {
+                               cmn->dtc[j].irq_friend = j - i;
+                               goto next;
+                       }
+               }
+               err = devm_request_irq(cmn->dev, irq, arm_cmn_handle_irq,
+                                      IRQF_NOBALANCING | IRQF_NO_THREAD,
+                                      dev_name(cmn->dev), &cmn->dtc[i]);
+               if (err)
+                       return err;
+
+               err = irq_set_affinity_hint(irq, cpumask_of(cmn->cpu));
+               if (err)
+                       return err;
+       next:
+               ; /* isn't C great? */
+       }
+       return 0;
+}
+
+static void arm_cmn_init_dtm(struct arm_cmn_node *xp)
+{
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               xp->wp_event[i] = -1;
+               writeq_relaxed(0, xp->pmu_base + CMN_DTM_WPn_MASK(i));
+               writeq_relaxed(~0ULL, xp->pmu_base + CMN_DTM_WPn_VAL(i));
+       }
+       xp->pmu_config_low = CMN_DTM_PMU_CONFIG_PMU_EN;
+       xp->dtc = -1;
+}
+
+static int arm_cmn_init_dtc(struct arm_cmn *cmn, struct arm_cmn_node *dn, int idx)
+{
+       struct arm_cmn_dtc *dtc = cmn->dtc + idx;
+       struct arm_cmn_node *xp;
+
+       dtc->base = dn->pmu_base - CMN_PMU_OFFSET;
+       dtc->irq = platform_get_irq(to_platform_device(cmn->dev), idx);
+       if (dtc->irq < 0)
+               return dtc->irq;
+
+       writel_relaxed(0, dtc->base + CMN_DT_PMCR);
+       writel_relaxed(0x1ff, dtc->base + CMN_DT_PMOVSR_CLR);
+       writel_relaxed(CMN_DT_PMCR_OVFL_INTR_EN, dtc->base + CMN_DT_PMCR);
+
+       /* We do at least know that a DTC's XP must be in that DTC's domain */
+       xp = arm_cmn_node_to_xp(dn);
+       xp->dtc = idx;
+
+       return 0;
+}
+
+static int arm_cmn_node_cmp(const void *a, const void *b)
+{
+       const struct arm_cmn_node *dna = a, *dnb = b;
+       int cmp;
+
+       cmp = dna->type - dnb->type;
+       if (!cmp)
+               cmp = dna->logid - dnb->logid;
+       return cmp;
+}
+
+static int arm_cmn_init_dtcs(struct arm_cmn *cmn)
+{
+       struct arm_cmn_node *dn;
+       int dtc_idx = 0;
+
+       cmn->dtc = devm_kcalloc(cmn->dev, cmn->num_dtcs, sizeof(cmn->dtc[0]), GFP_KERNEL);
+       if (!cmn->dtc)
+               return -ENOMEM;
+
+       sort(cmn->dns, cmn->num_dns, sizeof(cmn->dns[0]), arm_cmn_node_cmp, NULL);
+
+       cmn->xps = arm_cmn_node(cmn, CMN_TYPE_XP);
+
+       for (dn = cmn->dns; dn < cmn->dns + cmn->num_dns; dn++) {
+               if (dn->type != CMN_TYPE_XP)
+                       arm_cmn_init_node_to_xp(cmn, dn);
+               else if (cmn->num_dtcs == 1)
+                       dn->dtc = 0;
+
+               if (dn->type == CMN_TYPE_DTC)
+                       arm_cmn_init_dtc(cmn, dn, dtc_idx++);
+
+               /* To the PMU, RN-Ds don't add anything over RN-Is, so smoosh them together */
+               if (dn->type == CMN_TYPE_RND)
+                       dn->type = CMN_TYPE_RNI;
+       }
+
+       writel_relaxed(CMN_DT_DTC_CTL_DT_EN, cmn->dtc[0].base + CMN_DT_DTC_CTL);
+
+       return 0;
+}
+
+static void arm_cmn_init_node_info(struct arm_cmn *cmn, u32 offset, struct arm_cmn_node *node)
+{
+       int level;
+       u64 reg = readq_relaxed(cmn->base + offset + CMN_NODE_INFO);
+
+       node->type = FIELD_GET(CMN_NI_NODE_TYPE, reg);
+       node->id = FIELD_GET(CMN_NI_NODE_ID, reg);
+       node->logid = FIELD_GET(CMN_NI_LOGICAL_ID, reg);
+
+       node->pmu_base = cmn->base + offset + CMN_PMU_OFFSET;
+
+       if (node->type == CMN_TYPE_CFG)
+               level = 0;
+       else if (node->type == CMN_TYPE_XP)
+               level = 1;
+       else
+               level = 2;
+
+       dev_dbg(cmn->dev, "node%*c%#06hx%*ctype:%-#6x id:%-4hd off:%#x\n",
+                       (level * 2) + 1, ' ', node->id, 5 - (level * 2), ' ',
+                       node->type, node->logid, offset);
+}
+
+static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
+{
+       void __iomem *cfg_region;
+       struct arm_cmn_node cfg, *dn;
+       u16 child_count, child_poff;
+       u32 xp_offset[CMN_MAX_XPS];
+       u64 reg;
+       int i, j;
+
+       cfg_region = cmn->base + rgn_offset;
+       reg = readl_relaxed(cfg_region + CMN_CFGM_PERIPH_ID_2);
+       cmn->rev = FIELD_GET(CMN_CFGM_PID2_REVISION, reg);
+       dev_dbg(cmn->dev, "periph_id_2 revision: %d\n", cmn->rev);
+
+       arm_cmn_init_node_info(cmn, rgn_offset, &cfg);
+       if (cfg.type != CMN_TYPE_CFG)
+               return -ENODEV;
+
+       reg = readq_relaxed(cfg_region + CMN_CHILD_INFO);
+       child_count = FIELD_GET(CMN_CI_CHILD_COUNT, reg);
+       child_poff = FIELD_GET(CMN_CI_CHILD_PTR_OFFSET, reg);
+
+       cmn->num_xps = child_count;
+       cmn->num_dns = cmn->num_xps;
+
+       /* Pass 1: visit the XPs, enumerate their children */
+       for (i = 0; i < cmn->num_xps; i++) {
+               reg = readq_relaxed(cfg_region + child_poff + i * 8);
+               xp_offset[i] = reg & CMN_CHILD_NODE_ADDR;
+
+               reg = readq_relaxed(cmn->base + xp_offset[i] + CMN_CHILD_INFO);
+               cmn->num_dns += FIELD_GET(CMN_CI_CHILD_COUNT, reg);
+       }
+
+       /* Cheeky +1 to help terminate pointer-based iteration */
+       cmn->dns = devm_kcalloc(cmn->dev, cmn->num_dns + 1,
+                               sizeof(*cmn->dns), GFP_KERNEL);
+       if (!cmn->dns)
+               return -ENOMEM;
+
+       /* Pass 2: now we can actually populate the nodes */
+       dn = cmn->dns;
+       for (i = 0; i < cmn->num_xps; i++) {
+               void __iomem *xp_region = cmn->base + xp_offset[i];
+               struct arm_cmn_node *xp = dn++;
+
+               arm_cmn_init_node_info(cmn, xp_offset[i], xp);
+               arm_cmn_init_dtm(xp);
+               /*
+                * Thanks to the order in which XP logical IDs seem to be
+                * assigned, we can handily infer the mesh X dimension by
+                * looking out for the XP at (0,1) without needing to know
+                * the exact node ID format, which we can later derive.
+                */
+               if (xp->id == (1 << 3))
+                       cmn->mesh_x = xp->logid;
+
+               reg = readq_relaxed(xp_region + CMN_CHILD_INFO);
+               child_count = FIELD_GET(CMN_CI_CHILD_COUNT, reg);
+               child_poff = FIELD_GET(CMN_CI_CHILD_PTR_OFFSET, reg);
+
+               for (j = 0; j < child_count; j++) {
+                       reg = readq_relaxed(xp_region + child_poff + j * 8);
+                       /*
+                        * Don't even try to touch anything external, since in general
+                        * we haven't a clue how to power up arbitrary CHI requesters.
+                        * As of CMN-600r1 these could only be RN-SAMs or CXLAs,
+                        * neither of which have any PMU events anyway.
+                        * (Actually, CXLAs do seem to have grown some events in r1p2,
+                        * but they don't go to regular XP DTMs, and they depend on
+                        * secure configuration which we can't easily deal with)
+                        */
+                       if (reg & CMN_CHILD_NODE_EXTERNAL) {
+                               dev_dbg(cmn->dev, "ignoring external node %llx\n", reg);
+                               continue;
+                       }
+
+                       arm_cmn_init_node_info(cmn, reg & CMN_CHILD_NODE_ADDR, dn);
+
+                       switch (dn->type) {
+                       case CMN_TYPE_DTC:
+                               cmn->num_dtcs++;
+                               dn++;
+                               break;
+                       /* These guys have PMU events */
+                       case CMN_TYPE_DVM:
+                       case CMN_TYPE_HNI:
+                       case CMN_TYPE_HNF:
+                       case CMN_TYPE_SBSX:
+                       case CMN_TYPE_RNI:
+                       case CMN_TYPE_RND:
+                       case CMN_TYPE_CXRA:
+                       case CMN_TYPE_CXHA:
+                               dn++;
+                               break;
+                       /* Nothing to see here */
+                       case CMN_TYPE_RNSAM:
+                       case CMN_TYPE_CXLA:
+                               break;
+                       /* Something has gone horribly wrong */
+                       default:
+                               dev_err(cmn->dev, "invalid device node type: 0x%x\n", dn->type);
+                               return -ENODEV;
+                       }
+               }
+       }
+
+       /* Correct for any nodes we skipped */
+       cmn->num_dns = dn - cmn->dns;
+
+       /*
+        * If mesh_x wasn't set during discovery then we never saw
+        * an XP at (0,1), thus we must have an Nx1 configuration.
+        */
+       if (!cmn->mesh_x)
+               cmn->mesh_x = cmn->num_xps;
+       cmn->mesh_y = cmn->num_xps / cmn->mesh_x;
+
+       dev_dbg(cmn->dev, "mesh %dx%d, ID width %d\n",
+               cmn->mesh_x, cmn->mesh_y, arm_cmn_xyidbits(cmn));
+
+       return 0;
+}
+
+static int arm_cmn_acpi_probe(struct platform_device *pdev, struct arm_cmn *cmn)
+{
+       struct resource *cfg, *root;
+
+       cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!cfg)
+               return -EINVAL;
+
+       root = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!root)
+               return -EINVAL;
+
+       if (!resource_contains(cfg, root))
+               swap(cfg, root);
+       /*
+        * Note that devm_ioremap_resource() is dumb and won't let the platform
+        * device claim cfg when the ACPI companion device has already claimed
+        * root within it. But since they *are* already both claimed in the
+        * appropriate name, we don't really need to do it again here anyway.
+        */
+       cmn->base = devm_ioremap(cmn->dev, cfg->start, resource_size(cfg));
+       if (!cmn->base)
+               return -ENOMEM;
+
+       return root->start - cfg->start;
+}
+
+static int arm_cmn_of_probe(struct platform_device *pdev, struct arm_cmn *cmn)
+{
+       struct device_node *np = pdev->dev.of_node;
+       u32 rootnode;
+       int ret;
+
+       cmn->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(cmn->base))
+               return PTR_ERR(cmn->base);
+
+       ret = of_property_read_u32(np, "arm,root-node", &rootnode);
+       if (ret)
+               return ret;
+
+       return rootnode;
+}
+
+static int arm_cmn_probe(struct platform_device *pdev)
+{
+       struct arm_cmn *cmn;
+       const char *name;
+       static atomic_t id;
+       int err, rootnode, this_id;
+
+       cmn = devm_kzalloc(&pdev->dev, sizeof(*cmn), GFP_KERNEL);
+       if (!cmn)
+               return -ENOMEM;
+
+       cmn->dev = &pdev->dev;
+       platform_set_drvdata(pdev, cmn);
+
+       if (has_acpi_companion(cmn->dev))
+               rootnode = arm_cmn_acpi_probe(pdev, cmn);
+       else
+               rootnode = arm_cmn_of_probe(pdev, cmn);
+       if (rootnode < 0)
+               return rootnode;
+
+       err = arm_cmn_discover(cmn, rootnode);
+       if (err)
+               return err;
+
+       err = arm_cmn_init_dtcs(cmn);
+       if (err)
+               return err;
+
+       err = arm_cmn_init_irqs(cmn);
+       if (err)
+               return err;
+
+       cmn->cpu = raw_smp_processor_id();
+       cmn->pmu = (struct pmu) {
+               .module = THIS_MODULE,
+               .attr_groups = arm_cmn_attr_groups,
+               .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
+               .task_ctx_nr = perf_invalid_context,
+               .pmu_enable = arm_cmn_pmu_enable,
+               .pmu_disable = arm_cmn_pmu_disable,
+               .event_init = arm_cmn_event_init,
+               .add = arm_cmn_event_add,
+               .del = arm_cmn_event_del,
+               .start = arm_cmn_event_start,
+               .stop = arm_cmn_event_stop,
+               .read = arm_cmn_event_read,
+               .start_txn = arm_cmn_start_txn,
+               .commit_txn = arm_cmn_commit_txn,
+               .cancel_txn = arm_cmn_end_txn,
+       };
+
+       this_id = atomic_fetch_inc(&id);
+       if (this_id == 0) {
+               name = "arm_cmn";
+       } else {
+               name = devm_kasprintf(cmn->dev, GFP_KERNEL, "arm_cmn_%d", this_id);
+               if (!name)
+                       return -ENOMEM;
+       }
+
+       err = cpuhp_state_add_instance(arm_cmn_hp_state, &cmn->cpuhp_node);
+       if (err)
+               return err;
+
+       err = perf_pmu_register(&cmn->pmu, name, -1);
+       if (err)
+               cpuhp_state_remove_instance(arm_cmn_hp_state, &cmn->cpuhp_node);
+       return err;
+}
+
+static int arm_cmn_remove(struct platform_device *pdev)
+{
+       struct arm_cmn *cmn = platform_get_drvdata(pdev);
+       int i;
+
+       writel_relaxed(0, cmn->dtc[0].base + CMN_DT_DTC_CTL);
+
+       perf_pmu_unregister(&cmn->pmu);
+       cpuhp_state_remove_instance(arm_cmn_hp_state, &cmn->cpuhp_node);
+
+       for (i = 0; i < cmn->num_dtcs; i++)
+               irq_set_affinity_hint(cmn->dtc[i].irq, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id arm_cmn_of_match[] = {
+       { .compatible = "arm,cmn-600", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, arm_cmn_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id arm_cmn_acpi_match[] = {
+       { "ARMHC600", },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, arm_cmn_acpi_match);
+#endif
+
+static struct platform_driver arm_cmn_driver = {
+       .driver = {
+               .name = "arm-cmn",
+               .of_match_table = of_match_ptr(arm_cmn_of_match),
+               .acpi_match_table = ACPI_PTR(arm_cmn_acpi_match),
+       },
+       .probe = arm_cmn_probe,
+       .remove = arm_cmn_remove,
+};
+
+static int __init arm_cmn_init(void)
+{
+       int ret;
+
+       ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
+                                     "perf/arm/cmn:online", NULL,
+                                     arm_cmn_pmu_offline_cpu);
+       if (ret < 0)
+               return ret;
+
+       arm_cmn_hp_state = ret;
+       ret = platform_driver_register(&arm_cmn_driver);
+       if (ret)
+               cpuhp_remove_multi_state(arm_cmn_hp_state);
+       return ret;
+}
+
+static void __exit arm_cmn_exit(void)
+{
+       platform_driver_unregister(&arm_cmn_driver);
+       cpuhp_remove_multi_state(arm_cmn_hp_state);
+}
+
+module_init(arm_cmn_init);
+module_exit(arm_cmn_exit);
+
+MODULE_AUTHOR("Robin Murphy <robin.murphy@arm.com>");
+MODULE_DESCRIPTION("Arm CMN-600 PMU driver");
+MODULE_LICENSE("GPL v2");
index 96ed93c..98e68ed 100644 (file)
@@ -11,6 +11,7 @@
 #define DRVNAME                PMUNAME "_pmu"
 #define pr_fmt(fmt)    DRVNAME ": " fmt
 
+#include <linux/acpi.h>
 #include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/bug.h>
@@ -603,18 +604,19 @@ static struct dsu_pmu *dsu_pmu_alloc(struct platform_device *pdev)
 }
 
 /**
- * dsu_pmu_dt_get_cpus: Get the list of CPUs in the cluster.
+ * dsu_pmu_dt_get_cpus: Get the list of CPUs in the cluster
+ * from device tree.
  */
-static int dsu_pmu_dt_get_cpus(struct device_node *dev, cpumask_t *mask)
+static int dsu_pmu_dt_get_cpus(struct device *dev, cpumask_t *mask)
 {
        int i = 0, n, cpu;
        struct device_node *cpu_node;
 
-       n = of_count_phandle_with_args(dev, "cpus", NULL);
+       n = of_count_phandle_with_args(dev->of_node, "cpus", NULL);
        if (n <= 0)
                return -ENODEV;
        for (; i < n; i++) {
-               cpu_node = of_parse_phandle(dev, "cpus", i);
+               cpu_node = of_parse_phandle(dev->of_node, "cpus", i);
                if (!cpu_node)
                        break;
                cpu = of_cpu_node_to_id(cpu_node);
@@ -631,6 +633,36 @@ static int dsu_pmu_dt_get_cpus(struct device_node *dev, cpumask_t *mask)
        return 0;
 }
 
+/**
+ * dsu_pmu_acpi_get_cpus: Get the list of CPUs in the cluster
+ * from ACPI.
+ */
+static int dsu_pmu_acpi_get_cpus(struct device *dev, cpumask_t *mask)
+{
+#ifdef CONFIG_ACPI
+       int cpu;
+
+       /*
+        * A dsu pmu node is inside a cluster parent node along with cpu nodes.
+        * We need to find out all cpus that have the same parent with this pmu.
+        */
+       for_each_possible_cpu(cpu) {
+               struct acpi_device *acpi_dev;
+               struct device *cpu_dev = get_cpu_device(cpu);
+
+               if (!cpu_dev)
+                       continue;
+
+               acpi_dev = ACPI_COMPANION(cpu_dev);
+               if (acpi_dev &&
+                       acpi_dev->parent == ACPI_COMPANION(dev)->parent)
+                       cpumask_set_cpu(cpu, mask);
+       }
+#endif
+
+       return 0;
+}
+
 /*
  * dsu_pmu_probe_pmu: Probe the PMU details on a CPU in the cluster.
  */
@@ -676,6 +708,7 @@ static int dsu_pmu_device_probe(struct platform_device *pdev)
 {
        int irq, rc;
        struct dsu_pmu *dsu_pmu;
+       struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
        char *name;
        static atomic_t pmu_idx = ATOMIC_INIT(-1);
 
@@ -683,7 +716,16 @@ static int dsu_pmu_device_probe(struct platform_device *pdev)
        if (IS_ERR(dsu_pmu))
                return PTR_ERR(dsu_pmu);
 
-       rc = dsu_pmu_dt_get_cpus(pdev->dev.of_node, &dsu_pmu->associated_cpus);
+       if (IS_ERR_OR_NULL(fwnode))
+               return -ENOENT;
+
+       if (is_of_node(fwnode))
+               rc = dsu_pmu_dt_get_cpus(&pdev->dev, &dsu_pmu->associated_cpus);
+       else if (is_acpi_device_node(fwnode))
+               rc = dsu_pmu_acpi_get_cpus(&pdev->dev, &dsu_pmu->associated_cpus);
+       else
+               return -ENOENT;
+
        if (rc) {
                dev_warn(&pdev->dev, "Failed to parse the CPUs\n");
                return rc;
@@ -752,11 +794,21 @@ static const struct of_device_id dsu_pmu_of_match[] = {
        { .compatible = "arm,dsu-pmu", },
        {},
 };
+MODULE_DEVICE_TABLE(of, dsu_pmu_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id dsu_pmu_acpi_match[] = {
+       { "ARMHD500", 0},
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, dsu_pmu_acpi_match);
+#endif
 
 static struct platform_driver dsu_pmu_driver = {
        .driver = {
                .name   = DRVNAME,
                .of_match_table = of_match_ptr(dsu_pmu_of_match),
+               .acpi_match_table = ACPI_PTR(dsu_pmu_acpi_match),
                .suppress_bind_attrs = true,
        },
        .probe = dsu_pmu_device_probe,
@@ -826,7 +878,6 @@ static void __exit dsu_pmu_exit(void)
 module_init(dsu_pmu_init);
 module_exit(dsu_pmu_exit);
 
-MODULE_DEVICE_TABLE(of, dsu_pmu_of_match);
 MODULE_DESCRIPTION("Perf driver for ARM DynamIQ Shared Unit");
 MODULE_AUTHOR("Suzuki K Poulose <suzuki.poulose@arm.com>");
 MODULE_LICENSE("GPL v2");
index df352b3..cb2f55f 100644 (file)
 
 #include <asm/irq_regs.h>
 
+static int armpmu_count_irq_users(const int irq);
+
+struct pmu_irq_ops {
+       void (*enable_pmuirq)(unsigned int irq);
+       void (*disable_pmuirq)(unsigned int irq);
+       void (*free_pmuirq)(unsigned int irq, int cpu, void __percpu *devid);
+};
+
+static void armpmu_free_pmuirq(unsigned int irq, int cpu, void __percpu *devid)
+{
+       free_irq(irq, per_cpu_ptr(devid, cpu));
+}
+
+static const struct pmu_irq_ops pmuirq_ops = {
+       .enable_pmuirq = enable_irq,
+       .disable_pmuirq = disable_irq_nosync,
+       .free_pmuirq = armpmu_free_pmuirq
+};
+
+static void armpmu_free_pmunmi(unsigned int irq, int cpu, void __percpu *devid)
+{
+       free_nmi(irq, per_cpu_ptr(devid, cpu));
+}
+
+static const struct pmu_irq_ops pmunmi_ops = {
+       .enable_pmuirq = enable_nmi,
+       .disable_pmuirq = disable_nmi_nosync,
+       .free_pmuirq = armpmu_free_pmunmi
+};
+
+static void armpmu_enable_percpu_pmuirq(unsigned int irq)
+{
+       enable_percpu_irq(irq, IRQ_TYPE_NONE);
+}
+
+static void armpmu_free_percpu_pmuirq(unsigned int irq, int cpu,
+                                  void __percpu *devid)
+{
+       if (armpmu_count_irq_users(irq) == 1)
+               free_percpu_irq(irq, devid);
+}
+
+static const struct pmu_irq_ops percpu_pmuirq_ops = {
+       .enable_pmuirq = armpmu_enable_percpu_pmuirq,
+       .disable_pmuirq = disable_percpu_irq,
+       .free_pmuirq = armpmu_free_percpu_pmuirq
+};
+
+static void armpmu_enable_percpu_pmunmi(unsigned int irq)
+{
+       if (!prepare_percpu_nmi(irq))
+               enable_percpu_nmi(irq, IRQ_TYPE_NONE);
+}
+
+static void armpmu_disable_percpu_pmunmi(unsigned int irq)
+{
+       disable_percpu_nmi(irq);
+       teardown_percpu_nmi(irq);
+}
+
+static void armpmu_free_percpu_pmunmi(unsigned int irq, int cpu,
+                                     void __percpu *devid)
+{
+       if (armpmu_count_irq_users(irq) == 1)
+               free_percpu_nmi(irq, devid);
+}
+
+static const struct pmu_irq_ops percpu_pmunmi_ops = {
+       .enable_pmuirq = armpmu_enable_percpu_pmunmi,
+       .disable_pmuirq = armpmu_disable_percpu_pmunmi,
+       .free_pmuirq = armpmu_free_percpu_pmunmi
+};
+
 static DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu);
 static DEFINE_PER_CPU(int, cpu_irq);
+static DEFINE_PER_CPU(const struct pmu_irq_ops *, cpu_irq_ops);
+
+static bool has_nmi;
 
 static inline u64 arm_pmu_event_max_period(struct perf_event *event)
 {
@@ -544,6 +620,23 @@ static int armpmu_count_irq_users(const int irq)
        return count;
 }
 
+static const struct pmu_irq_ops *armpmu_find_irq_ops(int irq)
+{
+       const struct pmu_irq_ops *ops = NULL;
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               if (per_cpu(cpu_irq, cpu) != irq)
+                       continue;
+
+               ops = per_cpu(cpu_irq_ops, cpu);
+               if (ops)
+                       break;
+       }
+
+       return ops;
+}
+
 void armpmu_free_irq(int irq, int cpu)
 {
        if (per_cpu(cpu_irq, cpu) == 0)
@@ -551,18 +644,18 @@ void armpmu_free_irq(int irq, int cpu)
        if (WARN_ON(irq != per_cpu(cpu_irq, cpu)))
                return;
 
-       if (!irq_is_percpu_devid(irq))
-               free_irq(irq, per_cpu_ptr(&cpu_armpmu, cpu));
-       else if (armpmu_count_irq_users(irq) == 1)
-               free_percpu_irq(irq, &cpu_armpmu);
+       per_cpu(cpu_irq_ops, cpu)->free_pmuirq(irq, cpu, &cpu_armpmu);
 
        per_cpu(cpu_irq, cpu) = 0;
+       per_cpu(cpu_irq_ops, cpu) = NULL;
 }
 
 int armpmu_request_irq(int irq, int cpu)
 {
        int err = 0;
        const irq_handler_t handler = armpmu_dispatch_irq;
+       const struct pmu_irq_ops *irq_ops;
+
        if (!irq)
                return 0;
 
@@ -582,17 +675,44 @@ int armpmu_request_irq(int irq, int cpu)
                            IRQF_NO_THREAD;
 
                irq_set_status_flags(irq, IRQ_NOAUTOEN);
-               err = request_irq(irq, handler, irq_flags, "arm-pmu",
+
+               err = request_nmi(irq, handler, irq_flags, "arm-pmu",
                                  per_cpu_ptr(&cpu_armpmu, cpu));
+
+               /* If cannot get an NMI, get a normal interrupt */
+               if (err) {
+                       err = request_irq(irq, handler, irq_flags, "arm-pmu",
+                                         per_cpu_ptr(&cpu_armpmu, cpu));
+                       irq_ops = &pmuirq_ops;
+               } else {
+                       has_nmi = true;
+                       irq_ops = &pmunmi_ops;
+               }
        } else if (armpmu_count_irq_users(irq) == 0) {
-               err = request_percpu_irq(irq, handler, "arm-pmu",
-                                        &cpu_armpmu);
+               err = request_percpu_nmi(irq, handler, "arm-pmu", &cpu_armpmu);
+
+               /* If cannot get an NMI, get a normal interrupt */
+               if (err) {
+                       err = request_percpu_irq(irq, handler, "arm-pmu",
+                                                &cpu_armpmu);
+                       irq_ops = &percpu_pmuirq_ops;
+               } else {
+                       has_nmi= true;
+                       irq_ops = &percpu_pmunmi_ops;
+               }
+       } else {
+               /* Per cpudevid irq was already requested by another CPU */
+               irq_ops = armpmu_find_irq_ops(irq);
+
+               if (WARN_ON(!irq_ops))
+                       err = -EINVAL;
        }
 
        if (err)
                goto err_out;
 
        per_cpu(cpu_irq, cpu) = irq;
+       per_cpu(cpu_irq_ops, cpu) = irq_ops;
        return 0;
 
 err_out:
@@ -625,12 +745,8 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
        per_cpu(cpu_armpmu, cpu) = pmu;
 
        irq = armpmu_get_cpu_irq(pmu, cpu);
-       if (irq) {
-               if (irq_is_percpu_devid(irq))
-                       enable_percpu_irq(irq, IRQ_TYPE_NONE);
-               else
-                       enable_irq(irq);
-       }
+       if (irq)
+               per_cpu(cpu_irq_ops, cpu)->enable_pmuirq(irq);
 
        return 0;
 }
@@ -644,12 +760,8 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node)
                return 0;
 
        irq = armpmu_get_cpu_irq(pmu, cpu);
-       if (irq) {
-               if (irq_is_percpu_devid(irq))
-                       disable_percpu_irq(irq);
-               else
-                       disable_irq_nosync(irq);
-       }
+       if (irq)
+               per_cpu(cpu_irq_ops, cpu)->disable_pmuirq(irq);
 
        per_cpu(cpu_armpmu, cpu) = NULL;
 
@@ -870,8 +982,9 @@ int armpmu_register(struct arm_pmu *pmu)
        if (!__oprofile_cpu_pmu)
                __oprofile_cpu_pmu = pmu;
 
-       pr_info("enabled with %s PMU driver, %d counters available\n",
-               pmu->name, pmu->num_events);
+       pr_info("enabled with %s PMU driver, %d counters available%s\n",
+               pmu->name, pmu->num_events,
+               has_nmi ? ", using NMIs" : "");
 
        return 0;
 
index e51ddb6..cc00915 100644 (file)
@@ -1002,7 +1002,7 @@ static void __arm_spe_pmu_dev_probe(void *info)
        default:
                dev_warn(dev, "unknown PMSIDR_EL1.Interval [%d]; assuming 8\n",
                         fld);
-               /* Fallthrough */
+               fallthrough;
        case 8:
                spe_pmu->min_period = 4096;
        }
@@ -1021,7 +1021,7 @@ static void __arm_spe_pmu_dev_probe(void *info)
        default:
                dev_warn(dev, "unknown PMSIDR_EL1.CountSize [%d]; assuming 2\n",
                         fld);
-               /* Fallthrough */
+               fallthrough;
        case 2:
                spe_pmu->counter_sz = 12;
        }
index 25b0c97..b59ec22 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/cpumask.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/perf_event.h>
 #include <linux/types.h>
 
index aac9823..e116815 100644 (file)
@@ -805,14 +805,17 @@ static struct tx2_uncore_pmu *tx2_uncore_pmu_init_dev(struct device *dev,
        list_for_each_entry(rentry, &list, node) {
                if (resource_type(rentry->res) == IORESOURCE_MEM) {
                        res = *rentry->res;
+                       rentry = NULL;
                        break;
                }
        }
+       acpi_dev_free_resource_list(&list);
 
-       if (!rentry->res)
+       if (rentry) {
+               dev_err(dev, "PMU type %d: Fail to find resource\n", type);
                return NULL;
+       }
 
-       acpi_dev_free_resource_list(&list);
        base = devm_ioremap_resource(dev, &res);
        if (IS_ERR(base)) {
                dev_err(dev, "PMU type %d: Fail to map resource\n", type);
index edac28c..633cf07 100644 (file)
@@ -1453,17 +1453,6 @@ static char *xgene_pmu_dev_name(struct device *dev, u32 type, int id)
 }
 
 #if defined(CONFIG_ACPI)
-static int acpi_pmu_dev_add_resource(struct acpi_resource *ares, void *data)
-{
-       struct resource *res = data;
-
-       if (ares->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32)
-               acpi_dev_resource_memory(ares, res);
-
-       /* Always tell the ACPI core to skip this resource */
-       return 1;
-}
-
 static struct
 xgene_pmu_dev_ctx *acpi_get_pmu_hw_inf(struct xgene_pmu *xgene_pmu,
                                       struct acpi_device *adev, u32 type)
@@ -1475,6 +1464,7 @@ xgene_pmu_dev_ctx *acpi_get_pmu_hw_inf(struct xgene_pmu *xgene_pmu,
        struct hw_pmu_info *inf;
        void __iomem *dev_csr;
        struct resource res;
+       struct resource_entry *rentry;
        int enable_bit;
        int rc;
 
@@ -1483,11 +1473,23 @@ xgene_pmu_dev_ctx *acpi_get_pmu_hw_inf(struct xgene_pmu *xgene_pmu,
                return NULL;
 
        INIT_LIST_HEAD(&resource_list);
-       rc = acpi_dev_get_resources(adev, &resource_list,
-                                   acpi_pmu_dev_add_resource, &res);
+       rc = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+       if (rc <= 0) {
+               dev_err(dev, "PMU type %d: No resources found\n", type);
+               return NULL;
+       }
+
+       list_for_each_entry(rentry, &resource_list, node) {
+               if (resource_type(rentry->res) == IORESOURCE_MEM) {
+                       res = *rentry->res;
+                       rentry = NULL;
+                       break;
+               }
+       }
        acpi_dev_free_resource_list(&resource_list);
-       if (rc < 0) {
-               dev_err(dev, "PMU type %d: No resource address found\n", type);
+
+       if (rentry) {
+               dev_err(dev, "PMU type %d: No memory resource found\n", type);
                return NULL;
        }
 
index 71f257b..9061ece 100644 (file)
@@ -505,9 +505,9 @@ static int qcom_ipq806x_usb_phy_probe(struct platform_device *pdev)
        size = resource_size(res);
        phy_dwc3->base = devm_ioremap(phy_dwc3->dev, res->start, size);
 
-       if (IS_ERR(phy_dwc3->base)) {
+       if (!phy_dwc3->base) {
                dev_err(phy_dwc3->dev, "failed to map reg\n");
-               return PTR_ERR(phy_dwc3->base);
+               return -ENOMEM;
        }
 
        phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref");
@@ -557,7 +557,6 @@ static struct platform_driver qcom_ipq806x_usb_phy_driver = {
        .probe          = qcom_ipq806x_usb_phy_probe,
        .driver         = {
                .name   = "qcom-ipq806x-usb-phy",
-               .owner  = THIS_MODULE,
                .of_match_table = qcom_ipq806x_usb_phy_table,
        },
 };
index 562053c..6e6f992 100644 (file)
@@ -604,8 +604,8 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_serdes_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0xf),
        QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x1),
        QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x0),
-       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0x1f),
-       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f),
+       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
+       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x1f),
        QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x6),
        QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0xf),
        QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x0),
@@ -631,7 +631,6 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_serdes_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x0),
        QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
        QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x1),
-       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0xa),
        QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x1),
        QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31),
        QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x1),
@@ -640,7 +639,6 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_serdes_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0x2f),
        QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x19),
        QMP_PHY_INIT_CFG(QSERDES_COM_CLK_EP_DIV, 0x19),
-       QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x7),
 };
 
 static const struct qmp_phy_init_tbl ipq8074_pcie_tx_tbl[] = {
@@ -648,6 +646,8 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_tx_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x6),
        QMP_PHY_INIT_CFG(QSERDES_TX_RES_CODE_LANE_OFFSET, 0x2),
        QMP_PHY_INIT_CFG(QSERDES_TX_RCV_DETECT_LVL_2, 0x12),
+       QMP_PHY_INIT_CFG(QSERDES_TX_EMP_POST1_LVL, 0x36),
+       QMP_PHY_INIT_CFG(QSERDES_TX_SLEW_CNTL, 0x0a),
 };
 
 static const struct qmp_phy_init_tbl ipq8074_pcie_rx_tbl[] = {
@@ -658,7 +658,6 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_rx_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xdb),
        QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b),
        QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x4),
-       QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN_HALF, 0x4),
 };
 
 static const struct qmp_phy_init_tbl ipq8074_pcie_pcs_tbl[] = {
@@ -2046,6 +2045,9 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
        .pwrdn_ctrl             = SW_PWRDN,
 };
 
+static const char * const ipq8074_pciephy_clk_l[] = {
+       "aux", "cfg_ahb",
+};
 /* list of resets */
 static const char * const ipq8074_pciephy_reset_l[] = {
        "phy", "common",
@@ -2063,8 +2065,8 @@ static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
        .rx_tbl_num             = ARRAY_SIZE(ipq8074_pcie_rx_tbl),
        .pcs_tbl                = ipq8074_pcie_pcs_tbl,
        .pcs_tbl_num            = ARRAY_SIZE(ipq8074_pcie_pcs_tbl),
-       .clk_list               = NULL,
-       .num_clks               = 0,
+       .clk_list               = ipq8074_pciephy_clk_l,
+       .num_clks               = ARRAY_SIZE(ipq8074_pciephy_clk_l),
        .reset_list             = ipq8074_pciephy_reset_l,
        .num_resets             = ARRAY_SIZE(ipq8074_pciephy_reset_l),
        .vreg_list              = NULL,
index 4277f59..904b80a 100644 (file)
@@ -77,6 +77,8 @@
 #define QSERDES_COM_CORECLK_DIV_MODE1                  0x1bc
 
 /* Only for QMP V2 PHY - TX registers */
+#define QSERDES_TX_EMP_POST1_LVL                       0x018
+#define QSERDES_TX_SLEW_CNTL                           0x040
 #define QSERDES_TX_RES_CODE_LANE_OFFSET                        0x054
 #define QSERDES_TX_DEBUG_BUS_SEL                       0x064
 #define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN    0x068
index 6105427..327df1a 100644 (file)
@@ -53,7 +53,7 @@ static int qcom_usb_hs_phy_set_mode(struct phy *phy,
                case PHY_MODE_USB_OTG:
                case PHY_MODE_USB_HOST:
                        val |= ULPI_INT_IDGRD;
-                       /* fall through */
+                       fallthrough;
                case PHY_MODE_USB_DEVICE:
                        val |= ULPI_INT_SESS_VALID;
                default:
index a84e9f0..46ebdb1 100644 (file)
@@ -546,7 +546,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
                rport->state = OTG_STATE_B_IDLE;
                if (!vbus_attach)
                        rockchip_usb2phy_power_off(rport->phy);
-               /* fall through */
+               fallthrough;
        case OTG_STATE_B_IDLE:
                if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0) {
                        dev_dbg(&rport->phy->dev, "usb otg host connect\n");
@@ -754,11 +754,11 @@ static void rockchip_chg_detect_work(struct work_struct *work)
                        rphy->chg_type = POWER_SUPPLY_TYPE_USB_DCP;
                else
                        rphy->chg_type = POWER_SUPPLY_TYPE_USB_CDP;
-               /* fall through */
+               fallthrough;
        case USB_CHG_STATE_SECONDARY_DONE:
                rphy->chg_state = USB_CHG_STATE_DETECTED;
                delay = 0;
-               /* fall through */
+               fallthrough;
        case USB_CHG_STATE_DETECTED:
                /* put the controller in normal mode */
                property_enable(base, &rphy->phy_cfg->chg_det.opmode, true);
@@ -835,7 +835,7 @@ static void rockchip_usb2phy_sm_work(struct work_struct *work)
                        dev_dbg(&rport->phy->dev, "FS/LS online\n");
                        break;
                }
-               /* fall through */
+               fallthrough;
        case PHY_STATE_CONNECT:
                if (rport->suspended) {
                        dev_dbg(&rport->phy->dev, "Connected\n");
index a174b3c..819c49a 100644 (file)
@@ -725,8 +725,10 @@ static int serdes_am654_probe(struct platform_device *pdev)
        pm_runtime_enable(dev);
 
        phy = devm_phy_create(dev, NULL, &ops);
-       if (IS_ERR(phy))
-               return PTR_ERR(phy);
+       if (IS_ERR(phy)) {
+               ret = PTR_ERR(phy);
+               goto clk_err;
+       }
 
        phy_set_drvdata(phy, am654_phy);
        phy_provider = devm_of_phy_provider_register(dev, serdes_am654_xlate);
index cb2dd32..507f79d 100644 (file)
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
 #include <linux/of_platform.h>
+#include <linux/sys_soc.h>
 
 #define USB2PHY_ANA_CONFIG1            0x4c
 #define USB2PHY_DISCON_BYP_LATCH       BIT(31)
 
+#define USB2PHY_CHRG_DET                       0x14
+#define USB2PHY_CHRG_DET_USE_CHG_DET_REG       BIT(29)
+#define USB2PHY_CHRG_DET_DIS_CHG_DET           BIT(28)
+
 /* SoC Specific USB2_OTG register definitions */
 #define AM654_USB2_OTG_PD              BIT(8)
 #define AM654_USB2_VBUS_DET_EN         BIT(5)
@@ -43,6 +48,7 @@
 #define OMAP_USB2_HAS_START_SRP                        BIT(0)
 #define OMAP_USB2_HAS_SET_VBUS                 BIT(1)
 #define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT   BIT(2)
+#define OMAP_USB2_DISABLE_CHRG_DET             BIT(3)
 
 struct omap_usb {
        struct usb_phy          phy;
@@ -236,6 +242,13 @@ static int omap_usb_init(struct phy *x)
                omap_usb_writel(phy->phy_base, USB2PHY_ANA_CONFIG1, val);
        }
 
+       if (phy->flags & OMAP_USB2_DISABLE_CHRG_DET) {
+               val = omap_usb_readl(phy->phy_base, USB2PHY_CHRG_DET);
+               val |= USB2PHY_CHRG_DET_USE_CHG_DET_REG |
+                      USB2PHY_CHRG_DET_DIS_CHG_DET;
+               omap_usb_writel(phy->phy_base, USB2PHY_CHRG_DET, val);
+       }
+
        return 0;
 }
 
@@ -329,6 +342,26 @@ static const struct of_device_id omap_usb2_id_table[] = {
 };
 MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
 
+static void omap_usb2_init_errata(struct omap_usb *phy)
+{
+       static const struct soc_device_attribute am65x_sr10_soc_devices[] = {
+               { .family = "AM65X", .revision = "SR1.0" },
+               { /* sentinel */ }
+       };
+
+       /*
+        * Errata i2075: USB2PHY: USB2PHY Charger Detect is Enabled by
+        * Default Without VBUS Presence.
+        *
+        * AM654x SR1.0 has a silicon bug due to which D+ is pulled high after
+        * POR, which could cause enumeration failure with some USB hubs.
+        * Disabling the USB2_PHY Charger Detect function will put D+
+        * into the normal state.
+        */
+       if (soc_device_match(am65x_sr10_soc_devices))
+               phy->flags |= OMAP_USB2_DISABLE_CHRG_DET;
+}
+
 static int omap_usb2_probe(struct platform_device *pdev)
 {
        struct omap_usb *phy;
@@ -366,14 +399,14 @@ static int omap_usb2_probe(struct platform_device *pdev)
        phy->mask               = phy_data->mask;
        phy->power_on           = phy_data->power_on;
        phy->power_off          = phy_data->power_off;
+       phy->flags              = phy_data->flags;
 
-       if (phy_data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               phy->phy_base = devm_ioremap_resource(&pdev->dev, res);
-               if (IS_ERR(phy->phy_base))
-                       return PTR_ERR(phy->phy_base);
-               phy->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT;
-       }
+       omap_usb2_init_errata(phy);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       phy->phy_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(phy->phy_base))
+               return PTR_ERR(phy->phy_base);
 
        phy->syscon_phy_power = syscon_regmap_lookup_by_phandle(node,
                                                        "syscon-phy-power");
index 9ef2461..0652109 100644 (file)
@@ -58,6 +58,7 @@
 #define CHV_PADCTRL1_CFGLOCK           BIT(31)
 #define CHV_PADCTRL1_INVRXTX_SHIFT     4
 #define CHV_PADCTRL1_INVRXTX_MASK      GENMASK(7, 4)
+#define CHV_PADCTRL1_INVRXTX_TXDATA    BIT(7)
 #define CHV_PADCTRL1_INVRXTX_RXDATA    BIT(6)
 #define CHV_PADCTRL1_INVRXTX_TXENABLE  BIT(5)
 #define CHV_PADCTRL1_ODEN              BIT(3)
@@ -792,11 +793,22 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev,
 static void chv_gpio_clear_triggering(struct chv_pinctrl *pctrl,
                                      unsigned int offset)
 {
+       u32 invrxtx_mask = CHV_PADCTRL1_INVRXTX_MASK;
        u32 value;
 
+       /*
+        * One some devices the GPIO should output the inverted value from what
+        * device-drivers / ACPI code expects (inverted external buffer?). The
+        * BIOS makes this work by setting the CHV_PADCTRL1_INVRXTX_TXDATA flag,
+        * preserve this flag if the pin is already setup as GPIO.
+        */
+       value = chv_readl(pctrl, offset, CHV_PADCTRL0);
+       if (value & CHV_PADCTRL0_GPIOEN)
+               invrxtx_mask &= ~CHV_PADCTRL1_INVRXTX_TXDATA;
+
        value = chv_readl(pctrl, offset, CHV_PADCTRL1);
        value &= ~CHV_PADCTRL1_INTWAKECFG_MASK;
-       value &= ~CHV_PADCTRL1_INVRXTX_MASK;
+       value &= ~invrxtx_mask;
        chv_writel(pctrl, offset, CHV_PADCTRL1, value);
 }
 
index 2f3dfb5..35bbe59 100644 (file)
@@ -259,6 +259,10 @@ bool mtk_is_virt_gpio(struct mtk_pinctrl *hw, unsigned int gpio_n)
 
        desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n];
 
+       /* if the GPIO is not supported for eint mode */
+       if (desc->eint.eint_m == NO_EINT_SUPPORT)
+               return virt_gpio;
+
        if (desc->funcs && !desc->funcs[desc->eint.eint_m].name)
                virt_gpio = true;
 
index a767a05..48e2a6c 100644 (file)
@@ -414,7 +414,7 @@ static struct mvebu_mpp_mode mv98dx3236_mpp_modes[] = {
                 MPP_VAR_FUNCTION(0x1, "i2c0", "sck",        V_98DX3236_PLUS)),
        MPP_MODE(15,
                 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x4, "i2c0", "sda",        V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x1, "i2c0", "sda",        V_98DX3236_PLUS)),
        MPP_MODE(16,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
                 MPP_VAR_FUNCTION(0x4, "dev", "oe",          V_98DX3236_PLUS)),
index a2567e7..c4bcda9 100644 (file)
@@ -1077,12 +1077,10 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
         * when TLMM is powered on. To allow that, enable the GPIO
         * summary line to be wakeup capable at GIC.
         */
-       if (d->parent_data)
-               irq_chip_set_wake_parent(d, on);
-
-       irq_set_irq_wake(pctrl->irq, on);
+       if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs))
+               return irq_chip_set_wake_parent(d, on);
 
-       return 0;
+       return irq_set_irq_wake(pctrl->irq, on);
 }
 
 static int msm_gpio_irq_reqres(struct irq_data *d)
@@ -1243,6 +1241,9 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
        pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres;
        pctrl->irq_chip.irq_set_affinity = msm_gpio_irq_set_affinity;
        pctrl->irq_chip.irq_set_vcpu_affinity = msm_gpio_irq_set_vcpu_affinity;
+       pctrl->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND |
+                               IRQCHIP_SET_TYPE_MASKED |
+                               IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND;
 
        np = of_parse_phandle(pctrl->dev->of_node, "wakeup-parent", 0);
        if (np) {
index a660f12..826df0d 100644 (file)
@@ -1308,7 +1308,7 @@ static const struct msm_pingroup sm8250_groups[] = {
        [178] = PINGROUP(178, WEST, _, _, _, _, _, _, _, _, _),
        [179] = PINGROUP(179, WEST, _, _, _, _, _, _, _, _, _),
        [180] = UFS_RESET(ufs_reset, 0xb8000),
-       [181] = SDC_PINGROUP(sdc2_clk, 0x7000, 14, 6),
+       [181] = SDC_PINGROUP(sdc2_clk, 0xb7000, 14, 6),
        [182] = SDC_PINGROUP(sdc2_cmd, 0xb7000, 11, 3),
        [183] = SDC_PINGROUP(sdc2_data, 0xb7000, 9, 0),
 };
index 190e4a6..f64b828 100644 (file)
@@ -439,7 +439,9 @@ static int olpc_ec_probe(struct platform_device *pdev)
                                                                &config);
        if (IS_ERR(ec->dcon_rdev)) {
                dev_err(&pdev->dev, "failed to register DCON regulator\n");
-               return PTR_ERR(ec->dcon_rdev);
+               err = PTR_ERR(ec->dcon_rdev);
+               kfree(ec);
+               return err;
        }
 
        ec->dbgfs_dir = olpc_ec_setup_debugfs();
index 5e1d14e..0d46706 100644 (file)
@@ -431,7 +431,7 @@ static void olpc_xo175_ec_complete(void *arg)
                        input_sync(priv->pwrbtn);
                        input_report_key(priv->pwrbtn, KEY_POWER, 0);
                        input_sync(priv->pwrbtn);
-                       /* fall through */
+                       fallthrough;
                case EVENT_POWER_PRESS_WAKE:
                case EVENT_TIMED_HOST_WAKE:
                        pm_wakeup_event(priv->pwrbtn->dev.parent,
index 40219bb..0d91d13 100644 (file)
@@ -469,6 +469,7 @@ config FUJITSU_LAPTOP
        depends on BACKLIGHT_CLASS_DEVICE
        depends on ACPI_VIDEO || ACPI_VIDEO = n
        select INPUT_SPARSEKMAP
+       select NEW_LEDS
        select LEDS_CLASS
        help
          This is a driver for laptops built by Fujitsu:
@@ -1112,6 +1113,7 @@ config LG_LAPTOP
        depends on ACPI_WMI
        depends on INPUT
        select INPUT_SPARSEKMAP
+       select NEW_LEDS
        select LEDS_CLASS
        help
         This driver adds support for hotkeys as well as control of keyboard
index 60c18f2..49f4b73 100644 (file)
@@ -1001,7 +1001,7 @@ static acpi_status WMID_get_u32(u32 *value, u32 cap)
                        *value = tmp & 0x1;
                        return 0;
                }
-               /* fall through */
+               fallthrough;
        default:
                return AE_ERROR;
        }
@@ -1328,7 +1328,7 @@ static acpi_status get_u32(u32 *value, u32 cap)
                        status = AMW0_get_u32(value, cap);
                        break;
                }
-               /* fall through */
+               fallthrough;
        case ACER_WMID:
                status = WMID_get_u32(value, cap);
                break;
@@ -1371,7 +1371,7 @@ static acpi_status set_u32(u32 value, u32 cap)
 
                                return AMW0_set_u32(value, cap);
                        }
-                       /* fall through */
+                       fallthrough;
                case ACER_WMID:
                        return WMID_set_u32(value, cap);
                case ACER_WMID_v2:
@@ -1381,7 +1381,7 @@ static acpi_status set_u32(u32 value, u32 cap)
                                return wmid_v2_set_u32(value, cap);
                        else if (wmi_has_guid(WMID_GUID2))
                                return WMID_set_u32(value, cap);
-                       /* fall through */
+                       fallthrough;
                default:
                        return AE_BAD_PARAMETER;
                }
index b2e3d1e..1d9fbab 100644 (file)
@@ -115,6 +115,10 @@ static struct quirk_entry quirk_asus_vendor_backlight = {
        .wmi_backlight_set_devstate = true,
 };
 
+static struct quirk_entry quirk_asus_use_kbd_dock_devid = {
+       .use_kbd_dock_devid = true,
+};
+
 static int dmi_matched(const struct dmi_system_id *dmi)
 {
        pr_info("Identified laptop model '%s'\n", dmi->ident);
@@ -488,6 +492,34 @@ static const struct dmi_system_id asus_quirks[] = {
                },
                .driver_data = &quirk_asus_vendor_backlight,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Asus Transformer T100TA / T100HA / T100CHI",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       /* Match *T100* */
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T100"),
+               },
+               .driver_data = &quirk_asus_use_kbd_dock_devid,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Asus Transformer T101HA",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T101HA"),
+               },
+               .driver_data = &quirk_asus_use_kbd_dock_devid,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Asus Transformer T200TA",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"),
+               },
+               .driver_data = &quirk_asus_use_kbd_dock_devid,
+       },
        {},
 };
 
@@ -593,33 +625,9 @@ static struct asus_wmi_driver asus_nb_wmi_driver = {
        .detect_quirks = asus_nb_wmi_quirks,
 };
 
-static const struct dmi_system_id asus_nb_wmi_blacklist[] __initconst = {
-       {
-               /*
-                * asus-nb-wm adds no functionality. The T100TA has a detachable
-                * USB kbd, so no hotkeys and it has no WMI rfkill; and loading
-                * asus-nb-wm causes the camera LED to turn and _stay_ on.
-                */
-               .matches = {
-                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
-               },
-       },
-       {
-               /* The Asus T200TA has the same issue as the T100TA */
-               .matches = {
-                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T200TA"),
-               },
-       },
-       {} /* Terminating entry */
-};
 
 static int __init asus_nb_wmi_init(void)
 {
-       if (dmi_check_system(asus_nb_wmi_blacklist))
-               return -ENODEV;
-
        return asus_wmi_register_driver(&asus_nb_wmi_driver);
 }
 
index 8f4acdc..39e1a63 100644 (file)
@@ -365,12 +365,14 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
        if (err)
                goto err_free_dev;
 
-       result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
-       if (result >= 0) {
-               input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
-               input_report_switch(asus->inputdev, SW_TABLET_MODE, !result);
-       } else if (result != -ENODEV) {
-               pr_err("Error checking for keyboard-dock: %d\n", result);
+       if (asus->driver->quirks->use_kbd_dock_devid) {
+               result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
+               if (result >= 0) {
+                       input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
+                       input_report_switch(asus->inputdev, SW_TABLET_MODE, !result);
+               } else if (result != -ENODEV) {
+                       pr_err("Error checking for keyboard-dock: %d\n", result);
+               }
        }
 
        err = input_register_device(asus->inputdev);
@@ -442,6 +444,7 @@ static int asus_wmi_battery_add(struct power_supply *battery)
         */
        if (strcmp(battery->desc->name, "BAT0") != 0 &&
            strcmp(battery->desc->name, "BAT1") != 0 &&
+           strcmp(battery->desc->name, "BATC") != 0 &&
            strcmp(battery->desc->name, "BATT") != 0)
                return -ENODEV;
 
@@ -2114,7 +2117,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
                return;
        }
 
-       if (code == NOTIFY_KBD_DOCK_CHANGE) {
+       if (asus->driver->quirks->use_kbd_dock_devid && code == NOTIFY_KBD_DOCK_CHANGE) {
                result = asus_wmi_get_devstate_simple(asus,
                                                      ASUS_WMI_DEVID_KBD_DOCK);
                if (result >= 0) {
index 4f31b68..1a95c17 100644 (file)
@@ -33,6 +33,7 @@ struct quirk_entry {
        bool wmi_backlight_native;
        bool wmi_backlight_set_devstate;
        bool wmi_force_als_set;
+       bool use_kbd_dock_devid;
        int wapf;
        /*
         * For machines with AMD graphic chips, it will send out WMI event
index 5e9c229..70edc5b 100644 (file)
@@ -1587,10 +1587,10 @@ static ssize_t kbd_led_timeout_store(struct device *dev,
                switch (unit) {
                case KBD_TIMEOUT_DAYS:
                        value *= 24;
-                       /* fall through */
+                       fallthrough;
                case KBD_TIMEOUT_HOURS:
                        value *= 60;
-                       /* fall through */
+                       fallthrough;
                case KBD_TIMEOUT_MINUTES:
                        value *= 60;
                        unit = KBD_TIMEOUT_SECONDS;
index e85d8e5..f5901b0 100644 (file)
@@ -167,20 +167,54 @@ static bool intel_vbtn_has_buttons(acpi_handle handle)
        return ACPI_SUCCESS(status);
 }
 
+/*
+ * There are several laptops (non 2-in-1) models out there which support VGBS,
+ * but simply always return 0, which we translate to SW_TABLET_MODE=1. This in
+ * turn causes userspace (libinput) to suppress events from the builtin
+ * keyboard and touchpad, making the laptop essentially unusable.
+ *
+ * Since the problem of wrongly reporting SW_TABLET_MODE=1 in combination
+ * with libinput, leads to a non-usable system. Where as OTOH many people will
+ * not even notice when SW_TABLET_MODE is not being reported, a DMI based allow
+ * list is used here. This list mainly matches on the chassis-type of 2-in-1s.
+ *
+ * There are also some 2-in-1s which use the intel-vbtn ACPI interface to report
+ * SW_TABLET_MODE with a chassis-type of 8 ("Portable") or 10 ("Notebook"),
+ * these are matched on a per model basis, since many normal laptops with a
+ * possible broken VGBS ACPI-method also use these chassis-types.
+ */
+static const struct dmi_system_id dmi_switches_allow_list[] = {
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "31" /* Convertible */),
+               },
+       },
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "32" /* Detachable */),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Stream x360 Convertible PC 11"),
+               },
+       },
+       {} /* Array terminator */
+};
+
 static bool intel_vbtn_has_switches(acpi_handle handle)
 {
-       const char *chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
        unsigned long long vgbs;
        acpi_status status;
 
-       /*
-        * Some normal laptops have a VGBS method despite being non-convertible
-        * and their VGBS method always returns 0, causing detect_tablet_mode()
-        * to report SW_TABLET_MODE=1 to userspace, which causes issues.
-        * These laptops have a DMI chassis_type of 9 ("Laptop"), do not report
-        * switches on any devices with a DMI chassis_type of 9.
-        */
-       if (chassis_type && strcmp(chassis_type, "9") == 0)
+       if (!dmi_check_system(dmi_switches_allow_list))
                return false;
 
        status = acpi_evaluate_integer(handle, "VGBS", NULL, &vgbs);
index 7312818..7379768 100644 (file)
 
 static void intel_pmc_core_release(struct device *dev)
 {
-       /* Nothing to do. */
+       kfree(dev);
 }
 
-static struct platform_device pmc_core_device = {
-       .name = "intel_pmc_core",
-       .dev  = {
-               .release = intel_pmc_core_release,
-       },
-};
+static struct platform_device *pmc_core_device;
 
 /*
  * intel_pmc_core_platform_ids is the list of platforms where we want to
@@ -52,6 +47,8 @@ MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_platform_ids);
 
 static int __init pmc_core_platform_init(void)
 {
+       int retval;
+
        /* Skip creating the platform device if ACPI already has a device */
        if (acpi_dev_present("INT33A1", NULL, -1))
                return -ENODEV;
@@ -59,12 +56,23 @@ static int __init pmc_core_platform_init(void)
        if (!x86_match_cpu(intel_pmc_core_platform_ids))
                return -ENODEV;
 
-       return platform_device_register(&pmc_core_device);
+       pmc_core_device = kzalloc(sizeof(*pmc_core_device), GFP_KERNEL);
+       if (!pmc_core_device)
+               return -ENOMEM;
+
+       pmc_core_device->name = "intel_pmc_core";
+       pmc_core_device->dev.release = intel_pmc_core_release;
+
+       retval = platform_device_register(pmc_core_device);
+       if (retval)
+               kfree(pmc_core_device);
+
+       return retval;
 }
 
 static void __exit pmc_core_platform_exit(void)
 {
-       platform_device_unregister(&pmc_core_device);
+       platform_device_unregister(pmc_core_device);
 }
 
 module_init(pmc_core_platform_init);
index 8cf8c1b..1506ec0 100644 (file)
 #define MLXPLAT_CPLD_NR_NONE                   -1
 #define MLXPLAT_CPLD_PSU_DEFAULT_NR            10
 #define MLXPLAT_CPLD_PSU_MSNXXXX_NR            4
-#define MLXPLAT_CPLD_PSU_MSNXXXX_NR2           3
 #define MLXPLAT_CPLD_FAN1_DEFAULT_NR           11
 #define MLXPLAT_CPLD_FAN2_DEFAULT_NR           12
 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR           13
@@ -347,6 +346,15 @@ static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
        },
 };
 
+static struct i2c_board_info mlxplat_mlxcpld_ext_pwr[] = {
+       {
+               I2C_BOARD_INFO("dps460", 0x5b),
+       },
+       {
+               I2C_BOARD_INFO("dps460", 0x5a),
+       },
+};
+
 static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
        {
                I2C_BOARD_INFO("24c32", 0x50),
@@ -921,15 +929,15 @@ static struct mlxreg_core_data mlxplat_mlxcpld_ext_pwr_items_data[] = {
                .label = "pwr3",
                .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
                .mask = BIT(2),
-               .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
-               .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR2,
+               .hpdev.brdinfo = &mlxplat_mlxcpld_ext_pwr[0],
+               .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
        },
        {
                .label = "pwr4",
                .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
                .mask = BIT(3),
-               .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
-               .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR2,
+               .hpdev.brdinfo = &mlxplat_mlxcpld_ext_pwr[1],
+               .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
        },
 };
 
index 6aff6cf..c37349f 100644 (file)
@@ -32,7 +32,7 @@
 #define APU2_GPIO_REG_LED3             AMD_FCH_GPIO_REG_GPIO59_DEVSLP1
 #define APU2_GPIO_REG_MODESW           AMD_FCH_GPIO_REG_GPIO32_GE1
 #define APU2_GPIO_REG_SIMSWAP          AMD_FCH_GPIO_REG_GPIO33_GE2
-#define APU2_GPIO_REG_MPCIE2           AMD_FCH_GPIO_REG_GPIO59_DEVSLP0
+#define APU2_GPIO_REG_MPCIE2           AMD_FCH_GPIO_REG_GPIO55_DEVSLP0
 #define APU2_GPIO_REG_MPCIE3           AMD_FCH_GPIO_REG_GPIO51
 
 /* Order in which the GPIO lines are defined in the register list */
index ec51522..d8afed5 100644 (file)
@@ -84,28 +84,28 @@ static void surface_button_notify(struct acpi_device *device, u32 event)
        /* Power button press,release handle */
        case SURFACE_BUTTON_NOTIFY_PRESS_POWER:
                pressed = true;
-               /*fall through*/
+               fallthrough;
        case SURFACE_BUTTON_NOTIFY_RELEASE_POWER:
                key_code = KEY_POWER;
                break;
        /* Home button press,release handle */
        case SURFACE_BUTTON_NOTIFY_PRESS_HOME:
                pressed = true;
-               /*fall through*/
+               fallthrough;
        case SURFACE_BUTTON_NOTIFY_RELEASE_HOME:
                key_code = KEY_LEFTMETA;
                break;
        /* Volume up button press,release handle */
        case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP:
                pressed = true;
-               /*fall through*/
+               fallthrough;
        case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP:
                key_code = KEY_VOLUMEUP;
                break;
        /* Volume down button press,release handle */
        case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN:
                pressed = true;
-               /*fall through*/
+               fallthrough;
        case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN:
                key_code = KEY_VOLUMEDOWN;
                break;
index 4864a5c..eae3579 100644 (file)
@@ -2569,7 +2569,7 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
  */
 static int hotkey_kthread(void *data)
 {
-       struct tp_nvram_state s[2];
+       struct tp_nvram_state s[2] = { 0 };
        u32 poll_mask, event_mask;
        unsigned int si, so;
        unsigned long t;
@@ -4060,7 +4060,7 @@ static bool hotkey_notify_6xxx(const u32 hkey,
                 * AC status changed; can be triggered by plugging or
                 * unplugging AC adapter, docking or undocking. */
 
-               /* fallthrough */
+               fallthrough;
 
        case TP_HKEY_EV_KEY_NUMLOCK:
        case TP_HKEY_EV_KEY_FN:
@@ -4176,7 +4176,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                                known_ev = true;
                                break;
                        }
-                       /* fallthrough - to default */
+                       fallthrough;    /* to default */
                default:
                        known_ev = false;
                }
@@ -6266,7 +6266,7 @@ static int thermal_get_sensor(int idx, s32 *value)
                        idx -= 8;
                }
 #endif
-               /* fallthrough */
+               fallthrough;
        case TPACPI_THERMAL_TPEC_8:
                if (idx <= 7) {
                        if (!acpi_ec_read(t + idx, &tmp))
@@ -6829,8 +6829,10 @@ static int __init tpacpi_query_bcl_levels(acpi_handle handle)
        list_for_each_entry(child, &device->children, node) {
                acpi_status status = acpi_evaluate_object(child->handle, "_BCL",
                                                          NULL, &buffer);
-               if (ACPI_FAILURE(status))
+               if (ACPI_FAILURE(status)) {
+                       buffer.length = ACPI_ALLOCATE_BUFFER;
                        continue;
+               }
 
                obj = (union acpi_object *)buffer.pointer;
                if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
index 36fff00..e557d75 100644 (file)
@@ -2748,7 +2748,7 @@ static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
                                result = hci_write(dev, HCI_SYSTEM_EVENT, 1);
                                if (result == TOS_SUCCESS)
                                        pr_notice("Re-enabled hotkeys\n");
-                               /* Fall through */
+                               fallthrough;
                        default:
                                retries--;
                                break;
index 5c22301..dda60f8 100644 (file)
@@ -373,6 +373,23 @@ static const struct ts_dmi_data jumper_ezpad_mini3_data = {
        .properties     = jumper_ezpad_mini3_props,
 };
 
+static const struct property_entry mpman_converter9_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-min-x", 8),
+       PROPERTY_ENTRY_U32("touchscreen-min-y", 8),
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1664),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 880),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+       PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-mpman-converter9.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       { }
+};
+
+static const struct ts_dmi_data mpman_converter9_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = mpman_converter9_props,
+};
+
 static const struct property_entry mpman_mpwin895cl_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-min-x", 3),
        PROPERTY_ENTRY_U32("touchscreen-min-y", 9),
@@ -977,6 +994,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                },
        },
        {
+               /* MP Man Converter 9 */
+               .driver_data = (void *)&mpman_converter9_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MPMAN"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Converter9"),
+               },
+       },
+       {
                /* MP Man MPWIN895CL */
                .driver_data = (void *)&mpman_mpwin895cl_data,
                .matches = {
index 9469fe1..db65be0 100644 (file)
@@ -748,7 +748,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
                                                USB_CH_IP_CUR_LVL_1P5;
                        break;
                }
-               /* else, fall through */
+               fallthrough;
        case USB_STAT_HM_IDGND:
                dev_err(di->dev, "USB Type - Charging not allowed\n");
                di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05;
@@ -2410,7 +2410,7 @@ static void ab8500_charger_usb_state_changed_work(struct work_struct *work)
                 * of 1sec for enabling charging
                 */
                msleep(1000);
-               /* Intentional fall through */
+               fallthrough;
        case AB8500_BM_USB_STATE_CONFIGURED:
                /*
                 * USB is configured, enable charging with the charging
index 751c4f6..7eec415 100644 (file)
@@ -1542,7 +1542,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
                ab8500_fg_discharge_state_to(di,
                        AB8500_FG_DISCHARGE_INITMEASURING);
 
-               /* Intentional fallthrough */
+               fallthrough;
        case AB8500_FG_DISCHARGE_INITMEASURING:
                /*
                 * Discard a number of samples during startup.
@@ -1572,7 +1572,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
                ab8500_fg_discharge_state_to(di,
                        AB8500_FG_DISCHARGE_RECOVERY);
 
-               /* Intentional fallthrough */
+               fallthrough;
 
        case AB8500_FG_DISCHARGE_RECOVERY:
                sleep_time = di->bm->fg_params->recovery_sleep_timer;
index 2fb33a0..175c4f3 100644 (file)
@@ -1419,7 +1419,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
                abx500_chargalg_stop_charging(di);
                di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
                abx500_chargalg_state_to(di, STATE_HANDHELD);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_HANDHELD:
                break;
@@ -1435,7 +1435,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
                di->maintenance_chg = false;
                abx500_chargalg_state_to(di, STATE_SUSPENDED);
                power_supply_changed(di->chargalg_psy);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_SUSPENDED:
                /* CHARGING is suspended */
@@ -1444,7 +1444,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
        case STATE_BATT_REMOVED_INIT:
                abx500_chargalg_stop_charging(di);
                abx500_chargalg_state_to(di, STATE_BATT_REMOVED);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_BATT_REMOVED:
                if (!di->events.batt_rem)
@@ -1454,7 +1454,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
        case STATE_HW_TEMP_PROTECT_INIT:
                abx500_chargalg_stop_charging(di);
                abx500_chargalg_state_to(di, STATE_HW_TEMP_PROTECT);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_HW_TEMP_PROTECT:
                if (!di->events.main_thermal_prot &&
@@ -1465,7 +1465,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
        case STATE_OVV_PROTECT_INIT:
                abx500_chargalg_stop_charging(di);
                abx500_chargalg_state_to(di, STATE_OVV_PROTECT);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_OVV_PROTECT:
                if (!di->events.vbus_ovv &&
@@ -1479,7 +1479,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
        case STATE_CHG_NOT_OK_INIT:
                abx500_chargalg_stop_charging(di);
                abx500_chargalg_state_to(di, STATE_CHG_NOT_OK);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_CHG_NOT_OK:
                if (!di->events.mainextchnotok &&
@@ -1490,7 +1490,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
        case STATE_SAFETY_TIMER_EXPIRED_INIT:
                abx500_chargalg_stop_charging(di);
                abx500_chargalg_state_to(di, STATE_SAFETY_TIMER_EXPIRED);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_SAFETY_TIMER_EXPIRED:
                /* We exit this state when charger is removed */
@@ -1537,7 +1537,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
        case STATE_WAIT_FOR_RECHARGE_INIT:
                abx500_chargalg_hold_charging(di);
                abx500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_WAIT_FOR_RECHARGE:
                if (di->batt_data.percent <=
@@ -1558,7 +1558,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
                                di->bm->batt_id].maint_a_cur_lvl);
                abx500_chargalg_state_to(di, STATE_MAINTENANCE_A);
                power_supply_changed(di->chargalg_psy);
-               /* Intentional fallthrough*/
+               fallthrough;
 
        case STATE_MAINTENANCE_A:
                if (di->events.maintenance_timer_expired) {
@@ -1578,7 +1578,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
                                di->bm->batt_id].maint_b_cur_lvl);
                abx500_chargalg_state_to(di, STATE_MAINTENANCE_B);
                power_supply_changed(di->chargalg_psy);
-               /* Intentional fallthrough*/
+               fallthrough;
 
        case STATE_MAINTENANCE_B:
                if (di->events.maintenance_timer_expired) {
@@ -1597,7 +1597,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
                di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
                abx500_chargalg_state_to(di, STATE_TEMP_LOWHIGH);
                power_supply_changed(di->chargalg_psy);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_TEMP_LOWHIGH:
                if (!di->events.btemp_lowhigh)
@@ -1607,7 +1607,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
        case STATE_WD_EXPIRED_INIT:
                abx500_chargalg_stop_charging(di);
                abx500_chargalg_state_to(di, STATE_WD_EXPIRED);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_WD_EXPIRED:
                if (!di->events.ac_wd_expired &&
@@ -1618,7 +1618,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
        case STATE_TEMP_UNDEROVER_INIT:
                abx500_chargalg_stop_charging(di);
                abx500_chargalg_state_to(di, STATE_TEMP_UNDEROVER);
-               /* Intentional fallthrough */
+               fallthrough;
 
        case STATE_TEMP_UNDEROVER:
                if (!di->events.btemp_underover)
index d01dc03..0eaa86c 100644 (file)
@@ -349,7 +349,7 @@ static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power,
        case 100000:
                if (power->axp20x_id == AXP221_ID)
                        return -EINVAL;
-               /* fall through */
+               fallthrough;
        case 500000:
        case 900000:
                val = (900000 - intval) / 400000;
index 2a45e84..d89e08e 100644 (file)
@@ -383,7 +383,7 @@ static int cros_usbpd_charger_get_prop(struct power_supply *psy,
                 */
                if (ec_device->mkbp_event_supported || port->psy_online)
                        break;
-               /* fall through */
+               fallthrough;
        case POWER_SUPPLY_PROP_CURRENT_MAX:
        case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
index 5fca496..8878f91 100644 (file)
@@ -121,7 +121,7 @@ static irqreturn_t max8925_charger_handler(int irq, void *data)
        case MAX8925_IRQ_VCHG_THM_OK_F:
                /* Battery is not ready yet */
                dev_dbg(chip->dev, "Battery temperature is out of range\n");
-               /* Fall through */
+               fallthrough;
        case MAX8925_IRQ_VCHG_DC_OVP:
                dev_dbg(chip->dev, "Error detection\n");
                __set_charger(info, 0);
index 49c3508..7439753 100644 (file)
@@ -280,6 +280,12 @@ static int sbs_update_presence(struct sbs_info *chip, bool is_present)
        else
                client->flags &= ~I2C_CLIENT_PEC;
 
+       if (of_device_is_compatible(client->dev.parent->of_node, "google,cros-ec-i2c-tunnel")
+           && client->flags & I2C_CLIENT_PEC) {
+               dev_info(&client->dev, "Disabling PEC because of broken Cros-EC implementation\n");
+               client->flags &= ~I2C_CLIENT_PEC;
+       }
+
        dev_dbg(&client->dev, "PEC: %s\n", (client->flags & I2C_CLIENT_PEC) ?
                "enabled" : "disabled");
 
index 65832bc..18b33f1 100644 (file)
@@ -665,7 +665,7 @@ static int wm831x_power_probe(struct platform_device *pdev)
                break;
        default:
                dev_err(&pdev->dev, "Failed to find USB phy: %d\n", ret);
-               /* fall-through */
+               fallthrough;
        case -EPROBE_DEFER:
                goto err_bat_irq;
                break;
index 26923af..e05cee4 100644 (file)
@@ -227,7 +227,7 @@ static irqreturn_t wm8350_charger_handler(int irq, void *data)
        case WM8350_IRQ_EXT_USB_FB:
        case WM8350_IRQ_EXT_WALL_FB:
                wm8350_charger_config(wm8350, policy);
-               /* Fall through */
+               fallthrough;
        case WM8350_IRQ_EXT_BAT_FB:
                power_supply_changed(power->battery);
                power_supply_changed(power->usb);
index 6f55aae..983d75b 100644 (file)
@@ -1035,7 +1035,11 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L,         &rapl_defaults_core),
        X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE,           &rapl_defaults_core),
        X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L,         &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE,           &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE,          &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE,           &rapl_defaults_core),
        X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X,    &rapl_defaults_spr_server),
+       X86_MATCH_INTEL_FAM6_MODEL(LAKEFIELD,           &rapl_defaults_core),
 
        X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,     &rapl_defaults_byt),
        X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,        &rapl_defaults_cht),
index 24f04ff..9d66257 100644 (file)
@@ -769,7 +769,7 @@ static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf)
                switch (info->monitor_type) {
                case PS3AV_MONITOR_TYPE_DVI:
                        dvi = PS3AV_MODE_DVI;
-                       /* fall through */
+                       fallthrough;
                case PS3AV_MONITOR_TYPE_HDMI:
                        id = ps3av_hdmi_get_id(info);
                        break;
index f0e650c..c222066 100644 (file)
@@ -693,11 +693,11 @@ void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport,
        switch (ch) {
        case PS3AV_CMD_AUDIO_NUM_OF_CH_8:
                audio->audio_enable[3] = 1;
-               /* fall through */
+               fallthrough;
        case PS3AV_CMD_AUDIO_NUM_OF_CH_6:
                audio->audio_enable[2] = 1;
                audio->audio_enable[1] = 1;
-               /* fall through */
+               fallthrough;
        case PS3AV_CMD_AUDIO_NUM_OF_CH_2:
        default:
                audio->audio_enable[0] = 1;
index e4c422d..b9f8514 100644 (file)
@@ -37,7 +37,7 @@ config RAPIDIO_ENABLE_RX_TX_PORTS
 config RAPIDIO_DMA_ENGINE
        bool "DMA Engine support for RapidIO"
        depends on RAPIDIO
-       select DMADEVICES
+       depends on DMADEVICES
        select DMA_ENGINE
        help
          Say Y here if you want to use DMA Engine frameork for RapidIO data
index c07ceec..a303429 100644 (file)
@@ -2150,7 +2150,7 @@ static void mport_release_mapping(struct kref *ref)
        switch (map->dir) {
        case MAP_INBOUND:
                rio_unmap_inb_region(mport, map->phys_addr);
-               /* fall through */
+               fallthrough;
        case MAP_DMA:
                dma_free_coherent(mport->dev.parent, map->size,
                                  map->virt_addr, map->phys_addr);
index 569d9ad..ddecf25 100644 (file)
@@ -435,7 +435,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(action_threshold_ops, u64_get, action_threshold_set, "%
 
 static const char * const bins[] = { "00", "01", "10", "11" };
 
-static int array_dump(struct seq_file *m, void *v)
+static int array_show(struct seq_file *m, void *v)
 {
        struct ce_array *ca = &ce_arr;
        int i;
@@ -467,18 +467,7 @@ static int array_dump(struct seq_file *m, void *v)
        return 0;
 }
 
-static int array_open(struct inode *inode, struct file *filp)
-{
-       return single_open(filp, array_dump, NULL);
-}
-
-static const struct file_operations array_ops = {
-       .owner   = THIS_MODULE,
-       .open    = array_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(array);
 
 static int __init create_debugfs_nodes(void)
 {
@@ -513,7 +502,7 @@ static int __init create_debugfs_nodes(void)
                goto err;
        }
 
-       array = debugfs_create_file("array", S_IRUSR, d, NULL, &array_ops);
+       array = debugfs_create_file("array", S_IRUSR, d, NULL, &array_fops);
        if (!array) {
                pr_warn("Error creating array debugfs node!\n");
                goto err;
@@ -553,20 +542,20 @@ static struct notifier_block cec_nb = {
        .priority       = MCE_PRIO_CEC,
 };
 
-static void __init cec_init(void)
+static int __init cec_init(void)
 {
        if (ce_arr.disabled)
-               return;
+               return -ENODEV;
 
        ce_arr.array = (void *)get_zeroed_page(GFP_KERNEL);
        if (!ce_arr.array) {
                pr_err("Error allocating CE array page!\n");
-               return;
+               return -ENOMEM;
        }
 
        if (create_debugfs_nodes()) {
                free_page((unsigned long)ce_arr.array);
-               return;
+               return -ENOMEM;
        }
 
        INIT_DELAYED_WORK(&cec_work, cec_work_fn);
@@ -575,6 +564,7 @@ static void __init cec_init(void)
        mce_register_decode_chain(&cec_nb);
 
        pr_info("Correctable Errors collector initialized.\n");
+       return 0;
 }
 late_initcall(cec_init);
 
index fbc95ca..cd12241 100644 (file)
@@ -42,8 +42,9 @@
 
 #define AXP20X_DCDC2_V_OUT_MASK                GENMASK(5, 0)
 #define AXP20X_DCDC3_V_OUT_MASK                GENMASK(7, 0)
-#define AXP20X_LDO24_V_OUT_MASK                GENMASK(7, 4)
+#define AXP20X_LDO2_V_OUT_MASK         GENMASK(7, 4)
 #define AXP20X_LDO3_V_OUT_MASK         GENMASK(6, 0)
+#define AXP20X_LDO4_V_OUT_MASK         GENMASK(3, 0)
 #define AXP20X_LDO5_V_OUT_MASK         GENMASK(7, 4)
 
 #define AXP20X_PWR_OUT_EXTEN_MASK      BIT_MASK(0)
@@ -399,7 +400,7 @@ static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp)
                if (rate_count > 0)
                        break;
 
-               /* fall through */
+               fallthrough;
        default:
                /* Not supported for this regulator */
                return -ENOTSUPP;
@@ -542,14 +543,14 @@ static const struct regulator_desc axp20x_regulators[] = {
                 AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_DCDC3_MASK),
        AXP_DESC_FIXED(AXP20X, LDO1, "ldo1", "acin", 1300),
        AXP_DESC(AXP20X, LDO2, "ldo2", "ldo24in", 1800, 3300, 100,
-                AXP20X_LDO24_V_OUT, AXP20X_LDO24_V_OUT_MASK,
+                AXP20X_LDO24_V_OUT, AXP20X_LDO2_V_OUT_MASK,
                 AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_LDO2_MASK),
        AXP_DESC(AXP20X, LDO3, "ldo3", "ldo3in", 700, 3500, 25,
                 AXP20X_LDO3_V_OUT, AXP20X_LDO3_V_OUT_MASK,
                 AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_LDO3_MASK),
        AXP_DESC_RANGES(AXP20X, LDO4, "ldo4", "ldo24in",
                        axp20x_ldo4_ranges, AXP20X_LDO4_V_OUT_NUM_VOLTAGES,
-                       AXP20X_LDO24_V_OUT, AXP20X_LDO24_V_OUT_MASK,
+                       AXP20X_LDO24_V_OUT, AXP20X_LDO4_V_OUT_MASK,
                        AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_LDO4_MASK),
        AXP_DESC_IO(AXP20X, LDO5, "ldo5", "ldo5in", 1800, 3300, 100,
                    AXP20X_LDO5_V_OUT, AXP20X_LDO5_V_OUT_MASK,
@@ -1022,7 +1023,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
                 * (See include/linux/mfd/axp20x.h)
                 */
                reg = AXP803_DCDC_FREQ_CTRL;
-               /* Fall through - to the check below.*/
+               fallthrough;    /* to the check below */
        case AXP806_ID:
                /*
                 * AXP806 also have DCDC work frequency setting register at a
@@ -1030,7 +1031,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
                 */
                if (axp20x->variant == AXP806_ID)
                        reg = AXP806_DCDC_FREQ_CTRL;
-               /* Fall through */
+               fallthrough;
        case AXP221_ID:
        case AXP223_ID:
        case AXP809_ID:
@@ -1118,7 +1119,7 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
                 * (See include/linux/mfd/axp20x.h)
                 */
                reg = AXP806_DCDC_MODE_CTRL2;
-                /* Fall through - to the check below. */
+               fallthrough;    /* to the check below */
        case AXP221_ID:
        case AXP223_ID:
        case AXP809_ID:
index 75ff7c5..7ff507e 100644 (file)
@@ -236,8 +236,8 @@ static bool regulator_supply_is_couple(struct regulator_dev *rdev)
 static void regulator_unlock_recursive(struct regulator_dev *rdev,
                                       unsigned int n_coupled)
 {
-       struct regulator_dev *c_rdev;
-       int i;
+       struct regulator_dev *c_rdev, *supply_rdev;
+       int i, supply_n_coupled;
 
        for (i = n_coupled; i > 0; i--) {
                c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1];
@@ -245,10 +245,13 @@ static void regulator_unlock_recursive(struct regulator_dev *rdev,
                if (!c_rdev)
                        continue;
 
-               if (c_rdev->supply && !regulator_supply_is_couple(c_rdev))
-                       regulator_unlock_recursive(
-                                       c_rdev->supply->rdev,
-                                       c_rdev->coupling_desc.n_coupled);
+               if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) {
+                       supply_rdev = c_rdev->supply->rdev;
+                       supply_n_coupled = supply_rdev->coupling_desc.n_coupled;
+
+                       regulator_unlock_recursive(supply_rdev,
+                                                  supply_n_coupled);
+               }
 
                regulator_unlock(c_rdev);
        }
@@ -1461,7 +1464,7 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
                                      const char *consumer_dev_name,
                                      const char *supply)
 {
-       struct regulator_map *node;
+       struct regulator_map *node, *new_node;
        int has_dev;
 
        if (supply == NULL)
@@ -1472,6 +1475,22 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
        else
                has_dev = 0;
 
+       new_node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
+       if (new_node == NULL)
+               return -ENOMEM;
+
+       new_node->regulator = rdev;
+       new_node->supply = supply;
+
+       if (has_dev) {
+               new_node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
+               if (new_node->dev_name == NULL) {
+                       kfree(new_node);
+                       return -ENOMEM;
+               }
+       }
+
+       mutex_lock(&regulator_list_mutex);
        list_for_each_entry(node, &regulator_map_list, list) {
                if (node->dev_name && consumer_dev_name) {
                        if (strcmp(node->dev_name, consumer_dev_name) != 0)
@@ -1489,26 +1508,19 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
                         node->regulator->desc->name,
                         supply,
                         dev_name(&rdev->dev), rdev_get_name(rdev));
-               return -EBUSY;
+               goto fail;
        }
 
-       node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
-       if (node == NULL)
-               return -ENOMEM;
-
-       node->regulator = rdev;
-       node->supply = supply;
-
-       if (has_dev) {
-               node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
-               if (node->dev_name == NULL) {
-                       kfree(node);
-                       return -ENOMEM;
-               }
-       }
+       list_add(&new_node->list, &regulator_map_list);
+       mutex_unlock(&regulator_list_mutex);
 
-       list_add(&node->list, &regulator_map_list);
        return 0;
+
+fail:
+       mutex_unlock(&regulator_list_mutex);
+       kfree(new_node->dev_name);
+       kfree(new_node);
+       return -EBUSY;
 }
 
 static void unset_regulator_supplies(struct regulator_dev *rdev)
@@ -1580,44 +1592,53 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
                                          const char *supply_name)
 {
        struct regulator *regulator;
-       char buf[REG_STR_SIZE];
-       int err, size;
+       int err;
+
+       if (dev) {
+               char buf[REG_STR_SIZE];
+               int size;
+
+               size = snprintf(buf, REG_STR_SIZE, "%s-%s",
+                               dev->kobj.name, supply_name);
+               if (size >= REG_STR_SIZE)
+                       return NULL;
+
+               supply_name = kstrdup(buf, GFP_KERNEL);
+               if (supply_name == NULL)
+                       return NULL;
+       } else {
+               supply_name = kstrdup_const(supply_name, GFP_KERNEL);
+               if (supply_name == NULL)
+                       return NULL;
+       }
 
        regulator = kzalloc(sizeof(*regulator), GFP_KERNEL);
-       if (regulator == NULL)
+       if (regulator == NULL) {
+               kfree(supply_name);
                return NULL;
+       }
 
-       regulator_lock(rdev);
        regulator->rdev = rdev;
+       regulator->supply_name = supply_name;
+
+       regulator_lock(rdev);
        list_add(&regulator->list, &rdev->consumer_list);
+       regulator_unlock(rdev);
 
        if (dev) {
                regulator->dev = dev;
 
                /* Add a link to the device sysfs entry */
-               size = snprintf(buf, REG_STR_SIZE, "%s-%s",
-                               dev->kobj.name, supply_name);
-               if (size >= REG_STR_SIZE)
-                       goto overflow_err;
-
-               regulator->supply_name = kstrdup(buf, GFP_KERNEL);
-               if (regulator->supply_name == NULL)
-                       goto overflow_err;
-
                err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj,
-                                       buf);
+                                              supply_name);
                if (err) {
                        rdev_dbg(rdev, "could not add device link %s err %d\n",
                                  dev->kobj.name, err);
                        /* non-fatal */
                }
-       } else {
-               regulator->supply_name = kstrdup_const(supply_name, GFP_KERNEL);
-               if (regulator->supply_name == NULL)
-                       goto overflow_err;
        }
 
-       regulator->debugfs = debugfs_create_dir(regulator->supply_name,
+       regulator->debugfs = debugfs_create_dir(supply_name,
                                                rdev->debugfs);
        if (!regulator->debugfs) {
                rdev_dbg(rdev, "Failed to create debugfs directory\n");
@@ -1642,13 +1663,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
            _regulator_is_enabled(rdev))
                regulator->always_on = true;
 
-       regulator_unlock(rdev);
        return regulator;
-overflow_err:
-       list_del(&regulator->list);
-       kfree(regulator);
-       regulator_unlock(rdev);
-       return NULL;
 }
 
 static int _regulator_get_enable_time(struct regulator_dev *rdev)
@@ -1895,7 +1910,7 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
                case EXCLUSIVE_GET:
                        dev_warn(dev,
                                 "dummy supplies not allowed for exclusive requests\n");
-                       /* fall through */
+                       fallthrough;
 
                default:
                        return ERR_PTR(-ENODEV);
@@ -2230,10 +2245,13 @@ EXPORT_SYMBOL_GPL(regulator_bulk_unregister_supply_alias);
 static int regulator_ena_gpio_request(struct regulator_dev *rdev,
                                const struct regulator_config *config)
 {
-       struct regulator_enable_gpio *pin;
+       struct regulator_enable_gpio *pin, *new_pin;
        struct gpio_desc *gpiod;
 
        gpiod = config->ena_gpiod;
+       new_pin = kzalloc(sizeof(*new_pin), GFP_KERNEL);
+
+       mutex_lock(&regulator_list_mutex);
 
        list_for_each_entry(pin, &regulator_ena_gpio_list, list) {
                if (pin->gpiod == gpiod) {
@@ -2242,9 +2260,13 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev,
                }
        }
 
-       pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL);
-       if (pin == NULL)
+       if (new_pin == NULL) {
+               mutex_unlock(&regulator_list_mutex);
                return -ENOMEM;
+       }
+
+       pin = new_pin;
+       new_pin = NULL;
 
        pin->gpiod = gpiod;
        list_add(&pin->list, &regulator_ena_gpio_list);
@@ -2252,6 +2274,10 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev,
 update_ena_gpio_to_rdev:
        pin->request_count++;
        rdev->ena_pin = pin;
+
+       mutex_unlock(&regulator_list_mutex);
+       kfree(new_pin);
+
        return 0;
 }
 
@@ -2264,19 +2290,19 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev)
 
        /* Free the GPIO only in case of no use */
        list_for_each_entry_safe(pin, n, &regulator_ena_gpio_list, list) {
-               if (pin->gpiod == rdev->ena_pin->gpiod) {
-                       if (pin->request_count <= 1) {
-                               pin->request_count = 0;
-                               gpiod_put(pin->gpiod);
-                               list_del(&pin->list);
-                               kfree(pin);
-                               rdev->ena_pin = NULL;
-                               return;
-                       } else {
-                               pin->request_count--;
-                       }
-               }
+               if (pin != rdev->ena_pin)
+                       continue;
+
+               if (--pin->request_count)
+                       break;
+
+               gpiod_put(pin->gpiod);
+               list_del(&pin->list);
+               kfree(pin);
+               break;
        }
+
+       rdev->ena_pin = NULL;
 }
 
 /**
@@ -4949,13 +4975,9 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev)
                        return;
                }
 
-               regulator_lock(c_rdev);
-
                c_desc->coupled_rdevs[i] = c_rdev;
                c_desc->n_resolved++;
 
-               regulator_unlock(c_rdev);
-
                regulator_resolve_coupling(c_rdev);
        }
 }
@@ -5040,7 +5062,10 @@ static int regulator_init_coupling(struct regulator_dev *rdev)
        if (!of_check_coupling_data(rdev))
                return -EPERM;
 
+       mutex_lock(&regulator_list_mutex);
        rdev->coupling_desc.coupler = regulator_find_coupler(rdev);
+       mutex_unlock(&regulator_list_mutex);
+
        if (IS_ERR(rdev->coupling_desc.coupler)) {
                err = PTR_ERR(rdev->coupling_desc.coupler);
                rdev_err(rdev, "failed to get coupler: %d\n", err);
@@ -5141,6 +5166,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
                ret = -ENOMEM;
                goto rinse;
        }
+       device_initialize(&rdev->dev);
 
        /*
         * Duplicate the config so the driver could override it after
@@ -5148,9 +5174,8 @@ regulator_register(const struct regulator_desc *regulator_desc,
         */
        config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL);
        if (config == NULL) {
-               kfree(rdev);
                ret = -ENOMEM;
-               goto rinse;
+               goto clean;
        }
 
        init_data = regulator_of_get_init_data(dev, regulator_desc, config,
@@ -5162,10 +5187,8 @@ regulator_register(const struct regulator_desc *regulator_desc,
         * from a gpio extender or something else.
         */
        if (PTR_ERR(init_data) == -EPROBE_DEFER) {
-               kfree(config);
-               kfree(rdev);
                ret = -EPROBE_DEFER;
-               goto rinse;
+               goto clean;
        }
 
        /*
@@ -5206,9 +5229,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
        }
 
        if (config->ena_gpiod) {
-               mutex_lock(&regulator_list_mutex);
                ret = regulator_ena_gpio_request(rdev, config);
-               mutex_unlock(&regulator_list_mutex);
                if (ret != 0) {
                        rdev_err(rdev, "Failed to request enable GPIO: %d\n",
                                 ret);
@@ -5220,7 +5241,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
        }
 
        /* register with sysfs */
-       device_initialize(&rdev->dev);
        rdev->dev.class = &regulator_class;
        rdev->dev.parent = dev;
        dev_set_name(&rdev->dev, "regulator.%lu",
@@ -5248,27 +5268,22 @@ regulator_register(const struct regulator_desc *regulator_desc,
        if (ret < 0)
                goto wash;
 
-       mutex_lock(&regulator_list_mutex);
        ret = regulator_init_coupling(rdev);
-       mutex_unlock(&regulator_list_mutex);
        if (ret < 0)
                goto wash;
 
        /* add consumers devices */
        if (init_data) {
-               mutex_lock(&regulator_list_mutex);
                for (i = 0; i < init_data->num_consumer_supplies; i++) {
                        ret = set_consumer_device_supply(rdev,
                                init_data->consumer_supplies[i].dev_name,
                                init_data->consumer_supplies[i].supply);
                        if (ret < 0) {
-                               mutex_unlock(&regulator_list_mutex);
                                dev_err(dev, "Failed to set supply %s\n",
                                        init_data->consumer_supplies[i].supply);
                                goto unset_supplies;
                        }
                }
-               mutex_unlock(&regulator_list_mutex);
        }
 
        if (!rdev->desc->ops->get_voltage &&
@@ -5303,13 +5318,11 @@ wash:
        mutex_lock(&regulator_list_mutex);
        regulator_ena_gpio_free(rdev);
        mutex_unlock(&regulator_list_mutex);
-       put_device(&rdev->dev);
-       rdev = NULL;
 clean:
        if (dangling_of_gpiod)
                gpiod_put(config->ena_gpiod);
-       kfree(rdev);
        kfree(config);
+       put_device(&rdev->dev);
 rinse:
        if (dangling_cfg_gpiod)
                gpiod_put(cfg->ena_gpiod);
index 3117bbd..eb3fc1d 100644 (file)
@@ -170,6 +170,9 @@ static int cros_ec_regulator_init_info(struct device *dev,
        data->voltages_mV =
                devm_kmemdup(dev, resp.voltages_mv,
                             sizeof(u16) * data->num_voltages, GFP_KERNEL);
+       if (!data->voltages_mV)
+               return -ENOMEM;
+
        data->desc.n_voltages = data->num_voltages;
 
        /* Make sure the returned name is always a valid string */
index d54830e..142a70a 100644 (file)
@@ -182,7 +182,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
 
                drvdata->enable_clock = devm_clk_get(dev, NULL);
                if (IS_ERR(drvdata->enable_clock)) {
-                       dev_err(dev, "Cant get enable-clock from devicetree\n");
+                       dev_err(dev, "Can't get enable-clock from devicetree\n");
                        return -ENOENT;
                }
        } else {
index 3234b11..990bd50 100644 (file)
@@ -279,7 +279,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
                return ret;
        }
 
-       drvdata->state                  = -EINVAL;
+       drvdata->state                  = -ENOTRECOVERABLE;
        drvdata->duty_cycle_table       = duty_cycle_table;
        drvdata->desc.ops = &pwm_regulator_voltage_table_ops;
        drvdata->desc.n_voltages        = length / sizeof(*duty_cycle_table);
index 44e4cec..87b020d 100644 (file)
@@ -319,7 +319,7 @@ static int slg51000_regulator_init(struct slg51000 *chip)
                                rdesc->linear_min_sel = 0;
                                break;
                        }
-                       /* Fall through - to the check below.*/
+                       fallthrough;    /* to the check below */
 
                default:
                        rdesc->linear_min_sel = vsel_range[0];
index f7db250..430265c 100644 (file)
@@ -312,7 +312,7 @@ static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index)
        switch (info->flags) {
        case SMPS_OFFSET_EN:
                voltage = 100000;
-               /* fall through */
+               fallthrough;
        case 0:
                switch (index) {
                case 0:
index 6955fab..d94b739 100644 (file)
@@ -511,7 +511,6 @@ static void omap_rproc_mbox_callback(struct mbox_client *client, void *data)
                dev_info(dev, "received echo reply from %s\n", name);
                break;
        case RP_MBOX_SUSPEND_ACK:
-               /* Fall through */
        case RP_MBOX_SUSPEND_CANCEL:
                oproc->suspend_acked = msg == RP_MBOX_SUSPEND_ACK;
                complete(&oproc->pm_comp);
index d170fe6..e8aa869 100644 (file)
@@ -222,7 +222,7 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
 
        switch (id) {
        case IMX8MQ_RESET_PCIEPHY:
-       case IMX8MQ_RESET_PCIEPHY2: /* fallthrough */
+       case IMX8MQ_RESET_PCIEPHY2:
                /*
                 * wait for more than 10us to release phy g_rst and
                 * btnrst
@@ -232,12 +232,12 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
                break;
 
        case IMX8MQ_RESET_PCIE_CTRL_APPS_EN:
-       case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN:   /* fallthrough */
-       case IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N:        /* fallthrough */
-       case IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N: /* fallthrough */
-       case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N: /* fallthrough */
-       case IMX8MQ_RESET_MIPI_DSI_RESET_N:     /* fallthrough */
-       case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N:        /* fallthrough */
+       case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN:
+       case IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N:
+       case IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N:
+       case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N:
+       case IMX8MQ_RESET_MIPI_DSI_RESET_N:
+       case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N:
                value = assert ? 0 : bit;
                break;
        }
index 1995f5b..f40312b 100644 (file)
@@ -553,7 +553,7 @@ static void qcom_glink_receive_version(struct qcom_glink *glink,
                break;
        case GLINK_VERSION_1:
                glink->features &= features;
-               /* FALLTHROUGH */
+               fallthrough;
        default:
                qcom_glink_send_version_ack(glink);
                break;
@@ -584,7 +584,7 @@ static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
                        break;
 
                glink->features &= features;
-               /* FALLTHROUGH */
+               fallthrough;
        default:
                qcom_glink_send_version(glink);
                break;
index 9b70b37..8a89bc5 100644 (file)
@@ -740,7 +740,7 @@ static int wdt_ioctl(struct file *file, unsigned int cmd,
                        return -EINVAL;
                wdt_margin = new_margin;
                wdt_ping();
-               /* Fall through */
+               fallthrough;
        case WDIOC_GETTIMEOUT:
                return put_user(wdt_margin, (int __user *)arg);
 
index ca55ba9..f8b99cb 100644 (file)
@@ -353,7 +353,7 @@ static int pcf85063_load_capacitance(struct pcf85063 *pcf85063,
        default:
                dev_warn(&pcf85063->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000",
                         load);
-               /* fall through */
+               fallthrough;
        case 7000:
                break;
        case 12500:
index 47e0f41..57d351d 100644 (file)
@@ -108,7 +108,7 @@ static int pcf8523_load_capacitance(struct i2c_client *client)
        default:
                dev_warn(&client->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 12500",
                         load);
-               /* fall through */
+               fallthrough;
        case 12500:
                value |= REG_CONTROL1_CAP_SEL;
                break;
index c9bc3d4..0a969af 100644 (file)
@@ -331,7 +331,7 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev)
        default:
                dev_warn(&pdev->dev,
                         "invalid crystal-freq specified in device-tree. Assuming no crystal\n");
-               /* fall-through */
+               fallthrough;
        case 0:
                /* keep XTAL on in low-power mode */
                pers0_set = STMP3XXX_RTC_PERSISTENT0_XTAL24MHZ_PWRUP;
index cbb7708..1a44e32 100644 (file)
@@ -40,6 +40,7 @@
 MODULE_LICENSE("GPL");
 
 static struct dasd_discipline dasd_fba_discipline;
+static void *dasd_fba_zero_page;
 
 struct dasd_fba_private {
        struct dasd_fba_characteristics rdc_data;
@@ -270,7 +271,7 @@ static void ccw_write_zero(struct ccw1 *ccw, int count)
        ccw->cmd_code = DASD_FBA_CCW_WRITE;
        ccw->flags |= CCW_FLAG_SLI;
        ccw->count = count;
-       ccw->cda = (__u32) (addr_t) page_to_phys(ZERO_PAGE(0));
+       ccw->cda = (__u32) (addr_t) dasd_fba_zero_page;
 }
 
 /*
@@ -830,6 +831,11 @@ dasd_fba_init(void)
        int ret;
 
        ASCEBC(dasd_fba_discipline.ebcname, 4);
+
+       dasd_fba_zero_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!dasd_fba_zero_page)
+               return -ENOMEM;
+
        ret = ccw_driver_register(&dasd_fba_driver);
        if (!ret)
                wait_for_device_probe();
@@ -841,6 +847,7 @@ static void __exit
 dasd_fba_cleanup(void)
 {
        ccw_driver_unregister(&dasd_fba_driver);
+       free_page((unsigned long)dasd_fba_zero_page);
 }
 
 module_init(dasd_fba_init);
index 4dbbfd8..f314936 100644 (file)
@@ -1449,7 +1449,8 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
                if (!reqcnt)
                        return -ENOMEM;
                zcrypt_perdev_reqcnt(reqcnt, AP_DEVICES);
-               if (copy_to_user((int __user *) arg, reqcnt, sizeof(reqcnt)))
+               if (copy_to_user((int __user *) arg, reqcnt,
+                                sizeof(u32) * AP_DEVICES))
                        rc = -EFAULT;
                kfree(reqcnt);
                return rc;
index 3f5b613..c793dca 100644 (file)
@@ -1692,9 +1692,9 @@ int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
        *nr_apqns = 0;
 
        /* fetch status of all crypto cards */
-       device_status = kmalloc_array(MAX_ZDEV_ENTRIES_EXT,
-                                     sizeof(struct zcrypt_device_status_ext),
-                                     GFP_KERNEL);
+       device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT,
+                                      sizeof(struct zcrypt_device_status_ext),
+                                      GFP_KERNEL);
        if (!device_status)
                return -ENOMEM;
        zcrypt_device_status_mask_ext(device_status);
@@ -1762,7 +1762,7 @@ int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
                verify = 0;
        }
 
-       kfree(device_status);
+       kvfree(device_status);
        return rc;
 }
 EXPORT_SYMBOL(cca_findcard2);
index 3ce99e4..661d2a4 100644 (file)
@@ -1695,7 +1695,7 @@ static void ctcmpc_chx_attnbusy(fsm_instance *fsm, int event, void *arg)
                        grp->changed_side = 2;
                        break;
                }
-               /* Else, fall through */
+               fallthrough;
        case MPCG_STATE_XID0IOWAIX:
        case MPCG_STATE_XID7INITW:
        case MPCG_STATE_XID7INITX:
index ab316ba..85a1a45 100644 (file)
@@ -357,7 +357,7 @@ int ctc_mpc_alloc_channel(int port_num, void (*callback)(int, int))
                /*fsm_newstate(grp->fsm, MPCG_STATE_XID2INITW);*/
                if (callback)
                        grp->send_qllc_disc = 1;
-               /* Else, fall through */
+               fallthrough;
        case MPCG_STATE_XID0IOWAIT:
                fsm_deltimer(&grp->timer);
                grp->outstanding_xid2 = 0;
@@ -1470,7 +1470,7 @@ static void mpc_action_timeout(fsm_instance *fi, int event, void *arg)
                if ((fsm_getstate(rch->fsm) == CH_XID0_PENDING) &&
                   (fsm_getstate(wch->fsm) == CH_XID0_PENDING))
                        break;
-               /* Else, fall through */
+               fallthrough;
        default:
                fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
        }
@@ -2089,7 +2089,7 @@ static int mpc_send_qllc_discontact(struct net_device *dev)
                        grp->estconnfunc = NULL;
                        break;
                }
-               /* Else, fall through */
+               fallthrough;
        case MPCG_STATE_FLOWC:
        case MPCG_STATE_READY:
                grp->send_qllc_disc = 2;
index bba1b54..6a73982 100644 (file)
@@ -1071,7 +1071,7 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
                break;
        case -EIO:
                qeth_schedule_recovery(card);
-               /* fall through */
+               fallthrough;
        default:
                qeth_clear_ipacmd_list(card);
                goto err_idx;
@@ -2886,7 +2886,7 @@ void qeth_print_status_message(struct qeth_card *card)
                                card->info.mcl_level[3]);
                        break;
                }
-               /* fallthrough */
+               fallthrough;
        case QETH_CARD_TYPE_IQD:
                if (IS_VM_NIC(card) || (card->info.mcl_level[0] & 0x80)) {
                        card->info.mcl_level[0] = (char) _ebcasc[(__u8)
index ebdc032..f870c53 100644 (file)
@@ -356,7 +356,7 @@ static void qeth_set_cmd_adv_sup(struct ethtool_link_ksettings *cmd,
                                                     10000baseT_Full);
                ethtool_link_ksettings_add_link_mode(cmd, advertising,
                                                     10000baseT_Full);
-               /* fall through */
+               fallthrough;
        case SPEED_1000:
                ethtool_link_ksettings_add_link_mode(cmd, supported,
                                                     1000baseT_Full);
@@ -366,7 +366,7 @@ static void qeth_set_cmd_adv_sup(struct ethtool_link_ksettings *cmd,
                                                     1000baseT_Half);
                ethtool_link_ksettings_add_link_mode(cmd, advertising,
                                                     1000baseT_Half);
-               /* fall through */
+               fallthrough;
        case SPEED_100:
                ethtool_link_ksettings_add_link_mode(cmd, supported,
                                                     100baseT_Full);
@@ -376,7 +376,7 @@ static void qeth_set_cmd_adv_sup(struct ethtool_link_ksettings *cmd,
                                                     100baseT_Half);
                ethtool_link_ksettings_add_link_mode(cmd, advertising,
                                                     100baseT_Half);
-               /* fall through */
+               fallthrough;
        case SPEED_10:
                ethtool_link_ksettings_add_link_mode(cmd, supported,
                                                     10baseT_Full);
index 8b342a8..6384f7a 100644 (file)
@@ -284,11 +284,11 @@ static void qeth_l2_stop_card(struct qeth_card *card)
 
        if (card->state == CARD_STATE_SOFTSETUP) {
                qeth_clear_ipacmd_list(card);
-               qeth_drain_output_queues(card);
                card->state = CARD_STATE_DOWN;
        }
 
        qeth_qdio_clear_card(card, 0);
+       qeth_drain_output_queues(card);
        qeth_clear_working_pool_list(card);
        flush_workqueue(card->event_wq);
        qeth_flush_local_addrs(card);
@@ -488,7 +488,7 @@ static void qeth_l2_rx_mode_work(struct work_struct *work)
                                kfree(mac);
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
                default:
                        /* for next call to set_rx_mode(): */
                        mac->disp_flag = QETH_DISP_ADDR_DELETE;
index fe44b02..09ef518 100644 (file)
@@ -1168,11 +1168,11 @@ static void qeth_l3_stop_card(struct qeth_card *card)
        if (card->state == CARD_STATE_SOFTSETUP) {
                qeth_l3_clear_ip_htable(card, 1);
                qeth_clear_ipacmd_list(card);
-               qeth_drain_output_queues(card);
                card->state = CARD_STATE_DOWN;
        }
 
        qeth_qdio_clear_card(card, 0);
+       qeth_drain_output_queues(card);
        qeth_clear_working_pool_list(card);
        flush_workqueue(card->event_wq);
        qeth_flush_local_addrs(card);
@@ -1235,7 +1235,7 @@ static void qeth_l3_rx_mode_work(struct work_struct *work)
                                        break;
                                }
                                addr->ref_counter = 1;
-                               /* fall through */
+                               fallthrough;
                        default:
                                /* for next call to set_rx_mode(): */
                                addr->disp_flag = QETH_DISP_ADDR_DELETE;
index 461b3ba..84b57a8 100644 (file)
@@ -1832,7 +1832,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
        case REQUEST_SENSE:
                /* clear the internal sense magic */
                SCp->cmnd[6] = 0;
-               /* fall through */
+               fallthrough;
        default:
                /* OK, get it from the command */
                switch(SCp->sc_data_direction) {
index bb49d83..ccb061a 100644 (file)
@@ -2635,7 +2635,7 @@ static int blogic_resultcode(struct blogic_adapter *adapter,
        case BLOGIC_BAD_CMD_PARAM:
                blogic_warn("BusLogic Driver Protocol Error 0x%02X\n",
                                adapter, adapter_status);
-               /* fall through */
+               fallthrough;
        case BLOGIC_DATA_UNDERRUN:
        case BLOGIC_DATA_OVERRUN:
        case BLOGIC_NOEXPECT_BUSFREE:
index 0f17bd5..24ace18 100644 (file)
@@ -1034,11 +1034,14 @@ static int FlashPoint_ProbeHostAdapter(struct sccb_mgr_info *pCardInfo)
                        temp6 >>= 1;
                        switch (temp & 0x3) {
                        case AUTO_RATE_20:      /* Synchronous, 20 mega-transfers/second */
-                               temp6 |= 0x8000;        /* Fall through */
+                               temp6 |= 0x8000;
+                               fallthrough;
                        case AUTO_RATE_10:      /* Synchronous, 10 mega-transfers/second */
-                               temp5 |= 0x8000;        /* Fall through */
+                               temp5 |= 0x8000;
+                               fallthrough;
                        case AUTO_RATE_05:      /* Synchronous, 5 mega-transfers/second */
-                               temp2 |= 0x8000;        /* Fall through */
+                               temp2 |= 0x8000;
+                               fallthrough;
                        case AUTO_RATE_00:      /* Asynchronous */
                                break;
                        }
index f2f7e6e..d654a6c 100644 (file)
@@ -1943,7 +1943,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                                return;
 
                                        /* Reject message */
-                                       /* Fall through */
+                                       fallthrough;
                                default:
                                        /*
                                         * If we get something weird that we aren't expecting,
index 769af4c..fd6ae5c 100644 (file)
@@ -2809,7 +2809,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                            !(dev->raw_io_64) ||
                                            ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
                                                break;
-                                       /* fall through */
+                                       fallthrough;
                                case INQUIRY:
                                case READ_CAPACITY:
                                case TEST_UNIT_READY:
@@ -2884,7 +2884,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                /* Issue FIB to tell Firmware to flush it's cache */
                if ((aac_cache & 6) != 2)
                        return aac_synchronize(scsicmd);
-               /* fall through */
+               fallthrough;
        case INQUIRY:
        {
                struct inquiry_data inq_data;
@@ -3240,7 +3240,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                     SCSI_SENSE_BUFFERSIZE));
                        break;
                }
-               /* fall through */
+               fallthrough;
        case RESERVE:
        case RELEASE:
        case REZERO_UNIT:
@@ -3253,7 +3253,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
        case START_STOP:
                return aac_start_stop(scsicmd);
 
-       /* FALLTHRU */
+               fallthrough;
        default:
        /*
         *      Unhandled commands
index adbdc3b..383e74f 100644 (file)
@@ -1431,7 +1431,7 @@ retry_next:
                                                "enclosure services event");
                                scsi_device_set_state(device, SDEV_RUNNING);
                        }
-                       /* FALLTHRU */
+                       fallthrough;
                case CHANGE:
                        if ((channel == CONTAINER_CHANNEL)
                         && (!dev->fsa_dev[container].valid)) {
index 8588da0..a3aee14 100644 (file)
@@ -765,7 +765,7 @@ static int aac_eh_abort(struct scsi_cmnd* cmd)
                            !(aac->raw_io_64) ||
                            ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
                                break;
-                       /* fall through */
+                       fallthrough;
                case INQUIRY:
                case READ_CAPACITY:
                        /*
index c912d29..1c617c0 100644 (file)
@@ -2274,7 +2274,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
                        switch (scb->hscb->task_management) {
                        case SIU_TASKMGMT_ABORT_TASK:
                                tag = SCB_GET_TAG(scb);
-                               /* fall through */
+                               fallthrough;
                        case SIU_TASKMGMT_ABORT_TASK_SET:
                        case SIU_TASKMGMT_CLEAR_TASK_SET:
                                lun = scb->hscb->lun;
@@ -2285,7 +2285,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
                                break;
                        case SIU_TASKMGMT_LUN_RESET:
                                lun = scb->hscb->lun;
-                               /* fall through */
+                               fallthrough;
                        case SIU_TASKMGMT_TARGET_RESET:
                        {
                                struct ahd_devinfo devinfo;
@@ -3791,7 +3791,7 @@ ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo,
                        *bus_width = MSG_EXT_WDTR_BUS_16_BIT;
                        break;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case MSG_EXT_WDTR_BUS_8_BIT:
                *bus_width = MSG_EXT_WDTR_BUS_8_BIT;
                break;
@@ -5104,7 +5104,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
                break;
        case MSG_MESSAGE_REJECT:
                response = ahd_handle_msg_reject(ahd, devinfo);
-               /* FALLTHROUGH */
+               fallthrough;
        case MSG_NOOP:
                done = MSGLOOP_MSGCOMPLETE;
                break;
@@ -5454,7 +5454,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
                               ahd_name(ahd), ahd_inb(ahd, SCSISIGI));
 #endif
                ahd->msg_flags |= MSG_FLAG_EXPECT_QASREJ_BUSFREE;
-               /* FALLTHROUGH */
+               fallthrough;
        case MSG_TERM_IO_PROC:
        default:
                reject = TRUE;
@@ -6117,17 +6117,17 @@ ahd_free(struct ahd_softc *ahd)
        default:
        case 5:
                ahd_shutdown(ahd);
-               /* FALLTHROUGH */
+               fallthrough;
        case 4:
                ahd_dmamap_unload(ahd, ahd->shared_data_dmat,
                                  ahd->shared_data_map.dmamap);
-               /* FALLTHROUGH */
+               fallthrough;
        case 3:
                ahd_dmamem_free(ahd, ahd->shared_data_dmat, ahd->qoutfifo,
                                ahd->shared_data_map.dmamap);
                ahd_dmamap_destroy(ahd, ahd->shared_data_dmat,
                                   ahd->shared_data_map.dmamap);
-               /* FALLTHROUGH */
+               fallthrough;
        case 2:
                ahd_dma_tag_destroy(ahd, ahd->shared_data_dmat);
        case 1:
@@ -6513,7 +6513,7 @@ ahd_fini_scbdata(struct ahd_softc *ahd)
                }
                ahd_dma_tag_destroy(ahd, scb_data->sense_dmat);
        }
-               /* fall through */
+               fallthrough;
        case 6:
        {
                struct map_node *sg_map;
@@ -6528,7 +6528,7 @@ ahd_fini_scbdata(struct ahd_softc *ahd)
                }
                ahd_dma_tag_destroy(ahd, scb_data->sg_dmat);
        }
-               /* fall through */
+               fallthrough;
        case 5:
        {
                struct map_node *hscb_map;
@@ -7171,7 +7171,7 @@ ahd_init(struct ahd_softc *ahd)
                case FLX_CSTAT_OVER:
                case FLX_CSTAT_UNDER:
                        warn_user++;
-                       /* fall through */
+                       fallthrough;
                case FLX_CSTAT_INVALID:
                case FLX_CSTAT_OKAY:
                        if (warn_user == 0 && bootverbose == 0)
@@ -8175,12 +8175,12 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
                                if ((scb->flags & SCB_ACTIVE) == 0)
                                        printk("Inactive SCB in qinfifo\n");
                                ahd_done_with_status(ahd, scb, status);
-                               /* FALLTHROUGH */
+                               fallthrough;
                        case SEARCH_REMOVE:
                                break;
                        case SEARCH_PRINT:
                                printk(" 0x%x", ahd->qinfifo[qinpos]);
-                               /* FALLTHROUGH */
+                               fallthrough;
                        case SEARCH_COUNT:
                                ahd_qinfifo_requeue(ahd, prev_scb, scb);
                                prev_scb = scb;
@@ -8271,7 +8271,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
                                if ((mk_msg_scb->flags & SCB_ACTIVE) == 0)
                                        printk("Inactive SCB pending MK_MSG\n");
                                ahd_done_with_status(ahd, mk_msg_scb, status);
-                               /* FALLTHROUGH */
+                               fallthrough;
                        case SEARCH_REMOVE:
                        {
                                u_int tail_offset;
@@ -8295,7 +8295,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
                        }
                        case SEARCH_PRINT:
                                printk(" 0x%x", SCB_GET_TAG(scb));
-                               /* FALLTHROUGH */
+                               fallthrough;
                        case SEARCH_COUNT:
                                break;
                        }
@@ -8376,7 +8376,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
                        if ((scb->flags & SCB_ACTIVE) == 0)
                                printk("Inactive SCB in Waiting List\n");
                        ahd_done_with_status(ahd, scb, status);
-                       /* fall through */
+                       fallthrough;
                case SEARCH_REMOVE:
                        ahd_rem_wscb(ahd, scbid, prev, next, tid);
                        *list_tail = prev;
@@ -8385,7 +8385,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
                        break;
                case SEARCH_PRINT:
                        printk("0x%x ", scbid);
-                       /* fall through */
+                       fallthrough;
                case SEARCH_COUNT:
                        prev = scbid;
                        break;
@@ -9023,7 +9023,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
        case SCSI_STATUS_OK:
                printk("%s: Interrupted for status of 0???\n",
                       ahd_name(ahd));
-               /* FALLTHROUGH */
+               fallthrough;
        default:
                ahd_done(ahd, scb);
                break;
@@ -9512,7 +9512,7 @@ ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts)
                fmt3_ins = &instr.format3;
                fmt3_ins->address = ahd_resolve_seqaddr(ahd, fmt3_ins->address);
        }
-               /* fall through */
+               fallthrough;
        case AIC_OP_OR:
        case AIC_OP_AND:
        case AIC_OP_XOR:
@@ -9523,7 +9523,7 @@ ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts)
                        fmt1_ins->immediate = dconsts[fmt1_ins->immediate];
                }
                fmt1_ins->parity = 0;
-               /* fall through */
+               fallthrough;
        case AIC_OP_ROL:
        {
                int i, count;
index d019e3f..7c32130 100644 (file)
@@ -2035,7 +2035,7 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd)
                break;
        case CAM_AUTOSENSE_FAIL:
                new_status = DID_ERROR;
-               /* Fallthrough */
+               fallthrough;
        case CAM_SCSI_STATUS_ERROR:
                scsi_status = ahd_cmd_get_scsi_status(cmd);
 
index 3d4df90..2231c4a 100644 (file)
@@ -2404,7 +2404,7 @@ ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo,
                        *bus_width = MSG_EXT_WDTR_BUS_16_BIT;
                        break;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case MSG_EXT_WDTR_BUS_8_BIT:
                *bus_width = MSG_EXT_WDTR_BUS_8_BIT;
                break;
@@ -3599,7 +3599,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
                break;
        case MSG_MESSAGE_REJECT:
                response = ahc_handle_msg_reject(ahc, devinfo);
-               /* FALLTHROUGH */
+               fallthrough;
        case MSG_NOOP:
                done = MSGLOOP_MSGCOMPLETE;
                break;
@@ -4465,17 +4465,17 @@ ahc_free(struct ahc_softc *ahc)
        default:
        case 5:
                ahc_shutdown(ahc);
-               /* FALLTHROUGH */
+               fallthrough;
        case 4:
                ahc_dmamap_unload(ahc, ahc->shared_data_dmat,
                                  ahc->shared_data_dmamap);
-               /* FALLTHROUGH */
+               fallthrough;
        case 3:
                ahc_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo,
                                ahc->shared_data_dmamap);
                ahc_dmamap_destroy(ahc, ahc->shared_data_dmat,
                                   ahc->shared_data_dmamap);
-               /* FALLTHROUGH */
+               fallthrough;
        case 2:
                ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat);
        case 1:
@@ -4893,30 +4893,30 @@ ahc_fini_scbdata(struct ahc_softc *ahc)
                }
                ahc_dma_tag_destroy(ahc, scb_data->sg_dmat);
        }
-               /* fall through */
+               fallthrough;
        case 6:
                ahc_dmamap_unload(ahc, scb_data->sense_dmat,
                                  scb_data->sense_dmamap);
-               /* fall through */
+               fallthrough;
        case 5:
                ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense,
                                scb_data->sense_dmamap);
                ahc_dmamap_destroy(ahc, scb_data->sense_dmat,
                                   scb_data->sense_dmamap);
-               /* fall through */
+               fallthrough;
        case 4:
                ahc_dma_tag_destroy(ahc, scb_data->sense_dmat);
-               /* fall through */
+               fallthrough;
        case 3:
                ahc_dmamap_unload(ahc, scb_data->hscb_dmat,
                                  scb_data->hscb_dmamap);
-               /* fall through */
+               fallthrough;
        case 2:
                ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs,
                                scb_data->hscb_dmamap);
                ahc_dmamap_destroy(ahc, scb_data->hscb_dmat,
                                   scb_data->hscb_dmamap);
-               /* fall through */
+               fallthrough;
        case 1:
                ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat);
                break;
@@ -5981,7 +5981,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
                                        printk("Inactive SCB in Waiting List\n");
                                ahc_done(ahc, scb);
                        }
-                               /* fall through */
+                               fallthrough;
                        case SEARCH_REMOVE:
                                next = ahc_rem_wscb(ahc, next, prev);
                                break;
@@ -6987,7 +6987,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
                address -= address_offset;
                fmt3_ins->address = address;
        }
-               /* fall through */
+               fallthrough;
        case AIC_OP_OR:
        case AIC_OP_AND:
        case AIC_OP_XOR:
@@ -7013,7 +7013,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
                        fmt1_ins->opcode = AIC_OP_AND;
                        fmt1_ins->immediate = 0xff;
                }
-               /* fall through */
+               fallthrough;
        case AIC_OP_ROL:
                if ((ahc->features & AHC_ULTRA2) != 0) {
                        int i, count;
index c264b4b..e2d880a 100644 (file)
@@ -706,11 +706,11 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
        switch (pd->max_sas_lrate) {
        case SAS_LINK_RATE_6_0_GBPS:
                *speed_mask &= ~SAS_SPEED_60_DIS;
-               /* fall through*/
+               fallthrough;
        default:
        case SAS_LINK_RATE_3_0_GBPS:
                *speed_mask &= ~SAS_SPEED_30_DIS;
-               /* fall through*/
+               fallthrough;
        case SAS_LINK_RATE_1_5_GBPS:
                *speed_mask &= ~SAS_SPEED_15_DIS;
        }
@@ -718,7 +718,7 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
        switch (pd->min_sas_lrate) {
        case SAS_LINK_RATE_6_0_GBPS:
                *speed_mask |= SAS_SPEED_30_DIS;
-               /* fall through*/
+               fallthrough;
        case SAS_LINK_RATE_3_0_GBPS:
                *speed_mask |= SAS_SPEED_15_DIS;
        default:
@@ -730,7 +730,7 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
        switch (pd->max_sata_lrate) {
        case SAS_LINK_RATE_3_0_GBPS:
                *speed_mask &= ~SATA_SPEED_30_DIS;
-               /* fall through*/
+               fallthrough;
        default:
        case SAS_LINK_RATE_1_5_GBPS:
                *speed_mask &= ~SATA_SPEED_15_DIS;
@@ -789,7 +789,7 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
 
                /* link reset retries, this should be nominal */
                control_phy->link_reset_retries = 10;
-               /* fall through */
+               fallthrough;
 
        case RELEASE_SPINUP_HOLD: /* 0x02 */
                /* decide the func_mask */
index 1fcee65..0eb6e20 100644 (file)
@@ -490,7 +490,7 @@ int asd_abort_task(struct sas_task *task)
                switch (tcs.dl_opcode) {
                default:
                        res = asd_clear_nexus(task);
-                       /* fallthrough */
+                       fallthrough;
                case TC_NO_ERROR:
                        break;
                        /* The task hasn't been sent to the device xor
index fa562a0..ec895d0 100644 (file)
@@ -4470,7 +4470,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
        case PCI_DEVICE_ID_ARECA_1202:
        case PCI_DEVICE_ID_ARECA_1210:
                raid6 = 0;
-               /*FALLTHRU*/
+               fallthrough;
        case PCI_DEVICE_ID_ARECA_1120:
        case PCI_DEVICE_ID_ARECA_1130:
        case PCI_DEVICE_ID_ARECA_1160:
index 6c68c23..2e687ce 100644 (file)
@@ -603,7 +603,7 @@ static void fas216_handlesync(FAS216_Info *info, char *msg)
                msgqueue_flush(&info->scsi.msgs);
                msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
                info->scsi.phase = PHASE_MSGOUT_EXPECT;
-               /* fall through */
+               fallthrough;
 
        case async:
                dev->period = info->ifcfg.asyncperiod / 4;
@@ -916,7 +916,7 @@ static void fas216_disconnect_intr(FAS216_Info *info)
                        fas216_done(info, DID_ABORT);
                        break;
                }
-               /* else, fall through */
+               fallthrough;
 
        default:                                /* huh?                                 */
                printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %s\n",
@@ -1413,7 +1413,7 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne
        case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out     -> Status       */
        case STATE(STAT_STATUS, PHASE_DATAIN):  /* Data In      -> Status       */
                fas216_stoptransfer(info);
-               /* fall through */
+               fallthrough;
 
        case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status       */
        case STATE(STAT_STATUS, PHASE_MSGOUT):  /* Message Out  -> Status       */
@@ -1426,7 +1426,7 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne
        case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out     -> Message In   */
        case STATE(STAT_MESGIN, PHASE_DATAIN):  /* Data In      -> Message In   */
                fas216_stoptransfer(info);
-               /* fall through */
+               fallthrough;
 
        case STATE(STAT_MESGIN, PHASE_COMMAND): /* Command      -> Message In   */
        case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In   */
@@ -1581,7 +1581,7 @@ static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned
                        fas216_message(info);
                        break;
                }
-               /* else, fall through */
+               fallthrough;
 
        default:
                fas216_log(info, 0, "internal phase %s for function done?"
@@ -1964,7 +1964,7 @@ static void fas216_kick(FAS216_Info *info)
        switch (where_from) {
        case TYPE_QUEUE:
                fas216_allocate_tag(info, SCpnt);
-               /* fall through */
+               fallthrough;
        case TYPE_OTHER:
                fas216_start_command(info, SCpnt);
                break;
index 93da634..a13c203 100644 (file)
@@ -677,7 +677,7 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
        case ISCSI_PARAM_MAX_XMIT_DLENGTH:
                if (conn->max_xmit_dlength > 65536)
                        conn->max_xmit_dlength = 65536;
-               /* fall through */
+               fallthrough;
        default:
                return 0;
        }
index 8dc2e08..5c3513a 100644 (file)
@@ -1532,7 +1532,7 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn,
                break;
        case UNSOL_DATA_DIGEST_ERROR_NOTIFY:
                error = 1;
-               /* fall through */
+               fallthrough;
        case UNSOL_DATA_NOTIFY:
                pasync_handle = pasync_ctx->async_entry[ci].data;
                break;
index 29f9956..38d1c45 100644 (file)
@@ -2572,7 +2572,7 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
        case FCP_IODIR_RW:
                bfa_stats(itnim, input_reqs);
                bfa_stats(itnim, output_reqs);
-               /* fall through */
+               fallthrough;
        default:
                bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_fn_lpu(ioim->bfa));
        }
@@ -2807,7 +2807,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
 
        case BFI_IOIM_STS_TIMEDOUT:
                bfa_stats(ioim->itnim, iocomp_timedout);
-               /* fall through */
+               fallthrough;
        case BFI_IOIM_STS_ABORTED:
                rsp->io_status = BFI_IOIM_STS_ABORTED;
                bfa_stats(ioim->itnim, iocomp_aborted);
@@ -3203,7 +3203,7 @@ bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
        switch (event) {
        case BFA_TSKIM_SM_DONE:
                bfa_reqq_wcancel(&tskim->reqq_wait);
-               /* fall through */
+               fallthrough;
        case BFA_TSKIM_SM_QRESUME:
                bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup);
                bfa_tskim_send_abort(tskim);
index 297a77f..3486e40 100644 (file)
@@ -6422,7 +6422,7 @@ bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport,
        switch (event) {
        case BFA_FCS_VPORT_SM_OFFLINE:
                bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
-               /* fall through */
+               fallthrough;
 
        case BFA_FCS_VPORT_SM_RSP_OK:
        case BFA_FCS_VPORT_SM_RSP_ERROR:
@@ -6448,7 +6448,7 @@ bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
        switch (event) {
        case BFA_FCS_VPORT_SM_OFFLINE:
                bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
-               /* fall through */
+               fallthrough;
 
        case BFA_FCS_VPORT_SM_RSP_OK:
        case BFA_FCS_VPORT_SM_RSP_ERROR:
index 143c35b..c21aa37 100644 (file)
@@ -419,13 +419,13 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event)
 
        case RPSM_EVENT_LOGO_RCVD:
                bfa_fcs_rport_send_logo_acc(rport);
-               /* fall through */
+               fallthrough;
        case RPSM_EVENT_PRLO_RCVD:
                if (rport->prlo == BFA_TRUE)
                        bfa_fcs_rport_send_prlo_acc(rport);
 
                bfa_fcxp_discard(rport->fcxp);
-               /* fall through */
+               fallthrough;
        case RPSM_EVENT_FAILED:
                if (rport->plogi_retries < BFA_FCS_RPORT_MAX_RETRIES) {
                        rport->plogi_retries++;
@@ -856,7 +856,7 @@ bfa_fcs_rport_sm_adisc_online(struct bfa_fcs_rport_s *rport,
                 * At least go offline when a PLOGI is received.
                 */
                bfa_fcxp_discard(rport->fcxp);
-               /* fall through */
+               fallthrough;
 
        case RPSM_EVENT_FAILED:
        case RPSM_EVENT_ADDRESS_CHANGE:
@@ -1042,7 +1042,7 @@ bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport,
 
        case RPSM_EVENT_LOGO_RCVD:
                bfa_fcs_rport_send_logo_acc(rport);
-               /* fall through */
+               fallthrough;
        case RPSM_EVENT_PRLO_RCVD:
                if (rport->prlo == BFA_TRUE)
                        bfa_fcs_rport_send_prlo_acc(rport);
@@ -1131,7 +1131,7 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
                        bfa_fcs_rport_send_plogiacc(rport, NULL);
                        break;
                }
-               /* fall through */
+               fallthrough;
 
        case RPSM_EVENT_ADDRESS_CHANGE:
                if (!bfa_fcs_lport_is_online(rport->port)) {
@@ -1288,7 +1288,7 @@ bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport,
 
        case RPSM_EVENT_LOGO_RCVD:
                bfa_fcs_rport_send_logo_acc(rport);
-               /* fall through */
+               fallthrough;
        case RPSM_EVENT_PRLO_RCVD:
                if (rport->prlo == BFA_TRUE)
                        bfa_fcs_rport_send_prlo_acc(rport);
@@ -1332,7 +1332,7 @@ bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport,
 
        case RPSM_EVENT_LOGO_RCVD:
                bfa_fcs_rport_send_logo_acc(rport);
-               /* fall through */
+               fallthrough;
        case RPSM_EVENT_PRLO_RCVD:
                if (rport->prlo == BFA_TRUE)
                        bfa_fcs_rport_send_prlo_acc(rport);
index dd5821d..325ad8a 100644 (file)
@@ -969,7 +969,7 @@ bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
 
        case IOCPF_E_INITFAIL:
                bfa_iocpf_timer_stop(ioc);
-               /* fall through */
+               fallthrough;
 
        case IOCPF_E_TIMEOUT:
                writel(1, ioc->ioc_regs.ioc_sem_reg);
@@ -1045,7 +1045,7 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)
 
        case IOCPF_E_FAIL:
                bfa_iocpf_timer_stop(ioc);
-               /* fall through */
+               fallthrough;
 
        case IOCPF_E_TIMEOUT:
                bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
@@ -5988,7 +5988,7 @@ bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf,
        case BFA_DCONF_SM_IOCDISABLE:
        case BFA_DCONF_SM_FLASH_COMP:
                bfa_timer_stop(&dconf->timer);
-               /* fall through */
+               fallthrough;
        case BFA_DCONF_SM_TIMEOUT:
                bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
                bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);
index 1e266c1..11c0c3e 100644 (file)
@@ -6397,7 +6397,7 @@ bfa_dport_sm_starting(struct bfa_dport_s *dport, enum bfa_dport_sm_event event)
                        dport->test_state = BFA_DPORT_ST_INP;
                        bfa_dport_result_start(dport, BFA_DPORT_OPMODE_MANU);
                }
-               /* fall thru */
+               fallthrough;
 
        case BFA_DPORT_SM_REQFAIL:
                bfa_sm_set_state(dport, bfa_dport_sm_enabled);
index e72d7bb..0899209 100644 (file)
@@ -1404,7 +1404,6 @@ void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[],
                        break;
 
                case FCOE_KCQE_OPCODE_FCOE_ERROR:
-                       /* fall thru */
                default:
                        printk(KERN_ERR PFX "unknown opcode 0x%x\n",
                                                                kcqe->op_code);
index 98d4d39..7fa2060 100644 (file)
@@ -2939,7 +2939,7 @@ csio_hws_quiescing(struct csio_hw *hw, enum csio_hw_ev evt)
                case CSIO_HWE_FW_DLOAD:
                        csio_set_state(&hw->sm, csio_hws_resetting);
                        /* Download firmware */
-                       /* Fall through */
+                       fallthrough;
 
                case CSIO_HWE_HBA_RESET:
                        csio_set_state(&hw->sm, csio_hws_resetting);
index 61cf542..dc98f51 100644 (file)
@@ -1187,7 +1187,6 @@ csio_lns_online(struct csio_lnode *ln, enum csio_ln_ev evt)
                break;
 
        case CSIO_LNE_LINK_DOWN:
-               /* Fall through */
        case CSIO_LNE_DOWN_LINK:
                csio_set_state(&ln->sm, csio_lns_uninit);
                if (csio_is_phys_ln(ln)) {
index 0ca6951..9010cb6 100644 (file)
@@ -808,7 +808,7 @@ csio_wr_destroy_queues(struct csio_hw *hw, bool cmd)
 
                                csio_q_eqid(hw, i) = CSIO_MAX_QID;
                        }
-                       /* fall through */
+                       fallthrough;
                case CSIO_INGRESS:
                        if (csio_q_iqid(hw, i) != CSIO_MAX_QID) {
                                csio_wr_cleanup_iq_ftr(hw, i);
index 2b48954..37d9935 100644 (file)
@@ -643,7 +643,7 @@ static int abort_status_to_errno(struct cxgbi_sock *csk, int abort_reason,
                                 int *need_rst)
 {
        switch (abort_reason) {
-       case CPL_ERR_BAD_SYN: /* fall through */
+       case CPL_ERR_BAD_SYN:
        case CPL_ERR_CONN_RESET:
                return csk->state > CTP_ESTABLISHED ? -EPIPE : -ECONNRESET;
        case CPL_ERR_XMIT_TIMEDOUT:
index 4e82c14..2c34915 100644 (file)
@@ -1133,7 +1133,7 @@ static int abort_status_to_errno(struct cxgbi_sock *csk, int abort_reason,
                                                                int *need_rst)
 {
        switch (abort_reason) {
-       case CPL_ERR_BAD_SYN: /* fall through */
+       case CPL_ERR_BAD_SYN:
        case CPL_ERR_CONN_RESET:
                return csk->state > CTP_ESTABLISHED ?
                        -EPIPE : -ECONNRESET;
index 71aebaf..0e8621a 100644 (file)
@@ -2457,10 +2457,10 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
                return err;
        }
 
-       __kfree_skb(skb);
        log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX,
                  "itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n",
                  task->itt, skb, skb->len, skb->data_len, err);
+       __kfree_skb(skb);
        iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err);
        iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED);
        return err;
index 94250eb..e72440d 100644 (file)
@@ -748,16 +748,16 @@ static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level,
                /* SISL_MSI_ASYNC_ERROR is setup only for the primary HWQ */
                if (index == PRIMARY_HWQ)
                        cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 3, hwq);
-               /* fall through */
+               fallthrough;
        case UNMAP_TWO:
                cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 2, hwq);
-               /* fall through */
+               fallthrough;
        case UNMAP_ONE:
                cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 1, hwq);
-               /* fall through */
+               fallthrough;
        case FREE_IRQ:
                cfg->ops->free_afu_irqs(hwq->ctx_cookie);
-               /* fall through */
+               fallthrough;
        case UNDO_NOOP:
                /* No action required */
                break;
@@ -971,18 +971,18 @@ static void cxlflash_remove(struct pci_dev *pdev)
        switch (cfg->init_state) {
        case INIT_STATE_CDEV:
                cxlflash_release_chrdev(cfg);
-               /* fall through */
+               fallthrough;
        case INIT_STATE_SCSI:
                cxlflash_term_local_luns(cfg);
                scsi_remove_host(cfg->host);
-               /* fall through */
+               fallthrough;
        case INIT_STATE_AFU:
                term_afu(cfg);
-               /* fall through */
+               fallthrough;
        case INIT_STATE_PCI:
                cfg->ops->destroy_afu(cfg->afu_cookie);
                pci_disable_device(pdev);
-               /* fall through */
+               fallthrough;
        case INIT_STATE_NONE:
                free_mem(cfg);
                scsi_host_put(cfg->host);
@@ -2355,11 +2355,11 @@ retry:
                        cxlflash_schedule_async_reset(cfg);
                        break;
                }
-               /* fall through - to retry */
+               fallthrough;    /* to retry */
        case -EAGAIN:
                if (++nretry < 2)
                        goto retry;
-               /* fall through - to exit */
+               fallthrough;    /* to exit */
        default:
                break;
        }
@@ -2533,12 +2533,12 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp)
                        cfg->state = STATE_NORMAL;
                wake_up_all(&cfg->reset_waitq);
                ssleep(1);
-               /* fall through */
+               fallthrough;
        case STATE_RESET:
                wait_event(cfg->reset_waitq, cfg->state != STATE_RESET);
                if (cfg->state == STATE_NORMAL)
                        break;
-               /* fall through */
+               fallthrough;
        default:
                rc = FAILED;
                break;
@@ -3019,7 +3019,7 @@ retry:
                wait_event(cfg->reset_waitq, cfg->state != STATE_RESET);
                if (cfg->state == STATE_NORMAL)
                        goto retry;
-               /* else, fall through */
+               fallthrough;
        default:
                /* Ideally should not happen */
                dev_err(dev, "%s: Device is not ready, state=%d\n",
@@ -3531,7 +3531,7 @@ static long cxlflash_chr_ioctl(struct file *file, unsigned int cmd,
                if (likely(do_ioctl))
                        break;
 
-               /* fall through */
+               fallthrough;
        default:
                rc = -EINVAL;
                goto out;
index 593669a..5dddf67 100644 (file)
@@ -375,14 +375,13 @@ retry:
                        switch (sshdr.sense_key) {
                        case NO_SENSE:
                        case RECOVERED_ERROR:
-                               /* fall through */
                        case NOT_READY:
                                result &= ~SAM_STAT_CHECK_CONDITION;
                                break;
                        case UNIT_ATTENTION:
                                switch (sshdr.asc) {
                                case 0x29: /* Power on Reset or Device Reset */
-                                       /* fall through */
+                                       fallthrough;
                                case 0x2A: /* Device capacity changed */
                                case 0x3F: /* Report LUNs changed */
                                        /* Retry the command once more */
@@ -1791,13 +1790,12 @@ static int process_sense(struct scsi_device *sdev,
        switch (sshdr.sense_key) {
        case NO_SENSE:
        case RECOVERED_ERROR:
-               /* fall through */
        case NOT_READY:
                break;
        case UNIT_ATTENTION:
                switch (sshdr.asc) {
                case 0x29: /* Power on Reset or Device Reset */
-                       /* fall through */
+                       fallthrough;
                case 0x2A: /* Device settings/capacity changed */
                        rc = read_cap16(sdev, lli);
                        if (rc) {
@@ -2157,7 +2155,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, unsigned int cmd, void __user *arg)
                if (unlikely(rc))
                        goto cxlflash_ioctl_exit;
 
-               /* fall through */
+               fallthrough;
 
        case DK_CXLFLASH_MANAGE_LUN:
                known_ioctl = true;
@@ -2168,7 +2166,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, unsigned int cmd, void __user *arg)
                if (likely(do_ioctl))
                        break;
 
-               /* fall through */
+               fallthrough;
        default:
                rc = -EINVAL;
                goto cxlflash_ioctl_exit;
index 8acd4bb..4a3f783 100644 (file)
@@ -60,7 +60,7 @@ static int tur_done(struct scsi_device *sdev, struct hp_sw_dh_data *h,
                        ret = SCSI_DH_OK;
                        break;
                }
-               /* Fallthrough */
+               fallthrough;
        default:
                sdev_printk(KERN_WARNING, sdev,
                           "%s: sending tur failed, sense %x/%x/%x\n",
@@ -147,7 +147,7 @@ retry:
                                rc = SCSI_DH_RETRY;
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
                default:
                        sdev_printk(KERN_WARNING, sdev,
                                    "%s: sending start_stop_unit failed, "
index b02ac38..429d642 100644 (file)
@@ -1500,7 +1500,7 @@ bool esas2r_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi,
                        return complete_fmapi_req(a, rq, FI_STAT_SUCCESS);
                }
 
-       /* fall through */
+               fallthrough;
 
        case FI_ACT_UP: /* Upload the components */
        default:
index eb7d139..09c5c24 100644 (file)
@@ -1236,7 +1236,7 @@ static bool esas2r_format_init_msg(struct esas2r_adapter *a,
                        a->init_msg = ESAS2R_INIT_MSG_GET_INIT;
                        break;
                }
-               /* fall through */
+               fallthrough;
 
        case ESAS2R_INIT_MSG_GET_INIT:
                if (msg == ESAS2R_INIT_MSG_GET_INIT) {
@@ -1250,7 +1250,7 @@ static bool esas2r_format_init_msg(struct esas2r_adapter *a,
                                esas2r_hdebug("FAILED");
                        }
                }
-               /* fall through */
+               fallthrough;
 
        default:
                rq->req_stat = RS_SUCCESS;
index 89afa31..43a1fd1 100644 (file)
@@ -307,7 +307,7 @@ static void esp_reset_esp(struct esp *esp)
 
        case FASHME:
                esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
-               /* fallthrough... */
+               fallthrough;
 
        case FAS236:
        case PCSCSI:
@@ -1741,7 +1741,7 @@ again:
 
        case ESP_EVENT_DATA_IN:
                write = 1;
-               /* fallthru */
+               fallthrough;
 
        case ESP_EVENT_DATA_OUT: {
                struct esp_cmd_entry *ent = esp->active_cmd;
index 1409c76..5ea426e 100644 (file)
@@ -450,10 +450,10 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
                switch (fip->mode) {
                default:
                        LIBFCOE_FIP_DBG(fip, "invalid mode %d\n", fip->mode);
-                       /* fall-through */
+                       fallthrough;
                case FIP_MODE_AUTO:
                        LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
-                       /* fall-through */
+                       fallthrough;
                case FIP_MODE_FABRIC:
                case FIP_MODE_NON_FIP:
                        mutex_unlock(&fip->ctlr_mutex);
@@ -773,7 +773,7 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
                        fc_fcoe_set_mac(mac, fh->fh_d_id);
                        fip->update_mac(lport, mac);
                }
-               /* fall through */
+               fallthrough;
        case ELS_LS_RJT:
                op = fr_encaps(fp);
                if (op)
@@ -2439,7 +2439,7 @@ static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip,
                                          frport->enode_mac, 0);
                        break;
                }
-               /* fall through */
+               fallthrough;
        case FIP_ST_VNMP_START:
                LIBFCOE_FIP_DBG(fip, "vn_probe_req: "
                                "restart VN2VN negotiation\n");
index 2cc676e..29e4cdc 100644 (file)
@@ -340,7 +340,7 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt,
                        break;
                case BOARD_DTC3181E:
                        hostdata->io_width = 2; /* 16-bit PDMA */
-                       /* fall through */
+                       fallthrough;
                case BOARD_NCR53C400A:
                case BOARD_HP_C2502:
                        hostdata->c400_ctl_status = 9;
index 11caa4b..d9d21d2 100644 (file)
@@ -1144,7 +1144,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
                        hisi_hba->hw->get_events(hisi_hba, phy_no);
                        break;
                }
-               /* fallthru */
+               fallthrough;
        case PHY_FUNC_RELEASE_SPINUP_HOLD:
        default:
                return -EOPNOTSUPP;
index 91794a5..48d5da5 100644 (file)
@@ -4697,7 +4697,7 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
        case WRITE_6:
        case WRITE_12:
                is_write = 1;
-               /* fall through */
+               fallthrough;
        case READ_6:
        case READ_12:
                if (*cdb_len == 6) {
@@ -5147,7 +5147,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
        switch (cmd->cmnd[0]) {
        case WRITE_6:
                is_write = 1;
-               /* fall through */
+               fallthrough;
        case READ_6:
                first_block = (((cmd->cmnd[1] & 0x1F) << 16) |
                                (cmd->cmnd[2] << 8) |
@@ -5158,7 +5158,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
                break;
        case WRITE_10:
                is_write = 1;
-               /* fall through */
+               fallthrough;
        case READ_10:
                first_block =
                        (((u64) cmd->cmnd[2]) << 24) |
@@ -5171,7 +5171,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
                break;
        case WRITE_12:
                is_write = 1;
-               /* fall through */
+               fallthrough;
        case READ_12:
                first_block =
                        (((u64) cmd->cmnd[2]) << 24) |
@@ -5186,7 +5186,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
                break;
        case WRITE_16:
                is_write = 1;
-               /* fall through */
+               fallthrough;
        case READ_16:
                first_block =
                        (((u64) cmd->cmnd[2]) << 56) |
index 77f4d37..ea7c893 100644 (file)
@@ -1866,7 +1866,7 @@ static int ibmvfc_bsg_request(struct bsg_job *job)
                port_id = (bsg_request->rqst_data.h_els.port_id[0] << 16) |
                        (bsg_request->rqst_data.h_els.port_id[1] << 8) |
                        bsg_request->rqst_data.h_els.port_id[2];
-               /* fall through */
+               fallthrough;
        case FC_BSG_RPT_ELS:
                fc_flags = IBMVFC_FC_ELS;
                break;
@@ -1875,7 +1875,7 @@ static int ibmvfc_bsg_request(struct bsg_job *job)
                port_id = (bsg_request->rqst_data.h_ct.port_id[0] << 16) |
                        (bsg_request->rqst_data.h_ct.port_id[1] << 8) |
                        bsg_request->rqst_data.h_ct.port_id[2];
-               /* fall through */
+               fallthrough;
        case FC_BSG_RPT_CT:
                fc_flags = IBMVFC_FC_CT_IU;
                break;
@@ -4122,7 +4122,7 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
                return;
        case IBMVFC_MAD_CRQ_ERROR:
                ibmvfc_retry_host_init(vhost);
-               /* fall through */
+               fallthrough;
        case IBMVFC_MAD_DRIVER_FAILED:
                ibmvfc_free_event(evt);
                return;
index d9e94e8..cc3908c 100644 (file)
@@ -1581,7 +1581,7 @@ static long ibmvscsis_adapter_info(struct scsi_info *vscsi,
        case H_PERMISSION:
                if (connection_broken(vscsi))
                        flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED);
-               /* Fall through */
+               fallthrough;
        default:
                dev_err(&vscsi->dev, "adapter_info: h_copy_rdma to client failed, rc %ld\n",
                        rc);
@@ -2489,10 +2489,10 @@ static long ibmvscsis_ping_response(struct scsi_info *vscsi)
                break;
        case H_CLOSED:
                vscsi->flags |= CLIENT_FAILED;
-               /* Fall through */
+               fallthrough;
        case H_DROPPED:
                vscsi->flags |= RESPONSE_Q_DOWN;
-               /* Fall through */
+               fallthrough;
        case H_REMOTE_PARM:
                dev_err(&vscsi->dev, "ping_response: h_send_crq failed, rc %ld\n",
                        rc);
index 1459b14..862d35a 100644 (file)
@@ -801,7 +801,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
        case 1:         /* Phase 1 - Connected */
                imm_connect(dev, CONNECT_EPP_MAYBE);
                cmd->SCp.phase++;
-               /* fall through */
+               fallthrough;
 
        case 2:         /* Phase 2 - We are now talking to the scsi bus */
                if (!imm_select(dev, scmd_id(cmd))) {
@@ -809,7 +809,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
                        return 0;
                }
                cmd->SCp.phase++;
-               /* fall through */
+               fallthrough;
 
        case 3:         /* Phase 3 - Ready to accept a command */
                w_ctr(ppb, 0x0c);
@@ -819,7 +819,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
                if (!imm_send_command(cmd))
                        return 0;
                cmd->SCp.phase++;
-               /* fall through */
+               fallthrough;
 
        case 4:         /* Phase 4 - Setup scatter/gather buffers */
                if (scsi_bufflen(cmd)) {
@@ -835,7 +835,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
                cmd->SCp.phase++;
                if (cmd->SCp.this_residual & 0x01)
                        cmd->SCp.this_residual++;
-               /* fall through */
+               fallthrough;
 
        case 5:         /* Phase 5 - Pre-Data transfer stage */
                /* Spin lock for BUSY */
@@ -852,7 +852,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
                        if (imm_negotiate(dev))
                                return 0;
                cmd->SCp.phase++;
-               /* fall through */
+               fallthrough;
 
        case 6:         /* Phase 6 - Data transfer stage */
                /* Spin lock for BUSY */
@@ -868,7 +868,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
                                return 1;
                }
                cmd->SCp.phase++;
-               /* fall through */
+               fallthrough;
 
        case 7:         /* Phase 7 - Post data transfer stage */
                if ((dev->dp) && (dev->rd)) {
@@ -880,7 +880,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
                        }
                }
                cmd->SCp.phase++;
-               /* fall through */
+               fallthrough;
 
        case 8:         /* Phase 8 - Read status/message */
                /* Check for data overrun */
index 7f9b3f2..4cacb80 100644 (file)
@@ -778,7 +778,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
                        break;
                case SCU_EVENT_LINK_FAILURE:
                        scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
-                       /* fall through */
+                       fallthrough;
                case SCU_EVENT_HARD_RESET_RECEIVED:
                        /* Start the oob/sn state machine over again */
                        sci_change_state(&iphy->sm, SCI_PHY_STARTING);
index cd1e4b4..c3f540b 100644 (file)
@@ -310,7 +310,7 @@ static void isci_remote_device_not_ready(struct isci_host *ihost,
                /* Kill all outstanding requests for the device. */
                sci_remote_device_terminate_requests(idev);
 
-               /* Fall through - into the default case... */
+               fallthrough;    /* into the default case */
        default:
                clear_bit(IDEV_IO_READY, &idev->flags);
                break;
@@ -593,7 +593,7 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
 
                        break;
                }
-               /* fall through - and treat as unhandled... */
+               fallthrough;    /* and treat as unhandled */
        default:
                dev_dbg(scirdev_to_dev(idev),
                        "%s: device: %p event code: %x: %s\n",
index 474a434..68333f5 100644 (file)
@@ -225,7 +225,7 @@ static void sci_remote_node_context_continue_state_transitions(struct sci_remote
        case RNC_DEST_READY:
        case RNC_DEST_SUSPENDED_RESUME:
                rnc->destination_state = RNC_DEST_READY;
-               /* Fall through... */
+               fallthrough;
        case RNC_DEST_FINAL:
                sci_remote_node_context_resume(rnc, rnc->user_callback,
                                               rnc->user_cookie);
@@ -601,9 +601,9 @@ enum sci_status sci_remote_node_context_suspend(
                                 __func__, sci_rnc);
                        return SCI_FAILURE_INVALID_STATE;
                }
-               /* Fall through - and handle like SCI_RNC_POSTING */
+               fallthrough;    /* and handle like SCI_RNC_POSTING */
        case SCI_RNC_RESUMING:
-               /* Fall through - and handle like SCI_RNC_POSTING */
+               fallthrough;    /* and handle like SCI_RNC_POSTING */
        case SCI_RNC_POSTING:
                /* Set the destination state to AWAIT - this signals the
                 * entry into the SCI_RNC_READY state that a suspension
index 6561a07..6e08179 100644 (file)
@@ -894,7 +894,7 @@ sci_io_request_terminate(struct isci_request *ireq)
                 * and don't wait for the task response.
                 */
                sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
-               /* Fall through - and handle like ABORTING... */
+               fallthrough;    /* and handle like ABORTING */
        case SCI_REQ_ABORTING:
                if (!isci_remote_device_is_safe_to_abort(ireq->target_device))
                        set_bit(IREQ_PENDING_ABORT, &ireq->flags);
index b5dd1ca..d10efb6 100644 (file)
@@ -736,6 +736,7 @@ static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
        struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
        struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
        struct sockaddr_in6 addr;
+       struct socket *sock;
        int rc;
 
        switch(param) {
@@ -747,13 +748,17 @@ static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
                        spin_unlock_bh(&conn->session->frwd_lock);
                        return -ENOTCONN;
                }
+               sock = tcp_sw_conn->sock;
+               sock_hold(sock->sk);
+               spin_unlock_bh(&conn->session->frwd_lock);
+
                if (param == ISCSI_PARAM_LOCAL_PORT)
-                       rc = kernel_getsockname(tcp_sw_conn->sock,
+                       rc = kernel_getsockname(sock,
                                                (struct sockaddr *)&addr);
                else
-                       rc = kernel_getpeername(tcp_sw_conn->sock,
+                       rc = kernel_getpeername(sock,
                                                (struct sockaddr *)&addr);
-               spin_unlock_bh(&conn->session->frwd_lock);
+               sock_put(sock->sk);
                if (rc < 0)
                        return rc;
 
@@ -775,6 +780,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
        struct iscsi_tcp_conn *tcp_conn;
        struct iscsi_sw_tcp_conn *tcp_sw_conn;
        struct sockaddr_in6 addr;
+       struct socket *sock;
        int rc;
 
        switch (param) {
@@ -789,16 +795,18 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
                        return -ENOTCONN;
                }
                tcp_conn = conn->dd_data;
-
                tcp_sw_conn = tcp_conn->dd_data;
-               if (!tcp_sw_conn->sock) {
+               sock = tcp_sw_conn->sock;
+               if (!sock) {
                        spin_unlock_bh(&session->frwd_lock);
                        return -ENOTCONN;
                }
+               sock_hold(sock->sk);
+               spin_unlock_bh(&session->frwd_lock);
 
-               rc = kernel_getsockname(tcp_sw_conn->sock,
+               rc = kernel_getsockname(sock,
                                        (struct sockaddr *)&addr);
-               spin_unlock_bh(&session->frwd_lock);
+               sock_put(sock->sk);
                if (rc < 0)
                        return rc;
 
index d8cbc9c..e67abb1 100644 (file)
@@ -634,8 +634,6 @@ free_fp:
        fc_frame_free(fp);
 out:
        kref_put(&rdata->kref, fc_rport_destroy);
-       if (!IS_ERR(fp))
-               fc_frame_free(fp);
 }
 
 /**
index 16eb3b6..96a2952 100644 (file)
@@ -2108,7 +2108,7 @@ static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg)
        switch (op) {
        case ELS_LS_RJT:
                FC_EXCH_DBG(aborted_ep, "LS_RJT for RRQ\n");
-               /* fall through */
+               fallthrough;
        case ELS_LS_ACC:
                goto cleanup;
        default:
@@ -2622,7 +2622,7 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
        case FC_EOF_T:
                if (f_ctl & FC_FC_END_SEQ)
                        skb_trim(fp_skb(fp), fr_len(fp) - FC_FC_FILL(f_ctl));
-               /* fall through */
+               fallthrough;
        case FC_EOF_N:
                if (fh->fh_type == FC_TYPE_BLS)
                        fc_exch_recv_bls(ema->mp, fp);
index e11d4f0..7cfeb68 100644 (file)
@@ -752,7 +752,7 @@ static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                brp = fc_frame_payload_get(fp, sizeof(*brp));
                if (brp && brp->br_reason == FC_BA_RJT_LOG_ERR)
                        break;
-               /* fall thru */
+               fallthrough;
        default:
                /*
                 * we will let the command timeout
@@ -1536,7 +1536,7 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
                                   "device %x invalid REC reject %d/%d\n",
                                   fsp->rport->port_id, rjt->er_reason,
                                   rjt->er_explan);
-                       /* fall through */
+                       fallthrough;
                case ELS_RJT_UNSUP:
                        FC_FCP_DBG(fsp, "device does not support REC\n");
                        rpriv = fsp->rport->dd_data;
@@ -1668,7 +1668,7 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                FC_FCP_DBG(fsp, "REC %p fid %6.6x error unexpected error %d\n",
                           fsp, fsp->rport->port_id, error);
                fsp->status_code = FC_CMD_PLOGO;
-               /* fall through */
+               fallthrough;
 
        case -FC_EX_TIMEOUT:
                /*
@@ -1830,7 +1830,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                break;
        case -FC_EX_CLOSED:                     /* e.g., link failure */
                FC_FCP_DBG(fsp, "SRR error, exchange closed\n");
-               /* fall through */
+               fallthrough;
        default:
                fc_fcp_retry_cmd(fsp, FC_ERROR);
                break;
index b84dbc3..6557fda 100644 (file)
@@ -1578,7 +1578,7 @@ static void fc_lport_timeout(struct work_struct *work)
        case LPORT_ST_DPRT:
                FC_LPORT_DBG(lport, "Skipping lport state %s to SCR\n",
                             fc_lport_state(lport));
-               /* fall thru */
+               fallthrough;
        case LPORT_ST_SCR:
                fc_lport_enter_scr(lport);
                break;
index 18663a8..a60b228 100644 (file)
@@ -1723,7 +1723,7 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp)
                        kref_put(&rdata->kref, fc_rport_destroy);
                        goto busy;
                }
-               /* fall through */
+               fallthrough;
        default:
                FC_RPORT_DBG(rdata,
                             "Reject ELS 0x%02x while in state %s\n",
index 49c8a18..1e9c317 100644 (file)
@@ -248,7 +248,7 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode)
                hdr_lun = scsilun_to_int(&tmf->lun);
                if (hdr_lun != task->sc->device->lun)
                        return 0;
-               /* fall through */
+               fallthrough;
        case ISCSI_TM_FUNC_TARGET_WARM_RESET:
                /*
                 * Fail all SCSI cmd PDUs
@@ -1674,7 +1674,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
                                sc->result = DID_NO_CONNECT << 16;
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
                case ISCSI_STATE_IN_RECOVERY:
                        reason = FAILURE_SESSION_IN_RECOVERY;
                        sc->result = DID_IMM_RETRY << 16;
@@ -2239,7 +2239,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
                                              "progress\n");
                        goto success;
                }
-               /* fall through */
+               fallthrough;
        default:
                conn->tmf_state = TMF_INITIAL;
                goto failed;
index 6ef93c7..83f14b2 100644 (file)
@@ -128,7 +128,7 @@ static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv)
         * coalescing neighboring slab objects into a single frag which
         * triggers one of hardened usercopy checks.
         */
-       if (!recv && page_count(sg_page(sg)) >= 1 && !PageSlab(sg_page(sg)))
+       if (!recv && sendpage_ok(sg_page(sg)))
                return;
 
        if (recv) {
@@ -772,7 +772,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
                        iscsi_tcp_data_recv_prep(tcp_conn);
                        return 0;
                }
-       /* fall through */
+               fallthrough;
        case ISCSI_OP_LOGOUT_RSP:
        case ISCSI_OP_NOOP_IN:
        case ISCSI_OP_SCSI_TMFUNC_RSP:
index 1b93332..a488798 100644 (file)
@@ -209,7 +209,10 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
                task->num_scatter = si;
        }
 
-       task->data_dir = qc->dma_dir;
+       if (qc->tf.protocol == ATA_PROT_NODATA)
+               task->data_dir = DMA_NONE;
+       else
+               task->data_dir = qc->dma_dir;
        task->scatter = qc->sg;
        task->ata_task.retry_count = 1;
        task->task_state_flags = SAS_TASK_STATE_PENDING;
@@ -324,7 +327,7 @@ static int smp_ata_check_ready(struct ata_link *link)
        case SAS_END_DEVICE:
                if (ex_phy->attached_sata_dev)
                        return sas_ata_clear_pending(dev, ex_phy);
-               /* fall through */
+               fallthrough;
        default:
                return -ENODEV;
        }
index daf951b..d0f9e90 100644 (file)
@@ -108,7 +108,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
                        rphy = NULL;
                        break;
                }
-               /* fall through */
+               fallthrough;
        case SAS_END_DEVICE:
                rphy = sas_end_device_alloc(port->port);
                break;
@@ -182,10 +182,11 @@ int sas_notify_lldd_dev_found(struct domain_device *dev)
                pr_warn("driver on host %s cannot handle device %016llx, error:%d\n",
                        dev_name(sas_ha->dev),
                        SAS_ADDR(dev->sas_addr), res);
+               return res;
        }
        set_bit(SAS_DEV_FOUND, &dev->state);
        kref_get(&dev->kref);
-       return res;
+       return 0;
 }
 
 
index b7d1b1e..8d6bcc1 100644 (file)
@@ -1096,7 +1096,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
                } else
                        memcpy(dev->port->disc.fanout_sas_addr,
                               ex_phy->attached_sas_addr, SAS_ADDR_SIZE);
-               /* fallthrough */
+               fallthrough;
        case SAS_EDGE_EXPANDER_DEVICE:
                child = sas_ex_discover_expander(dev, phy_id);
                break;
index 9e0975e..1bf9398 100644 (file)
@@ -622,7 +622,7 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
                                sas_scsi_clear_queue_lu(work_q, cmd);
                                goto Again;
                        }
-                       /* fallthrough */
+                       fallthrough;
                case TASK_IS_NOT_AT_LU:
                case TASK_ABORT_FAILED:
                        pr_notice("task 0x%p is not at LU: I_T recover\n",
index ef2015f..d0141a2 100644 (file)
@@ -3202,7 +3202,7 @@ port_out:
        case SLI_MGMT_GHAT:
        case SLI_MGMT_GRPL:
                rsp_size = FC_MAX_NS_RSP;
-               /* fall through */
+               fallthrough;
        case SLI_MGMT_DHBA:
        case SLI_MGMT_DHAT:
                pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID;
@@ -3215,7 +3215,7 @@ port_out:
        case SLI_MGMT_GPAT:
        case SLI_MGMT_GPAS:
                rsp_size = FC_MAX_NS_RSP;
-               /* fall through */
+               fallthrough;
        case SLI_MGMT_DPRT:
        case SLI_MGMT_DPA:
                pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID;
index 48dc63f..b609451 100644 (file)
@@ -3517,6 +3517,9 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
                                FC_TLV_DESC_LENGTH_FROM_SZ(prdf->reg_d1));
        prdf->reg_d1.reg_desc.count = cpu_to_be32(ELS_RDF_REG_TAG_CNT);
        prdf->reg_d1.desc_tags[0] = cpu_to_be32(ELS_DTAG_LNK_INTEGRITY);
+       prdf->reg_d1.desc_tags[1] = cpu_to_be32(ELS_DTAG_DELIVERY);
+       prdf->reg_d1.desc_tags[2] = cpu_to_be32(ELS_DTAG_PEER_CONGEST);
+       prdf->reg_d1.desc_tags[3] = cpu_to_be32(ELS_DTAG_CONGESTION);
 
        lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
                              "Issue RDF:       did:x%x",
@@ -4656,7 +4659,9 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 out:
        if (ndlp && NLP_CHK_NODE_ACT(ndlp) && shost) {
                spin_lock_irq(shost->host_lock);
-               ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
+               if (mbox)
+                       ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN;
+               ndlp->nlp_flag &= ~NLP_RM_DFLT_RPI;
                spin_unlock_irq(shost->host_lock);
 
                /* If the node is not being used by another discovery thread,
@@ -9134,7 +9139,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                                lpfc_nlp_put(ndlp);
                                return;
                        }
-                       /* fall through */
+                       fallthrough;
                default:
                        /* Try to recover from this error */
                        if (phba->sli_rev == LPFC_SLI_REV4)
index 142a021..bb02fd8 100644 (file)
@@ -71,6 +71,7 @@ static void lpfc_disc_timeout_handler(struct lpfc_vport *);
 static void lpfc_disc_flush_list(struct lpfc_vport *vport);
 static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
 static int lpfc_fcf_inuse(struct lpfc_hba *);
+static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
 
 void
 lpfc_terminate_rport_io(struct fc_rport *rport)
@@ -1138,11 +1139,13 @@ out:
        return;
 }
 
-
 void
 lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_vport *vport = pmb->vport;
+       LPFC_MBOXQ_t *sparam_mb;
+       struct lpfc_dmabuf *sparam_mp;
+       int rc;
 
        if (pmb->u.mb.mbxStatus)
                goto out;
@@ -1167,12 +1170,42 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        }
 
        /* Start discovery by sending a FLOGI. port_state is identically
-        * LPFC_FLOGI while waiting for FLOGI cmpl. Check if sending
-        * the FLOGI is being deferred till after MBX_READ_SPARAM completes.
+        * LPFC_FLOGI while waiting for FLOGI cmpl.
         */
        if (vport->port_state != LPFC_FLOGI) {
-               if (!(phba->hba_flag & HBA_DEFER_FLOGI))
+               /* Issue MBX_READ_SPARAM to update CSPs before FLOGI if
+                * bb-credit recovery is in place.
+                */
+               if (phba->bbcredit_support && phba->cfg_enable_bbcr &&
+                   !(phba->link_flag & LS_LOOPBACK_MODE)) {
+                       sparam_mb = mempool_alloc(phba->mbox_mem_pool,
+                                                 GFP_KERNEL);
+                       if (!sparam_mb)
+                               goto sparam_out;
+
+                       rc = lpfc_read_sparam(phba, sparam_mb, 0);
+                       if (rc) {
+                               mempool_free(sparam_mb, phba->mbox_mem_pool);
+                               goto sparam_out;
+                       }
+                       sparam_mb->vport = vport;
+                       sparam_mb->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
+                       rc = lpfc_sli_issue_mbox(phba, sparam_mb, MBX_NOWAIT);
+                       if (rc == MBX_NOT_FINISHED) {
+                               sparam_mp = (struct lpfc_dmabuf *)
+                                               sparam_mb->ctx_buf;
+                               lpfc_mbuf_free(phba, sparam_mp->virt,
+                                              sparam_mp->phys);
+                               kfree(sparam_mp);
+                               sparam_mb->ctx_buf = NULL;
+                               mempool_free(sparam_mb, phba->mbox_mem_pool);
+                               goto sparam_out;
+                       }
+
+                       phba->hba_flag |= HBA_DEFER_FLOGI;
+               }  else {
                        lpfc_initial_flogi(vport);
+               }
        } else {
                if (vport->fc_flag & FC_PT2PT)
                        lpfc_disc_start(vport);
@@ -1184,6 +1217,7 @@ out:
                         "0306 CONFIG_LINK mbxStatus error x%x "
                         "HBA state x%x\n",
                         pmb->u.mb.mbxStatus, vport->port_state);
+sparam_out:
        mempool_free(pmb, phba->mbox_mem_pool);
 
        lpfc_linkdown(phba);
@@ -3239,21 +3273,6 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
        lpfc_linkup(phba);
        sparam_mbox = NULL;
 
-       if (!(phba->hba_flag & HBA_FCOE_MODE)) {
-               cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-               if (!cfglink_mbox)
-                       goto out;
-               vport->port_state = LPFC_LOCAL_CFG_LINK;
-               lpfc_config_link(phba, cfglink_mbox);
-               cfglink_mbox->vport = vport;
-               cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
-               rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT);
-               if (rc == MBX_NOT_FINISHED) {
-                       mempool_free(cfglink_mbox, phba->mbox_mem_pool);
-                       goto out;
-               }
-       }
-
        sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!sparam_mbox)
                goto out;
@@ -3274,7 +3293,20 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
                goto out;
        }
 
-       if (phba->hba_flag & HBA_FCOE_MODE) {
+       if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+               cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+               if (!cfglink_mbox)
+                       goto out;
+               vport->port_state = LPFC_LOCAL_CFG_LINK;
+               lpfc_config_link(phba, cfglink_mbox);
+               cfglink_mbox->vport = vport;
+               cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
+               rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT);
+               if (rc == MBX_NOT_FINISHED) {
+                       mempool_free(cfglink_mbox, phba->mbox_mem_pool);
+                       goto out;
+               }
+       } else {
                vport->port_state = LPFC_VPORT_UNKNOWN;
                /*
                 * Add the driver's default FCF record at FCF index 0 now. This
@@ -3331,10 +3363,6 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
                }
                /* Reset FCF roundrobin bmask for new discovery */
                lpfc_sli4_clear_fcf_rr_bmask(phba);
-       } else {
-               if (phba->bbcredit_support && phba->cfg_enable_bbcr &&
-                   !(phba->link_flag & LS_LOOPBACK_MODE))
-                       phba->hba_flag |= HBA_DEFER_FLOGI;
        }
 
        /* Prepare for LINK up registrations */
@@ -4728,15 +4756,14 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba,
                case CMD_GEN_REQUEST64_CR:
                        if (iocb->context_un.ndlp == ndlp)
                                return 1;
-                       /* fall through */
+                       fallthrough;
                case CMD_ELS_REQUEST64_CR:
                        if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID)
                                return 1;
-                       /* fall through */
+                       fallthrough;
                case CMD_XMIT_ELS_RSP64_CX:
                        if (iocb->context1 == (uint8_t *) ndlp)
                                return 1;
-                       /* fall through */
                }
        } else if (pring->ringno == LPFC_FCP_RING) {
                /* Skip match check if waiting to relogin to FCP target */
@@ -6055,7 +6082,7 @@ restart_disc:
 
        case LPFC_LINK_UP:
                lpfc_issue_clear_la(phba, vport);
-               /* fall through */
+               fallthrough;
        case LPFC_LINK_UNKNOWN:
        case LPFC_WARM_START:
        case LPFC_INIT_START:
index c4ba827..12e4e76 100644 (file)
@@ -4800,7 +4800,7 @@ struct send_frame_wqe {
        uint32_t fc_hdr_wd5;           /* word 15 */
 };
 
-#define ELS_RDF_REG_TAG_CNT            1
+#define ELS_RDF_REG_TAG_CNT            4
 struct lpfc_els_rdf_reg_desc {
        struct fc_df_desc_fpin_reg      reg_desc;       /* descriptor header */
        __be32                          desc_tags[ELS_RDF_REG_TAG_CNT];
index c697259..ca25e54 100644 (file)
@@ -11376,7 +11376,6 @@ lpfc_irq_clear_aff(struct lpfc_hba_eq_hdl *eqhdl)
 {
        cpumask_clear(&eqhdl->aff_mask);
        irq_clear_status_flags(eqhdl->irq, IRQ_NO_BALANCING);
-       irq_set_affinity_hint(eqhdl->irq, &eqhdl->aff_mask);
 }
 
 /**
index cad53d1..92d6e7b 100644 (file)
@@ -464,7 +464,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        case  NLP_STE_NPR_NODE:
                if (!(ndlp->nlp_flag & NLP_NPR_ADISC))
                        break;
-               /* fall through */
+               fallthrough;
        case  NLP_STE_REG_LOGIN_ISSUE:
        case  NLP_STE_PRLI_ISSUE:
        case  NLP_STE_UNMAPPED_NODE:
index e5be334..0c39ed5 100644 (file)
@@ -1225,7 +1225,7 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
                                         lpfc_ncmd, nCmd,
                                         lpfc_ncmd->cur_iocbq.sli4_xritag,
                                         bf_get(lpfc_wcqe_c_xb, wcqe));
-                       /* fall through */
+                       fallthrough;
                default:
 out_err:
                        lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR,
index 5e802c8..983eeb0 100644 (file)
@@ -1093,7 +1093,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
                                        break;
                                }
-                               /* fall through */
+                               fallthrough;
                        case SCSI_PROT_WRITE_INSERT:
                                /*
                                 * For WRITE_INSERT, force the error
@@ -1213,7 +1213,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                                        rc = BG_ERR_TGT | BG_ERR_CHECK;
                                        break;
                                }
-                               /* fall through */
+                               fallthrough;
                        case SCSI_PROT_WRITE_INSERT:
                                /*
                                 * For WRITE_INSERT, force the
@@ -1295,7 +1295,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                        switch (op) {
                        case SCSI_PROT_WRITE_PASS:
                                rc = BG_ERR_CHECK;
-                               /* fall through */
+                               fallthrough;
 
                        case SCSI_PROT_WRITE_INSERT:
                                /*
@@ -3980,7 +3980,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                                        lpfc_cmd->cur_iocbq.sli4_lxritag,
                                        0, 0);
                        }
-                       /* fall through */
+                       fallthrough;
                default:
                        cmd->result = DID_ERROR << 16;
                        break;
index 4cd7ded..e158cd7 100644 (file)
@@ -9339,7 +9339,7 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number,
                         */
                        if (piocb->iocb_cmpl)
                                piocb->iocb_cmpl = NULL;
-                       /*FALLTHROUGH*/
+                       fallthrough;
                case CMD_CREATE_XRI_CR:
                case CMD_CLOSE_XRI_CN:
                case CMD_CLOSE_XRI_CX:
@@ -9653,7 +9653,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                cmnd = CMD_XMIT_SEQUENCE64_CR;
                if (phba->link_flag & LS_LOOPBACK_MODE)
                        bf_set(wqe_xo, &wqe->xmit_sequence.wge_ctl, 1);
-               /* fall through */
+               fallthrough;
        case CMD_XMIT_SEQUENCE64_CR:
                /* word3 iocb=io_tag32 wqe=reserved */
                wqe->xmit_sequence.rsvd3 = 0;
@@ -13630,7 +13630,7 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
        case FC_STATUS_RQ_BUF_LEN_EXCEEDED:
                lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
                                "2537 Receive Frame Truncated!!\n");
-               /* fall through */
+               fallthrough;
        case FC_STATUS_RQ_SUCCESS:
                spin_lock_irqsave(&phba->hbalock, iflags);
                lpfc_sli4_rq_release(hrq, drq);
@@ -13678,7 +13678,7 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
                                        atomic_read(&tgtp->rcv_fcp_cmd_out),
                                        atomic_read(&tgtp->xmt_fcp_release));
                }
-               /* fallthrough */
+               fallthrough;
 
        case FC_STATUS_INSUFF_BUF_NEED_BUF:
                hrq->RQ_no_posted_buf++;
@@ -14162,7 +14162,7 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
        case FC_STATUS_RQ_BUF_LEN_EXCEEDED:
                lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
                                "6126 Receive Frame Truncated!!\n");
-               /* fall through */
+               fallthrough;
        case FC_STATUS_RQ_SUCCESS:
                spin_lock_irqsave(&phba->hbalock, iflags);
                lpfc_sli4_rq_release(hrq, drq);
@@ -14209,7 +14209,7 @@ drop:
                                        atomic_read(&tgtp->rcv_fcp_cmd_out),
                                        atomic_read(&tgtp->xmt_fcp_release));
                }
-               /* fallthrough */
+               fallthrough;
 
        case FC_STATUS_INSUFF_BUF_NEED_BUF:
                hrq->RQ_no_posted_buf++;
@@ -15096,7 +15096,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
                        status = -EINVAL;
                        goto out;
                }
-               /* fall through - otherwise default to smallest count */
+               fallthrough;    /* otherwise default to smallest count */
        case 256:
                bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
                       LPFC_EQ_CNT_256);
@@ -15238,7 +15238,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
                               LPFC_CQ_CNT_WORD7);
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
                                "0361 Unsupported CQ count: "
@@ -15249,7 +15249,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
                        status = -EINVAL;
                        goto out;
                }
-               /* fall through - otherwise default to smallest count */
+               fallthrough;    /* otherwise default to smallest count */
        case 256:
                bf_set(lpfc_cq_context_count, &cq_create->u.request.context,
                       LPFC_CQ_CNT_256);
@@ -15417,7 +15417,7 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp,
                                               LPFC_CQ_CNT_WORD7);
                                        break;
                                }
-                               /* fall through */
+                               fallthrough;
                        default:
                                lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
                                                "3118 Bad CQ count. (%d)\n",
@@ -15426,7 +15426,7 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp,
                                        status = -EINVAL;
                                        goto out;
                                }
-                               /* fall through - otherwise default to smallest */
+                               fallthrough;    /* otherwise default to smallest */
                        case 256:
                                bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
                                       &cq_set->u.request, LPFC_CQ_CNT_256);
@@ -15702,7 +15702,7 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
                        status = -EINVAL;
                        goto out;
                }
-               /* fall through - otherwise default to smallest count */
+               fallthrough;    /* otherwise default to smallest count */
        case 16:
                bf_set(lpfc_mq_context_ring_size,
                       &mq_create_ext->u.request.context,
@@ -16123,7 +16123,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
                                status = -EINVAL;
                                goto out;
                        }
-                       /* fall through - otherwise default to smallest count */
+                       fallthrough;    /* otherwise default to smallest count */
                case 512:
                        bf_set(lpfc_rq_context_rqe_count,
                               &rq_create->u.request.context,
@@ -16260,7 +16260,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
                                status = -EINVAL;
                                goto out;
                        }
-                       /* fall through - otherwise default to smallest count */
+                       fallthrough;    /* otherwise default to smallest count */
                case 512:
                        bf_set(lpfc_rq_context_rqe_count,
                               &rq_create->u.request.context,
index 20adec4..c657abf 100644 (file)
@@ -20,7 +20,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "12.8.0.3"
+#define LPFC_DRIVER_VERSION "12.8.0.4"
 #define LPFC_DRIVER_NAME               "lpfc"
 
 /* Used for SLI 2/3 */
index 0484ee5..ac40604 100644 (file)
@@ -491,9 +491,9 @@ mega_get_ldrv_num(adapter_t *adapter, struct scsi_cmnd *cmd, int channel)
 
        if (adapter->support_random_del && adapter->read_ldidmap )
                switch (cmd->cmnd[0]) {
-               case READ_6:    /* fall through */
-               case WRITE_6:   /* fall through */
-               case READ_10:   /* fall through */
+               case READ_6:
+               case WRITE_6:
+               case READ_10:
                case WRITE_10:
                        ldrv_num += 0x80;
                }
@@ -852,7 +852,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy)
                        return scb;
 
 #if MEGA_HAVE_CLUSTERING
-               case RESERVE:   /* Fall through */
+               case RESERVE:
                case RELEASE:
 
                        /*
@@ -987,7 +987,7 @@ mega_prepare_passthru(adapter_t *adapter, scb_t *scb, struct scsi_cmnd *cmd,
 
                        adapter->flag |= (1L << cmd->device->channel);
                }
-               /* Fall through */
+               fallthrough;
        default:
                pthru->numsgelements = mega_build_sglist(adapter, scb,
                                &pthru->dataxferaddr, &pthru->dataxferlen);
@@ -1050,7 +1050,7 @@ mega_prepare_extpassthru(adapter_t *adapter, scb_t *scb,
 
                        adapter->flag |= (1L << cmd->device->channel);
                }
-               /* Fall through */
+               fallthrough;
        default:
                epthru->numsgelements = mega_build_sglist(adapter, scb,
                                &epthru->dataxferaddr, &epthru->dataxferlen);
index 19469a2..4a27ac8 100644 (file)
@@ -1581,7 +1581,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
                                return NULL;
                        }
 
-                       /* Fall through */
+                       fallthrough;
 
                case READ_CAPACITY:
                        /*
index 861f714..2b7e7b5 100644 (file)
@@ -3522,7 +3522,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
                        megasas_complete_int_cmd(instance, cmd);
                        break;
                }
-               /* fall through */
+               fallthrough;
 
        case MFI_CMD_LD_READ:
        case MFI_CMD_LD_WRITE:
index 0824410..b0c01cf 100644 (file)
@@ -3534,7 +3534,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
                                atomic_dec(&lbinfo->scsi_pending_cmds[cmd_fusion->pd_r1_lb]);
                                cmd_fusion->scmd->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
                        }
-                       /* Fall through - and complete IO */
+                       fallthrough;    /* and complete IO */
                case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */
                        atomic_dec(&instance->fw_outstanding);
                        if (cmd_fusion->r1_alt_dev_handle == MR_DEVHANDLE_INVALID) {
@@ -3689,7 +3689,7 @@ int megasas_irqpoll(struct irq_poll *irqpoll, int budget)
        instance = irq_ctx->instance;
 
        if (irq_ctx->irq_line_enable) {
-               disable_irq(irq_ctx->os_irq);
+               disable_irq_nosync(irq_ctx->os_irq);
                irq_ctx->irq_line_enable = false;
        }
 
index fd1d030..0a9f4e4 100644 (file)
@@ -1457,7 +1457,7 @@ static void cmd_complete(struct mesh_state *ms)
                /* huh?  we expected a phase mismatch */
                ms->n_msgin = 0;
                ms->msgphase = msg_in;
-               /* fall through */
+               fallthrough;
 
        case msg_in:
                /* should have some message bytes in fifo */
index 1d64524..8062bd9 100644 (file)
@@ -1733,7 +1733,7 @@ _base_irqpoll(struct irq_poll *irqpoll, int budget)
        reply_q = container_of(irqpoll, struct adapter_reply_queue,
                        irqpoll);
        if (reply_q->irq_line_enable) {
-               disable_irq(reply_q->os_irq);
+               disable_irq_nosync(reply_q->os_irq);
                reply_q->irq_line_enable = false;
        }
        num_entries = _base_process_reply_queue(reply_q);
@@ -4681,7 +4681,7 @@ _base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc)
                        ioc_info(ioc, "performance mode: balanced\n");
                        return;
                }
-               /* Fall through */
+               fallthrough;
        case MPT_PERF_MODE_LATENCY:
                /*
                 * Enable interrupt coalescing on all reply queues
index 4326030..7c119b9 100644 (file)
@@ -1002,7 +1002,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
                }
                /* drop to default case for posting the request */
        }
-               /* fall through */
+               fallthrough;
        default:
                ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
                    data_in_dma, data_in_sz);
index 08fc4b3..2e2756d 100644 (file)
@@ -5470,7 +5470,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
 
        case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
                scsi_set_resid(scmd, 0);
-               /* fall through */
+               fallthrough;
        case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
        case MPI2_IOCSTATUS_SUCCESS:
                scmd->result = (DID_OK << 16) | scsi_status;
@@ -6480,7 +6480,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc,
                        if (!test_bit(handle, ioc->pend_os_device_add))
                                break;
 
-                       /* fall through */
+                       fallthrough;
 
                case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
 
@@ -7208,7 +7208,7 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc,
                        event_data->PortEntry[i].PortStatus &= 0xF0;
                        event_data->PortEntry[i].PortStatus |=
                                MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED;
-                       /* fall through */
+                       fallthrough;
                case MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED:
                        if (ioc->shost_recovery)
                                break;
@@ -10653,7 +10653,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                case MPI26_MFGPAGE_DEVID_CFG_SEC_3916:
                        dev_info(&pdev->dev,
                            "HBA is in Configurable Secure mode\n");
-                       /* fall through */
+                       fallthrough;
                case MPI26_MFGPAGE_DEVID_HARD_SEC_3816:
                case MPI26_MFGPAGE_DEVID_HARD_SEC_3916:
                        ioc->is_aero_ioc = ioc->is_gen35_ioc = 1;
index d4bd31a..b2869c5 100644 (file)
@@ -650,7 +650,7 @@ static void myrb_bgi_control(struct myrb_hba *cb)
                if (sdev && cb->bgi_status.status == MYRB_BGI_INPROGRESS)
                        sdev_printk(KERN_INFO, sdev,
                                    "Background Initialization Aborted\n");
-               /* Fallthrough */
+               fallthrough;
        case MYRB_STATUS_NO_BGI_INPROGRESS:
                cb->bgi_status.status = MYRB_BGI_INVALID;
                break;
@@ -1528,7 +1528,7 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
                        scmd->scsi_done(scmd);
                        return 0;
                }
-               /* fall through */
+               fallthrough;
        case WRITE_6:
                lba = (((scmd->cmnd[1] & 0x1F) << 16) |
                       (scmd->cmnd[2] << 8) |
@@ -1545,7 +1545,7 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
                        scmd->scsi_done(scmd);
                        return 0;
                }
-               /* fall through */
+               fallthrough;
        case WRITE_10:
        case VERIFY:            /* 0x2F */
        case WRITE_VERIFY:      /* 0x2E */
@@ -1562,7 +1562,7 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
                        scmd->scsi_done(scmd);
                        return 0;
                }
-               /* fall through */
+               fallthrough;
        case WRITE_12:
        case VERIFY_12: /* 0xAF */
        case WRITE_VERIFY_12:   /* 0xAE */
index f88adab..03d7013 100644 (file)
@@ -3640,7 +3640,7 @@ ncr_script_copy_and_bind (struct ncb *np, ncrcmd *src, ncrcmd *dst, int len)
                                                new = old;
                                                break;
                                        }
-                                       /* fall through */
+                                       fallthrough;
                                default:
                                        panic("ncr_script_copy_and_bind: weird relocation %x\n", old);
                                        break;
@@ -3910,14 +3910,14 @@ static void __init ncr_prepare_setting(struct ncb *np)
                                        np->scsi_mode = SMODE_HVD;
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
                case 3: /* SYMBIOS controllers report HVD through GPIO3 */
                        if (INB(nc_gpreg) & 0x08)
                                break;
-                       /* fall through */
+                       fallthrough;
                case 2: /* Set HVD unconditionally */
                        np->scsi_mode = SMODE_HVD;
-                       /* fall through */
+                       fallthrough;
                case 1: /* Trust previous settings for HVD */
                        if (np->sv_stest2 & 0x20)
                                np->scsi_mode = SMODE_HVD;
@@ -4296,7 +4296,7 @@ static int ncr_queue_command (struct ncb *np, struct scsi_cmnd *cmd)
                        break;
                cp->phys.header.wgoalp  = cpu_to_scr(goalp);
                cp->phys.header.wlastp  = cpu_to_scr(lastp);
-               /* fall through */
+               fallthrough;
        case DMA_FROM_DEVICE:
                goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
                if (segments <= MAX_SCATTERL)
@@ -6717,7 +6717,7 @@ void ncr_int_sir (struct ncb *np)
                        OUTL_DSP (scr_to_cpu(tp->lp[0]->jump_ccb[0]));
                        return;
                }
-               /* fall through */
+               fallthrough;
        case SIR_RESEL_BAD_TARGET:      /* Will send a TARGET RESET message */
        case SIR_RESEL_BAD_LUN:         /* Will send a TARGET RESET message */
        case SIR_RESEL_BAD_I_T_L_Q:     /* Will send an ABORT TAG message   */
@@ -6825,7 +6825,7 @@ void ncr_int_sir (struct ncb *np)
                */
                OUTB (HS_PRT, HS_BUSY);
 
-               /* fall through */
+               fallthrough;
 
        case SIR_NEGO_PROTO:
                /*-------------------------------------------------------
index 8655ff1..bc5a623 100644 (file)
@@ -1113,7 +1113,7 @@ static irqreturn_t nspintr(int irq, void *dev_id)
                        nsp_scsi_done(tmpSC);
                        return IRQ_HANDLED;
                }
-               /* fall thru */
+               fallthrough;
        default:
                if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
                        return IRQ_HANDLED;
index 337e79d..9889bab 100644 (file)
@@ -818,7 +818,7 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
 
                res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
                if (res)
-                       return res;
+                       goto ex_err;
                ccb = &pm8001_ha->ccb_info[ccb_tag];
                ccb->device = pm8001_dev;
                ccb->ccb_tag = ccb_tag;
index 0ae800c..aa41f7a 100644 (file)
@@ -717,7 +717,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
                        }
                        cmd->SCp.phase++;
                }
-               /* fall through */
+               fallthrough;
 
        case 2:         /* Phase 2 - We are now talking to the scsi bus */
                if (!ppa_select(dev, scmd_id(cmd))) {
@@ -725,7 +725,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
                        return 0;
                }
                cmd->SCp.phase++;
-               /* fall through */
+               fallthrough;
 
        case 3:         /* Phase 3 - Ready to accept a command */
                w_ctr(ppb, 0x0c);
@@ -735,7 +735,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
                if (!ppa_send_command(cmd))
                        return 0;
                cmd->SCp.phase++;
-               /* fall through */
+               fallthrough;
 
        case 4:         /* Phase 4 - Setup scatter/gather buffers */
                if (scsi_bufflen(cmd)) {
@@ -749,7 +749,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
                }
                cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
                cmd->SCp.phase++;
-               /* fall through */
+               fallthrough;
 
        case 5:         /* Phase 5 - Data transfer stage */
                w_ctr(ppb, 0x0c);
@@ -762,7 +762,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
                if (retv == 0)
                        return 1;
                cmd->SCp.phase++;
-               /* fall through */
+               fallthrough;
 
        case 6:         /* Phase 6 - Read status/message */
                cmd->result = DID_OK << 16;
index 3f04f2c..5ca424d 100644 (file)
@@ -3863,7 +3863,7 @@ void qedf_stag_change_work(struct work_struct *work)
            container_of(work, struct qedf_ctx, stag_work.work);
 
        if (!qedf) {
-               QEDF_ERR(&qedf->dbg_ctx, "qedf is NULL");
+               QEDF_ERR(NULL, "qedf is NULL");
                return;
        }
        QEDF_ERR(&qedf->dbg_ctx, "Performing software context reset.\n");
index 1bc090d..a165120 100644 (file)
@@ -1626,7 +1626,7 @@ typedef struct {
         */
        uint8_t  firmware_options[2];
 
-       uint16_t frame_payload_size;
+       __le16  frame_payload_size;
        __le16  max_iocb_allocation;
        __le16  execution_throttle;
        uint8_t  retry_count;
index de9fd7f..b569fd6 100644 (file)
@@ -177,7 +177,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
                        break;
                case CS_TIMEOUT:
                        rval = QLA_FUNCTION_TIMEOUT;
-                       /* fall through */
+                       fallthrough;
                default:
                        ql_dbg(ql_dbg_disc, vha, 0x2033,
                            "%s failed, completion status (%x) on port_id: "
index 57a2d76..0bd04a6 100644 (file)
@@ -857,7 +857,7 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
                                            fcport);
                                        break;
                                }
-                               /* fall through */
+                               fallthrough;
                        default:
                                if (fcport_is_smaller(fcport)) {
                                        /* local adapter is bigger */
@@ -4603,18 +4603,18 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
                        nv->firmware_options[1] = BIT_7 | BIT_5;
                        nv->add_firmware_options[0] = BIT_5;
                        nv->add_firmware_options[1] = BIT_5 | BIT_4;
-                       nv->frame_payload_size = 2048;
+                       nv->frame_payload_size = cpu_to_le16(2048);
                        nv->special_options[1] = BIT_7;
                } else if (IS_QLA2200(ha)) {
                        nv->firmware_options[0] = BIT_2 | BIT_1;
                        nv->firmware_options[1] = BIT_7 | BIT_5;
                        nv->add_firmware_options[0] = BIT_5;
                        nv->add_firmware_options[1] = BIT_5 | BIT_4;
-                       nv->frame_payload_size = 1024;
+                       nv->frame_payload_size = cpu_to_le16(1024);
                } else if (IS_QLA2100(ha)) {
                        nv->firmware_options[0] = BIT_3 | BIT_1;
                        nv->firmware_options[1] = BIT_5;
-                       nv->frame_payload_size = 1024;
+                       nv->frame_payload_size = cpu_to_le16(1024);
                }
 
                nv->max_iocb_allocation = cpu_to_le16(256);
index e3d2dea..0954fa4 100644 (file)
@@ -2874,7 +2874,7 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res)
                                            &vha->dpc_flags);
                                        qla2xxx_wake_dpc(vha);
                                }
-                               /* fall through */
+                               fallthrough;
                        default:
                                ql_dbg(ql_dbg_disc, vha, 0x20eb,
                                    "%s %8phC cmd error fw_status 0x%x 0x%x 0x%x\n",
index ab5275d..25e0a16 100644 (file)
@@ -1580,11 +1580,11 @@ global_port_update:
                                qla2xxx_wake_dpc(vha);
                        }
                }
-               /* fall through */
+               fallthrough;
        case MBA_IDC_COMPLETE:
                if (ha->notify_lb_portup_comp && !vha->vp_idx)
                        complete(&ha->lb_portup_comp);
-               /* Fallthru */
+               fallthrough;
        case MBA_IDC_TIME_EXT:
                if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) ||
                    IS_QLA8044(ha))
@@ -2188,7 +2188,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
                                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        qla2xxx_wake_dpc(vha);
                }
-               /* fall through */
+               fallthrough;
        default:
                data[0] = MBS_COMMAND_ERROR;
                break;
@@ -2368,7 +2368,7 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
        case CS_PORT_UNAVAILABLE:
        case CS_PORT_LOGGED_OUT:
                fcport->nvme_flag |= NVME_FLAG_RESETTING;
-               /* fall through */
+               fallthrough;
        case CS_ABORTED:
        case CS_PORT_BUSY:
                fd->transferred_length = 0;
@@ -3485,7 +3485,7 @@ process_err:
                        } else {
                                qlt_24xx_process_atio_queue(vha, 1);
                        }
-                       /* fall through */
+                       fallthrough;
                case ABTS_RESP_24XX:
                case CTIO_TYPE7:
                case CTIO_CRC2:
index e161c05..411b8a9 100644 (file)
@@ -2457,7 +2457,7 @@ qla2x00_write_optrom_data(struct scsi_qla_host *vha, void *buf,
                                sec_mask = 0x10000;
                                break;
                        }
-                       /* Fall through... */
+                       fallthrough;
 
                case 0x1f: /* Atmel flash. */
                        /* 512k sector size. */
@@ -2466,7 +2466,7 @@ qla2x00_write_optrom_data(struct scsi_qla_host *vha, void *buf,
                                sec_mask =   0x80000000;
                                break;
                        }
-                       /* Fall through... */
+                       fallthrough;
 
                case 0x01: /* AMD flash. */
                        if (flash_id == 0x38 || flash_id == 0x40 ||
@@ -2499,7 +2499,7 @@ qla2x00_write_optrom_data(struct scsi_qla_host *vha, void *buf,
                                sec_mask = 0x1e000;
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
                default:
                        /* Default to 16 kb sector size. */
                        rest_addr = 0x3fff;
index 9028916..2d445bd 100644 (file)
@@ -442,7 +442,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha,
                ql_dbg(ql_dbg_tgt, vha, 0xe073,
                        "qla_target(%d):%s: CRC2 Response pkt\n",
                        vha->vp_idx, __func__);
-               /* fall through */
+               fallthrough;
        case CTIO_TYPE7:
        {
                struct ctio7_from_24xx *entry = (struct ctio7_from_24xx *)pkt;
@@ -4423,7 +4423,7 @@ static int qlt_issue_task_mgmt(struct fc_port *sess, u64 lun,
        case QLA_TGT_CLEAR_TS:
        case QLA_TGT_ABORT_TS:
                abort_cmds_for_lun(vha, lun, a->u.isp24.fcp_hdr.s_id);
-               /* fall through */
+               fallthrough;
        case QLA_TGT_CLEAR_ACA:
                h = qlt_find_qphint(vha, mcmd->unpacked_lun);
                mcmd->qpair = h->qpair;
@@ -5057,7 +5057,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
                        res = 1;
                        break;
                }
-               /* fall through */
+               fallthrough;
        case ELS_LOGO:
        case ELS_PRLO:
                spin_lock_irqsave(&ha->tgt.sess_lock, flags);
index bab87e4..676778c 100644 (file)
@@ -2907,7 +2907,7 @@ static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
                                                chap_tbl.secret_len);
                        }
                }
-               /* fall through */
+               fallthrough;
        default:
                return iscsi_session_get_param(cls_sess, param, buf);
        }
index 3790e8b..48ff7d8 100644 (file)
@@ -200,15 +200,15 @@ static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int f
        /* Write mailbox command registers. */
        switch (mbox_param[param[0]] >> 4) {
        case 6: sbus_writew(param[5], qpti->qregs + MBOX5);
-               /* Fall through */
+               fallthrough;
        case 5: sbus_writew(param[4], qpti->qregs + MBOX4);
-               /* Fall through */
+               fallthrough;
        case 4: sbus_writew(param[3], qpti->qregs + MBOX3);
-               /* Fall through */
+               fallthrough;
        case 3: sbus_writew(param[2], qpti->qregs + MBOX2);
-               /* Fall through */
+               fallthrough;
        case 2: sbus_writew(param[1], qpti->qregs + MBOX1);
-               /* Fall through */
+               fallthrough;
        case 1: sbus_writew(param[0], qpti->qregs + MBOX0);
        }
 
@@ -259,15 +259,15 @@ static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int f
        /* Read back output parameters. */
        switch (mbox_param[param[0]] & 0xf) {
        case 6: param[5] = sbus_readw(qpti->qregs + MBOX5);
-               /* Fall through */
+               fallthrough;
        case 5: param[4] = sbus_readw(qpti->qregs + MBOX4);
-               /* Fall through */
+               fallthrough;
        case 4: param[3] = sbus_readw(qpti->qregs + MBOX3);
-               /* Fall through */
+               fallthrough;
        case 3: param[2] = sbus_readw(qpti->qregs + MBOX2);
-               /* Fall through */
+               fallthrough;
        case 2: param[1] = sbus_readw(qpti->qregs + MBOX1);
-               /* Fall through */
+               fallthrough;
        case 1: param[0] = sbus_readw(qpti->qregs + MBOX0);
        }
 
index 139f007..1ad7260 100644 (file)
@@ -4482,8 +4482,6 @@ static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                goto fini;
        }
 
-       if (zc == ZC2_IMPLICIT_OPEN)
-               zbc_close_zone(devip, zsp);
        zbc_open_zone(devip, zsp, true);
 fini:
        write_unlock(macc_lckp);
index 927b1e6..7d3571a 100644 (file)
@@ -599,7 +599,7 @@ int scsi_check_sense(struct scsi_cmnd *scmd)
                        set_host_byte(scmd, DID_ALLOC_FAILURE);
                        return SUCCESS;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case COPY_ABORTED:
        case VOLUME_OVERFLOW:
        case MISCOMPARE:
@@ -621,7 +621,7 @@ int scsi_check_sense(struct scsi_cmnd *scmd)
                        return ADD_TO_MLQUEUE;
                else
                        set_host_byte(scmd, DID_TARGET_FAILURE);
-               /* FALLTHROUGH */
+               fallthrough;
 
        case ILLEGAL_REQUEST:
                if (sshdr.asc == 0x20 || /* Invalid command operation code */
@@ -734,7 +734,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
        switch (status_byte(scmd->result)) {
        case GOOD:
                scsi_handle_queue_ramp_up(scmd->device);
-               /* FALLTHROUGH */
+               fallthrough;
        case COMMAND_TERMINATED:
                return SUCCESS;
        case CHECK_CONDITION:
@@ -755,7 +755,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
                return FAILED;
        case QUEUE_FULL:
                scsi_handle_queue_full(scmd->device);
-               /* fall through */
+               fallthrough;
        case BUSY:
                return NEEDS_RETRY;
        default:
@@ -1302,7 +1302,7 @@ retry_tur:
        case NEEDS_RETRY:
                if (retry_cnt--)
                        goto retry_tur;
-               /*FALLTHRU*/
+               fallthrough;
        case SUCCESS:
                return 0;
        default:
@@ -1739,7 +1739,7 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd)
                if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
                    status_byte(scmd->result) == RESERVATION_CONFLICT)
                        return 0;
-               /* fall through */
+               fallthrough;
        case DID_SOFT_ERROR:
                return (scmd->request->cmd_flags & REQ_FAILFAST_DRIVER);
        }
@@ -1810,7 +1810,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
                        set_host_byte(scmd, DID_TIME_OUT);
                        return SUCCESS;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case DID_NO_CONNECT:
        case DID_BAD_TARGET:
                /*
@@ -1854,7 +1854,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
                         * lower down
                         */
                        break;
-               /* fallthrough */
+               fallthrough;
        case DID_BUS_BUSY:
        case DID_PARITY:
                goto maybe_retry;
@@ -1892,7 +1892,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
                 * the case of trying to send too many commands to a
                 * tagged queueing device.
                 */
-               /* FALLTHROUGH */
+               fallthrough;
        case BUSY:
                /*
                 * device can't talk to us at the moment.  Should only
@@ -1905,7 +1905,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
                if (scmd->cmnd[0] == REPORT_LUNS)
                        scmd->device->sdev_target->expecting_lun_change = 0;
                scsi_handle_queue_ramp_up(scmd->device);
-               /* FALLTHROUGH */
+               fallthrough;
        case COMMAND_TERMINATED:
                return SUCCESS;
        case TASK_ABORTED:
@@ -2376,22 +2376,22 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg)
                rtn = scsi_try_bus_device_reset(scmd);
                if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
                        break;
-               /* FALLTHROUGH */
+               fallthrough;
        case SG_SCSI_RESET_TARGET:
                rtn = scsi_try_target_reset(scmd);
                if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
                        break;
-               /* FALLTHROUGH */
+               fallthrough;
        case SG_SCSI_RESET_BUS:
                rtn = scsi_try_bus_reset(scmd);
                if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
                        break;
-               /* FALLTHROUGH */
+               fallthrough;
        case SG_SCSI_RESET_HOST:
                rtn = scsi_try_host_reset(scmd);
                if (rtn == SUCCESS)
                        break;
-               /* FALLTHROUGH */
+               fallthrough;
        default:
                rtn = FAILED;
                break;
index 45d04b7..14872c9 100644 (file)
@@ -117,14 +117,14 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
                case NOT_READY: /* This happens if there is no disc in drive */
                        if (sdev->removable)
                                break;
-                       /* FALLTHROUGH */
+                       fallthrough;
                case UNIT_ATTENTION:
                        if (sdev->removable) {
                                sdev->changed = 1;
                                result = 0;     /* This is no longer considered an error */
                                break;
                        }
-                       /* FALLTHROUGH -- for non-removable media */
+                       fallthrough;    /* for non-removable media */
                default:
                        sdev_printk(KERN_INFO, sdev,
                                    "ioctl_internal_command return code = %x\n",
index 7c6dd6f..7affaaf 100644 (file)
@@ -795,7 +795,7 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
                }
                if (!scsi_end_request(req, blk_stat, blk_rq_err_bytes(req)))
                        return;
-               /*FALLTHRU*/
+               fallthrough;
        case ACTION_REPREP:
                scsi_io_completion_reprep(cmd, q);
                break;
index 95018e6..16503e2 100644 (file)
@@ -2964,26 +2964,32 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
 
        if (sdkp->device->type == TYPE_ZBC) {
                /* Host-managed */
-               q->limits.zoned = BLK_ZONED_HM;
+               blk_queue_set_zoned(sdkp->disk, BLK_ZONED_HM);
        } else {
                sdkp->zoned = (buffer[8] >> 4) & 3;
-               if (sdkp->zoned == 1 && !disk_has_partitions(sdkp->disk)) {
+               if (sdkp->zoned == 1) {
                        /* Host-aware */
-                       q->limits.zoned = BLK_ZONED_HA;
+                       blk_queue_set_zoned(sdkp->disk, BLK_ZONED_HA);
                } else {
-                       /*
-                        * Treat drive-managed devices and host-aware devices
-                        * with partitions as regular block devices.
-                        */
-                       q->limits.zoned = BLK_ZONED_NONE;
-                       if (sdkp->zoned == 2 && sdkp->first_scan)
-                               sd_printk(KERN_NOTICE, sdkp,
-                                         "Drive-managed SMR disk\n");
+                       /* Regular disk or drive managed disk */
+                       blk_queue_set_zoned(sdkp->disk, BLK_ZONED_NONE);
                }
        }
-       if (blk_queue_is_zoned(q) && sdkp->first_scan)
+
+       if (!sdkp->first_scan)
+               goto out;
+
+       if (blk_queue_is_zoned(q)) {
                sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n",
                      q->limits.zoned == BLK_ZONED_HM ? "managed" : "aware");
+       } else {
+               if (sdkp->zoned == 1)
+                       sd_printk(KERN_NOTICE, sdkp,
+                                 "Host-aware SMR disk used as regular disk\n");
+               else if (sdkp->zoned == 2)
+                       sd_printk(KERN_NOTICE, sdkp,
+                                 "Drive-managed SMR disk\n");
+       }
 
  out:
        kfree(buffer);
@@ -3404,10 +3410,6 @@ static int sd_probe(struct device *dev)
        sdkp->first_scan = 1;
        sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS;
 
-       error = sd_zbc_init_disk(sdkp);
-       if (error)
-               goto out_free_index;
-
        sd_revalidate_disk(gd);
 
        gd->flags = GENHD_FL_EXT_DEVT;
index 4933e7d..a3aad60 100644 (file)
@@ -215,7 +215,6 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp)
 
 #ifdef CONFIG_BLK_DEV_ZONED
 
-int sd_zbc_init_disk(struct scsi_disk *sdkp);
 void sd_zbc_release_disk(struct scsi_disk *sdkp);
 int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer);
 int sd_zbc_revalidate_zones(struct scsi_disk *sdkp);
@@ -231,11 +230,6 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba,
 
 #else /* CONFIG_BLK_DEV_ZONED */
 
-static inline int sd_zbc_init_disk(struct scsi_disk *sdkp)
-{
-       return 0;
-}
-
 static inline void sd_zbc_release_disk(struct scsi_disk *sdkp) {}
 
 static inline int sd_zbc_read_zones(struct scsi_disk *sdkp,
@@ -259,7 +253,7 @@ static inline blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd,
 static inline unsigned int sd_zbc_complete(struct scsi_cmnd *cmd,
                        unsigned int good_bytes, struct scsi_sense_hdr *sshdr)
 {
-       return 0;
+       return good_bytes;
 }
 
 static inline blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd,
index 0e94ff0..cf07b7f 100644 (file)
@@ -651,6 +651,28 @@ static void sd_zbc_print_zones(struct scsi_disk *sdkp)
                          sdkp->zone_blocks);
 }
 
+static int sd_zbc_init_disk(struct scsi_disk *sdkp)
+{
+       sdkp->zones_wp_offset = NULL;
+       spin_lock_init(&sdkp->zones_wp_offset_lock);
+       sdkp->rev_wp_offset = NULL;
+       mutex_init(&sdkp->rev_mutex);
+       INIT_WORK(&sdkp->zone_wp_offset_work, sd_zbc_update_wp_offset_workfn);
+       sdkp->zone_wp_update_buf = kzalloc(SD_BUF_SIZE, GFP_KERNEL);
+       if (!sdkp->zone_wp_update_buf)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void sd_zbc_release_disk(struct scsi_disk *sdkp)
+{
+       kvfree(sdkp->zones_wp_offset);
+       sdkp->zones_wp_offset = NULL;
+       kfree(sdkp->zone_wp_update_buf);
+       sdkp->zone_wp_update_buf = NULL;
+}
+
 static void sd_zbc_revalidate_zones_cb(struct gendisk *disk)
 {
        struct scsi_disk *sdkp = scsi_disk(disk);
@@ -667,7 +689,24 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
        u32 max_append;
        int ret = 0;
 
-       if (!sd_is_zoned(sdkp))
+       /*
+        * For all zoned disks, initialize zone append emulation data if not
+        * already done. This is necessary also for host-aware disks used as
+        * regular disks due to the presence of partitions as these partitions
+        * may be deleted and the disk zoned model changed back from
+        * BLK_ZONED_NONE to BLK_ZONED_HA.
+        */
+       if (sd_is_zoned(sdkp) && !sdkp->zone_wp_update_buf) {
+               ret = sd_zbc_init_disk(sdkp);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * There is nothing to do for regular disks, including host-aware disks
+        * that have partitions.
+        */
+       if (!blk_queue_is_zoned(q))
                return 0;
 
        /*
@@ -764,28 +803,3 @@ err:
 
        return ret;
 }
-
-int sd_zbc_init_disk(struct scsi_disk *sdkp)
-{
-       if (!sd_is_zoned(sdkp))
-               return 0;
-
-       sdkp->zones_wp_offset = NULL;
-       spin_lock_init(&sdkp->zones_wp_offset_lock);
-       sdkp->rev_wp_offset = NULL;
-       mutex_init(&sdkp->rev_mutex);
-       INIT_WORK(&sdkp->zone_wp_offset_work, sd_zbc_update_wp_offset_workfn);
-       sdkp->zone_wp_update_buf = kzalloc(SD_BUF_SIZE, GFP_KERNEL);
-       if (!sdkp->zone_wp_update_buf)
-               return -ENOMEM;
-
-       return 0;
-}
-
-void sd_zbc_release_disk(struct scsi_disk *sdkp)
-{
-       kvfree(sdkp->zones_wp_offset);
-       sdkp->zones_wp_offset = NULL;
-       kfree(sdkp->zone_wp_update_buf);
-       sdkp->zone_wp_update_buf = NULL;
-}
index 20472aa..bfa8d77 100644 (file)
@@ -1820,14 +1820,7 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
                struct iovec *iov = NULL;
                struct iov_iter i;
 
-#ifdef CONFIG_COMPAT
-               if (in_compat_syscall())
-                       res = compat_import_iovec(rw, hp->dxferp, iov_count,
-                                                 0, &iov, &i);
-               else
-#endif
-                       res = import_iovec(rw, hp->dxferp, iov_count,
-                                          0, &iov, &i);
+               res = import_iovec(rw, hp->dxferp, iov_count, 0, &iov, &i);
                if (res < 0)
                        return res;
 
index bd38c8c..ca1e6cf 100644 (file)
@@ -516,7 +516,7 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info,
                break;
        case BMIC_SENSE_DIAG_OPTIONS:
                cdb_length = 0;
-               /* fall through */
+               fallthrough;
        case BMIC_IDENTIFY_CONTROLLER:
        case BMIC_IDENTIFY_PHYSICAL_DEVICE:
        case BMIC_SENSE_SUBSYSTEM_INFORMATION:
@@ -527,7 +527,7 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info,
                break;
        case BMIC_SET_DIAG_OPTIONS:
                cdb_length = 0;
-               /* fall through */
+               fallthrough;
        case BMIC_WRITE_HOST_WELLNESS:
                request->data_direction = SOP_WRITE_FLAG;
                cdb[0] = BMIC_WRITE;
@@ -2324,7 +2324,7 @@ static int pqi_raid_bypass_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
        switch (scmd->cmnd[0]) {
        case WRITE_6:
                is_write = true;
-               /* fall through */
+               fallthrough;
        case READ_6:
                first_block = (u64)(((scmd->cmnd[1] & 0x1f) << 16) |
                        (scmd->cmnd[2] << 8) | scmd->cmnd[3]);
@@ -2334,21 +2334,21 @@ static int pqi_raid_bypass_submit_scsi_cmd(struct pqi_ctrl_info *ctrl_info,
                break;
        case WRITE_10:
                is_write = true;
-               /* fall through */
+               fallthrough;
        case READ_10:
                first_block = (u64)get_unaligned_be32(&scmd->cmnd[2]);
                block_cnt = (u32)get_unaligned_be16(&scmd->cmnd[7]);
                break;
        case WRITE_12:
                is_write = true;
-               /* fall through */
+               fallthrough;
        case READ_12:
                first_block = (u64)get_unaligned_be32(&scmd->cmnd[2]);
                block_cnt = get_unaligned_be32(&scmd->cmnd[6]);
                break;
        case WRITE_16:
                is_write = true;
-               /* fall through */
+               fallthrough;
        case READ_16:
                first_block = get_unaligned_be64(&scmd->cmnd[2]);
                block_cnt = get_unaligned_be32(&scmd->cmnd[10]);
@@ -2948,7 +2948,7 @@ static unsigned int pqi_process_io_intr(struct pqi_ctrl_info *ctrl_info,
                case PQI_RESPONSE_IU_AIO_PATH_IO_SUCCESS:
                        if (io_request->scmd)
                                io_request->scmd->result = 0;
-                       /* fall through */
+                       fallthrough;
                case PQI_RESPONSE_IU_GENERAL_MANAGEMENT:
                        break;
                case PQI_RESPONSE_IU_VENDOR_GENERAL:
@@ -3115,12 +3115,11 @@ static void pqi_process_soft_reset(struct pqi_ctrl_info *ctrl_info,
 
        switch (reset_status) {
        case RESET_INITIATE_DRIVER:
-               /* fall through */
        case RESET_TIMEDOUT:
                dev_info(&ctrl_info->pci_dev->dev,
                        "resetting controller %u\n", ctrl_info->ctrl_id);
                sis_soft_reset(ctrl_info);
-               /* fall through */
+               fallthrough;
        case RESET_INITIATE_FIRMWARE:
                rc = pqi_ofa_ctrl_restart(ctrl_info);
                pqi_ofa_free_host_buffer(ctrl_info);
index 0c4aa46..3b3a53c 100644 (file)
@@ -877,10 +877,10 @@ static void get_sectorsize(struct scsi_cd *cd)
                case 2340:
                case 2352:
                        sector_size = 2048;
-                       /* fall through */
+                       fallthrough;
                case 2048:
                        cd->capacity *= 4;
-                       /* fall through */
+                       fallthrough;
                case 512:
                        break;
                default:
index 87fbc0e..e2e5356 100644 (file)
@@ -339,14 +339,14 @@ static void st_analyze_sense(struct st_request *SRpnt, struct st_cmdstatus *s)
                switch (sense[0] & 0x7f) {
                case 0x71:
                        s->deferred = 1;
-                       /* fall through */
+                       fallthrough;
                case 0x70:
                        s->fixed_format = 1;
                        s->flags = sense[2] & 0xe0;
                        break;
                case 0x73:
                        s->deferred = 1;
-                       /* fall through */
+                       fallthrough;
                case 0x72:
                        s->fixed_format = 0;
                        ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
@@ -2723,7 +2723,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
        switch (cmd_in) {
        case MTFSFM:
                chg_eof = 0;    /* Changed from the FSF after this */
-               /* fall through */
+               fallthrough;
        case MTFSF:
                cmd[0] = SPACE;
                cmd[1] = 0x01;  /* Space FileMarks */
@@ -2738,7 +2738,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
                break;
        case MTBSFM:
                chg_eof = 0;    /* Changed from the FSF after this */
-               /* fall through */
+               fallthrough;
        case MTBSF:
                cmd[0] = SPACE;
                cmd[1] = 0x01;  /* Space FileMarks */
index 701b842..2e3fbc2 100644 (file)
@@ -397,12 +397,12 @@ static int sun3scsi_dma_finish(int write_flag)
                case CSR_LEFT_3:
                        *vaddr = (dregs->bpack_lo & 0xff00) >> 8;
                        vaddr--;
-                       /* Fall through */
+                       fallthrough;
 
                case CSR_LEFT_2:
                        *vaddr = (dregs->bpack_hi & 0x00ff);
                        vaddr--;
-                       /* Fall through */
+                       fallthrough;
 
                case CSR_LEFT_1:
                        *vaddr = (dregs->bpack_hi & 0xff00) >> 8;
index 6d7651a..c6db61b 100644 (file)
@@ -523,7 +523,7 @@ void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
                                        new = old;
                                        break;
                                }
-                               /* fall through */
+                               fallthrough;
                        default:
                                new = 0;
                                panic("sym_fw_bind_script: "
index 8410117..cc11daa 100644 (file)
@@ -3059,7 +3059,7 @@ static void sym_sir_bad_scsi_status(struct sym_hcb *np, int num, struct sym_ccb
                        sym_print_addr(cp->cmd, "%s\n",
                                s_status == S_BUSY ? "BUSY" : "QUEUE FULL\n");
                }
-               /* fall through */
+               fallthrough;
        default:        /* S_INT, S_INT_COND_MET, S_CONFLICT */
                sym_complete_error (np, cp);
                break;
@@ -4620,7 +4620,7 @@ static void sym_int_sir(struct sym_hcb *np)
         *  Negotiation failed.
         *  Target does not want answer message.
         */
-       /* fall through */
+               fallthrough;
        case SIR_NEGO_PROTO:
                sym_nego_default(np, tp, cp);
                goto out;
index d37e2a6..e13d535 100644 (file)
@@ -695,7 +695,7 @@ static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
                                          data, len);
                if (!x)
                        break;
-               /* fall through */
+               fallthrough;
        default:
                x = sym_read_T93C46_nvram(np, nvram);
                break;
index bcfbbd0..5b2bc1a 100644 (file)
@@ -110,7 +110,7 @@ static int ufs_bsg_request(struct bsg_job *job)
                        goto out;
                }
 
-               /* fall through */
+               fallthrough;
        case UPIU_TRANSACTION_NOP_OUT:
        case UPIU_TRANSACTION_TASK_REQ:
                ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req,
index da199fa..1d157ff 100644 (file)
@@ -1612,7 +1612,7 @@ start:
                 * currently running. Hence, fall through to cancel gating
                 * work and to enable clocks.
                 */
-               /* fallthrough */
+               fallthrough;
        case CLKS_OFF:
                ufshcd_scsi_block_requests(hba);
                hba->clk_gating.state = REQ_CLKS_ON;
@@ -1624,7 +1624,7 @@ start:
                 * fall through to check if we should wait for this
                 * work to be done or not.
                 */
-               /* fallthrough */
+               fallthrough;
        case REQ_CLKS_ON:
                if (async) {
                        rc = -EAGAIN;
@@ -4737,7 +4737,7 @@ ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int scsi_status)
        switch (scsi_status) {
        case SAM_STAT_CHECK_CONDITION:
                ufshcd_copy_sense_data(lrbp);
-               /* fallthrough */
+               fallthrough;
        case SAM_STAT_GOOD:
                result |= DID_OK << 16 |
                          COMMAND_COMPLETE << 8 |
@@ -6277,7 +6277,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
        switch (msgcode) {
        case UPIU_TRANSACTION_NOP_OUT:
                cmd_type = DEV_CMD_TYPE_NOP;
-               /* fall through */
+               fallthrough;
        case UPIU_TRANSACTION_QUERY_REQ:
                ufshcd_hold(hba, false);
                mutex_lock(&hba->dev_cmd.lock);
index ca1c39b..3b18034 100644 (file)
@@ -148,7 +148,7 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf)
        default:
                scmd_printk(KERN_WARNING, sc, "Unknown response %d",
                            resp->response);
-               /* fall through */
+               fallthrough;
        case VIRTIO_SCSI_S_FAILURE:
                set_host_byte(sc, DID_ERROR);
                break;
index 8dbb4db..081f54a 100644 (file)
@@ -607,7 +607,7 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
                case BTSTAT_TAGREJECT:
                case BTSTAT_BADMSG:
                        cmd->result = (DRIVER_INVALID << 24);
-                       /* fall through */
+                       fallthrough;
 
                case BTSTAT_HAHARDWARE:
                case BTSTAT_INVPHASE:
index f81046f..87dafbc 100644 (file)
@@ -1854,7 +1854,7 @@ round_4(unsigned int x)
                case 1: --x;
                        break;
                case 2: ++x;
-                       /* fall through */
+                       fallthrough;
                case 3: ++x;
        }
        return x;
index f0068e9..259fc24 100644 (file)
@@ -1111,7 +1111,7 @@ static void scsifront_backend_changed(struct xenbus_device *dev,
        case XenbusStateClosed:
                if (dev->state == XenbusStateClosed)
                        break;
-               /* fall through - Missed the backend's Closing state */
+               fallthrough;    /* Missed the backend's Closing state */
        case XenbusStateClosing:
                scsifront_disconnect(info);
                break;
index e19102f..b25d0f7 100644 (file)
@@ -353,7 +353,7 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
 
                debugfs_create_u32("nmodem_supported", 0400, qcom_socinfo->dbg_root,
                                   &qcom_socinfo->info.nmodem_supported);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 14):
                qcom_socinfo->info.num_clusters = __le32_to_cpu(info->num_clusters);
                qcom_socinfo->info.ncluster_array_offset = __le32_to_cpu(info->ncluster_array_offset);
@@ -368,14 +368,14 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
                                   &qcom_socinfo->info.num_defective_parts);
                debugfs_create_u32("ndefective_parts_array_offset", 0400, qcom_socinfo->dbg_root,
                                   &qcom_socinfo->info.ndefective_parts_array_offset);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 13):
                qcom_socinfo->info.nproduct_id = __le32_to_cpu(info->nproduct_id);
 
                debugfs_create_u32("nproduct_id", 0400, qcom_socinfo->dbg_root,
                                   &qcom_socinfo->info.nproduct_id);
                DEBUGFS_ADD(info, chip_id);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 12):
                qcom_socinfo->info.chip_family =
                        __le32_to_cpu(info->chip_family);
@@ -392,7 +392,7 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
                debugfs_create_x32("raw_device_number", 0400,
                                   qcom_socinfo->dbg_root,
                                   &qcom_socinfo->info.raw_device_num);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 11):
        case SOCINFO_VERSION(0, 10):
        case SOCINFO_VERSION(0, 9):
@@ -400,12 +400,12 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
 
                debugfs_create_u32("foundry_id", 0400, qcom_socinfo->dbg_root,
                                   &qcom_socinfo->info.foundry_id);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 8):
        case SOCINFO_VERSION(0, 7):
                DEBUGFS_ADD(info, pmic_model);
                DEBUGFS_ADD(info, pmic_die_rev);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 6):
                qcom_socinfo->info.hw_plat_subtype =
                        __le32_to_cpu(info->hw_plat_subtype);
@@ -413,7 +413,7 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
                debugfs_create_u32("hardware_platform_subtype", 0400,
                                   qcom_socinfo->dbg_root,
                                   &qcom_socinfo->info.hw_plat_subtype);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 5):
                qcom_socinfo->info.accessory_chip =
                        __le32_to_cpu(info->accessory_chip);
@@ -421,27 +421,27 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
                debugfs_create_u32("accessory_chip", 0400,
                                   qcom_socinfo->dbg_root,
                                   &qcom_socinfo->info.accessory_chip);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 4):
                qcom_socinfo->info.plat_ver = __le32_to_cpu(info->plat_ver);
 
                debugfs_create_u32("platform_version", 0400,
                                   qcom_socinfo->dbg_root,
                                   &qcom_socinfo->info.plat_ver);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 3):
                qcom_socinfo->info.hw_plat = __le32_to_cpu(info->hw_plat);
 
                debugfs_create_u32("hardware_platform", 0400,
                                   qcom_socinfo->dbg_root,
                                   &qcom_socinfo->info.hw_plat);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 2):
                qcom_socinfo->info.raw_ver  = __le32_to_cpu(info->raw_ver);
 
                debugfs_create_u32("raw_version", 0400, qcom_socinfo->dbg_root,
                                   &qcom_socinfo->info.raw_ver);
-               /* Fall through */
+               fallthrough;
        case SOCINFO_VERSION(0, 1):
                DEBUGFS_ADD(info, build_id);
                break;
index 42cf37a..b0bba8a 100644 (file)
@@ -1990,44 +1990,17 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
                                                            event->id,
                                                            &pmc->irq, pmc);
 
-                       /*
-                        * GPIOs don't have an equivalent interrupt in the
-                        * parent controller (GIC). However some code, such
-                        * as the one in irq_get_irqchip_state(), require a
-                        * valid IRQ chip to be set. Make sure that's the
-                        * case by passing NULL here, which will install a
-                        * dummy IRQ chip for the interrupt in the parent
-                        * domain.
-                        */
-                       if (domain->parent)
-                               irq_domain_set_hwirq_and_chip(domain->parent,
-                                                             virq, 0, NULL,
-                                                             NULL);
-
+                       /* GPIO hierarchies stop at the PMC level */
+                       if (!err && domain->parent)
+                               err = irq_domain_disconnect_hierarchy(domain->parent,
+                                                                     virq);
                        break;
                }
        }
 
-       /*
-        * For interrupts that don't have associated wake events, assign a
-        * dummy hardware IRQ number. This is used in the ->irq_set_type()
-        * and ->irq_set_wake() callbacks to return early for these IRQs.
-        */
-       if (i == soc->num_wake_events) {
-               err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX,
-                                                   &pmc->irq, pmc);
-
-               /*
-                * Interrupts without a wake event don't have a corresponding
-                * interrupt in the parent controller (GIC). Pass NULL for the
-                * chip here, which causes a dummy IRQ chip to be installed
-                * for the interrupt in the parent domain, to make this
-                * explicit.
-                */
-               if (domain->parent)
-                       irq_domain_set_hwirq_and_chip(domain->parent, virq, 0,
-                                                     NULL, NULL);
-       }
+       /* If there is no wake-up event, there is no PMC mapping */
+       if (i == soc->num_wake_events)
+               err = irq_domain_disconnect_hierarchy(domain, virq);
 
        return err;
 }
@@ -2043,9 +2016,6 @@ static int tegra210_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
        unsigned int offset, bit;
        u32 value;
 
-       if (data->hwirq == ULONG_MAX)
-               return 0;
-
        offset = data->hwirq / 32;
        bit = data->hwirq % 32;
 
@@ -2080,9 +2050,6 @@ static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type)
        unsigned int offset, bit;
        u32 value;
 
-       if (data->hwirq == ULONG_MAX)
-               return 0;
-
        offset = data->hwirq / 32;
        bit = data->hwirq % 32;
 
@@ -2123,10 +2090,6 @@ static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
        unsigned int offset, bit;
        u32 value;
 
-       /* nothing to do if there's no associated wake event */
-       if (WARN_ON(data->hwirq == ULONG_MAX))
-               return 0;
-
        offset = data->hwirq / 32;
        bit = data->hwirq % 32;
 
@@ -2154,10 +2117,6 @@ static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
        struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
        u32 value;
 
-       /* nothing to do if there's no associated wake event */
-       if (data->hwirq == ULONG_MAX)
-               return 0;
-
        value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq));
 
        switch (type) {
@@ -2184,6 +2143,34 @@ static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
        return 0;
 }
 
+static void tegra_irq_mask_parent(struct irq_data *data)
+{
+       if (data->parent_data)
+               irq_chip_mask_parent(data);
+}
+
+static void tegra_irq_unmask_parent(struct irq_data *data)
+{
+       if (data->parent_data)
+               irq_chip_unmask_parent(data);
+}
+
+static void tegra_irq_eoi_parent(struct irq_data *data)
+{
+       if (data->parent_data)
+               irq_chip_eoi_parent(data);
+}
+
+static int tegra_irq_set_affinity_parent(struct irq_data *data,
+                                        const struct cpumask *dest,
+                                        bool force)
+{
+       if (data->parent_data)
+               return irq_chip_set_affinity_parent(data, dest, force);
+
+       return -EINVAL;
+}
+
 static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
 {
        struct irq_domain *parent = NULL;
@@ -2199,10 +2186,10 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
                return 0;
 
        pmc->irq.name = dev_name(pmc->dev);
-       pmc->irq.irq_mask = irq_chip_mask_parent;
-       pmc->irq.irq_unmask = irq_chip_unmask_parent;
-       pmc->irq.irq_eoi = irq_chip_eoi_parent;
-       pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent;
+       pmc->irq.irq_mask = tegra_irq_mask_parent;
+       pmc->irq.irq_unmask = tegra_irq_unmask_parent;
+       pmc->irq.irq_eoi = tegra_irq_eoi_parent;
+       pmc->irq.irq_set_affinity = tegra_irq_set_affinity_parent;
        pmc->irq.irq_set_type = pmc->soc->irq_set_type;
        pmc->irq.irq_set_wake = pmc->soc->irq_set_wake;
 
@@ -2229,7 +2216,7 @@ static int tegra_pmc_clk_notify_cb(struct notifier_block *nb,
 
        case POST_RATE_CHANGE:
                pmc->rate = data->new_rate;
-               /* fall through */
+               fallthrough;
 
        case ABORT_RATE_CHANGE:
                mutex_unlock(&pmc->powergates_lock);
index e6e0fb9..da02016 100644 (file)
@@ -1372,7 +1372,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
                return ret;
        }
 
-       /* Read Instat 1, Instat 2 and Instat 3 registers */
+       /* Read Intstat 1, Intstat 2 and Intstat 3 registers */
        ret = sdw_read(slave, SDW_SCP_INT1);
        if (ret < 0) {
                dev_err(slave->bus->dev,
index 37290a7..6e36deb 100644 (file)
@@ -717,6 +717,7 @@ error:
        kfree(wbuf);
 error_1:
        kfree(wr_msg);
+       bus->defer_msg.msg = NULL;
        return ret;
 }
 
@@ -840,9 +841,10 @@ static int do_bank_switch(struct sdw_stream_runtime *stream)
 error:
        list_for_each_entry(m_rt, &stream->master_list, stream_node) {
                bus = m_rt->bus;
-
-               kfree(bus->defer_msg.msg->buf);
-               kfree(bus->defer_msg.msg);
+               if (bus->defer_msg.msg) {
+                       kfree(bus->defer_msg.msg->buf);
+                       kfree(bus->defer_msg.msg);
+               }
        }
 
 msg_unlock:
index 681d090..9cfa15e 100644 (file)
@@ -1295,7 +1295,7 @@ static const struct of_device_id bcm_qspi_of_match[] = {
        },
        {
                .compatible = "brcm,spi-bcm-qspi",
-               .data = &bcm_qspi_rev_data,
+               .data = &bcm_qspi_no_rev_data,
        },
        {
                .compatible = "brcm,spi-bcm7216-qspi",
index c45d76c..41986ac 100644 (file)
@@ -75,7 +75,7 @@
 #define DRV_NAME       "spi-bcm2835"
 
 /* define polling limits */
-unsigned int polling_limit_us = 30;
+static unsigned int polling_limit_us = 30;
 module_param(polling_limit_us, uint, 0664);
 MODULE_PARM_DESC(polling_limit_us,
                 "time in us to run a transfer in polling mode\n");
index 2f71781..03b034c 100644 (file)
@@ -164,10 +164,10 @@ static inline void bcm2835aux_rd_fifo(struct bcm2835aux_spi *bs)
                switch (count) {
                case 3:
                        *bs->rx_buf++ = (data >> 16) & 0xff;
-                       /* fallthrough */
+                       fallthrough;
                case 2:
                        *bs->rx_buf++ = (data >> 8) & 0xff;
-                       /* fallthrough */
+                       fallthrough;
                case 1:
                        *bs->rx_buf++ = (data >> 0) & 0xff;
                        /* fallthrough - no default */
index 1c1a9d1..c6795c6 100644 (file)
@@ -907,14 +907,16 @@ static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata,
        struct dma_async_tx_descriptor *tx;
        dma_cookie_t cookie;
        dma_addr_t dma_dst;
+       struct device *ddev;
 
        if (!cqspi->rx_chan || !virt_addr_valid(buf)) {
                memcpy_fromio(buf, cqspi->ahb_base + from, len);
                return 0;
        }
 
-       dma_dst = dma_map_single(dev, buf, len, DMA_FROM_DEVICE);
-       if (dma_mapping_error(dev, dma_dst)) {
+       ddev = cqspi->rx_chan->device->dev;
+       dma_dst = dma_map_single(ddev, buf, len, DMA_FROM_DEVICE);
+       if (dma_mapping_error(ddev, dma_dst)) {
                dev_err(dev, "dma mapping failed\n");
                return -ENOMEM;
        }
@@ -948,7 +950,7 @@ static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata,
        }
 
 err_unmap:
-       dma_unmap_single(dev, dma_dst, len, DMA_FROM_DEVICE);
+       dma_unmap_single(ddev, dma_dst, len, DMA_FROM_DEVICE);
 
        return ret;
 }
@@ -1128,8 +1130,17 @@ static int cqspi_request_mmap_dma(struct cqspi_st *cqspi)
        return 0;
 }
 
+static const char *cqspi_get_name(struct spi_mem *mem)
+{
+       struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master);
+       struct device *dev = &cqspi->pdev->dev;
+
+       return devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev), mem->spi->chip_select);
+}
+
 static const struct spi_controller_mem_ops cqspi_mem_ops = {
        .exec_op = cqspi_exec_mem_op,
+       .get_name = cqspi_get_name,
 };
 
 static int cqspi_setup_flash(struct cqspi_st *cqspi)
index 54ad0ac..ee90588 100644 (file)
@@ -226,7 +226,7 @@ static void fsl_spi_free_dummy_rx(void)
        case 1:
                kfree(fsl_dummy_rx);
                fsl_dummy_rx = NULL;
-               /* fall through */
+               fallthrough;
        default:
                fsl_dummy_rx_refcnt--;
                break;
@@ -294,7 +294,7 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
                switch (mspi->subblock) {
                default:
                        dev_warn(dev, "cell-index unspecified, assuming SPI1\n");
-                       /* fall through */
+                       fallthrough;
                case 0:
                        mspi->subblock = QE_CR_SUBBLOCK_SPI1;
                        break;
index 91c6aff..108a7d5 100644 (file)
@@ -174,17 +174,17 @@ static const struct fsl_dspi_devtype_data devtype_data[] = {
                .fifo_size              = 16,
        },
        [LS2080A] = {
-               .trans_mode             = DSPI_DMA_MODE,
+               .trans_mode             = DSPI_XSPI_MODE,
                .max_clock_factor       = 8,
                .fifo_size              = 4,
        },
        [LS2085A] = {
-               .trans_mode             = DSPI_DMA_MODE,
+               .trans_mode             = DSPI_XSPI_MODE,
                .max_clock_factor       = 8,
                .fifo_size              = 4,
        },
        [LX2160A] = {
-               .trans_mode             = DSPI_DMA_MODE,
+               .trans_mode             = DSPI_XSPI_MODE,
                .max_clock_factor       = 8,
                .fifo_size              = 4,
        },
@@ -1273,11 +1273,17 @@ static int dspi_probe(struct platform_device *pdev)
        void __iomem *base;
        bool big_endian;
 
-       ctlr = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
+       dspi = devm_kzalloc(&pdev->dev, sizeof(*dspi), GFP_KERNEL);
+       if (!dspi)
+               return -ENOMEM;
+
+       ctlr = spi_alloc_master(&pdev->dev, 0);
        if (!ctlr)
                return -ENOMEM;
 
-       dspi = spi_controller_get_devdata(ctlr);
+       spi_controller_set_devdata(ctlr, dspi);
+       platform_set_drvdata(pdev, dspi);
+
        dspi->pdev = pdev;
        dspi->ctlr = ctlr;
 
@@ -1414,8 +1420,6 @@ poll_mode:
        if (dspi->devtype_data->trans_mode != DSPI_DMA_MODE)
                ctlr->ptp_sts_supported = true;
 
-       platform_set_drvdata(pdev, ctlr);
-
        ret = spi_register_controller(ctlr);
        if (ret != 0) {
                dev_err(&pdev->dev, "Problem registering DSPI ctlr\n");
@@ -1437,8 +1441,7 @@ out_ctlr_put:
 
 static int dspi_remove(struct platform_device *pdev)
 {
-       struct spi_controller *ctlr = platform_get_drvdata(pdev);
-       struct fsl_dspi *dspi = spi_controller_get_devdata(ctlr);
+       struct fsl_dspi *dspi = platform_get_drvdata(pdev);
 
        /* Disconnect from the SPI framework */
        spi_unregister_controller(dspi->ctlr);
index e605812..6d148ab 100644 (file)
@@ -564,13 +564,14 @@ static void fsl_espi_cpu_irq(struct fsl_espi *espi, u32 events)
 static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
 {
        struct fsl_espi *espi = context_data;
-       u32 events;
+       u32 events, mask;
 
        spin_lock(&espi->lock);
 
        /* Get interrupt events(tx/rx) */
        events = fsl_espi_read_reg(espi, ESPI_SPIE);
-       if (!events) {
+       mask = fsl_espi_read_reg(espi, ESPI_SPIM);
+       if (!(events & mask)) {
                spin_unlock(&espi->lock);
                return IRQ_NONE;
        }
index 9522d1b..df981e5 100644 (file)
@@ -90,7 +90,7 @@ static struct spi_test spi_tests[] = {
        {
                .description    = "tx/rx-transfer - crossing PAGE_SIZE",
                .fill_option    = FILL_COUNT_8,
-               .iterate_len    = { ITERATE_MAX_LEN },
+               .iterate_len    = { ITERATE_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
                .iterate_rx_align = ITERATE_ALIGN,
                .transfer_count = 1,
index bd23c46..127b8bd 100644 (file)
@@ -506,7 +506,7 @@ static int sprd_adi_probe(struct platform_device *pdev)
                default:
                        dev_err(&pdev->dev,
                                "failed to find hwlock id, %d\n", ret);
-                       /* fall-through */
+                       fallthrough;
                case -EPROBE_DEFER:
                        goto put_ctlr;
                }
index d4b33b3..3056428 100644 (file)
@@ -936,7 +936,11 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
        }
 
        if (sr & STM32H7_SPI_SR_SUSP) {
-               dev_warn(spi->dev, "Communication suspended\n");
+               static DEFINE_RATELIMIT_STATE(rs,
+                                             DEFAULT_RATELIMIT_INTERVAL * 10,
+                                             1);
+               if (__ratelimit(&rs))
+                       dev_dbg_ratelimited(spi->dev, "Communication suspended\n");
                if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
                        stm32h7_spi_read_rxfifo(spi, false);
                /*
@@ -2060,7 +2064,7 @@ static int stm32_spi_resume(struct device *dev)
        }
 
        ret = pm_runtime_get_sync(dev);
-       if (ret) {
+       if (ret < 0) {
                dev_err(dev, "Unable to power device:%d\n", ret);
                return ret;
        }
index dc12af0..0cab239 100644 (file)
@@ -1327,8 +1327,6 @@ out:
        if (msg->status && ctlr->handle_err)
                ctlr->handle_err(ctlr, msg);
 
-       spi_res_release(ctlr, msg);
-
        spi_finalize_current_message(ctlr);
 
        return ret;
@@ -1725,6 +1723,13 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
 
        spi_unmap_msg(ctlr, mesg);
 
+       /* In the prepare_messages callback the spi bus has the opportunity to
+        * split a transfer to smaller chunks.
+        * Release splited transfers here since spi_map_msg is done on the
+        * splited transfers.
+        */
+       spi_res_release(ctlr, mesg);
+
        if (ctlr->cur_msg_prepared && ctlr->unprepare_message) {
                ret = ctlr->unprepare_message(ctlr, mesg);
                if (ret) {
index 823dc99..a8d2525 100644 (file)
@@ -425,7 +425,7 @@ void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
                        *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
                        break;
                }
-               /* Fall through */
+               fallthrough;
        default:
                *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
        }
index 1ca2ac5..354486b 100644 (file)
@@ -342,7 +342,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
                                set_irq(dev, irq++);
                                break;
                        }
-                       /* fallthrough */
+                       fallthrough;
                case SSB_DEV_EXTIF:
                        set_irq(dev, 0);
                        break;
index b97a5c3..f49ab1a 100644 (file)
@@ -228,7 +228,7 @@ static void __iomem *ssb_ioremap(struct ssb_bus *bus,
        switch (bus->bustype) {
        case SSB_BUSTYPE_SSB:
                /* Only map the first core for now. */
-               /* fallthrough... */
+               fallthrough;
        case SSB_BUSTYPE_PCMCIA:
                mmio = ioremap(baseaddr, SSB_CORE_SIZE);
                break;
index 8b100a7..237531b 100644 (file)
@@ -173,8 +173,7 @@ static int gbaudio_remove_controls(struct snd_card *card, struct device *dev,
                id.index = control->index;
                kctl = snd_ctl_find_id(card, &id);
                if (!kctl) {
-                       dev_err(dev, "%d: Failed to find %s\n", err,
-                               control->name);
+                       dev_err(dev, "Failed to find %s\n", control->name);
                        continue;
                }
                err = snd_ctl_remove(card, kctl);
index 2f9fdbd..83b38ae 100644 (file)
@@ -456,6 +456,15 @@ static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
        val = ucontrol->value.integer.value[0] & mask;
        connect = !!val;
 
+       ret = gb_pm_runtime_get_sync(bundle);
+       if (ret)
+               return ret;
+
+       ret = gb_audio_gb_get_control(module->mgmt_connection, data->ctl_id,
+                                     GB_AUDIO_INVALID_INDEX, &gbvalue);
+       if (ret)
+               goto exit;
+
        /* update ucontrol */
        if (gbvalue.value.integer_value[0] != val) {
                for (wi = 0; wi < wlist->num_widgets; wi++) {
@@ -466,25 +475,17 @@ static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
                gbvalue.value.integer_value[0] =
                        cpu_to_le32(ucontrol->value.integer.value[0]);
 
-               ret = gb_pm_runtime_get_sync(bundle);
-               if (ret)
-                       return ret;
-
                ret = gb_audio_gb_set_control(module->mgmt_connection,
                                              data->ctl_id,
                                              GB_AUDIO_INVALID_INDEX, &gbvalue);
-
-               gb_pm_runtime_put_autosuspend(bundle);
-
-               if (ret) {
-                       dev_err_ratelimited(codec_dev,
-                                           "%d:Error in %s for %s\n", ret,
-                                           __func__, kcontrol->id.name);
-                       return ret;
-               }
        }
 
-       return 0;
+exit:
+       gb_pm_runtime_put_autosuspend(bundle);
+       if (ret)
+               dev_err_ratelimited(codec_dev, "%d:Error in %s for %s\n", ret,
+                                   __func__, kcontrol->id.name);
+       return ret;
 }
 
 #define SOC_DAPM_MIXER_GB(xname, kcount, data) \
index 8ea65be..a4e4eef 100644 (file)
@@ -4984,7 +4984,7 @@ enum mipi_port_id __get_mipi_port(struct atomisp_device *isp,
                if (MIPI_PORT1_ID + 1 != N_MIPI_PORT_ID) {
                        return MIPI_PORT1_ID + 1;
                }
-       /* fall through */
+               fallthrough;
        default:
                dev_err(isp->dev, "unsupported port: %d\n", port);
                return MIPI_PORT0_ID;
index cccc5bf..1b2b2c6 100644 (file)
@@ -704,14 +704,14 @@ static bool is_pipe_valid_to_current_run_mode(struct atomisp_sub_device *asd,
 
                        return false;
                }
-       /* fall-through */
+               fallthrough;
        case ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE:
                if (pipe_id == IA_CSS_PIPE_ID_CAPTURE ||
                    pipe_id == IA_CSS_PIPE_ID_PREVIEW)
                        return true;
 
                return false;
-       /* fall-through */
+               fallthrough;
        case ATOMISP_RUN_MODE_VIDEO:
                if (!asd->continuous_mode->val) {
                        if (pipe_id == IA_CSS_PIPE_ID_VIDEO ||
@@ -720,7 +720,7 @@ static bool is_pipe_valid_to_current_run_mode(struct atomisp_sub_device *asd,
                        else
                                return false;
                }
-       /* fall through  */
+               fallthrough;
        case ATOMISP_RUN_MODE_SDV:
                if (pipe_id == IA_CSS_PIPE_ID_CAPTURE ||
                    pipe_id == IA_CSS_PIPE_ID_VIDEO)
@@ -2765,7 +2765,7 @@ static unsigned int atomisp_get_pipe_index(struct atomisp_sub_device *asd,
                if (!atomisp_is_mbuscode_raw(asd->fmt[asd->capture_pad].fmt.code)) {
                        return IA_CSS_PIPE_ID_CAPTURE;
                }
-               /* fall through */
+               fallthrough;
        case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
                if (asd->yuvpp_mode)
                        return IA_CSS_PIPE_ID_YUVPP;
index f8d616f..65b0c8a 100644 (file)
@@ -1467,7 +1467,6 @@ enum ia_css_pipe_id atomisp_get_css_pipe_id(struct atomisp_sub_device *asd)
        case ATOMISP_RUN_MODE_VIDEO:
                return IA_CSS_PIPE_ID_VIDEO;
        case ATOMISP_RUN_MODE_STILL_CAPTURE:
-       /* fall through */
        default:
                return IA_CSS_PIPE_ID_CAPTURE;
        }
index a000a1e..0114b04 100644 (file)
@@ -1086,7 +1086,7 @@ static int atomisp_subdev_probe(struct atomisp_device *isp)
                case RAW_CAMERA:
                        dev_dbg(isp->dev, "raw_index: %d\n", raw_index);
                        raw_index = isp->input_cnt;
-                       /* fall through */
+                       fallthrough;
                case SOC_CAMERA:
                        dev_dbg(isp->dev, "SOC_INDEX: %d\n", isp->input_cnt);
                        if (isp->input_cnt >= ATOM_ISP_MAX_INPUTS) {
index 4fb9bfd..f13af23 100644 (file)
@@ -660,7 +660,7 @@ static void free_private_bo_pages(struct hmm_buffer_object *bo,
                                break;
                        }
 
-                       /* fall through */
+                       fallthrough;
 
                /*
                 * if dynamic memory pool doesn't exist, need to free
index 54434c2..a68cbb4 100644 (file)
@@ -4510,7 +4510,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
 #endif
                                        pipe->stop_requested = false;
                                }
-                               /* fall through */
+                               fallthrough;
                        case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
                        case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
                                frame = (struct ia_css_frame *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
index 2404184..6386a39 100644 (file)
@@ -110,7 +110,7 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx,
        case V4L2_MPEG2_PICTURE_CODING_TYPE_B:
                backward_addr = hantro_get_ref(ctx,
                                               slice_params->backward_ref_ts);
-               /* fall-through */
+               fallthrough;
        case V4L2_MPEG2_PICTURE_CODING_TYPE_P:
                forward_addr = hantro_get_ref(ctx,
                                              slice_params->forward_ref_ts);
index 7e9aad6..f610fa5 100644 (file)
@@ -112,7 +112,7 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu,
        case V4L2_MPEG2_PICTURE_CODING_TYPE_B:
                backward_addr = hantro_get_ref(ctx,
                                               slice_params->backward_ref_ts);
-               /* fall-through */
+               fallthrough;
        case V4L2_MPEG2_PICTURE_CODING_TYPE_P:
                forward_addr = hantro_get_ref(ctx,
                                              slice_params->forward_ref_ts);
index d92fd80..21ebf77 100644 (file)
@@ -488,7 +488,7 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
                        passthrough_cycles = incc->cycles;
                        break;
                }
-               /* fallthrough - non-passthrough RGB565 (CSI-2 bus) */
+               fallthrough;    /* non-passthrough RGB565 (CSI-2 bus) */
        default:
                burst_size = (image.pix.width & 0xf) ? 8 : 16;
                passthrough_bits = 16;
index bc27f94..7c6b91f 100644 (file)
@@ -199,6 +199,7 @@ static int cedrus_request_validate(struct media_request *req)
        struct v4l2_ctrl *ctrl_test;
        unsigned int count;
        unsigned int i;
+       int ret = 0;
 
        list_for_each_entry(obj, &req->objects, list) {
                struct vb2_buffer *vb;
@@ -243,12 +244,16 @@ static int cedrus_request_validate(struct media_request *req)
                if (!ctrl_test) {
                        v4l2_info(&ctx->dev->v4l2_dev,
                                  "Missing required codec control\n");
-                       return -ENOENT;
+                       ret = -ENOENT;
+                       break;
                }
        }
 
        v4l2_ctrl_request_hdl_put(hdl);
 
+       if (ret)
+               return ret;
+
        return vb2_request_validate(req);
 }
 
index 6e4df33..aa3ff67 100644 (file)
@@ -303,13 +303,13 @@ usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr,
        switch (len) {
        case 4:
                buf[3] = usbvision_read_reg(usbvision, USBVISION_SER_DAT4);
-               /* fall through */
+               fallthrough;
        case 3:
                buf[2] = usbvision_read_reg(usbvision, USBVISION_SER_DAT3);
-               /* fall through */
+               fallthrough;
        case 2:
                buf[1] = usbvision_read_reg(usbvision, USBVISION_SER_DAT2);
-               /* fall through */
+               fallthrough;
        case 1:
                buf[0] = usbvision_read_reg(usbvision, USBVISION_SER_DAT1);
                break;
index 1007eea..4c440bd 100644 (file)
@@ -25,7 +25,7 @@ config RTLLIB_CRYPTO_CCMP
 config RTLLIB_CRYPTO_TKIP
        tristate "Support for rtllib TKIP crypto"
        depends on RTLLIB
-       select CRYPTO_ARC4
+       select CRYPTO_LIB_ARC4
        select CRYPTO_MICHAEL_MIC
        default y
        help
@@ -35,7 +35,7 @@ config RTLLIB_CRYPTO_TKIP
 
 config RTLLIB_CRYPTO_WEP
        tristate "Support for rtllib WEP crypto"
-       select CRYPTO_ARC4
+       select CRYPTO_LIB_ARC4
        depends on RTLLIB
        default y
        help
index 8d2a58e..8c2ff37 100644 (file)
@@ -5,8 +5,9 @@
  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
  */
 
+#include <crypto/arc4.h>
 #include <crypto/hash.h>
-#include <crypto/skcipher.h>
+#include <linux/fips.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -16,7 +17,6 @@
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
 #include <linux/string.h>
-#include <linux/scatterlist.h>
 #include <linux/crc32.h>
 #include <linux/etherdevice.h>
 
@@ -45,9 +45,9 @@ struct rtllib_tkip_data {
        u32 dot11RSNAStatsTKIPLocalMICFailures;
 
        int key_idx;
-       struct crypto_sync_skcipher *rx_tfm_arc4;
+       struct arc4_ctx rx_ctx_arc4;
+       struct arc4_ctx tx_ctx_arc4;
        struct crypto_shash *rx_tfm_michael;
-       struct crypto_sync_skcipher *tx_tfm_arc4;
        struct crypto_shash *tx_tfm_michael;
        /* scratch buffers for virt_to_page() (crypto API) */
        u8 rx_hdr[16];
@@ -58,16 +58,13 @@ static void *rtllib_tkip_init(int key_idx)
 {
        struct rtllib_tkip_data *priv;
 
+       if (fips_enabled)
+               return NULL;
+
        priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
        if (priv == NULL)
                goto fail;
        priv->key_idx = key_idx;
-       priv->tx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
-       if (IS_ERR(priv->tx_tfm_arc4)) {
-               pr_debug("Could not allocate crypto API arc4\n");
-               priv->tx_tfm_arc4 = NULL;
-               goto fail;
-       }
 
        priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
        if (IS_ERR(priv->tx_tfm_michael)) {
@@ -76,13 +73,6 @@ static void *rtllib_tkip_init(int key_idx)
                goto fail;
        }
 
-       priv->rx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
-       if (IS_ERR(priv->rx_tfm_arc4)) {
-               pr_debug("Could not allocate crypto API arc4\n");
-               priv->rx_tfm_arc4 = NULL;
-               goto fail;
-       }
-
        priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
        if (IS_ERR(priv->rx_tfm_michael)) {
                pr_debug("Could not allocate crypto API michael_mic\n");
@@ -94,9 +84,7 @@ static void *rtllib_tkip_init(int key_idx)
 fail:
        if (priv) {
                crypto_free_shash(priv->tx_tfm_michael);
-               crypto_free_sync_skcipher(priv->tx_tfm_arc4);
                crypto_free_shash(priv->rx_tfm_michael);
-               crypto_free_sync_skcipher(priv->rx_tfm_arc4);
                kfree(priv);
        }
 
@@ -110,11 +98,9 @@ static void rtllib_tkip_deinit(void *priv)
 
        if (_priv) {
                crypto_free_shash(_priv->tx_tfm_michael);
-               crypto_free_sync_skcipher(_priv->tx_tfm_arc4);
                crypto_free_shash(_priv->rx_tfm_michael);
-               crypto_free_sync_skcipher(_priv->rx_tfm_arc4);
        }
-       kfree(priv);
+       kzfree(priv);
 }
 
 
@@ -289,7 +275,6 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        int ret = 0;
        u8 rc4key[16],  *icv;
        u32 crc;
-       struct scatterlist sg;
 
        if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
            skb->len < hdr_len)
@@ -331,8 +316,6 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
 
        if (!tcb_desc->bHwSec) {
-               SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4);
-
                icv = skb_put(skb, 4);
                crc = ~crc32_le(~0, pos, len);
                icv[0] = crc;
@@ -340,15 +323,8 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
                icv[2] = crc >> 16;
                icv[3] = crc >> 24;
 
-               sg_init_one(&sg, pos, len+4);
-
-
-               crypto_sync_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
-               skcipher_request_set_sync_tfm(req, tkey->tx_tfm_arc4);
-               skcipher_request_set_callback(req, 0, NULL, NULL);
-               skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
-               ret = crypto_skcipher_encrypt(req);
-               skcipher_request_zero(req);
+               arc4_setkey(&tkey->tx_ctx_arc4, rc4key, 16);
+               arc4_crypt(&tkey->tx_ctx_arc4, pos, pos, len + 4);
        }
 
        tkey->tx_iv16++;
@@ -376,9 +352,7 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        u8 rc4key[16];
        u8 icv[4];
        u32 crc;
-       struct scatterlist sg;
        int plen;
-       int err;
 
        if (skb->len < hdr_len + 8 + 4)
                return -1;
@@ -414,8 +388,6 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        pos += 8;
 
        if (!tcb_desc->bHwSec || (skb->cb[0] == 1)) {
-               SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4);
-
                if ((iv32 < tkey->rx_iv32 ||
                    (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) &&
                    tkey->initialized) {
@@ -439,22 +411,8 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 
                plen = skb->len - hdr_len - 12;
 
-               sg_init_one(&sg, pos, plen+4);
-
-               crypto_sync_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
-               skcipher_request_set_sync_tfm(req, tkey->rx_tfm_arc4);
-               skcipher_request_set_callback(req, 0, NULL, NULL);
-               skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
-               err = crypto_skcipher_decrypt(req);
-               skcipher_request_zero(req);
-               if (err) {
-                       if (net_ratelimit()) {
-                               netdev_dbg(skb->dev,
-                                          "Failed to decrypt received packet from %pM\n",
-                                          hdr->addr2);
-                       }
-                       return -7;
-               }
+               arc4_setkey(&tkey->rx_ctx_arc4, rc4key, 16);
+               arc4_crypt(&tkey->rx_ctx_arc4, pos, pos, plen + 4);
 
                crc = ~crc32_le(~0, pos, plen);
                icv[0] = crc;
@@ -657,17 +615,13 @@ static int rtllib_tkip_set_key(void *key, int len, u8 *seq, void *priv)
        struct rtllib_tkip_data *tkey = priv;
        int keyidx;
        struct crypto_shash *tfm = tkey->tx_tfm_michael;
-       struct crypto_sync_skcipher *tfm2 = tkey->tx_tfm_arc4;
        struct crypto_shash *tfm3 = tkey->rx_tfm_michael;
-       struct crypto_sync_skcipher *tfm4 = tkey->rx_tfm_arc4;
 
        keyidx = tkey->key_idx;
        memset(tkey, 0, sizeof(*tkey));
        tkey->key_idx = keyidx;
        tkey->tx_tfm_michael = tfm;
-       tkey->tx_tfm_arc4 = tfm2;
        tkey->rx_tfm_michael = tfm3;
-       tkey->rx_tfm_arc4 = tfm4;
 
        if (len == TKIP_KEY_LEN) {
                memcpy(tkey->key, key, TKIP_KEY_LEN);
index b1ea650..7cdd17f 100644 (file)
@@ -5,7 +5,8 @@
  * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
  */
 
-#include <crypto/skcipher.h>
+#include <crypto/arc4.h>
+#include <linux/fips.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -14,7 +15,6 @@
 #include <linux/string.h>
 #include "rtllib.h"
 
-#include <linux/scatterlist.h>
 #include <linux/crc32.h>
 
 struct prism2_wep_data {
@@ -23,8 +23,8 @@ struct prism2_wep_data {
        u8 key[WEP_KEY_LEN + 1];
        u8 key_len;
        u8 key_idx;
-       struct crypto_sync_skcipher *tx_tfm;
-       struct crypto_sync_skcipher *rx_tfm;
+       struct arc4_ctx rx_ctx_arc4;
+       struct arc4_ctx tx_ctx_arc4;
 };
 
 
@@ -32,48 +32,24 @@ static void *prism2_wep_init(int keyidx)
 {
        struct prism2_wep_data *priv;
 
+       if (fips_enabled)
+               return NULL;
+
        priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
        if (priv == NULL)
-               goto fail;
+               return NULL;
        priv->key_idx = keyidx;
 
-       priv->tx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
-       if (IS_ERR(priv->tx_tfm)) {
-               pr_debug("rtllib_crypt_wep: could not allocate crypto API arc4\n");
-               priv->tx_tfm = NULL;
-               goto fail;
-       }
-       priv->rx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
-       if (IS_ERR(priv->rx_tfm)) {
-               pr_debug("rtllib_crypt_wep: could not allocate crypto API arc4\n");
-               priv->rx_tfm = NULL;
-               goto fail;
-       }
-
        /* start WEP IV from a random value */
        get_random_bytes(&priv->iv, 4);
 
        return priv;
-
-fail:
-       if (priv) {
-               crypto_free_sync_skcipher(priv->tx_tfm);
-               crypto_free_sync_skcipher(priv->rx_tfm);
-               kfree(priv);
-       }
-       return NULL;
 }
 
 
 static void prism2_wep_deinit(void *priv)
 {
-       struct prism2_wep_data *_priv = priv;
-
-       if (_priv) {
-               crypto_free_sync_skcipher(_priv->tx_tfm);
-               crypto_free_sync_skcipher(_priv->rx_tfm);
-       }
-       kfree(priv);
+       kzfree(priv);
 }
 
 /* Perform WEP encryption on given skb that has at least 4 bytes of headroom
@@ -92,8 +68,6 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
                                    MAX_DEV_ADDR_SIZE);
        u32 crc;
        u8 *icv;
-       struct scatterlist sg;
-       int err;
 
        if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
            skb->len < hdr_len){
@@ -131,8 +105,6 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        memcpy(key + 3, wep->key, wep->key_len);
 
        if (!tcb_desc->bHwSec) {
-               SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm);
-
                /* Append little-endian CRC32 and encrypt it to produce ICV */
                crc = ~crc32_le(~0, pos, len);
                icv = skb_put(skb, 4);
@@ -141,14 +113,8 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
                icv[2] = crc >> 16;
                icv[3] = crc >> 24;
 
-               sg_init_one(&sg, pos, len+4);
-               crypto_sync_skcipher_setkey(wep->tx_tfm, key, klen);
-               skcipher_request_set_sync_tfm(req, wep->tx_tfm);
-               skcipher_request_set_callback(req, 0, NULL, NULL);
-               skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
-               err = crypto_skcipher_encrypt(req);
-               skcipher_request_zero(req);
-               return err;
+               arc4_setkey(&wep->tx_ctx_arc4, key, klen);
+               arc4_crypt(&wep->tx_ctx_arc4, pos, pos, len + 4);
        }
 
        return 0;
@@ -172,8 +138,6 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
                                    MAX_DEV_ADDR_SIZE);
        u32 crc;
        u8 icv[4];
-       struct scatterlist sg;
-       int err;
 
        if (skb->len < hdr_len + 8)
                return -1;
@@ -195,17 +159,9 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        plen = skb->len - hdr_len - 8;
 
        if (!tcb_desc->bHwSec) {
-               SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm);
-
-               sg_init_one(&sg, pos, plen+4);
-               crypto_sync_skcipher_setkey(wep->rx_tfm, key, klen);
-               skcipher_request_set_sync_tfm(req, wep->rx_tfm);
-               skcipher_request_set_callback(req, 0, NULL, NULL);
-               skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
-               err = crypto_skcipher_decrypt(req);
-               skcipher_request_zero(req);
-               if (err)
-                       return -7;
+               arc4_setkey(&wep->rx_ctx_arc4, key, klen);
+               arc4_crypt(&wep->rx_ctx_arc4, pos, pos, plen + 4);
+
                crc = ~crc32_le(~0, pos, plen);
                icv[0] = crc;
                icv[1] = crc >> 8;
index 1edca5c..ef883d4 100644 (file)
@@ -8,3 +8,4 @@ config RTL8192U
        select CRYPTO
        select CRYPTO_AES
        select CRYPTO_CCM
+       select CRYPTO_LIB_ARC4
index ffe624e..4b415cc 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
  */
 
+#include <linux/fips.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -17,9 +18,8 @@
 
 #include "ieee80211.h"
 
+#include <crypto/arc4.h>
 #include <crypto/hash.h>
-#include <crypto/skcipher.h>
-       #include <linux/scatterlist.h>
 #include <linux/crc32.h>
 
 MODULE_AUTHOR("Jouni Malinen");
@@ -49,9 +49,9 @@ struct ieee80211_tkip_data {
 
        int key_idx;
 
-       struct crypto_sync_skcipher *rx_tfm_arc4;
+       struct arc4_ctx rx_ctx_arc4;
+       struct arc4_ctx tx_ctx_arc4;
        struct crypto_shash *rx_tfm_michael;
-       struct crypto_sync_skcipher *tx_tfm_arc4;
        struct crypto_shash *tx_tfm_michael;
 
        /* scratch buffers for virt_to_page() (crypto API) */
@@ -62,19 +62,14 @@ static void *ieee80211_tkip_init(int key_idx)
 {
        struct ieee80211_tkip_data *priv;
 
+       if (fips_enabled)
+               return NULL;
+
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                goto fail;
        priv->key_idx = key_idx;
 
-       priv->tx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
-       if (IS_ERR(priv->tx_tfm_arc4)) {
-               printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
-                               "crypto API arc4\n");
-               priv->tx_tfm_arc4 = NULL;
-               goto fail;
-       }
-
        priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
        if (IS_ERR(priv->tx_tfm_michael)) {
                printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
@@ -83,14 +78,6 @@ static void *ieee80211_tkip_init(int key_idx)
                goto fail;
        }
 
-       priv->rx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
-       if (IS_ERR(priv->rx_tfm_arc4)) {
-               printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
-                               "crypto API arc4\n");
-               priv->rx_tfm_arc4 = NULL;
-               goto fail;
-       }
-
        priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
        if (IS_ERR(priv->rx_tfm_michael)) {
                printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
@@ -104,9 +91,7 @@ static void *ieee80211_tkip_init(int key_idx)
 fail:
        if (priv) {
                crypto_free_shash(priv->tx_tfm_michael);
-               crypto_free_sync_skcipher(priv->tx_tfm_arc4);
                crypto_free_shash(priv->rx_tfm_michael);
-               crypto_free_sync_skcipher(priv->rx_tfm_arc4);
                kfree(priv);
        }
 
@@ -120,11 +105,9 @@ static void ieee80211_tkip_deinit(void *priv)
 
        if (_priv) {
                crypto_free_shash(_priv->tx_tfm_michael);
-               crypto_free_sync_skcipher(_priv->tx_tfm_arc4);
                crypto_free_shash(_priv->rx_tfm_michael);
-               crypto_free_sync_skcipher(_priv->rx_tfm_arc4);
        }
-       kfree(priv);
+       kzfree(priv);
 }
 
 
@@ -290,10 +273,8 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        u8 *pos;
        struct rtl_80211_hdr_4addr *hdr;
        struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
-       int ret = 0;
        u8 rc4key[16],  *icv;
        u32 crc;
-       struct scatterlist sg;
 
        if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
            skb->len < hdr_len)
@@ -334,21 +315,15 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
 
        if (!tcb_desc->bHwSec) {
-               SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4);
-
                icv = skb_put(skb, 4);
                crc = ~crc32_le(~0, pos, len);
                icv[0] = crc;
                icv[1] = crc >> 8;
                icv[2] = crc >> 16;
                icv[3] = crc >> 24;
-               crypto_sync_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
-               sg_init_one(&sg, pos, len + 4);
-               skcipher_request_set_sync_tfm(req, tkey->tx_tfm_arc4);
-               skcipher_request_set_callback(req, 0, NULL, NULL);
-               skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
-               ret = crypto_skcipher_encrypt(req);
-               skcipher_request_zero(req);
+
+               arc4_setkey(&tkey->tx_ctx_arc4, rc4key, 16);
+               arc4_crypt(&tkey->tx_ctx_arc4, pos, pos, len + 4);
        }
 
        tkey->tx_iv16++;
@@ -357,12 +332,7 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
                tkey->tx_iv32++;
        }
 
-       if (!tcb_desc->bHwSec)
-               return ret;
-       else
-               return 0;
-
-
+       return 0;
 }
 
 static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
@@ -376,9 +346,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        u8 rc4key[16];
        u8 icv[4];
        u32 crc;
-       struct scatterlist sg;
        int plen;
-       int err;
 
        if (skb->len < hdr_len + 8 + 4)
                return -1;
@@ -412,8 +380,6 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        pos += 8;
 
        if (!tcb_desc->bHwSec) {
-               SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4);
-
                if (iv32 < tkey->rx_iv32 ||
                (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
                        if (net_ratelimit()) {
@@ -434,23 +400,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 
                plen = skb->len - hdr_len - 12;
 
-               crypto_sync_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
-               sg_init_one(&sg, pos, plen + 4);
-
-               skcipher_request_set_sync_tfm(req, tkey->rx_tfm_arc4);
-               skcipher_request_set_callback(req, 0, NULL, NULL);
-               skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
-
-               err = crypto_skcipher_decrypt(req);
-               skcipher_request_zero(req);
-               if (err) {
-                       if (net_ratelimit()) {
-                               netdev_dbg(skb->dev, "TKIP: failed to decrypt "
-                                               "received packet from %pM\n",
-                                               hdr->addr2);
-                       }
-                       return -7;
-               }
+               arc4_setkey(&tkey->rx_ctx_arc4, rc4key, 16);
+               arc4_crypt(&tkey->rx_ctx_arc4, pos, pos, plen + 4);
 
                crc = ~crc32_le(~0, pos, plen);
                icv[0] = crc;
@@ -655,17 +606,13 @@ static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv)
        struct ieee80211_tkip_data *tkey = priv;
        int keyidx;
        struct crypto_shash *tfm = tkey->tx_tfm_michael;
-       struct crypto_sync_skcipher *tfm2 = tkey->tx_tfm_arc4;
        struct crypto_shash *tfm3 = tkey->rx_tfm_michael;
-       struct crypto_sync_skcipher *tfm4 = tkey->rx_tfm_arc4;
 
        keyidx = tkey->key_idx;
        memset(tkey, 0, sizeof(*tkey));
        tkey->key_idx = keyidx;
        tkey->tx_tfm_michael = tfm;
-       tkey->tx_tfm_arc4 = tfm2;
        tkey->rx_tfm_michael = tfm3;
-       tkey->rx_tfm_arc4 = tfm4;
 
        if (len == TKIP_KEY_LEN) {
                memcpy(tkey->key, key, TKIP_KEY_LEN);
index 26482c3..1c56e2d 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
  */
 
+#include <linux/fips.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -14,8 +15,7 @@
 
 #include "ieee80211.h"
 
-#include <crypto/skcipher.h>
-#include <linux/scatterlist.h>
+#include <crypto/arc4.h>
 #include <linux/crc32.h>
 
 MODULE_AUTHOR("Jouni Malinen");
@@ -28,8 +28,8 @@ struct prism2_wep_data {
        u8 key[WEP_KEY_LEN + 1];
        u8 key_len;
        u8 key_idx;
-       struct crypto_sync_skcipher *tx_tfm;
-       struct crypto_sync_skcipher *rx_tfm;
+       struct arc4_ctx rx_ctx_arc4;
+       struct arc4_ctx tx_ctx_arc4;
 };
 
 
@@ -37,39 +37,24 @@ static void *prism2_wep_init(int keyidx)
 {
        struct prism2_wep_data *priv;
 
+       if (fips_enabled)
+               return NULL;
+
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return NULL;
        priv->key_idx = keyidx;
 
-       priv->tx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
-       if (IS_ERR(priv->tx_tfm))
-               goto free_priv;
-       priv->rx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
-       if (IS_ERR(priv->rx_tfm))
-               goto free_tx;
-
        /* start WEP IV from a random value */
        get_random_bytes(&priv->iv, 4);
 
        return priv;
-free_tx:
-       crypto_free_sync_skcipher(priv->tx_tfm);
-free_priv:
-       kfree(priv);
-       return NULL;
 }
 
 
 static void prism2_wep_deinit(void *priv)
 {
-       struct prism2_wep_data *_priv = priv;
-
-       if (_priv) {
-               crypto_free_sync_skcipher(_priv->tx_tfm);
-               crypto_free_sync_skcipher(_priv->rx_tfm);
-       }
-       kfree(priv);
+       kzfree(priv);
 }
 
 /* Perform WEP encryption on given skb that has at least 4 bytes of headroom
@@ -87,8 +72,6 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
        u32 crc;
        u8 *icv;
-       struct scatterlist sg;
-       int err;
 
        if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
            skb->len < hdr_len)
@@ -124,8 +107,6 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        memcpy(key + 3, wep->key, wep->key_len);
 
        if (!tcb_desc->bHwSec) {
-               SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm);
-
                /* Append little-endian CRC32 and encrypt it to produce ICV */
                crc = ~crc32_le(~0, pos, len);
                icv = skb_put(skb, 4);
@@ -134,16 +115,8 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
                icv[2] = crc >> 16;
                icv[3] = crc >> 24;
 
-               crypto_sync_skcipher_setkey(wep->tx_tfm, key, klen);
-               sg_init_one(&sg, pos, len + 4);
-
-               skcipher_request_set_sync_tfm(req, wep->tx_tfm);
-               skcipher_request_set_callback(req, 0, NULL, NULL);
-               skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
-
-               err = crypto_skcipher_encrypt(req);
-               skcipher_request_zero(req);
-               return err;
+               arc4_setkey(&wep->tx_ctx_arc4, key, klen);
+               arc4_crypt(&wep->tx_ctx_arc4, pos, pos, len + 4);
        }
 
        return 0;
@@ -166,8 +139,6 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
        u32 crc;
        u8 icv[4];
-       struct scatterlist sg;
-       int err;
 
        if (skb->len < hdr_len + 8)
                return -1;
@@ -189,19 +160,8 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        plen = skb->len - hdr_len - 8;
 
        if (!tcb_desc->bHwSec) {
-               SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm);
-
-               crypto_sync_skcipher_setkey(wep->rx_tfm, key, klen);
-               sg_init_one(&sg, pos, plen + 4);
-
-               skcipher_request_set_sync_tfm(req, wep->rx_tfm);
-               skcipher_request_set_callback(req, 0, NULL, NULL);
-               skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
-
-               err = crypto_skcipher_decrypt(req);
-               skcipher_request_zero(req);
-               if (err)
-                       return -7;
+               arc4_setkey(&wep->rx_ctx_arc4, key, klen);
+               arc4_crypt(&wep->rx_ctx_arc4, pos, pos, plen + 4);
 
                crc = ~crc32_le(~0, pos, plen);
                icv[0] = crc;
index fa1bf8b..2720f73 100644 (file)
@@ -524,13 +524,8 @@ static void hfa384x_usb_defer(struct work_struct *data)
  */
 void hfa384x_create(struct hfa384x *hw, struct usb_device *usb)
 {
-       memset(hw, 0, sizeof(*hw));
        hw->usb = usb;
 
-       /* set up the endpoints */
-       hw->endp_in = usb_rcvbulkpipe(usb, 1);
-       hw->endp_out = usb_sndbulkpipe(usb, 2);
-
        /* Set up the waitq */
        init_waitqueue_head(&hw->cmdq);
 
index 456603f..4b08dc1 100644 (file)
@@ -61,23 +61,14 @@ static int prism2sta_probe_usb(struct usb_interface *interface,
                               const struct usb_device_id *id)
 {
        struct usb_device *dev;
-       const struct usb_endpoint_descriptor *epd;
-       const struct usb_host_interface *iface_desc = interface->cur_altsetting;
+       struct usb_endpoint_descriptor *bulk_in, *bulk_out;
+       struct usb_host_interface *iface_desc = interface->cur_altsetting;
        struct wlandevice *wlandev = NULL;
        struct hfa384x *hw = NULL;
        int result = 0;
 
-       if (iface_desc->desc.bNumEndpoints != 2) {
-               result = -ENODEV;
-               goto failed;
-       }
-
-       result = -EINVAL;
-       epd = &iface_desc->endpoint[1].desc;
-       if (!usb_endpoint_is_bulk_in(epd))
-               goto failed;
-       epd = &iface_desc->endpoint[2].desc;
-       if (!usb_endpoint_is_bulk_out(epd))
+       result = usb_find_common_endpoints(iface_desc, &bulk_in, &bulk_out, NULL, NULL);
+       if (result)
                goto failed;
 
        dev = interface_to_usbdev(interface);
@@ -96,6 +87,8 @@ static int prism2sta_probe_usb(struct usb_interface *interface,
        }
 
        /* Initialize the hw data */
+       hw->endp_in = usb_rcvbulkpipe(dev, bulk_in->bEndpointAddress);
+       hw->endp_out = usb_sndbulkpipe(dev, bulk_out->bEndpointAddress);
        hfa384x_create(hw, dev);
        hw->wlandev = wlandev;
 
index 30ea37e..bd37f2a 100644 (file)
@@ -444,7 +444,7 @@ cxgbit_uld_lro_rx_handler(void *hndl, const __be64 *rsp,
        case CPL_RX_ISCSI_DDP:
        case CPL_FW4_ACK:
                lro_flush = false;
-               /* fall through */
+               fallthrough;
        case CPL_ABORT_RPL_RSS:
        case CPL_PASS_ESTABLISH:
        case CPL_PEER_CLOSE:
index c968961..7b56fe9 100644 (file)
@@ -1389,14 +1389,27 @@ static u32 iscsit_do_crypto_hash_sg(
        sg = cmd->first_data_sg;
        page_off = cmd->first_data_sg_off;
 
+       if (data_length && page_off) {
+               struct scatterlist first_sg;
+               u32 len = min_t(u32, data_length, sg->length - page_off);
+
+               sg_init_table(&first_sg, 1);
+               sg_set_page(&first_sg, sg_page(sg), len, sg->offset + page_off);
+
+               ahash_request_set_crypt(hash, &first_sg, NULL, len);
+               crypto_ahash_update(hash);
+
+               data_length -= len;
+               sg = sg_next(sg);
+       }
+
        while (data_length) {
-               u32 cur_len = min_t(u32, data_length, (sg->length - page_off));
+               u32 cur_len = min_t(u32, data_length, sg->length);
 
                ahash_request_set_crypt(hash, sg, NULL, cur_len);
                crypto_ahash_update(hash);
 
                data_length -= cur_len;
-               page_off = 0;
                /* iscsit_map_iovec has already checked for invalid sg pointers */
                sg = sg_next(sg);
        }
@@ -3740,7 +3753,7 @@ check_rsp_state:
        case ISTATE_SEND_LOGOUTRSP:
                if (!iscsit_logout_post_handler(cmd, conn))
                        return -ECONNRESET;
-               /* fall through */
+               fallthrough;
        case ISTATE_SEND_STATUS:
        case ISTATE_SEND_ASYNCMSG:
        case ISTATE_SEND_NOPIN:
index 85748e3..893d1b4 100644 (file)
@@ -1149,7 +1149,7 @@ void iscsit_free_conn(struct iscsi_conn *conn)
 }
 
 void iscsi_target_login_sess_out(struct iscsi_conn *conn,
-               struct iscsi_np *np, bool zero_tsih, bool new_sess)
+                                bool zero_tsih, bool new_sess)
 {
        if (!new_sess)
                goto old_sess_out;
@@ -1167,7 +1167,6 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn,
        conn->sess = NULL;
 
 old_sess_out:
-       iscsi_stop_login_thread_timer(np);
        /*
         * If login negotiation fails check if the Time2Retain timer
         * needs to be restarted.
@@ -1407,8 +1406,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
 new_sess_out:
        new_sess = true;
 old_sess_out:
+       iscsi_stop_login_thread_timer(np);
        tpg_np = conn->tpg_np;
-       iscsi_target_login_sess_out(conn, np, zero_tsih, new_sess);
+       iscsi_target_login_sess_out(conn, zero_tsih, new_sess);
        new_sess = false;
 
        if (tpg) {
index 3b8e363..fc95e61 100644 (file)
@@ -22,8 +22,7 @@ extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
 extern void iscsit_free_conn(struct iscsi_conn *);
 extern int iscsit_start_kthreads(struct iscsi_conn *);
 extern void iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
-extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *,
-                               bool, bool);
+extern void iscsi_target_login_sess_out(struct iscsi_conn *, bool, bool);
 extern int iscsi_target_login_thread(void *);
 extern void iscsi_handle_login_thread_timeout(struct timer_list *t);
 
index f88a52f..8b40f10 100644 (file)
@@ -535,12 +535,11 @@ static bool iscsi_target_sk_check_and_clear(struct iscsi_conn *conn, unsigned in
 
 static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login)
 {
-       struct iscsi_np *np = login->np;
        bool zero_tsih = login->zero_tsih;
 
        iscsi_remove_failed_auth_entry(conn);
        iscsi_target_nego_release(conn);
-       iscsi_target_login_sess_out(conn, np, zero_tsih, true);
+       iscsi_target_login_sess_out(conn, zero_tsih, true);
 }
 
 struct conn_timeout {
index 8fc8865..5f79ea0 100644 (file)
@@ -345,7 +345,7 @@ static int core_scsi3_pr_seq_non_holder(struct se_cmd *cmd, u32 pr_reg_type,
                break;
        case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
                we = 1;
-               /* fall through */
+               fallthrough;
        case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
                /*
                 * Some commands are only allowed for registered I_T Nexuses.
@@ -354,7 +354,7 @@ static int core_scsi3_pr_seq_non_holder(struct se_cmd *cmd, u32 pr_reg_type,
                break;
        case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
                we = 1;
-               /* fall through */
+               fallthrough;
        case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
                /*
                 * Each registered I_T Nexus is a reservation holder.
index f1e8188..6e8b8d3 100644 (file)
@@ -734,7 +734,7 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
                }
                if (!protect)
                        return TCM_NO_SENSE;
-               /* Fallthrough */
+               fallthrough;
        default:
                pr_err("Unable to determine pi_prot_type for CDB: 0x%02x "
                       "PROTECT: 0x%02x\n", cdb[0], protect);
index 9fb0be0..ff26ab0 100644 (file)
@@ -1840,7 +1840,8 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
         * out unpacked_lun for the original se_cmd.
         */
        if (tm_type == TMR_ABORT_TASK && (flags & TARGET_SCF_LOOKUP_LUN_FROM_TAG)) {
-               if (!target_lookup_lun_from_tag(se_sess, tag, &unpacked_lun))
+               if (!target_lookup_lun_from_tag(se_sess, tag,
+                                               &se_cmd->orig_fe_lun))
                        goto failure;
        }
 
@@ -2236,7 +2237,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
                        ret = cmd->se_tfo->queue_data_in(cmd);
                        break;
                }
-               /* fall through */
+               fallthrough;
        case DMA_NONE:
 queue_status:
                trace_target_cmd_complete(cmd);
@@ -2431,7 +2432,7 @@ queue_rsp:
                                goto queue_full;
                        break;
                }
-               /* fall through */
+               fallthrough;
        case DMA_NONE:
 queue_status:
                trace_target_cmd_complete(cmd);
index e9f0dda..a7ed566 100644 (file)
@@ -537,7 +537,7 @@ static void ft_send_work(struct work_struct *work)
        case FCP_PTA_ACA:
                task_attr = TCM_ACA_TAG;
                break;
-       case FCP_PTA_SIMPLE: /* Fallthrough */
+       case FCP_PTA_SIMPLE:
        default:
                task_attr = TCM_SIMPLE_TAG;
        }
index bf7bae4..6dc879f 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2015, 2017, 2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/bitops.h>
@@ -191,7 +191,7 @@ static int qpnp_tm_get_temp(void *data, int *temp)
                chip->temp = mili_celsius;
        }
 
-       *temp = chip->temp < 0 ? 0 : chip->temp;
+       *temp = chip->temp;
 
        return 0;
 }
index e64db5f..4ffa2e2 100644 (file)
@@ -220,7 +220,7 @@ static int calibrate_8916(struct tsens_priv *priv)
                p2[4] = (qfprom_cdata[1] & MSM8916_S4_P2_MASK) >> MSM8916_S4_P2_SHIFT;
                for (i = 0; i < priv->num_sensors; i++)
                        p2[i] = ((base1 + p2[i]) << 3);
-               /* Fall through */
+               fallthrough;
        case ONE_PT_CALIB2:
                base0 = (qfprom_cdata[0] & MSM8916_BASE0_MASK);
                p1[0] = (qfprom_cdata[0] & MSM8916_S0_P1_MASK) >> MSM8916_S0_P1_SHIFT;
@@ -355,7 +355,7 @@ static int calibrate_8974(struct tsens_priv *priv)
                        p2[8] = (calib[5] & S8_P2_BKP_MASK) >> S8_P2_BKP_SHIFT;
                        p2[9] = (calib[5] & S9_P2_BKP_MASK) >> S9_P2_BKP_SHIFT;
                        p2[10] = (calib[5] & S10_P2_BKP_MASK) >> S10_P2_BKP_SHIFT;
-                       /* Fall through */
+                       fallthrough;
                case ONE_PT_CALIB:
                case ONE_PT_CALIB2:
                        base1 = bkp[0] & BASE1_MASK;
@@ -390,7 +390,7 @@ static int calibrate_8974(struct tsens_priv *priv)
                        p2[8] = (calib[4] & S8_P2_MASK) >> S8_P2_SHIFT;
                        p2[9] = (calib[4] & S9_P2_MASK) >> S9_P2_SHIFT;
                        p2[10] = (calib[4] & S10_P2_MASK) >> S10_P2_SHIFT;
-                       /* Fall through */
+                       fallthrough;
                case ONE_PT_CALIB:
                case ONE_PT_CALIB2:
                        base1 = calib[0] & BASE1_MASK;
@@ -420,7 +420,7 @@ static int calibrate_8974(struct tsens_priv *priv)
                        p2[i] <<= 2;
                        p2[i] |= BIT_APPEND;
                }
-               /* Fall through */
+               fallthrough;
        case ONE_PT_CALIB2:
                for (i = 0; i < priv->num_sensors; i++) {
                        p1[i] += base1;
index b682a4d..3c19a38 100644 (file)
@@ -202,7 +202,7 @@ static int calibrate_v1(struct tsens_priv *priv)
                p2[9] = (qfprom_cdata[3] & S9_P2_MASK) >> S9_P2_SHIFT;
                for (i = 0; i < priv->num_sensors; i++)
                        p2[i] = ((base1 + p2[i]) << 2);
-               /* Fall through */
+               fallthrough;
        case ONE_PT_CALIB2:
                base0 = (qfprom_cdata[4] & BASE0_MASK) >> BASE0_SHIFT;
                p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT;
@@ -263,7 +263,7 @@ static int calibrate_8976(struct tsens_priv *priv)
 
                for (i = 0; i < priv->num_sensors; i++)
                        p2[i] = ((base1 + p2[i]) << 2);
-               /* Fall through */
+               fallthrough;
        case ONE_PT_CALIB2:
                base0 = qfprom_cdata[0] & MSM8976_BASE0_MASK;
                p1[0] = (qfprom_cdata[0] & MSM8976_S0_P1_MASK) >> MSM8976_S0_P1_SHIFT;
index 72bf159..a6616e5 100644 (file)
@@ -1516,7 +1516,7 @@ EXPORT_SYMBOL_GPL(thermal_zone_device_register);
  */
 void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 {
-       int i;
+       int i, tz_id;
        const struct thermal_zone_params *tzp;
        struct thermal_cooling_device *cdev;
        struct thermal_zone_device *pos = NULL;
@@ -1525,6 +1525,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
                return;
 
        tzp = tz->tzp;
+       tz_id = tz->id;
 
        mutex_lock(&thermal_list_lock);
        list_for_each_entry(pos, &thermal_tz_list, node)
@@ -1567,7 +1568,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
        mutex_destroy(&tz->lock);
        device_unregister(&tz->device);
 
-       thermal_notify_tz_delete(tz->id);
+       thermal_notify_tz_delete(tz_id);
 }
 EXPORT_SYMBOL_GPL(thermal_zone_device_unregister);
 
index 63b02bf..fdb8a49 100644 (file)
@@ -37,20 +37,21 @@ static struct temp_sensor_data omap4430_mpu_temp_sensor_data = {
 
 /*
  * Temperature values in milli degree celsius
- * ADC code values from 530 to 923
+ * ADC code values from 13 to 107, see TRM
+ * "18.4.10.2.3 ADC Codes Versus Temperature".
  */
 static const int
 omap4430_adc_to_temp[OMAP4430_ADC_END_VALUE - OMAP4430_ADC_START_VALUE + 1] = {
-       -38000, -35000, -34000, -32000, -30000, -28000, -26000, -24000, -22000,
-       -20000, -18000, -17000, -15000, -13000, -12000, -10000, -8000, -6000,
-       -5000, -3000, -1000, 0, 2000, 3000, 5000, 6000, 8000, 10000, 12000,
-       13000, 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28000, 30000,
-       32000, 33000, 35000, 37000, 38000, 40000, 42000, 43000, 45000, 47000,
-       48000, 50000, 52000, 53000, 55000, 57000, 58000, 60000, 62000, 64000,
-       66000, 68000, 70000, 71000, 73000, 75000, 77000, 78000, 80000, 82000,
-       83000, 85000, 87000, 88000, 90000, 92000, 93000, 95000, 97000, 98000,
-       100000, 102000, 103000, 105000, 107000, 109000, 111000, 113000, 115000,
-       117000, 118000, 120000, 122000, 123000,
+       -40000, -38000, -35000, -34000, -32000, -30000, -28000, -26000, -24000,
+       -22000, -20000, -18500, -17000, -15000, -13500, -12000, -10000, -8000,
+       -6500, -5000, -3500, -1500, 0, 2000, 3500, 5000, 6500, 8500, 10000,
+       12000, 13500, 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28500,
+       30000, 32000, 33500, 35000, 37000, 38500, 40000, 42000, 43500, 45000,
+       47000, 48500, 50000, 52000, 53500, 55000, 57000, 58500, 60000, 62000,
+       64000, 66000, 68000, 70000, 71500, 73500, 75000, 77000, 78500, 80000,
+       82000, 83500, 85000, 87000, 88500, 90000, 92000, 93500, 95000, 97000,
+       98500, 100000, 102000, 103500, 105000, 107000, 109000, 111000, 113000,
+       115000, 117000, 118500, 120000, 122000, 123500, 125000,
 };
 
 /* OMAP4430 data */
index a453ff8..9a3955c 100644 (file)
  * and thresholds for OMAP4430.
  */
 
-/* ADC conversion table limits */
-#define OMAP4430_ADC_START_VALUE                       0
-#define OMAP4430_ADC_END_VALUE                         127
+/*
+ * ADC conversion table limits. Ignore values outside the TRM listed
+ * range to avoid bogus thermal shutdowns. See omap4430 TRM chapter
+ * "18.4.10.2.3 ADC Codes Versus Temperature".
+ */
+#define OMAP4430_ADC_START_VALUE                       13
+#define OMAP4430_ADC_END_VALUE                         107
 /* bandgap clock limits (no control on 4430) */
 #define OMAP4430_MAX_FREQ                              32768
 #define OMAP4430_MIN_FREQ                              32768
index f77ceae..394a23c 100644 (file)
@@ -453,7 +453,7 @@ static void tb_ctl_rx_callback(struct tb_ring *ring, struct ring_frame *frame,
                                   "RX: checksum mismatch, dropping packet\n");
                        goto rx;
                }
-               /* Fall through */
+               fallthrough;
        case TB_CFG_PKG_ICM_EVENT:
                if (tb_ctl_handle_event(pkg->ctl, frame->eof, pkg, frame->size))
                        goto rx;
index 3ebca44..0c8471b 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/crc32.h>
+#include <linux/delay.h>
 #include <linux/property.h>
 #include <linux/slab.h>
 #include "tb.h"
@@ -389,8 +390,8 @@ static int tb_drom_parse_entries(struct tb_switch *sw)
                struct tb_drom_entry_header *entry = (void *) (sw->drom + pos);
                if (pos + 1 == drom_size || pos + entry->len > drom_size
                                || !entry->len) {
-                       tb_sw_warn(sw, "drom buffer overrun, aborting\n");
-                       return -EIO;
+                       tb_sw_warn(sw, "DROM buffer overrun\n");
+                       return -EILSEQ;
                }
 
                switch (entry->type) {
@@ -526,7 +527,8 @@ int tb_drom_read(struct tb_switch *sw)
        u16 size;
        u32 crc;
        struct tb_drom_header *header;
-       int res;
+       int res, retries = 1;
+
        if (sw->drom)
                return 0;
 
@@ -612,7 +614,17 @@ parse:
                tb_sw_warn(sw, "drom device_rom_revision %#x unknown\n",
                        header->device_rom_revision);
 
-       return tb_drom_parse_entries(sw);
+       res = tb_drom_parse_entries(sw);
+       /* If the DROM parsing fails, wait a moment and retry once */
+       if (res == -EILSEQ && retries--) {
+               tb_sw_warn(sw, "parsing DROM failed, retrying\n");
+               msleep(100);
+               res = tb_drom_read_n(sw, 0, sw->drom, size);
+               if (!res)
+                       goto parse;
+       }
+
+       return res;
 err:
        kfree(sw->drom);
        sw->drom = NULL;
index 712395f..a921de9 100644 (file)
@@ -684,6 +684,7 @@ static int tb_init_port(struct tb_port *port)
                if (res == -ENODEV) {
                        tb_dbg(port->sw->tb, " Port %d: not implemented\n",
                               port->port);
+                       port->disabled = true;
                        return 0;
                }
                return res;
@@ -2092,7 +2093,7 @@ static int tb_switch_add_dma_port(struct tb_switch *sw)
                if (tb_route(sw))
                        return 0;
 
-               /* fallthrough */
+               fallthrough;
        case 3:
                ret = tb_switch_set_uuid(sw);
                if (ret)
index a413d55..3c620a9 100644 (file)
@@ -186,7 +186,7 @@ struct tb_switch {
  * @cap_adap: Offset of the adapter specific capability (%0 if not present)
  * @cap_usb4: Offset to the USB4 port capability (%0 if not present)
  * @port: Port number on switch
- * @disabled: Disabled by eeprom
+ * @disabled: Disabled by eeprom or enabled but not implemented
  * @bonded: true if the port is bonded (two lanes combined as one)
  * @dual_link_port: If the switch is connected using two ports, points
  *                 to the other port.
index 2aae2c7..829b6cc 100644 (file)
@@ -315,7 +315,7 @@ static inline u32 tb_dp_cap_set_rate(u32 val, u32 rate)
        switch (rate) {
        default:
                WARN(1, "invalid rate %u passed, defaulting to 1620 MB/s\n", rate);
-               /* Fallthrough */
+               fallthrough;
        case 1620:
                val |= DP_COMMON_CAP_RATE_RBR << DP_COMMON_CAP_RATE_SHIFT;
                break;
@@ -355,7 +355,7 @@ static inline u32 tb_dp_cap_set_lanes(u32 val, u32 lanes)
        default:
                WARN(1, "invalid number of lanes %u passed, defaulting to 1\n",
                     lanes);
-               /* Fallthrough */
+               fallthrough;
        case 1:
                val |= DP_COMMON_CAP_1_LANE << DP_COMMON_CAP_LANES_SHIFT;
                break;
@@ -951,10 +951,18 @@ static void tb_usb3_reclaim_available_bandwidth(struct tb_tunnel *tunnel,
        int ret, max_rate, allocate_up, allocate_down;
 
        ret = usb4_usb3_port_actual_link_rate(tunnel->src_port);
-       if (ret <= 0) {
-               tb_tunnel_warn(tunnel, "tunnel is not up\n");
+       if (ret < 0) {
+               tb_tunnel_warn(tunnel, "failed to read actual link rate\n");
                return;
+       } else if (!ret) {
+               /* Use maximum link rate if the link valid is not set */
+               ret = usb4_usb3_port_max_link_rate(tunnel->src_port);
+               if (ret < 0) {
+                       tb_tunnel_warn(tunnel, "failed to read maximum link rate\n");
+                       return;
+               }
        }
+
        /*
         * 90% of the max rate can be allocated for isochronous
         * transfers.
index 2a0e51a..92c9a47 100644 (file)
@@ -492,7 +492,7 @@ static void xencons_backend_changed(struct xenbus_device *dev,
        case XenbusStateClosed:
                if (dev->state == XenbusStateClosed)
                        break;
-               /* fall through - Missed the backend's CLOSING state. */
+               fallthrough;    /* Missed the backend's CLOSING state */
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;
index 21e76a2..a8e19b4 100644 (file)
@@ -243,7 +243,7 @@ done:
                /* Fall back to a 3 byte encoding */
                word.bytes = 3;
                word.word &= 0x00ffffff;
-               /* Fall through */
+               fallthrough;
        case 3:
                /* 3 byte encoding */
                word.word |= 0x82000000;
index 0a29a94..35cf121 100644 (file)
@@ -1584,7 +1584,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
                        gsm_process_modem(tty, dlci, modem, clen);
                        tty_kref_put(tty);
                }
-               /* Fall through */
+               fallthrough;
        case 1:         /* Line state will go via DLCI 0 controls only */
        default:
                tty_insert_flip_string(port, data, len);
@@ -1986,7 +1986,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
                gsm->address = 0;
                gsm->state = GSM_ADDRESS;
                gsm->fcs = INIT_FCS;
-               /* Fall through */
+               fallthrough;
        case GSM_ADDRESS:       /* Address continuation */
                gsm->fcs = gsm_fcs_add(gsm->fcs, c);
                if (gsm_read_ea(&gsm->address, c))
index b09eac4..8e975cb 100644 (file)
@@ -602,7 +602,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
                case TCOFLUSH:
                        flush_tx_queue(tty);
                }
-               /* fall through - to default */
+               fallthrough;    /* to default */
 
        default:
                error = n_tty_ioctl_helper(tty, file, cmd, arg);
index f75696f..934dd2f 100644 (file)
@@ -605,7 +605,6 @@ static void receive_char(struct r3964_info *pInfo, const unsigned char c)
                }
                break;
        case R3964_WAIT_FOR_RX_REPEAT:
-               /* FALLTHROUGH */
        case R3964_IDLE:
                if (c == STX) {
                        /* Prevent rx_queue from overflow: */
index db88dee..f8e9999 100644 (file)
@@ -39,7 +39,7 @@ static void serial8250_em_serial_out(struct uart_port *p, int offset, int value)
                break;
        case UART_IER: /* IER @ 0x04 */
                value &= 0x0f; /* only 4 valid bits - not Xscale */
-               /* fall-through */
+               fallthrough;
        case UART_DLL_EM: /* DLL @ 0x24 (+9) */
        case UART_DLM_EM: /* DLM @ 0x28 (+9) */
                writel(value, p->membase + (offset << 2));
index 04b9af7..2d0e7c7 100644 (file)
@@ -744,6 +744,24 @@ static const struct exar8250_board pbn_exar_XR17V35x = {
        .exit           = pci_xr17v35x_exit,
 };
 
+static const struct exar8250_board pbn_fastcom35x_2 = {
+       .num_ports      = 2,
+       .setup          = pci_xr17v35x_setup,
+       .exit           = pci_xr17v35x_exit,
+};
+
+static const struct exar8250_board pbn_fastcom35x_4 = {
+       .num_ports      = 4,
+       .setup          = pci_xr17v35x_setup,
+       .exit           = pci_xr17v35x_exit,
+};
+
+static const struct exar8250_board pbn_fastcom35x_8 = {
+       .num_ports      = 8,
+       .setup          = pci_xr17v35x_setup,
+       .exit           = pci_xr17v35x_exit,
+};
+
 static const struct exar8250_board pbn_exar_XR17V4358 = {
        .num_ports      = 12,
        .setup          = pci_xr17v35x_setup,
@@ -811,9 +829,9 @@ static const struct pci_device_id exar_pci_tbl[] = {
        EXAR_DEVICE(EXAR, XR17V358, pbn_exar_XR17V35x),
        EXAR_DEVICE(EXAR, XR17V4358, pbn_exar_XR17V4358),
        EXAR_DEVICE(EXAR, XR17V8358, pbn_exar_XR17V8358),
-       EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_exar_XR17V35x),
-       EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_exar_XR17V35x),
-       EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_exar_XR17V35x),
+       EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_fastcom35x_2),
+       EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_fastcom35x_4),
+       EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_fastcom35x_8),
 
        EXAR_DEVICE(COMMTECH, 4222PCI335, pbn_fastcom335_2),
        EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4),
index d1d253c..31c9e83 100644 (file)
@@ -255,7 +255,7 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level)
        case CHIP_ID_F81866:
                sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1,
                                   0);
-               /* fall through */
+               fallthrough;
        case CHIP_ID_F81865:
                sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_SHARE,
                                   F81866_IRQ_SHARE);
index 1a74d51..55bb7b8 100644 (file)
@@ -631,7 +631,7 @@ pci_timedia_setup(struct serial_private *priv,
                break;
        case 3:
                offset = board->uart_offset;
-               /* FALLTHROUGH */
+               fallthrough;
        case 4: /* BAR 2 */
        case 5: /* BAR 3 */
        case 6: /* BAR 4 */
@@ -5566,6 +5566,17 @@ static const struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_wch384_4 },
 
+       /*
+        * Realtek RealManage
+        */
+       {       PCI_VENDOR_ID_REALTEK, 0x816a,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0, pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_REALTEK, 0x816b,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0, pbn_b0_1_115200 },
+
        /* Fintek PCI serial cards */
        { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 },
        { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 },
index 0947569..c71d647 100644 (file)
@@ -1872,7 +1872,7 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
        switch (iir & 0x3f) {
        case UART_IIR_RX_TIMEOUT:
                serial8250_rx_dma_flush(up);
-               /* fall-through */
+               fallthrough;
        case UART_IIR_RLSI:
                return true;
        }
@@ -2275,6 +2275,10 @@ int serial8250_do_startup(struct uart_port *port)
 
        if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) {
                unsigned char iir1;
+
+               if (port->irqflags & IRQF_SHARED)
+                       disable_irq_nosync(port->irq);
+
                /*
                 * Test for UARTs that do not reassert THRE when the
                 * transmitter is idle and the interrupt has already
@@ -2284,8 +2288,6 @@ int serial8250_do_startup(struct uart_port *port)
                 * allow register changes to become visible.
                 */
                spin_lock_irqsave(&port->lock, flags);
-               if (up->port.irqflags & IRQF_SHARED)
-                       disable_irq_nosync(port->irq);
 
                wait_for_xmitr(up, UART_LSR_THRE);
                serial_port_out_sync(port, UART_IER, UART_IER_THRI);
@@ -2297,9 +2299,10 @@ int serial8250_do_startup(struct uart_port *port)
                iir = serial_port_in(port, UART_IIR);
                serial_port_out(port, UART_IER, 0);
 
+               spin_unlock_irqrestore(&port->lock, flags);
+
                if (port->irqflags & IRQF_SHARED)
                        enable_irq(port->irq);
-               spin_unlock_irqrestore(&port->lock, flags);
 
                /*
                 * If the interrupt is not reasserted, or we otherwise
index e0b73a5..a2978ab 100644 (file)
@@ -75,7 +75,7 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
                break;
        case UART_LCR:
                valshift = 8;
-               /* fall through */
+               fallthrough;
        case UART_MCR:
                offset = UNIPHIER_UART_LCR_MCR;
                break;
@@ -101,7 +101,7 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value)
        case UART_SCR:
                /* No SCR for this hardware.  Use CHAR as a scratch register */
                valshift = 8;
-               /* fall through */
+               fallthrough;
        case UART_FCR:
                offset = UNIPHIER_UART_CHAR_FCR;
                break;
@@ -109,7 +109,7 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value)
                valshift = 8;
                /* Divisor latch access bit does not exist. */
                value &= ~UART_LCR_DLAB;
-               /* fall through */
+               fallthrough;
        case UART_MCR:
                offset = UNIPHIER_UART_LCR_MCR;
                break;
index 8a0352e..9409be9 100644 (file)
@@ -517,6 +517,7 @@ config SERIAL_IMX_CONSOLE
 
 config SERIAL_IMX_EARLYCON
        bool "Earlycon on IMX serial port"
+       depends on ARCH_MXC || COMPILE_TEST
        depends on OF
        select SERIAL_EARLYCON
        help
index d056ee6..caf167f 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_SERIAL_ZS) += zs.o
 obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
 obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
 obj-$(CONFIG_SERIAL_IMX) += imx.o
+obj-$(CONFIG_SERIAL_IMX_EARLYCON) += imx_earlycon.o
 obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
 obj-$(CONFIG_SERIAL_ICOM) += icom.o
 obj-$(CONFIG_SERIAL_MESON) += meson_uart.o
index c010f63..6749859 100644 (file)
@@ -2241,9 +2241,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
        clk_disable(uap->clk);
 }
 
-static void __init
-pl011_console_get_options(struct uart_amba_port *uap, int *baud,
-                            int *parity, int *bits)
+static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
+                                     int *parity, int *bits)
 {
        if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) {
                unsigned int lcr_h, ibrd, fbrd;
@@ -2276,7 +2275,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
        }
 }
 
-static int __init pl011_console_setup(struct console *co, char *options)
+static int pl011_console_setup(struct console *co, char *options)
 {
        struct uart_amba_port *uap;
        int baud = 38400;
@@ -2344,8 +2343,8 @@ static int __init pl011_console_setup(struct console *co, char *options)
  *
  *     Returns 0 if console matches; otherwise non-zero to use default matching
  */
-static int __init pl011_console_match(struct console *co, char *name, int idx,
-                                     char *options)
+static int pl011_console_match(struct console *co, char *name, int idx,
+                              char *options)
 {
        unsigned char iotype;
        resource_size_t addr;
@@ -2615,7 +2614,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
 
 static int pl011_register_port(struct uart_amba_port *uap)
 {
-       int ret;
+       int ret, i;
 
        /* Ensure interrupts from this UART are masked and cleared */
        pl011_write(0, uap, REG_IMSC);
@@ -2626,6 +2625,9 @@ static int pl011_register_port(struct uart_amba_port *uap)
                if (ret < 0) {
                        dev_err(uap->port.dev,
                                "Failed to register AMBA-PL011 driver\n");
+                       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+                               if (amba_ports[i] == uap)
+                                       amba_ports[i] = NULL;
                        return ret;
                }
        }
index e43471b..bb5fc8b 100644 (file)
@@ -1845,7 +1845,7 @@ static void atmel_get_ip_name(struct uart_port *port)
                version = atmel_uart_readl(port, ATMEL_US_VERSION);
                switch (version) {
                case 0x814:     /* sama5d2 */
-                       /* fall through */
+                       fallthrough;
                case 0x701:     /* sama5d4 */
                        atmel_port->fidi_min = 3;
                        atmel_port->fidi_max = 65535;
index 8573fc9..76b94d0 100644 (file)
@@ -587,7 +587,6 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id)
                        transmit_chars(up, lsr);
                        break;
                case UART_IIR_RX_TIMEOUT:
-                       /* FALLTHROUGH */
                case UART_IIR_RDI:
                        serial_omap_rdi(up, lsr);
                        break;
@@ -598,7 +597,6 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id)
                        /* simply try again */
                        break;
                case UART_IIR_XOFF:
-                       /* FALLTHROUGH */
                default:
                        break;
                }
index 3aa29d2..184b458 100644 (file)
@@ -361,11 +361,16 @@ static int qcom_geni_serial_get_char(struct uart_port *uport)
                        return NO_POLL_CHAR;
 
                if (word_cnt == 1 && (status & RX_LAST))
+                       /*
+                        * NOTE: If RX_LAST_BYTE_VALID is 0 it needs to be
+                        * treated as if it was BYTES_PER_FIFO_WORD.
+                        */
                        private_data->poll_cached_bytes_cnt =
                                (status & RX_LAST_BYTE_VALID_MSK) >>
                                RX_LAST_BYTE_VALID_SHFT;
-               else
-                       private_data->poll_cached_bytes_cnt = 4;
+
+               if (private_data->poll_cached_bytes_cnt == 0)
+                       private_data->poll_cached_bytes_cnt = BYTES_PER_FIFO_WORD;
 
                private_data->poll_cached_bytes =
                        readl(uport->membase + SE_GENI_RX_FIFOn);
@@ -1098,7 +1103,7 @@ static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport)
 }
 
 #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
-static int __init qcom_geni_console_setup(struct console *co, char *options)
+static int qcom_geni_console_setup(struct console *co, char *options)
 {
        struct uart_port *uport;
        struct qcom_geni_serial_port *port;
index b5ef86a..85366e0 100644 (file)
@@ -259,7 +259,7 @@ static void rda_uart_set_termios(struct uart_port *port,
        case CS5:
        case CS6:
                dev_warn(port->dev, "bit size not supported, using 7 bits\n");
-               /* Fall through */
+               fallthrough;
        case CS7:
                ctrl &= ~RDA_UART_DBITS_8;
                break;
index 8ed3482..8ae3e03 100644 (file)
@@ -1905,9 +1905,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
                ourport->tx_irq = ret + 1;
        }
 
-       ret = platform_get_irq(platdev, 1);
-       if (ret > 0)
-               ourport->tx_irq = ret;
+       if (!s3c24xx_serial_has_interrupt_mask(port)) {
+               ret = platform_get_irq(platdev, 1);
+               if (ret > 0)
+                       ourport->tx_irq = ret;
+       }
        /*
         * DMA is currently supported only on DT platforms, if DMA properties
         * are specified.
index b87914a..bd13014 100644 (file)
@@ -876,7 +876,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
                                tegra_uart_write(tup, ier, UART_IER);
                                break;
                        }
-                       /* Fall through */
+                       fallthrough;
                case 2: /* Receive */
                        if (!tup->use_rx_pio) {
                                is_rx_start = tup->rx_in_progress;
index 3403dd7..124524e 100644 (file)
@@ -1916,24 +1916,12 @@ static inline bool uart_console_enabled(struct uart_port *port)
        return uart_console(port) && (port->cons->flags & CON_ENABLED);
 }
 
-static void __uart_port_spin_lock_init(struct uart_port *port)
+static void uart_port_spin_lock_init(struct uart_port *port)
 {
        spin_lock_init(&port->lock);
        lockdep_set_class(&port->lock, &port_lock_key);
 }
 
-/*
- * Ensure that the serial console lock is initialised early.
- * If this port is a console, then the spinlock is already initialised.
- */
-static inline void uart_port_spin_lock_init(struct uart_port *port)
-{
-       if (uart_console(port))
-               return;
-
-       __uart_port_spin_lock_init(port);
-}
-
 #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
 /**
  *     uart_console_write - write a console message to a serial port
@@ -2086,7 +2074,15 @@ uart_set_options(struct uart_port *port, struct console *co,
        struct ktermios termios;
        static struct ktermios dummy;
 
-       uart_port_spin_lock_init(port);
+       /*
+        * Ensure that the serial-console lock is initialised early.
+        *
+        * Note that the console-enabled check is needed because of kgdboc,
+        * which can end up calling uart_set_options() for an already enabled
+        * console via tty_find_polling_driver() and uart_poll_init().
+        */
+       if (!uart_console_enabled(port) && !port->console_reinit)
+               uart_port_spin_lock_init(port);
 
        memset(&termios, 0, sizeof(struct ktermios));
 
@@ -2101,7 +2097,7 @@ uart_set_options(struct uart_port *port, struct console *co,
        switch (parity) {
        case 'o': case 'O':
                termios.c_cflag |= PARODD;
-               /*fall through*/
+               fallthrough;
        case 'e': case 'E':
                termios.c_cflag |= PARENB;
                break;
@@ -2379,13 +2375,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
                uart_change_pm(state, UART_PM_STATE_ON);
 
                /*
-                * If this driver supports console, and it hasn't been
-                * successfully registered yet, initialise spin lock for it.
-                */
-               if (port->cons && !(port->cons->flags & CON_ENABLED))
-                       __uart_port_spin_lock_init(port);
-
-               /*
                 * Ensure that the modem control lines are de-activated.
                 * keep the DTR setting that is set in uart_set_options()
                 * We probably don't need a spinlock around this, but
@@ -2801,10 +2790,12 @@ static ssize_t console_store(struct device *dev,
                if (oldconsole && !newconsole) {
                        ret = unregister_console(uport->cons);
                } else if (!oldconsole && newconsole) {
-                       if (uart_console(uport))
+                       if (uart_console(uport)) {
+                               uport->console_reinit = 1;
                                register_console(uport->cons);
-                       else
+                       } else {
                                ret = -ENOENT;
+                       }
                }
        } else {
                ret = -ENXIO;
@@ -2900,7 +2891,12 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
                goto out;
        }
 
-       uart_port_spin_lock_init(uport);
+       /*
+        * If this port is in use as a console then the spinlock is already
+        * initialised.
+        */
+       if (!uart_console_enabled(uport))
+               uart_port_spin_lock_init(uport);
 
        if (uport->cons && uport->dev)
                of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
index 143300a..ba503dd 100644 (file)
@@ -970,7 +970,7 @@ static int stm32_init_port(struct stm32_port *stm32port,
                return ret;
 
        if (stm32port->info->cfg.has_wakeup) {
-               stm32port->wakeirq = platform_get_irq(pdev, 1);
+               stm32port->wakeirq = platform_get_irq_optional(pdev, 1);
                if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO)
                        return stm32port->wakeirq ? : -ENODEV;
        }
index 8ce9a7a..319e5ce 100644 (file)
@@ -514,7 +514,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
                        switch (ret) {
                        case 2:
                                sunsu_change_mouse_baud(up);
-                               /* fallthru */
+                               fallthrough;
                        case 1:
                                break;
 
index 7ea06bb..001e19d 100644 (file)
@@ -306,7 +306,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
                switch (ret) {
                case 2:
                        sunzilog_change_mouse_baud(up);
-                       /* fallthru */
+                       fallthrough;
                case 1:
                        break;
 
index 2833f14..a9b1ee2 100644 (file)
@@ -544,7 +544,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
 
                cdns_uart->baud = cdns_uart_set_baud_rate(cdns_uart->port,
                                cdns_uart->baud);
-               /* fall through */
+               fallthrough;
        case ABORT_RATE_CHANGE:
                if (!locked)
                        spin_lock_irqsave(&cdns_uart->port->lock, flags);
index 9245fff..e18f318 100644 (file)
@@ -866,7 +866,7 @@ static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
                        ld->ops->flush_buffer(tty);
                        tty_unthrottle(tty);
                }
-               /* fall through */
+               fallthrough;
        case TCOFLUSH:
                tty_driver_flush_buffer(tty);
                break;
index ccb533f..19cd4a4 100644 (file)
@@ -1201,7 +1201,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
        unsigned int old_rows, old_row_size, first_copied_row;
        unsigned int new_cols, new_rows, new_row_size, new_screen_size;
        unsigned int user;
-       unsigned short *newscreen;
+       unsigned short *oldscreen, *newscreen;
        struct uni_screen *new_uniscr = NULL;
 
        WARN_CONSOLE_UNLOCKED();
@@ -1299,10 +1299,11 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
        if (new_scr_end > new_origin)
                scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
                            new_scr_end - new_origin);
-       kfree(vc->vc_screenbuf);
+       oldscreen = vc->vc_screenbuf;
        vc->vc_screenbuf = newscreen;
        vc->vc_screenbuf_size = new_screen_size;
        set_origin(vc);
+       kfree(oldscreen);
 
        /* do part of a reset_terminal() */
        vc->vc_top = 0;
@@ -1553,7 +1554,7 @@ static void csi_J(struct vc_data *vc, int vpar)
                        break;
                case 3: /* include scrollback */
                        flush_scrollback(vc);
-                       /* fallthrough */
+                       fallthrough;
                case 2: /* erase whole display */
                        vc_uniscr_clear_lines(vc, 0, vc->vc_rows);
                        count = vc->vc_cols * vc->vc_rows;
@@ -2167,7 +2168,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                lf(vc);
                if (!is_kbd(vc, lnm))
                        return;
-               /* fall through */
+               fallthrough;
        case 13:
                cr(vc);
                return;
@@ -2306,7 +2307,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                        return;
                }
                vc->vc_priv = EPecma;
-               /* fall through */
+               fallthrough;
        case ESgetpars:
                if (c == ';' && vc->vc_npar < NPAR - 1) {
                        vc->vc_npar++;
index 91c3017..a4e520b 100644 (file)
@@ -806,12 +806,22 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
                console_lock();
                vcp = vc_cons[i].d;
                if (vcp) {
+                       int ret;
+                       int save_scan_lines = vcp->vc_scan_lines;
+                       int save_font_height = vcp->vc_font.height;
+
                        if (v.v_vlin)
                                vcp->vc_scan_lines = v.v_vlin;
                        if (v.v_clin)
                                vcp->vc_font.height = v.v_clin;
                        vcp->vc_resize_user = 1;
-                       vc_resize(vcp, v.v_cols, v.v_rows);
+                       ret = vc_resize(vcp, v.v_cols, v.v_rows);
+                       if (ret) {
+                               vcp->vc_scan_lines = save_scan_lines;
+                               vcp->vc_font.height = save_font_height;
+                               console_unlock();
+                               return ret;
+                       }
                }
                console_unlock();
        }
index f7f6229..60f4711 100644 (file)
@@ -710,7 +710,8 @@ static int c67x00_add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
                        if (ret)
                                return ret;
                        break;
-               }               /* else fallthrough */
+               }
+               fallthrough;
        case STATUS_STAGE:
                pid = !usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
                ret = c67x00_create_td(c67x00, urb, NULL, 0, pid, 1,
index 9917868..7f6f3ab 100644 (file)
@@ -378,21 +378,19 @@ static void acm_ctrl_irq(struct urb *urb)
        if (current_size < expected_size) {
                /* notification is transmitted fragmented, reassemble */
                if (acm->nb_size < expected_size) {
-                       if (acm->nb_size) {
-                               kfree(acm->notification_buffer);
-                               acm->nb_size = 0;
-                       }
+                       u8 *new_buffer;
                        alloc_size = roundup_pow_of_two(expected_size);
-                       /*
-                        * kmalloc ensures a valid notification_buffer after a
-                        * use of kfree in case the previous allocation was too
-                        * small. Final freeing is done on disconnect.
-                        */
-                       acm->notification_buffer =
-                               kmalloc(alloc_size, GFP_ATOMIC);
-                       if (!acm->notification_buffer)
+                       /* Final freeing is done on disconnect. */
+                       new_buffer = krealloc(acm->notification_buffer,
+                                             alloc_size, GFP_ATOMIC);
+                       if (!new_buffer) {
+                               acm->nb_index = 0;
                                goto exit;
+                       }
+
+                       acm->notification_buffer = new_buffer;
                        acm->nb_size = alloc_size;
+                       dr = (struct usb_cdc_notification *)acm->notification_buffer;
                }
 
                copy_size = min(current_size,
index 084c48c..67cbd42 100644 (file)
@@ -827,6 +827,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo
        if (rv < 0)
                return rv;
 
+       if (!usblp->present) {
+               count = -ENODEV;
+               goto done;
+       }
+
        if ((avail = usblp->rstatus) < 0) {
                printk(KERN_ERR "usblp%d: error %d reading from printer\n",
                    usblp->minor, (int)avail);
index f81606c..b351962 100644 (file)
@@ -269,8 +269,30 @@ static int usb_probe_device(struct device *dev)
        if (error)
                return error;
 
+       /* Probe the USB device with the driver in hand, but only
+        * defer to a generic driver in case the current USB
+        * device driver has an id_table or a match function; i.e.,
+        * when the device driver was explicitly matched against
+        * a device.
+        *
+        * If the device driver does not have either of these,
+        * then we assume that it can bind to any device and is
+        * not truly a more specialized/non-generic driver, so a
+        * return value of -ENODEV should not force the device
+        * to be handled by the generic USB driver, as there
+        * can still be another, more specialized, device driver.
+        *
+        * This accommodates the usbip driver.
+        *
+        * TODO: What if, in the future, there are multiple
+        * specialized USB device drivers for a particular device?
+        * In such cases, there is a need to try all matching
+        * specialised device drivers prior to setting the
+        * use_generic_driver bit.
+        */
        error = udriver->probe(udev);
-       if (error == -ENODEV && udriver != &usb_generic_driver) {
+       if (error == -ENODEV && udriver != &usb_generic_driver &&
+           (udriver->id_table || udriver->match)) {
                udev->use_generic_driver = 1;
                return -EPROBE_DEFER;
        }
@@ -831,14 +853,17 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
                udev = to_usb_device(dev);
                udrv = to_usb_device_driver(drv);
 
-               if (udrv->id_table &&
-                   usb_device_match_id(udev, udrv->id_table) != NULL) {
-                       return 1;
-               }
+               if (udrv->id_table)
+                       return usb_device_match_id(udev, udrv->id_table) != NULL;
 
                if (udrv->match)
                        return udrv->match(udev);
-               return 0;
+
+               /* If the device driver under consideration does not have a
+                * id_table or a match function, then let the driver's probe
+                * function decide.
+                */
+               return 1;
 
        } else if (is_usb_interface(dev)) {
                struct usb_interface *intf;
@@ -905,6 +930,28 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
+static int __usb_bus_reprobe_drivers(struct device *dev, void *data)
+{
+       struct usb_device_driver *new_udriver = data;
+       struct usb_device *udev;
+       int ret;
+
+       /* Don't reprobe if current driver isn't usb_generic_driver */
+       if (dev->driver != &usb_generic_driver.drvwrap.driver)
+               return 0;
+
+       udev = to_usb_device(dev);
+       if (usb_device_match_id(udev, new_udriver->id_table) == NULL &&
+           (!new_udriver->match || new_udriver->match(udev) == 0))
+               return 0;
+
+       ret = device_reprobe(dev);
+       if (ret && ret != -EPROBE_DEFER)
+               dev_err(dev, "Failed to reprobe device (error %d)\n", ret);
+
+       return 0;
+}
+
 /**
  * usb_register_device_driver - register a USB device (not interface) driver
  * @new_udriver: USB operations for the device driver
@@ -934,13 +981,20 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver,
 
        retval = driver_register(&new_udriver->drvwrap.driver);
 
-       if (!retval)
+       if (!retval) {
                pr_info("%s: registered new device driver %s\n",
                        usbcore_name, new_udriver->name);
-       else
+               /*
+                * Check whether any device could be better served with
+                * this new driver
+                */
+               bus_for_each_dev(&usb_bus_type, NULL, new_udriver,
+                                __usb_bus_reprobe_drivers);
+       } else {
                printk(KERN_ERR "%s: error %d registering device "
                        "       driver %s\n",
                        usbcore_name, retval, new_udriver->name);
+       }
 
        return retval;
 }
index b6f2d4b..2b2f1ab 100644 (file)
@@ -205,8 +205,9 @@ static int __check_usb_generic(struct device_driver *drv, void *data)
        udrv = to_usb_device_driver(drv);
        if (udrv == &usb_generic_driver)
                return 0;
-
-       return usb_device_match_id(udev, udrv->id_table) != NULL;
+       if (usb_device_match_id(udev, udrv->id_table) != NULL)
+               return 1;
+       return (udrv->match && udrv->match(udev));
 }
 
 static bool usb_generic_driver_match(struct usb_device *udev)
index 4dc443a..ec0d6c5 100644 (file)
@@ -315,11 +315,14 @@ EXPORT_SYMBOL_GPL(usb_hcd_pci_probe);
 void usb_hcd_pci_remove(struct pci_dev *dev)
 {
        struct usb_hcd          *hcd;
+       int                     hcd_driver_flags;
 
        hcd = pci_get_drvdata(dev);
        if (!hcd)
                return;
 
+       hcd_driver_flags = hcd->driver->flags;
+
        if (pci_dev_run_wake(dev))
                pm_runtime_get_noresume(&dev->dev);
 
@@ -347,7 +350,7 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
                up_read(&companions_rwsem);
        }
        usb_put_hcd(hcd);
-       if ((hcd->driver->flags & HCD_MASK) < HCD_USB3)
+       if ((hcd_driver_flags & HCD_MASK) < HCD_USB3)
                pci_free_irq_vectors(dev);
        pci_disable_device(dev);
 }
index 052d5ac..5b768b8 100644 (file)
@@ -727,7 +727,7 @@ static void hub_irq(struct urb *urb)
                if ((++hub->nerrors < 10) || hub->error)
                        goto resubmit;
                hub->error = status;
-               /* FALL THROUGH */
+               fallthrough;
 
        /* let hub_wq handle things */
        case 0:                 /* we got data:  port status changed */
index 6197938..ae1de9c 100644 (file)
@@ -1205,6 +1205,34 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf,
        }
 }
 
+/*
+ * usb_disable_device_endpoints -- Disable all endpoints for a device
+ * @dev: the device whose endpoints are being disabled
+ * @skip_ep0: 0 to disable endpoint 0, 1 to skip it.
+ */
+static void usb_disable_device_endpoints(struct usb_device *dev, int skip_ep0)
+{
+       struct usb_hcd *hcd = bus_to_hcd(dev->bus);
+       int i;
+
+       if (hcd->driver->check_bandwidth) {
+               /* First pass: Cancel URBs, leave endpoint pointers intact. */
+               for (i = skip_ep0; i < 16; ++i) {
+                       usb_disable_endpoint(dev, i, false);
+                       usb_disable_endpoint(dev, i + USB_DIR_IN, false);
+               }
+               /* Remove endpoints from the host controller internal state */
+               mutex_lock(hcd->bandwidth_mutex);
+               usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+               mutex_unlock(hcd->bandwidth_mutex);
+       }
+       /* Second pass: remove endpoint pointers */
+       for (i = skip_ep0; i < 16; ++i) {
+               usb_disable_endpoint(dev, i, true);
+               usb_disable_endpoint(dev, i + USB_DIR_IN, true);
+       }
+}
+
 /**
  * usb_disable_device - Disable all the endpoints for a USB device
  * @dev: the device whose endpoints are being disabled
@@ -1218,7 +1246,6 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf,
 void usb_disable_device(struct usb_device *dev, int skip_ep0)
 {
        int i;
-       struct usb_hcd *hcd = bus_to_hcd(dev->bus);
 
        /* getting rid of interfaces will disconnect
         * any drivers bound to them (a key side effect)
@@ -1264,22 +1291,8 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
 
        dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
                skip_ep0 ? "non-ep0" : "all");
-       if (hcd->driver->check_bandwidth) {
-               /* First pass: Cancel URBs, leave endpoint pointers intact. */
-               for (i = skip_ep0; i < 16; ++i) {
-                       usb_disable_endpoint(dev, i, false);
-                       usb_disable_endpoint(dev, i + USB_DIR_IN, false);
-               }
-               /* Remove endpoints from the host controller internal state */
-               mutex_lock(hcd->bandwidth_mutex);
-               usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
-               mutex_unlock(hcd->bandwidth_mutex);
-               /* Second pass: remove endpoint pointers */
-       }
-       for (i = skip_ep0; i < 16; ++i) {
-               usb_disable_endpoint(dev, i, true);
-               usb_disable_endpoint(dev, i + USB_DIR_IN, true);
-       }
+
+       usb_disable_device_endpoints(dev, skip_ep0);
 }
 
 /**
@@ -1522,6 +1535,9 @@ EXPORT_SYMBOL_GPL(usb_set_interface);
  * The caller must own the device lock.
  *
  * Return: Zero on success, else a negative error code.
+ *
+ * If this routine fails the device will probably be in an unusable state
+ * with endpoints disabled, and interfaces only partially enabled.
  */
 int usb_reset_configuration(struct usb_device *dev)
 {
@@ -1537,10 +1553,7 @@ int usb_reset_configuration(struct usb_device *dev)
         * calls during probe() are fine
         */
 
-       for (i = 1; i < 16; ++i) {
-               usb_disable_endpoint(dev, i, true);
-               usb_disable_endpoint(dev, i + USB_DIR_IN, true);
-       }
+       usb_disable_device_endpoints(dev, 1); /* skip ep0*/
 
        config = dev->actconfig;
        retval = 0;
@@ -1553,34 +1566,10 @@ int usb_reset_configuration(struct usb_device *dev)
                mutex_unlock(hcd->bandwidth_mutex);
                return -ENOMEM;
        }
-       /* Make sure we have enough bandwidth for each alternate setting 0 */
-       for (i = 0; i < config->desc.bNumInterfaces; i++) {
-               struct usb_interface *intf = config->interface[i];
-               struct usb_host_interface *alt;
 
-               alt = usb_altnum_to_altsetting(intf, 0);
-               if (!alt)
-                       alt = &intf->altsetting[0];
-               if (alt != intf->cur_altsetting)
-                       retval = usb_hcd_alloc_bandwidth(dev, NULL,
-                                       intf->cur_altsetting, alt);
-               if (retval < 0)
-                       break;
-       }
-       /* If not, reinstate the old alternate settings */
+       /* xHCI adds all endpoints in usb_hcd_alloc_bandwidth */
+       retval = usb_hcd_alloc_bandwidth(dev, config, NULL, NULL);
        if (retval < 0) {
-reset_old_alts:
-               for (i--; i >= 0; i--) {
-                       struct usb_interface *intf = config->interface[i];
-                       struct usb_host_interface *alt;
-
-                       alt = usb_altnum_to_altsetting(intf, 0);
-                       if (!alt)
-                               alt = &intf->altsetting[0];
-                       if (alt != intf->cur_altsetting)
-                               usb_hcd_alloc_bandwidth(dev, NULL,
-                                               alt, intf->cur_altsetting);
-               }
                usb_enable_lpm(dev);
                mutex_unlock(hcd->bandwidth_mutex);
                return retval;
@@ -1589,8 +1578,12 @@ reset_old_alts:
                        USB_REQ_SET_CONFIGURATION, 0,
                        config->desc.bConfigurationValue, 0,
                        NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (retval < 0)
-               goto reset_old_alts;
+       if (retval < 0) {
+               usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+               usb_enable_lpm(dev);
+               mutex_unlock(hcd->bandwidth_mutex);
+               return retval;
+       }
        mutex_unlock(hcd->bandwidth_mutex);
 
        /* re-init hc/hcd interface/endpoint state */
index 7c1198f..10574fa 100644 (file)
@@ -370,6 +370,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x0926, 0x0202), .driver_info =
                        USB_QUIRK_ENDPOINT_IGNORE },
 
+       /* Sound Devices MixPre-D */
+       { USB_DEVICE(0x0926, 0x0208), .driver_info =
+                       USB_QUIRK_ENDPOINT_IGNORE },
+
        /* Keytouch QWERTY Panel keyboard */
        { USB_DEVICE(0x0926, 0x3333), .driver_info =
                        USB_QUIRK_CONFIG_INTF_STRINGS },
@@ -393,6 +397,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Generic RTL8153 based ethernet adapters */
        { USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM },
 
+       /* SONiX USB DEVICE Touchpad */
+       { USB_DEVICE(0x0c45, 0x7056), .driver_info =
+                       USB_QUIRK_IGNORE_REMOTE_WAKEUP },
+
        /* Action Semiconductor flash disk */
        { USB_DEVICE(0x10d6, 0x2200), .driver_info =
                        USB_QUIRK_STRING_FETCH_255 },
@@ -465,6 +473,8 @@ static const struct usb_device_id usb_quirk_list[] = {
 
        { USB_DEVICE(0x2386, 0x3119), .driver_info = USB_QUIRK_NO_LPM },
 
+       { USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
+
        /* DJI CineSSD */
        { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
 
@@ -509,6 +519,7 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = {
  */
 static const struct usb_device_id usb_endpoint_ignore[] = {
        { USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 },
+       { USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0208, 1), .driver_info = 0x85 },
        { }
 };
 
index a2ca38e..8d13419 100644 (file)
@@ -889,7 +889,11 @@ read_descriptors(struct file *filp, struct kobject *kobj,
        size_t srclen, n;
        int cfgno;
        void *src;
+       int retval;
 
+       retval = usb_lock_device_interruptible(udev);
+       if (retval < 0)
+               return -EINTR;
        /* The binary attribute begins with the device descriptor.
         * Following that are the raw descriptor entries for all the
         * configurations (config plus subsidiary descriptors).
@@ -914,6 +918,7 @@ read_descriptors(struct file *filp, struct kobject *kobj,
                        off -= srclen;
                }
        }
+       usb_unlock_device(udev);
        return count - nleft;
 }
 
index 422aea2..2eb34c8 100644 (file)
@@ -646,9 +646,8 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
                        if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
                                break;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
-               /* FALLTHROUGH */
        default:
                break;
        }
@@ -1411,7 +1410,7 @@ static void dwc3_check_params(struct dwc3 *dwc)
        default:
                dev_err(dev, "invalid maximum_speed parameter %d\n",
                        dwc->maximum_speed);
-               /* fall through */
+               fallthrough;
        case USB_SPEED_UNKNOWN:
                /* default to superspeed */
                dwc->maximum_speed = USB_SPEED_SUPER;
index 88b75b5..1f7f4d8 100644 (file)
@@ -737,13 +737,13 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
                goto err_disable_clks;
        }
 
-       ret = reset_control_deassert(priv->reset);
+       ret = reset_control_reset(priv->reset);
        if (ret)
-               goto err_assert_reset;
+               goto err_disable_clks;
 
        ret = dwc3_meson_g12a_get_phys(priv);
        if (ret)
-               goto err_assert_reset;
+               goto err_disable_clks;
 
        ret = priv->drvdata->setup_regmaps(priv, base);
        if (ret)
@@ -752,7 +752,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
        if (priv->vbus) {
                ret = regulator_enable(priv->vbus);
                if (ret)
-                       goto err_assert_reset;
+                       goto err_disable_clks;
        }
 
        /* Get dr_mode */
@@ -765,13 +765,13 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
 
        ret = priv->drvdata->usb_init(priv);
        if (ret)
-               goto err_assert_reset;
+               goto err_disable_clks;
 
        /* Init PHYs */
        for (i = 0 ; i < PHY_COUNT ; ++i) {
                ret = phy_init(priv->phys[i]);
                if (ret)
-                       goto err_assert_reset;
+                       goto err_disable_clks;
        }
 
        /* Set PHY Power */
@@ -809,9 +809,6 @@ err_phys_exit:
        for (i = 0 ; i < PHY_COUNT ; ++i)
                phy_exit(priv->phys[i]);
 
-err_assert_reset:
-       reset_control_assert(priv->reset);
-
 err_disable_clks:
        clk_bulk_disable_unprepare(priv->drvdata->num_clks,
                                   priv->drvdata->clks);
index e44bfc3..c2a0f64 100644 (file)
@@ -1054,27 +1054,25 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
  * dwc3_prepare_one_trb - setup one TRB from one request
  * @dep: endpoint for which this request is prepared
  * @req: dwc3_request pointer
+ * @trb_length: buffer size of the TRB
  * @chain: should this TRB be chained to the next?
  * @node: only for isochronous endpoints. First TRB needs different type.
  */
 static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
-               struct dwc3_request *req, unsigned chain, unsigned node)
+               struct dwc3_request *req, unsigned int trb_length,
+               unsigned chain, unsigned node)
 {
        struct dwc3_trb         *trb;
-       unsigned int            length;
        dma_addr_t              dma;
        unsigned                stream_id = req->request.stream_id;
        unsigned                short_not_ok = req->request.short_not_ok;
        unsigned                no_interrupt = req->request.no_interrupt;
        unsigned                is_last = req->request.is_last;
 
-       if (req->request.num_sgs > 0) {
-               length = sg_dma_len(req->start_sg);
+       if (req->request.num_sgs > 0)
                dma = sg_dma_address(req->start_sg);
-       } else {
-               length = req->request.length;
+       else
                dma = req->request.dma;
-       }
 
        trb = &dep->trb_pool[dep->trb_enqueue];
 
@@ -1086,7 +1084,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 
        req->num_trbs++;
 
-       __dwc3_prepare_one_trb(dep, trb, dma, length, chain, node,
+       __dwc3_prepare_one_trb(dep, trb, dma, trb_length, chain, node,
                        stream_id, short_not_ok, no_interrupt, is_last);
 }
 
@@ -1096,16 +1094,27 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
        struct scatterlist *sg = req->start_sg;
        struct scatterlist *s;
        int             i;
-
+       unsigned int length = req->request.length;
        unsigned int remaining = req->request.num_mapped_sgs
                - req->num_queued_sgs;
 
+       /*
+        * If we resume preparing the request, then get the remaining length of
+        * the request and resume where we left off.
+        */
+       for_each_sg(req->request.sg, s, req->num_queued_sgs, i)
+               length -= sg_dma_len(s);
+
        for_each_sg(sg, s, remaining, i) {
-               unsigned int length = req->request.length;
                unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
                unsigned int rem = length % maxp;
+               unsigned int trb_length;
                unsigned chain = true;
 
+               trb_length = min_t(unsigned int, length, sg_dma_len(s));
+
+               length -= trb_length;
+
                /*
                 * IOMMU driver is coalescing the list of sgs which shares a
                 * page boundary into one and giving it to USB driver. With
@@ -1113,7 +1122,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
                 * sgs passed. So mark the chain bit to false if it isthe last
                 * mapped sg.
                 */
-               if (i == remaining - 1)
+               if ((i == remaining - 1) || !length)
                        chain = false;
 
                if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) {
@@ -1123,7 +1132,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
                        req->needs_extra_trb = true;
 
                        /* prepare normal TRB */
-                       dwc3_prepare_one_trb(dep, req, true, i);
+                       dwc3_prepare_one_trb(dep, req, trb_length, true, i);
 
                        /* Now prepare one extra TRB to align transfer size */
                        trb = &dep->trb_pool[dep->trb_enqueue];
@@ -1134,8 +1143,39 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
                                        req->request.short_not_ok,
                                        req->request.no_interrupt,
                                        req->request.is_last);
+               } else if (req->request.zero && req->request.length &&
+                          !usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+                          !rem && !chain) {
+                       struct dwc3     *dwc = dep->dwc;
+                       struct dwc3_trb *trb;
+
+                       req->needs_extra_trb = true;
+
+                       /* Prepare normal TRB */
+                       dwc3_prepare_one_trb(dep, req, trb_length, true, i);
+
+                       /* Prepare one extra TRB to handle ZLP */
+                       trb = &dep->trb_pool[dep->trb_enqueue];
+                       req->num_trbs++;
+                       __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
+                                              !req->direction, 1,
+                                              req->request.stream_id,
+                                              req->request.short_not_ok,
+                                              req->request.no_interrupt,
+                                              req->request.is_last);
+
+                       /* Prepare one more TRB to handle MPS alignment */
+                       if (!req->direction) {
+                               trb = &dep->trb_pool[dep->trb_enqueue];
+                               req->num_trbs++;
+                               __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp,
+                                                      false, 1, req->request.stream_id,
+                                                      req->request.short_not_ok,
+                                                      req->request.no_interrupt,
+                                                      req->request.is_last);
+                       }
                } else {
-                       dwc3_prepare_one_trb(dep, req, chain, i);
+                       dwc3_prepare_one_trb(dep, req, trb_length, chain, i);
                }
 
                /*
@@ -1150,6 +1190,16 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
 
                req->num_queued_sgs++;
 
+               /*
+                * The number of pending SG entries may not correspond to the
+                * number of mapped SG entries. If all the data are queued, then
+                * don't include unused SG entries.
+                */
+               if (length == 0) {
+                       req->num_pending_sgs -= req->request.num_mapped_sgs - req->num_queued_sgs;
+                       break;
+               }
+
                if (!dwc3_calc_trbs_left(dep))
                        break;
        }
@@ -1169,7 +1219,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
                req->needs_extra_trb = true;
 
                /* prepare normal TRB */
-               dwc3_prepare_one_trb(dep, req, true, 0);
+               dwc3_prepare_one_trb(dep, req, length, true, 0);
 
                /* Now prepare one extra TRB to align transfer size */
                trb = &dep->trb_pool[dep->trb_enqueue];
@@ -1180,6 +1230,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
                                req->request.no_interrupt,
                                req->request.is_last);
        } else if (req->request.zero && req->request.length &&
+                  !usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
                   (IS_ALIGNED(req->request.length, maxp))) {
                struct dwc3     *dwc = dep->dwc;
                struct dwc3_trb *trb;
@@ -1187,18 +1238,29 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
                req->needs_extra_trb = true;
 
                /* prepare normal TRB */
-               dwc3_prepare_one_trb(dep, req, true, 0);
+               dwc3_prepare_one_trb(dep, req, length, true, 0);
 
-               /* Now prepare one extra TRB to handle ZLP */
+               /* Prepare one extra TRB to handle ZLP */
                trb = &dep->trb_pool[dep->trb_enqueue];
                req->num_trbs++;
                __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
-                               false, 1, req->request.stream_id,
+                               !req->direction, 1, req->request.stream_id,
                                req->request.short_not_ok,
                                req->request.no_interrupt,
                                req->request.is_last);
+
+               /* Prepare one more TRB to handle MPS alignment for OUT */
+               if (!req->direction) {
+                       trb = &dep->trb_pool[dep->trb_enqueue];
+                       req->num_trbs++;
+                       __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp,
+                                              false, 1, req->request.stream_id,
+                                              req->request.short_not_ok,
+                                              req->request.no_interrupt,
+                                              req->request.is_last);
+               }
        } else {
-               dwc3_prepare_one_trb(dep, req, false, 0);
+               dwc3_prepare_one_trb(dep, req, length, false, 0);
        }
 }
 
@@ -2671,8 +2733,17 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
                                status);
 
        if (req->needs_extra_trb) {
+               unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
+
                ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
                                status);
+
+               /* Reclaim MPS padding TRB for ZLP */
+               if (!req->direction && req->request.zero && req->request.length &&
+                   !usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+                   (IS_ALIGNED(req->request.length, maxp)))
+                       ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, status);
+
                req->needs_extra_trb = false;
        }
 
index 331c951..950c943 100644 (file)
@@ -2039,7 +2039,6 @@ static int do_scsi_command(struct fsg_common *common)
        case RELEASE:
        case RESERVE:
        case SEND_DIAGNOSTIC:
-               fallthrough;
 
        default:
 unknown_cmnd:
index 1d90008..1f63875 100644 (file)
@@ -1181,9 +1181,11 @@ static int ncm_unwrap_ntb(struct gether *port,
        int             ndp_index;
        unsigned        dg_len, dg_len2;
        unsigned        ndp_len;
+       unsigned        block_len;
        struct sk_buff  *skb2;
        int             ret = -EINVAL;
-       unsigned        max_size = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
+       unsigned        ntb_max = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
+       unsigned        frame_max = le16_to_cpu(ecm_desc.wMaxSegmentSize);
        const struct ndp_parser_opts *opts = ncm->parser_opts;
        unsigned        crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
        int             dgram_counter;
@@ -1205,8 +1207,9 @@ static int ncm_unwrap_ntb(struct gether *port,
        }
        tmp++; /* skip wSequence */
 
+       block_len = get_ncm(&tmp, opts->block_length);
        /* (d)wBlockLength */
-       if (get_ncm(&tmp, opts->block_length) > max_size) {
+       if (block_len > ntb_max) {
                INFO(port->func.config->cdev, "OUT size exceeded\n");
                goto err;
        }
@@ -1215,15 +1218,23 @@ static int ncm_unwrap_ntb(struct gether *port,
 
        /* Run through all the NDP's in the NTB */
        do {
-               /* NCM 3.2 */
-               if (((ndp_index % 4) != 0) &&
-                               (ndp_index < opts->nth_size)) {
+               /*
+                * NCM 3.2
+                * dwNdpIndex
+                */
+               if (((ndp_index % 4) != 0) ||
+                               (ndp_index < opts->nth_size) ||
+                               (ndp_index > (block_len -
+                                             opts->ndp_size))) {
                        INFO(port->func.config->cdev, "Bad index: %#X\n",
                             ndp_index);
                        goto err;
                }
 
-               /* walk through NDP */
+               /*
+                * walk through NDP
+                * dwSignature
+                */
                tmp = (void *)(skb->data + ndp_index);
                if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
                        INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
@@ -1234,14 +1245,15 @@ static int ncm_unwrap_ntb(struct gether *port,
                ndp_len = get_unaligned_le16(tmp++);
                /*
                 * NCM 3.3.1
+                * wLength
                 * entry is 2 items
                 * item size is 16/32 bits, opts->dgram_item_len * 2 bytes
                 * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry
                 * Each entry is a dgram index and a dgram length.
                 */
                if ((ndp_len < opts->ndp_size
-                               + 2 * 2 * (opts->dgram_item_len * 2))
-                               || (ndp_len % opts->ndplen_align != 0)) {
+                               + 2 * 2 * (opts->dgram_item_len * 2)) ||
+                               (ndp_len % opts->ndplen_align != 0)) {
                        INFO(port->func.config->cdev, "Bad NDP length: %#X\n",
                             ndp_len);
                        goto err;
@@ -1258,8 +1270,21 @@ static int ncm_unwrap_ntb(struct gether *port,
 
                do {
                        index = index2;
+                       /* wDatagramIndex[0] */
+                       if ((index < opts->nth_size) ||
+                                       (index > block_len - opts->dpe_size)) {
+                               INFO(port->func.config->cdev,
+                                    "Bad index: %#X\n", index);
+                               goto err;
+                       }
+
                        dg_len = dg_len2;
-                       if (dg_len < 14 + crc_len) { /* ethernet hdr + crc */
+                       /*
+                        * wDatagramLength[0]
+                        * ethernet hdr + crc or larger than max frame size
+                        */
+                       if ((dg_len < 14 + crc_len) ||
+                                       (dg_len > frame_max)) {
                                INFO(port->func.config->cdev,
                                     "Bad dgram length: %#X\n", dg_len);
                                goto err;
@@ -1283,6 +1308,13 @@ static int ncm_unwrap_ntb(struct gether *port,
                        index2 = get_ncm(&tmp, opts->dgram_item_len);
                        dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
 
+                       /* wDatagramIndex[1] */
+                       if (index2 > block_len - opts->dpe_size) {
+                               INFO(port->func.config->cdev,
+                                    "Bad index: %#X\n", index2);
+                               goto err;
+                       }
+
                        /*
                         * Copy the data into a new skb.
                         * This ensures the truesize is correct
@@ -1299,7 +1331,6 @@ static int ncm_unwrap_ntb(struct gether *port,
                        ndp_len -= 2 * (opts->dgram_item_len * 2);
 
                        dgram_counter++;
-
                        if (index2 == 0 || dg_len2 == 0)
                                break;
                } while (ndp_len > 2 * (opts->dgram_item_len * 2));
index d94b814..184165e 100644 (file)
@@ -753,12 +753,13 @@ static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
                goto err_sts;
 
        return 0;
+
 err_sts:
-       usb_ep_free_request(fu->ep_status, stream->req_status);
-       stream->req_status = NULL;
-err_out:
        usb_ep_free_request(fu->ep_out, stream->req_out);
        stream->req_out = NULL;
+err_out:
+       usb_ep_free_request(fu->ep_in, stream->req_in);
+       stream->req_in = NULL;
 out:
        return -ENOMEM;
 }
index eaa13fd..e313c3b 100644 (file)
@@ -14,6 +14,7 @@
 #define __U_F_H__
 
 #include <linux/usb/gadget.h>
+#include <linux/overflow.h>
 
 /* Variable Length Array Macros **********************************************/
 #define vla_group(groupname) size_t groupname##__next = 0
 
 #define vla_item(groupname, type, name, n) \
        size_t groupname##_##name##__offset = ({                               \
-               size_t align_mask = __alignof__(type) - 1;                     \
-               size_t offset = (groupname##__next + align_mask) & ~align_mask;\
-               size_t size = (n) * sizeof(type);                              \
-               groupname##__next = offset + size;                             \
+               size_t offset = 0;                                             \
+               if (groupname##__next != SIZE_MAX) {                           \
+                       size_t align_mask = __alignof__(type) - 1;             \
+                       size_t size = array_size(n, sizeof(type));             \
+                       offset = (groupname##__next + align_mask) &            \
+                                 ~align_mask;                                 \
+                       if (check_add_overflow(offset, size,                   \
+                                              &groupname##__next)) {          \
+                               groupname##__next = SIZE_MAX;                  \
+                               offset = 0;                                    \
+                       }                                                      \
+               }                                                              \
                offset;                                                        \
        })
 
 #define vla_item_with_sz(groupname, type, name, n) \
-       size_t groupname##_##name##__sz = (n) * sizeof(type);                  \
-       size_t groupname##_##name##__offset = ({                               \
-               size_t align_mask = __alignof__(type) - 1;                     \
-               size_t offset = (groupname##__next + align_mask) & ~align_mask;\
-               size_t size = groupname##_##name##__sz;                        \
-               groupname##__next = offset + size;                             \
-               offset;                                                        \
+       size_t groupname##_##name##__sz = array_size(n, sizeof(type));          \
+       size_t groupname##_##name##__offset = ({                                \
+               size_t offset = 0;                                              \
+               if (groupname##__next != SIZE_MAX) {                            \
+                       size_t align_mask = __alignof__(type) - 1;              \
+                       offset = (groupname##__next + align_mask) &             \
+                                 ~align_mask;                                  \
+                       if (check_add_overflow(offset, groupname##_##name##__sz,\
+                                                       &groupname##__next)) {  \
+                               groupname##__next = SIZE_MAX;                   \
+                               offset = 0;                                     \
+                       }                                                       \
+               }                                                               \
+               offset;                                                         \
        })
 
 #define vla_ptr(ptr, groupname, name) \
index fa67930..a6426dd 100644 (file)
@@ -328,7 +328,7 @@ static int usba_config_fifo_table(struct usba_udc *udc)
        switch (fifo_mode) {
        default:
                fifo_mode = 0;
-               /* fall through */
+               fallthrough;
        case 0:
                udc->fifo_cfg = NULL;
                n = 0;
index b2638e8..a6f7b25 100644 (file)
@@ -250,7 +250,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
                break;
        case FSL_USB2_PHY_UTMI_WIDE:
                portctrl |= PORTSCX_PTW_16BIT;
-               /* fall through */
+               fallthrough;
        case FSL_USB2_PHY_UTMI:
        case FSL_USB2_PHY_UTMI_DUAL:
                if (udc->pdata->have_sysif_regs) {
index cfafdd9..10324a7 100644 (file)
@@ -2340,12 +2340,12 @@ static int pxa25x_udc_probe(struct platform_device *pdev)
        case PXA250_A0:
        case PXA250_A1:
                /* A0/A1 "not released"; ep 13, 15 unusable */
-               /* fall through */
+               fallthrough;
        case PXA250_B2: case PXA210_B2:
        case PXA250_B1: case PXA210_B1:
        case PXA250_B0: case PXA210_B0:
                /* OUT-DMA is broken ... */
-               /* fall through */
+               fallthrough;
        case PXA250_C0: case PXA210_C0:
                break;
 #elif  defined(CONFIG_ARCH_IXP4XX)
index 6257be4..3575b72 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
+#include <linux/usb/otg.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <linux/debugfs.h>
index ce0eaf7..087402a 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 /*-------------------------------------------------------------------------*/
-#include <linux/usb/otg.h>
 
 #define        PORT_WAKE_BITS  (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
 
index a87c0b2..3055d9a 100644 (file)
@@ -1019,7 +1019,7 @@ static int isp116x_hub_control(struct usb_hcd *hcd,
                        spin_lock_irqsave(&isp116x->lock, flags);
                        isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);
                        spin_unlock_irqrestore(&isp116x->lock, flags);
-                       /* fall through */
+                       fallthrough;
                case C_HUB_LOCAL_POWER:
                        DBG("C_HUB_LOCAL_POWER\n");
                        break;
@@ -1421,10 +1421,10 @@ static int isp116x_bus_suspend(struct usb_hcd *hcd)
                isp116x_write_reg32(isp116x, HCCONTROL,
                                    (val & ~HCCONTROL_HCFS) |
                                    HCCONTROL_USB_RESET);
-               /* fall through */
+               fallthrough;
        case HCCONTROL_USB_RESET:
                ret = -EBUSY;
-               /* fall through */
+               fallthrough;
        default:                /* HCCONTROL_USB_SUSPEND */
                spin_unlock_irqrestore(&isp116x->lock, flags);
                break;
index bd40e59..5f5e8a6 100644 (file)
@@ -171,9 +171,8 @@ static int exynos_ohci_probe(struct platform_device *pdev)
        hcd->rsrc_len = resource_size(res);
 
        irq = platform_get_irq(pdev, 0);
-       if (!irq) {
-               dev_err(&pdev->dev, "Failed to get IRQ\n");
-               err = -ENODEV;
+       if (irq < 0) {
+               err = irq;
                goto fail_io;
        }
 
index b8961c0..8c1bbac 100644 (file)
@@ -957,7 +957,8 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev)
                        ehci_bios_handoff(pdev, op_reg_base, cap, offset);
                        break;
                case 0: /* Illegal reserved cap, set cap=0 so we exit */
-                       cap = 0; /* fall through */
+                       cap = 0;
+                       fallthrough;
                default:
                        dev_warn(&pdev->dev,
                                 "EHCI: unrecognized capability %02x\n",
index fcc5ac5..ccb0156 100644 (file)
@@ -699,7 +699,7 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event)
        switch (comp_code) {
        case COMP_SUCCESS:
                remain_length = 0;
-       /* FALLTHROUGH */
+               fallthrough;
        case COMP_SHORT_PACKET:
                status = 0;
                break;
index 92e25a6..c88bffd 100644 (file)
@@ -274,7 +274,7 @@ static int xhci_slot_context_show(struct seq_file *s, void *unused)
 
 static int xhci_endpoint_context_show(struct seq_file *s, void *unused)
 {
-       int                     dci;
+       int                     ep_index;
        dma_addr_t              dma;
        struct xhci_hcd         *xhci;
        struct xhci_ep_ctx      *ep_ctx;
@@ -283,9 +283,9 @@ static int xhci_endpoint_context_show(struct seq_file *s, void *unused)
 
        xhci = hcd_to_xhci(bus_to_hcd(dev->udev->bus));
 
-       for (dci = 1; dci < 32; dci++) {
-               ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, dci);
-               dma = dev->out_ctx->dma + dci * CTX_SIZE(xhci->hcc_params);
+       for (ep_index = 0; ep_index < 31; ep_index++) {
+               ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
+               dma = dev->out_ctx->dma + (ep_index + 1) * CTX_SIZE(xhci->hcc_params);
                seq_printf(s, "%pad: %s\n", &dma,
                           xhci_decode_ep_context(le32_to_cpu(ep_ctx->ep_info),
                                                  le32_to_cpu(ep_ctx->ep_info2),
index c3554e3..c799ca5 100644 (file)
@@ -740,15 +740,6 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
 {
        u32 pls = status_reg & PORT_PLS_MASK;
 
-       /* resume state is a xHCI internal state.
-        * Do not report it to usb core, instead, pretend to be U3,
-        * thus usb core knows it's not ready for transfer
-        */
-       if (pls == XDEV_RESUME) {
-               *status |= USB_SS_PORT_LS_U3;
-               return;
-       }
-
        /* When the CAS bit is set then warm reset
         * should be performed on port
         */
@@ -771,6 +762,16 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
                pls |= USB_PORT_STAT_CONNECTION;
        } else {
                /*
+                * Resume state is an xHCI internal state.  Do not report it to
+                * usb core, instead, pretend to be U3, thus usb core knows
+                * it's not ready for transfer.
+                */
+               if (pls == XDEV_RESUME) {
+                       *status |= USB_SS_PORT_LS_U3;
+                       return;
+               }
+
+               /*
                 * If CAS bit isn't set but the Port is already at
                 * Compliance Mode, fake a connection so the USB core
                 * notices the Compliance state and resets the port.
@@ -1483,7 +1484,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        break;
                case USB_PORT_FEAT_C_SUSPEND:
                        bus_state->port_c_suspend &= ~(1 << wIndex);
-                       /* fall through */
+                       fallthrough;
                case USB_PORT_FEAT_C_RESET:
                case USB_PORT_FEAT_C_BH_PORT_RESET:
                case USB_PORT_FEAT_C_CONNECTION:
index 696fad5..fe405cd 100644 (file)
@@ -1311,7 +1311,7 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
                        interval = xhci_parse_microframe_interval(udev, ep);
                        break;
                }
-               /* Fall through - SS and HS isoc/int have same decoding */
+               fallthrough;    /* SS and HS isoc/int have same decoding */
 
        case USB_SPEED_SUPER_PLUS:
        case USB_SPEED_SUPER:
@@ -1331,7 +1331,7 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
                 * since it uses the same rules as low speed interrupt
                 * endpoints.
                 */
-               /* fall through */
+               fallthrough;
 
        case USB_SPEED_LOW:
                if (usb_endpoint_xfer_int(&ep->desc) ||
index 59b1965..f97ac9f 100644 (file)
 #define RENESAS_RETRY  10000
 #define RENESAS_DELAY  10
 
-#define ROM_VALID_01 0x2013
-#define ROM_VALID_02 0x2026
-
-static int renesas_verify_fw_version(struct pci_dev *pdev, u32 version)
-{
-       switch (version) {
-       case ROM_VALID_01:
-       case ROM_VALID_02:
-               return 0;
-       }
-       dev_err(&pdev->dev, "FW has invalid version :%d\n", version);
-       return -EINVAL;
-}
-
 static int renesas_fw_download_image(struct pci_dev *dev,
                                     const u32 *fw, size_t step, bool rom)
 {
@@ -202,10 +188,7 @@ static int renesas_check_rom_state(struct pci_dev *pdev)
 
        version &= RENESAS_FW_VERSION_FIELD;
        version = version >> RENESAS_FW_VERSION_OFFSET;
-
-       err = renesas_verify_fw_version(pdev, version);
-       if (err)
-               return err;
+       dev_dbg(&pdev->dev, "Found ROM version: %x\n", version);
 
        /*
         * Test if ROM is present and loaded, if so we can skip everything
index 2c255d0..a741a38 100644 (file)
@@ -2103,7 +2103,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                        break;
                xhci_dbg(xhci, "TRB error %u, halted endpoint index = %u\n",
                         trb_comp_code, ep_index);
-               /* else fall through */
+               fallthrough;
        case COMP_STALL_ERROR:
                /* Did we transfer part of the data (middle) phase? */
                if (trb_type == TRB_DATA || trb_type == TRB_NORMAL)
index 014d793..190923d 100644 (file)
@@ -1136,7 +1136,7 @@ static struct phy *tegra_xusb_get_phy(struct tegra_xusb *tegra, char *name,
        unsigned int i, phy_count = 0;
 
        for (i = 0; i < tegra->soc->num_types; i++) {
-               if (!strncmp(tegra->soc->phy_types[i].name, "usb2",
+               if (!strncmp(tegra->soc->phy_types[i].name, name,
                                                            strlen(name)))
                        return tegra->phys[phy_count+port];
 
@@ -1258,6 +1258,8 @@ static int tegra_xusb_init_usb_phy(struct tegra_xusb *tegra)
 
        INIT_WORK(&tegra->id_work, tegra_xhci_id_work);
        tegra->id_nb.notifier_call = tegra_xhci_id_notify;
+       tegra->otg_usb2_port = -EINVAL;
+       tegra->otg_usb3_port = -EINVAL;
 
        for (i = 0; i < tegra->num_usb_phys; i++) {
                struct phy *phy = tegra_xusb_get_phy(tegra, "usb2", i);
index 3c41b14..f4cedca 100644 (file)
@@ -3236,10 +3236,11 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
 
        wait_for_completion(cfg_cmd->completion);
 
-       ep->ep_state &= ~EP_SOFT_CLEAR_TOGGLE;
        xhci_free_command(xhci, cfg_cmd);
 cleanup:
        xhci_free_command(xhci, stop_cmd);
+       if (ep->ep_state & EP_SOFT_CLEAR_TOGGLE)
+               ep->ep_state &= ~EP_SOFT_CLEAR_TOGGLE;
 }
 
 static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
@@ -4618,7 +4619,7 @@ static unsigned long long xhci_calculate_intel_u1_timeout(
                        break;
                }
                /* Otherwise the calculation is the same as isoc eps */
-               /* fall through */
+               fallthrough;
        case USB_ENDPOINT_XFER_ISOC:
                timeout_ns = xhci_service_interval_to_ns(desc);
                timeout_ns = DIV_ROUND_UP_ULL(timeout_ns * 105, 100);
index 407fe75..f868613 100644 (file)
@@ -426,7 +426,7 @@ static int lvs_rh_probe(struct usb_interface *intf,
                        USB_DT_SS_HUB_SIZE, USB_CTRL_GET_TIMEOUT);
        if (ret < (USB_DT_HUB_NONVAR_SIZE + 2)) {
                dev_err(&hdev->dev, "wrong root hub descriptor read %d\n", ret);
-               return ret;
+               return ret < 0 ? ret : -EINVAL;
        }
 
        /* submit urb to poll interrupt endpoint */
index 6e7d34e..b2e0988 100644 (file)
@@ -492,7 +492,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
        prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE);
        dev_dbg(&dev->interface->dev, "%s - submit %c\n", __func__,
                dev->cntl_buffer[0]);
-       retval = usb_submit_urb(dev->cntl_urb, GFP_KERNEL);
+       retval = usb_submit_urb(dev->cntl_urb, GFP_ATOMIC);
        if (retval >= 0)
                timeout = schedule_timeout(YUREX_WRITE_TIMEOUT);
        finish_wait(&dev->waitq, &wait);
index c545b27..edb5b63 100644 (file)
@@ -975,7 +975,7 @@ static int cppi_channel_program(struct dma_channel *ch,
                musb_dbg(musb, "%cX DMA%d not allocated!",
                                cppi_ch->transmit ? 'T' : 'R',
                                cppi_ch->index);
-               /* FALLTHROUGH */
+               fallthrough;
        case MUSB_DMA_STATUS_FREE:
                break;
        }
index 5a56a03..849e0b7 100644 (file)
@@ -852,7 +852,7 @@ static void musb_handle_intr_suspend(struct musb *musb, u8 devctl)
        case OTG_STATE_B_IDLE:
                if (!musb->is_active)
                        break;
-               /* fall through */
+               fallthrough;
        case OTG_STATE_B_PERIPHERAL:
                musb_g_suspend(musb);
                musb->is_active = musb->g.b_hnp_enable;
@@ -972,9 +972,8 @@ static void musb_handle_intr_disconnect(struct musb *musb, u8 devctl)
        case OTG_STATE_A_PERIPHERAL:
                musb_hnp_stop(musb);
                musb_root_disconnect(musb);
-               /* FALLTHROUGH */
+               fallthrough;
        case OTG_STATE_B_WAIT_ACON:
-               /* FALLTHROUGH */
        case OTG_STATE_B_PERIPHERAL:
        case OTG_STATE_B_IDLE:
                musb_g_disconnect(musb);
@@ -1009,7 +1008,7 @@ static void musb_handle_intr_reset(struct musb *musb)
                switch (musb->xceiv->otg->state) {
                case OTG_STATE_A_SUSPEND:
                        musb_g_reset(musb);
-                       /* FALLTHROUGH */
+                       fallthrough;
                case OTG_STATE_A_WAIT_BCON:     /* OPT TD.4.7-900ms */
                        /* never use invalid T(a_wait_bcon) */
                        musb_dbg(musb, "HNP: in %s, %d msec timeout",
@@ -1030,7 +1029,7 @@ static void musb_handle_intr_reset(struct musb *musb)
                        break;
                case OTG_STATE_B_IDLE:
                        musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
-                       /* FALLTHROUGH */
+                       fallthrough;
                case OTG_STATE_B_PERIPHERAL:
                        musb_g_reset(musb);
                        break;
@@ -1471,7 +1470,7 @@ static int ep_config_from_table(struct musb *musb)
        switch (fifo_mode) {
        default:
                fifo_mode = 0;
-               /* FALLTHROUGH */
+               fallthrough;
        case 0:
                cfg = mode_0_cfg;
                n = ARRAY_SIZE(mode_0_cfg);
@@ -2018,7 +2017,7 @@ static void musb_pm_runtime_check_session(struct musb *musb)
                        musb->quirk_retries--;
                        return;
                }
-               /* fall through */
+               fallthrough;
        case MUSB_QUIRK_A_DISCONNECT_19:
                if (musb->quirk_retries && !musb->flush_irq_work) {
                        musb_dbg(musb,
index 19556c1..30085b2 100644 (file)
@@ -232,7 +232,7 @@ static int dsps_check_status(struct musb *musb, void *unused)
                        dsps_mod_timer_optional(glue);
                        break;
                }
-               /* fall through */
+               fallthrough;
 
        case OTG_STATE_A_WAIT_BCON:
                /* keep VBUS on for host-only mode */
@@ -242,7 +242,7 @@ static int dsps_check_status(struct musb *musb, void *unused)
                }
                musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
                skip_session = 1;
-               /* fall through */
+               fallthrough;
 
        case OTG_STATE_A_IDLE:
        case OTG_STATE_B_IDLE:
@@ -793,7 +793,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
        case USB_SPEED_SUPER:
                dev_warn(dev, "ignore incorrect maximum_speed "
                                "(super-speed) setting in dts");
-               /* fall through */
+               fallthrough;
        default:
                config->maximum_speed = USB_SPEED_HIGH;
        }
index 0ae3e0b..44d3cb0 100644 (file)
@@ -735,7 +735,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
                        musb_writeb(mbase, MUSB_TESTMODE,
                                        musb->test_mode_nr);
                }
-               /* FALLTHROUGH */
+               fallthrough;
 
        case MUSB_EP0_STAGE_STATUSOUT:
                /* end of sequence #1: write to host (TX state) */
@@ -767,7 +767,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
                 */
                retval = IRQ_HANDLED;
                musb->ep0_state = MUSB_EP0_STAGE_SETUP;
-               /* FALLTHROUGH */
+               fallthrough;
 
        case MUSB_EP0_STAGE_SETUP:
 setup:
index 8b7d22a..30c5e7d 100644 (file)
@@ -360,7 +360,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
                                qh = first_qh(head);
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
 
                case USB_ENDPOINT_XFER_ISOC:
                case USB_ENDPOINT_XFER_INT:
@@ -1019,7 +1019,7 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
                        musb->ep0_stage = MUSB_EP0_OUT;
                        more = true;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case MUSB_EP0_OUT:
                fifo_count = min_t(size_t, qh->maxpacket,
                                   urb->transfer_buffer_length -
@@ -2222,7 +2222,7 @@ static int musb_urb_enqueue(
                        interval = max_t(u8, epd->bInterval, 1);
                        break;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case USB_ENDPOINT_XFER_ISOC:
                /* ISO always uses logarithmic encoding */
                interval = min_t(u8, epd->bInterval, 16);
index cb7ae29..cafc695 100644 (file)
@@ -211,7 +211,7 @@ void musb_root_disconnect(struct musb *musb)
                        musb->g.is_a_peripheral = 1;
                        break;
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case OTG_STATE_A_HOST:
                musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
                musb->is_active = 0;
index d62c78b..4232f1c 100644 (file)
@@ -104,7 +104,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
                        if (error)
                                break;
                        musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
-                       /* Fall through */
+                       fallthrough;
                case OTG_STATE_A_WAIT_VRISE:
                case OTG_STATE_A_WAIT_BCON:
                case OTG_STATE_A_HOST:
index 99890d1..c26683a 100644 (file)
@@ -464,7 +464,7 @@ static void musb_do_idle(struct timer_list *t)
                        dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n",
                                        usb_otg_state_string(musb->xceiv->otg->state));
                }
-               /* FALLTHROUGH */
+               fallthrough;
        case OTG_STATE_A_IDLE:
                tusb_musb_set_vbus(musb, 0);
        default:
index d4ee3cb..f6d3731 100644 (file)
@@ -176,6 +176,7 @@ static int ingenic_usb_phy_init(struct usb_phy *phy)
 
        /* Wait for PHY to reset */
        usleep_range(30, 300);
+       reg = readl(priv->base + REG_USBPCR_OFFSET);
        writel(reg & ~USBPCR_POR, priv->base + REG_USBPCR_OFFSET);
        usleep_range(300, 1000);
 
index 871cdcc..9823bb4 100644 (file)
@@ -713,6 +713,7 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(XSENS_VID, XSENS_AWINDA_STATION_PID) },
        { USB_DEVICE(XSENS_VID, XSENS_CONVERTER_PID) },
        { USB_DEVICE(XSENS_VID, XSENS_MTDEVBOARD_PID) },
+       { USB_DEVICE(XSENS_VID, XSENS_MTIUSBCONVERTER_PID) },
        { USB_DEVICE(XSENS_VID, XSENS_MTW_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_OMNI1509) },
        { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
index e837352..b5ca17a 100644 (file)
 #define XSENS_AWINDA_DONGLE_PID 0x0102
 #define XSENS_MTW_PID          0x0200  /* Xsens MTw */
 #define XSENS_MTDEVBOARD_PID   0x0300  /* Motion Tracker Development Board */
+#define XSENS_MTIUSBCONVERTER_PID      0x0301  /* MTi USB converter */
 #define XSENS_CONVERTER_PID    0xD00D  /* Xsens USB-serial converter */
 
 /* Xsens devices using FTDI VID */
index 89b3192..0c6f160 100644 (file)
@@ -1094,14 +1094,18 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(QUALCOMM_VENDOR_ID, UBLOX_PRODUCT_R410M),
          .driver_info = RSVD(1) | RSVD(3) },
        /* Quectel products using Quectel vendor ID */
-       { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21),
-         .driver_info = RSVD(4) },
-       { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25),
-         .driver_info = RSVD(4) },
-       { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG95),
-         .driver_info = RSVD(4) },
-       { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
-         .driver_info = RSVD(4) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21, 0xff, 0xff, 0xff),
+         .driver_info = NUMEP2 },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21, 0xff, 0, 0) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25, 0xff, 0xff, 0xff),
+         .driver_info = NUMEP2 },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25, 0xff, 0, 0) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG95, 0xff, 0xff, 0xff),
+         .driver_info = NUMEP2 },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG95, 0xff, 0, 0) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96, 0xff, 0xff, 0xff),
+         .driver_info = NUMEP2 },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96, 0xff, 0, 0) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff),
          .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },
@@ -1819,6 +1823,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9003, 0xff) },   /* Simcom SIM7500/SIM7600 MBIM mode */
        { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9011, 0xff),     /* Simcom SIM7500/SIM7600 RNDIS mode */
          .driver_info = RSVD(7) },
+       { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9205, 0xff) },   /* Simcom SIM7070/SIM7080/SIM7090 AT+ECM mode */
+       { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9206, 0xff) },   /* Simcom SIM7070/SIM7080/SIM7090 AT-only mode */
        { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
          .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) },
        { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D),
index c8a988d..15dc258 100644 (file)
@@ -592,7 +592,7 @@ static unsigned long sddr55_get_capacity(struct us_data *us) {
        case 0x64:
                info->pageshift = 8;
                info->smallpageshift = 1;
-               /* fall through */
+               fallthrough;
        case 0x5d: // 5d is a ROM card with pagesize 512.
                return 0x00200000;
 
index d592071..8183504 100644 (file)
@@ -662,8 +662,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
        if (devinfo->resetting) {
                cmnd->result = DID_ERROR << 16;
                cmnd->scsi_done(cmnd);
-               spin_unlock_irqrestore(&devinfo->lock, flags);
-               return 0;
+               goto zombie;
        }
 
        /* Find a free uas-tag */
@@ -688,7 +687,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
                break;
        case DMA_BIDIRECTIONAL:
                cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
-               /* fall through */
+               fallthrough;
        case DMA_TO_DEVICE:
                cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB;
        case DMA_NONE:
@@ -699,6 +698,16 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
                cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
 
        err = uas_submit_urbs(cmnd, devinfo);
+       /*
+        * in case of fatal errors the SCSI layer is peculiar
+        * a command that has finished is a success for the purpose
+        * of queueing, no matter how fatal the error
+        */
+       if (err == -ENODEV) {
+               cmnd->result = DID_ERROR << 16;
+               cmnd->scsi_done(cmnd);
+               goto zombie;
+       }
        if (err) {
                /* If we did nothing, give up now */
                if (cmdinfo->state & SUBMIT_STATUS_URB) {
@@ -709,6 +718,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
        }
 
        devinfo->cmnd[idx] = cmnd;
+zombie:
        spin_unlock_irqrestore(&devinfo->lock, flags);
        return 0;
 }
index 220ae2c..5732e96 100644 (file)
@@ -2328,7 +2328,7 @@ UNUSUAL_DEV(  0x357d, 0x7788, 0x0114, 0x0114,
                "JMicron",
                "USB to ATA/ATAPI Bridge",
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
-               US_FL_BROKEN_FUA ),
+               US_FL_BROKEN_FUA | US_FL_IGNORE_UAS ),
 
 /* Reported by Andrey Rahmatullin <wrar@altlinux.org> */
 UNUSUAL_DEV(  0x4102, 0x1020, 0x0100,  0x0100,
index 162b09d..711ab24 100644 (file)
  * and don't forget to CC: the USB development list <linux-usb@vger.kernel.org>
  */
 
+/* Reported-by: Till Dörges <doerges@pre-sense.de> */
+UNUSUAL_DEV(0x054c, 0x087d, 0x0000, 0x9999,
+               "Sony",
+               "PSZ-HA*",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_REPORT_OPCODES),
+
 /* Reported-by: Julian Groß <julian.g@posteo.de> */
 UNUSUAL_DEV(0x059f, 0x105f, 0x0000, 0x9999,
                "LaCie",
@@ -80,6 +87,13 @@ UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_BROKEN_FUA),
 
+/* Reported-by: Thinh Nguyen <thinhn@synopsys.com> */
+UNUSUAL_DEV(0x154b, 0xf00d, 0x0000, 0x9999,
+               "PNY",
+               "Pro Elite SSD",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_ATA_1X),
+
 /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
 UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
                "VIA",
index e4021e1..676b525 100644 (file)
@@ -61,14 +61,11 @@ enum {
 
 #define PMC_USB_ALTMODE_ORI_SHIFT      1
 #define PMC_USB_ALTMODE_UFP_SHIFT      3
-#define PMC_USB_ALTMODE_ORI_AUX_SHIFT  4
-#define PMC_USB_ALTMODE_ORI_HSL_SHIFT  5
 
 /* DP specific Mode Data bits */
 #define PMC_USB_ALTMODE_DP_MODE_SHIFT  8
 
 /* TBT specific Mode Data bits */
-#define PMC_USB_ALTMODE_HPD_HIGH       BIT(14)
 #define PMC_USB_ALTMODE_TBT_TYPE       BIT(17)
 #define PMC_USB_ALTMODE_CABLE_TYPE     BIT(18)
 #define PMC_USB_ALTMODE_ACTIVE_LINK    BIT(20)
@@ -128,13 +125,19 @@ static int hsl_orientation(struct pmc_usb_port *port)
 static int pmc_usb_command(struct pmc_usb_port *port, u8 *msg, u32 len)
 {
        u8 response[4];
+       int ret;
 
        /*
         * Error bit will always be 0 with the USBC command.
-        * Status can be checked from the response message.
+        * Status can be checked from the response message if the
+        * function intel_scu_ipc_dev_command succeeds.
         */
-       intel_scu_ipc_dev_command(port->pmc->ipc, PMC_USBC_CMD, 0, msg, len,
-                                 response, sizeof(response));
+       ret = intel_scu_ipc_dev_command(port->pmc->ipc, PMC_USBC_CMD, 0, msg,
+                                       len, response, sizeof(response));
+
+       if (ret)
+               return ret;
+
        if (response[2] & PMC_USB_RESP_STATUS_FAILURE) {
                if (response[2] & PMC_USB_RESP_STATUS_FATAL)
                        return -EIO;
@@ -179,15 +182,9 @@ pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state)
        req.mode_data = (port->orientation - 1) << PMC_USB_ALTMODE_ORI_SHIFT;
        req.mode_data |= (port->role - 1) << PMC_USB_ALTMODE_UFP_SHIFT;
 
-       req.mode_data |= sbu_orientation(port) << PMC_USB_ALTMODE_ORI_AUX_SHIFT;
-       req.mode_data |= hsl_orientation(port) << PMC_USB_ALTMODE_ORI_HSL_SHIFT;
-
        req.mode_data |= (state->mode - TYPEC_STATE_MODAL) <<
                         PMC_USB_ALTMODE_DP_MODE_SHIFT;
 
-       if (data->status & DP_STATUS_HPD_STATE)
-               req.mode_data |= PMC_USB_ALTMODE_HPD_HIGH;
-
        ret = pmc_usb_command(port, (void *)&req, sizeof(req));
        if (ret)
                return ret;
@@ -212,9 +209,6 @@ pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state)
        req.mode_data = (port->orientation - 1) << PMC_USB_ALTMODE_ORI_SHIFT;
        req.mode_data |= (port->role - 1) << PMC_USB_ALTMODE_UFP_SHIFT;
 
-       req.mode_data |= sbu_orientation(port) << PMC_USB_ALTMODE_ORI_AUX_SHIFT;
-       req.mode_data |= hsl_orientation(port) << PMC_USB_ALTMODE_ORI_HSL_SHIFT;
-
        if (TBT_ADAPTER(data->device_mode) == TBT_ADAPTER_TBT3)
                req.mode_data |= PMC_USB_ALTMODE_TBT_TYPE;
 
@@ -497,6 +491,7 @@ err_remove_ports:
        for (i = 0; i < pmc->num_ports; i++) {
                typec_switch_unregister(pmc->port[i].typec_sw);
                typec_mux_unregister(pmc->port[i].typec_mux);
+               usb_role_switch_unregister(pmc->port[i].usb_sw);
        }
 
        return ret;
@@ -510,6 +505,7 @@ static int pmc_usb_remove(struct platform_device *pdev)
        for (i = 0; i < pmc->num_ports; i++) {
                typec_switch_unregister(pmc->port[i].typec_sw);
                typec_mux_unregister(pmc->port[i].typec_mux);
+               usb_role_switch_unregister(pmc->port[i].usb_sw);
        }
 
        return 0;
index f57d91f..bd80e03 100644 (file)
@@ -157,7 +157,7 @@ static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
        case 0x3:
                if (sink)
                        return TYPEC_CC_RP_3_0;
-               /* fall through */
+               fallthrough;
        case 0x0:
        default:
                return TYPEC_CC_OPEN;
index 3ef3720..a48e3f9 100644 (file)
@@ -3372,13 +3372,31 @@ static void run_state_machine(struct tcpm_port *port)
                        tcpm_set_state(port, SNK_HARD_RESET_SINK_OFF, 0);
                break;
        case SRC_HARD_RESET_VBUS_OFF:
-               tcpm_set_vconn(port, true);
+               /*
+                * 7.1.5 Response to Hard Resets
+                * Hard Reset Signaling indicates a communication failure has occurred and the
+                * Source Shall stop driving VCONN, Shall remove Rp from the VCONN pin and Shall
+                * drive VBUS to vSafe0V as shown in Figure 7-9.
+                */
+               tcpm_set_vconn(port, false);
                tcpm_set_vbus(port, false);
                tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE,
                               tcpm_data_role_for_source(port));
-               tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
+               /*
+                * If tcpc fails to notify vbus off, TCPM will wait for PD_T_SAFE_0V +
+                * PD_T_SRC_RECOVER before turning vbus back on.
+                * From Table 7-12 Sequence Description for a Source Initiated Hard Reset:
+                * 4. Policy Engine waits tPSHardReset after sending Hard Reset Signaling and then
+                * tells the Device Policy Manager to instruct the power supply to perform a
+                * Hard Reset. The transition to vSafe0V Shall occur within tSafe0V (t2).
+                * 5. After tSrcRecover the Source applies power to VBUS in an attempt to
+                * re-establish communication with the Sink and resume USB Default Operation.
+                * The transition to vSafe5V Shall occur within tSrcTurnOn(t4).
+                */
+               tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SAFE_0V + PD_T_SRC_RECOVER);
                break;
        case SRC_HARD_RESET_VBUS_ON:
+               tcpm_set_vconn(port, true);
                tcpm_set_vbus(port, true);
                port->tcpc->set_pd_rx(port->tcpc, true);
                tcpm_set_attached_state(port, true);
@@ -3944,7 +3962,11 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
                tcpm_set_state(port, SNK_HARD_RESET_WAIT_VBUS, 0);
                break;
        case SRC_HARD_RESET_VBUS_OFF:
-               tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, 0);
+               /*
+                * After establishing the vSafe0V voltage condition on VBUS, the Source Shall wait
+                * tSrcRecover before re-applying VCONN and restoring VBUS to vSafe5V.
+                */
+               tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
                break;
        case HARD_RESET_SEND:
                break;
index 048381c..261131c 100644 (file)
@@ -288,8 +288,6 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con,
        struct typec_altmode *alt;
        struct ucsi_dp *dp;
 
-       mutex_lock(&con->lock);
-
        /* We can't rely on the firmware with the capabilities. */
        desc->vdo |= DP_CAP_DP_SIGNALING | DP_CAP_RECEPTACLE;
 
@@ -298,15 +296,12 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con,
        desc->vdo |= all_assignments << 16;
 
        alt = typec_port_register_altmode(con->port, desc);
-       if (IS_ERR(alt)) {
-               mutex_unlock(&con->lock);
+       if (IS_ERR(alt))
                return alt;
-       }
 
        dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
        if (!dp) {
                typec_unregister_altmode(alt);
-               mutex_unlock(&con->lock);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -319,7 +314,5 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con,
        alt->ops = &ucsi_displayport_ops;
        typec_altmode_set_drvdata(alt, dp);
 
-       mutex_unlock(&con->lock);
-
        return alt;
 }
index affd024..758b988 100644 (file)
@@ -146,40 +146,33 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd)
        return UCSI_CCI_LENGTH(cci);
 }
 
-static int ucsi_run_command(struct ucsi *ucsi, u64 command,
-                           void *data, size_t size)
+int ucsi_send_command(struct ucsi *ucsi, u64 command,
+                     void *data, size_t size)
 {
        u8 length;
        int ret;
 
+       mutex_lock(&ucsi->ppm_lock);
+
        ret = ucsi_exec_command(ucsi, command);
        if (ret < 0)
-               return ret;
+               goto out;
 
        length = ret;
 
        if (data) {
                ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, data, size);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
        ret = ucsi_acknowledge_command(ucsi);
        if (ret)
-               return ret;
+               goto out;
 
-       return length;
-}
-
-int ucsi_send_command(struct ucsi *ucsi, u64 command,
-                     void *retval, size_t size)
-{
-       int ret;
-
-       mutex_lock(&ucsi->ppm_lock);
-       ret = ucsi_run_command(ucsi, command, retval, size);
+       ret = length;
+out:
        mutex_unlock(&ucsi->ppm_lock);
-
        return ret;
 }
 EXPORT_SYMBOL_GPL(ucsi_send_command);
@@ -205,7 +198,7 @@ void ucsi_altmode_update_active(struct ucsi_connector *con)
        int i;
 
        command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(con->num);
-       ret = ucsi_run_command(con->ucsi, command, &cur, sizeof(cur));
+       ret = ucsi_send_command(con->ucsi, command, &cur, sizeof(cur));
        if (ret < 0) {
                if (con->ucsi->version > 0x0100) {
                        dev_err(con->ucsi->dev,
@@ -223,14 +216,18 @@ void ucsi_altmode_update_active(struct ucsi_connector *con)
                                            con->partner_altmode[i] == altmode);
 }
 
-static u8 ucsi_altmode_next_mode(struct typec_altmode **alt, u16 svid)
+static int ucsi_altmode_next_mode(struct typec_altmode **alt, u16 svid)
 {
        u8 mode = 1;
        int i;
 
-       for (i = 0; alt[i]; i++)
+       for (i = 0; alt[i]; i++) {
+               if (i > MODE_DISCOVERY_MAX)
+                       return -ERANGE;
+
                if (alt[i]->svid == svid)
                        mode++;
+       }
 
        return mode;
 }
@@ -265,8 +262,11 @@ static int ucsi_register_altmode(struct ucsi_connector *con,
                        goto err;
                }
 
-               desc->mode = ucsi_altmode_next_mode(con->port_altmode,
-                                                   desc->svid);
+               ret = ucsi_altmode_next_mode(con->port_altmode, desc->svid);
+               if (ret < 0)
+                       return ret;
+
+               desc->mode = ret;
 
                switch (desc->svid) {
                case USB_TYPEC_DP_SID:
@@ -299,8 +299,11 @@ static int ucsi_register_altmode(struct ucsi_connector *con,
                        goto err;
                }
 
-               desc->mode = ucsi_altmode_next_mode(con->partner_altmode,
-                                                   desc->svid);
+               ret = ucsi_altmode_next_mode(con->partner_altmode, desc->svid);
+               if (ret < 0)
+                       return ret;
+
+               desc->mode = ret;
 
                alt = typec_partner_register_altmode(con->partner, desc);
                if (IS_ERR(alt)) {
@@ -354,7 +357,7 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient)
                command |= UCSI_GET_ALTMODE_RECIPIENT(recipient);
                command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num);
                command |= UCSI_GET_ALTMODE_OFFSET(i);
-               len = ucsi_run_command(con->ucsi, command, &alt, sizeof(alt));
+               len = ucsi_send_command(con->ucsi, command, &alt, sizeof(alt));
                /*
                 * We are collecting all altmodes first and then registering.
                 * Some type-C device will return zero length data beyond last
@@ -431,7 +434,7 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient)
                command |= UCSI_GET_ALTMODE_RECIPIENT(recipient);
                command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num);
                command |= UCSI_GET_ALTMODE_OFFSET(i);
-               len = ucsi_run_command(con->ucsi, command, alt, sizeof(alt));
+               len = ucsi_send_command(con->ucsi, command, alt, sizeof(alt));
                if (len <= 0)
                        return len;
 
@@ -502,7 +505,7 @@ static void ucsi_get_pdos(struct ucsi_connector *con, int is_partner)
        command |= UCSI_GET_PDOS_PARTNER_PDO(is_partner);
        command |= UCSI_GET_PDOS_NUM_PDOS(UCSI_MAX_PDOS - 1);
        command |= UCSI_GET_PDOS_SRC_PDOS;
-       ret = ucsi_run_command(ucsi, command, con->src_pdos,
+       ret = ucsi_send_command(ucsi, command, con->src_pdos,
                               sizeof(con->src_pdos));
        if (ret < 0) {
                dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret);
@@ -681,7 +684,7 @@ static void ucsi_handle_connector_change(struct work_struct *work)
                 */
                command = UCSI_GET_CAM_SUPPORTED;
                command |= UCSI_CONNECTOR_NUMBER(con->num);
-               ucsi_run_command(con->ucsi, command, NULL, 0);
+               ucsi_send_command(con->ucsi, command, NULL, 0);
        }
 
        if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE)
@@ -736,20 +739,24 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
        u32 cci;
        int ret;
 
+       mutex_lock(&ucsi->ppm_lock);
+
        ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command,
                                     sizeof(command));
        if (ret < 0)
-               return ret;
+               goto out;
 
        tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);
 
        do {
-               if (time_is_before_jiffies(tmo))
-                       return -ETIMEDOUT;
+               if (time_is_before_jiffies(tmo)) {
+                       ret = -ETIMEDOUT;
+                       goto out;
+               }
 
                ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci));
                if (ret)
-                       return ret;
+                       goto out;
 
                /* If the PPM is still doing something else, reset it again. */
                if (cci & ~UCSI_CCI_RESET_COMPLETE) {
@@ -757,13 +764,15 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
                                                     &command,
                                                     sizeof(command));
                        if (ret < 0)
-                               return ret;
+                               goto out;
                }
 
                msleep(20);
        } while (!(cci & UCSI_CCI_RESET_COMPLETE));
 
-       return 0;
+out:
+       mutex_unlock(&ucsi->ppm_lock);
+       return ret;
 }
 
 static int ucsi_role_cmd(struct ucsi_connector *con, u64 command)
@@ -775,9 +784,7 @@ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command)
                u64 c;
 
                /* PPM most likely stopped responding. Resetting everything. */
-               mutex_lock(&con->ucsi->ppm_lock);
                ucsi_reset_ppm(con->ucsi);
-               mutex_unlock(&con->ucsi->ppm_lock);
 
                c = UCSI_SET_NOTIFICATION_ENABLE | con->ucsi->ntfy;
                ucsi_send_command(con->ucsi, c, NULL, 0);
@@ -901,12 +908,15 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
        con->num = index + 1;
        con->ucsi = ucsi;
 
+       /* Delay other interactions with the con until registration is complete */
+       mutex_lock(&con->lock);
+
        /* Get connector capability */
        command = UCSI_GET_CONNECTOR_CAPABILITY;
        command |= UCSI_CONNECTOR_NUMBER(con->num);
-       ret = ucsi_run_command(ucsi, command, &con->cap, sizeof(con->cap));
+       ret = ucsi_send_command(ucsi, command, &con->cap, sizeof(con->cap));
        if (ret < 0)
-               return ret;
+               goto out;
 
        if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP)
                cap->data = TYPEC_PORT_DRD;
@@ -938,27 +948,32 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
 
        ret = ucsi_register_port_psy(con);
        if (ret)
-               return ret;
+               goto out;
 
        /* Register the connector */
        con->port = typec_register_port(ucsi->dev, cap);
-       if (IS_ERR(con->port))
-               return PTR_ERR(con->port);
+       if (IS_ERR(con->port)) {
+               ret = PTR_ERR(con->port);
+               goto out;
+       }
 
        /* Alternate modes */
        ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON);
-       if (ret)
+       if (ret) {
                dev_err(ucsi->dev, "con%d: failed to register alt modes\n",
                        con->num);
+               goto out;
+       }
 
        /* Get the status */
        command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
-       ret = ucsi_run_command(ucsi, command, &con->status,
-                              sizeof(con->status));
+       ret = ucsi_send_command(ucsi, command, &con->status, sizeof(con->status));
        if (ret < 0) {
                dev_err(ucsi->dev, "con%d: failed to get status\n", con->num);
-               return 0;
+               ret = 0;
+               goto out;
        }
+       ret = 0; /* ucsi_send_command() returns length on success */
 
        switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
        case UCSI_CONSTAT_PARTNER_TYPE_UFP:
@@ -983,17 +998,21 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
 
        if (con->partner) {
                ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP);
-               if (ret)
+               if (ret) {
                        dev_err(ucsi->dev,
                                "con%d: failed to register alternate modes\n",
                                con->num);
-               else
+                       ret = 0;
+               } else {
                        ucsi_altmode_update_active(con);
+               }
        }
 
        trace_ucsi_register_port(con->num, &con->status);
 
-       return 0;
+out:
+       mutex_unlock(&con->lock);
+       return ret;
 }
 
 /**
@@ -1009,8 +1028,6 @@ static int ucsi_init(struct ucsi *ucsi)
        int ret;
        int i;
 
-       mutex_lock(&ucsi->ppm_lock);
-
        /* Reset the PPM */
        ret = ucsi_reset_ppm(ucsi);
        if (ret) {
@@ -1021,13 +1038,13 @@ static int ucsi_init(struct ucsi *ucsi)
        /* Enable basic notifications */
        ucsi->ntfy = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR;
        command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy;
-       ret = ucsi_run_command(ucsi, command, NULL, 0);
+       ret = ucsi_send_command(ucsi, command, NULL, 0);
        if (ret < 0)
                goto err_reset;
 
        /* Get PPM capabilities */
        command = UCSI_GET_CAPABILITY;
-       ret = ucsi_run_command(ucsi, command, &ucsi->cap, sizeof(ucsi->cap));
+       ret = ucsi_send_command(ucsi, command, &ucsi->cap, sizeof(ucsi->cap));
        if (ret < 0)
                goto err_reset;
 
@@ -1054,12 +1071,10 @@ static int ucsi_init(struct ucsi *ucsi)
        /* Enable all notifications */
        ucsi->ntfy = UCSI_ENABLE_NTFY_ALL;
        command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy;
-       ret = ucsi_run_command(ucsi, command, NULL, 0);
+       ret = ucsi_send_command(ucsi, command, NULL, 0);
        if (ret < 0)
                goto err_unregister;
 
-       mutex_unlock(&ucsi->ppm_lock);
-
        return 0;
 
 err_unregister:
@@ -1074,8 +1089,6 @@ err_unregister:
 err_reset:
        ucsi_reset_ppm(ucsi);
 err:
-       mutex_unlock(&ucsi->ppm_lock);
-
        return ret;
 }
 
index 9fc4f33..fbfe8f5 100644 (file)
@@ -78,7 +78,7 @@ static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset,
        if (ret)
                goto out_clear_bit;
 
-       if (!wait_for_completion_timeout(&ua->complete, msecs_to_jiffies(5000)))
+       if (!wait_for_completion_timeout(&ua->complete, 60 * HZ))
                ret = -ETIMEDOUT;
 
 out_clear_bit:
@@ -112,11 +112,15 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
 
 static int ucsi_acpi_probe(struct platform_device *pdev)
 {
+       struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
        struct ucsi_acpi *ua;
        struct resource *res;
        acpi_status status;
        int ret;
 
+       if (adev->dep_unmet)
+               return -EPROBE_DEFER;
+
        ua = devm_kzalloc(&pdev->dev, sizeof(*ua), GFP_KERNEL);
        if (!ua)
                return -ENOMEM;
index 4271c40..d7d32b6 100644 (file)
@@ -30,9 +30,7 @@ config IFCVF
          be called ifcvf.
 
 config MLX5_VDPA
-       bool "MLX5 VDPA support library for ConnectX devices"
-       depends on MLX5_CORE
-       default n
+       bool
        help
          Support library for Mellanox VDPA drivers. Provides code that is
          common for all types of VDPA drivers. The following drivers are planned:
@@ -40,7 +38,8 @@ config MLX5_VDPA
 
 config MLX5_VDPA_NET
        tristate "vDPA driver for ConnectX devices"
-       depends on MLX5_VDPA
+       select MLX5_VDPA
+       depends on MLX5_CORE
        default n
        help
          VDPA network driver for ConnectX6 and newer. Provides offloading
index 08f267a..64696d6 100644 (file)
@@ -84,7 +84,7 @@ struct ifcvf_hw {
        void __iomem * const *base;
        char config_msix_name[256];
        struct vdpa_callback config_cb;
-
+       unsigned int config_irq;
 };
 
 struct ifcvf_adapter {
index 076d7ac..8b40285 100644 (file)
@@ -55,6 +55,7 @@ static void ifcvf_free_irq(struct ifcvf_adapter *adapter, int queues)
                vf->vring[i].irq = -EINVAL;
        }
 
+       devm_free_irq(&pdev->dev, vf->config_irq, vf);
        ifcvf_free_irq_vectors(pdev);
 }
 
@@ -74,10 +75,14 @@ static int ifcvf_request_irq(struct ifcvf_adapter *adapter)
        snprintf(vf->config_msix_name, 256, "ifcvf[%s]-config\n",
                 pci_name(pdev));
        vector = 0;
-       irq = pci_irq_vector(pdev, vector);
-       ret = devm_request_irq(&pdev->dev, irq,
+       vf->config_irq = pci_irq_vector(pdev, vector);
+       ret = devm_request_irq(&pdev->dev, vf->config_irq,
                               ifcvf_config_changed, 0,
                               vf->config_msix_name, vf);
+       if (ret) {
+               IFCVF_ERR(pdev, "Failed to request config irq\n");
+               return ret;
+       }
 
        for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++) {
                snprintf(vf->vring[i].msix_name, 256, "ifcvf[%s]-%d\n",
index 9df69d5..74264e5 100644 (file)
 #define to_mvdev(__vdev) container_of((__vdev), struct mlx5_vdpa_dev, vdev)
 
 #define VALID_FEATURES_MASK                                                                        \
-       (BIT(VIRTIO_NET_F_CSUM) | BIT(VIRTIO_NET_F_GUEST_CSUM) |                                   \
-        BIT(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) | BIT(VIRTIO_NET_F_MTU) | BIT(VIRTIO_NET_F_MAC) |   \
-        BIT(VIRTIO_NET_F_GUEST_TSO4) | BIT(VIRTIO_NET_F_GUEST_TSO6) |                             \
-        BIT(VIRTIO_NET_F_GUEST_ECN) | BIT(VIRTIO_NET_F_GUEST_UFO) | BIT(VIRTIO_NET_F_HOST_TSO4) | \
-        BIT(VIRTIO_NET_F_HOST_TSO6) | BIT(VIRTIO_NET_F_HOST_ECN) | BIT(VIRTIO_NET_F_HOST_UFO) |   \
-        BIT(VIRTIO_NET_F_MRG_RXBUF) | BIT(VIRTIO_NET_F_STATUS) | BIT(VIRTIO_NET_F_CTRL_VQ) |      \
-        BIT(VIRTIO_NET_F_CTRL_RX) | BIT(VIRTIO_NET_F_CTRL_VLAN) |                                 \
-        BIT(VIRTIO_NET_F_CTRL_RX_EXTRA) | BIT(VIRTIO_NET_F_GUEST_ANNOUNCE) |                      \
-        BIT(VIRTIO_NET_F_MQ) | BIT(VIRTIO_NET_F_CTRL_MAC_ADDR) | BIT(VIRTIO_NET_F_HASH_REPORT) |  \
-        BIT(VIRTIO_NET_F_RSS) | BIT(VIRTIO_NET_F_RSC_EXT) | BIT(VIRTIO_NET_F_STANDBY) |           \
-        BIT(VIRTIO_NET_F_SPEED_DUPLEX) | BIT(VIRTIO_F_NOTIFY_ON_EMPTY) |                          \
-        BIT(VIRTIO_F_ANY_LAYOUT) | BIT(VIRTIO_F_VERSION_1) | BIT(VIRTIO_F_ACCESS_PLATFORM) |      \
-        BIT(VIRTIO_F_RING_PACKED) | BIT(VIRTIO_F_ORDER_PLATFORM) | BIT(VIRTIO_F_SR_IOV))
+       (BIT_ULL(VIRTIO_NET_F_CSUM) | BIT_ULL(VIRTIO_NET_F_GUEST_CSUM) |                                   \
+        BIT_ULL(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) | BIT_ULL(VIRTIO_NET_F_MTU) | BIT_ULL(VIRTIO_NET_F_MAC) |   \
+        BIT_ULL(VIRTIO_NET_F_GUEST_TSO4) | BIT_ULL(VIRTIO_NET_F_GUEST_TSO6) |                             \
+        BIT_ULL(VIRTIO_NET_F_GUEST_ECN) | BIT_ULL(VIRTIO_NET_F_GUEST_UFO) | BIT_ULL(VIRTIO_NET_F_HOST_TSO4) | \
+        BIT_ULL(VIRTIO_NET_F_HOST_TSO6) | BIT_ULL(VIRTIO_NET_F_HOST_ECN) | BIT_ULL(VIRTIO_NET_F_HOST_UFO) |   \
+        BIT_ULL(VIRTIO_NET_F_MRG_RXBUF) | BIT_ULL(VIRTIO_NET_F_STATUS) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ) |      \
+        BIT_ULL(VIRTIO_NET_F_CTRL_RX) | BIT_ULL(VIRTIO_NET_F_CTRL_VLAN) |                                 \
+        BIT_ULL(VIRTIO_NET_F_CTRL_RX_EXTRA) | BIT_ULL(VIRTIO_NET_F_GUEST_ANNOUNCE) |                      \
+        BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR) | BIT_ULL(VIRTIO_NET_F_HASH_REPORT) |  \
+        BIT_ULL(VIRTIO_NET_F_RSS) | BIT_ULL(VIRTIO_NET_F_RSC_EXT) | BIT_ULL(VIRTIO_NET_F_STANDBY) |           \
+        BIT_ULL(VIRTIO_NET_F_SPEED_DUPLEX) | BIT_ULL(VIRTIO_F_NOTIFY_ON_EMPTY) |                          \
+        BIT_ULL(VIRTIO_F_ANY_LAYOUT) | BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_ACCESS_PLATFORM) |      \
+        BIT_ULL(VIRTIO_F_RING_PACKED) | BIT_ULL(VIRTIO_F_ORDER_PLATFORM) | BIT_ULL(VIRTIO_F_SR_IOV))
 
 #define VALID_STATUS_MASK                                                                          \
        (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK |        \
@@ -149,7 +149,7 @@ static bool mlx5_vdpa_debug;
 
 #define MLX5_LOG_VIO_FLAG(_feature)                                                                \
        do {                                                                                       \
-               if (features & BIT(_feature))                                                      \
+               if (features & BIT_ULL(_feature))                                                  \
                        mlx5_vdpa_info(mvdev, "%s\n", #_feature);                                  \
        } while (0)
 
@@ -750,10 +750,10 @@ static bool vq_is_tx(u16 idx)
 
 static u16 get_features_12_3(u64 features)
 {
-       return (!!(features & BIT(VIRTIO_NET_F_HOST_TSO4)) << 9) |
-              (!!(features & BIT(VIRTIO_NET_F_HOST_TSO6)) << 8) |
-              (!!(features & BIT(VIRTIO_NET_F_CSUM)) << 7) |
-              (!!(features & BIT(VIRTIO_NET_F_GUEST_CSUM)) << 6);
+       return (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO4)) << 9) |
+              (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO6)) << 8) |
+              (!!(features & BIT_ULL(VIRTIO_NET_F_CSUM)) << 7) |
+              (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_CSUM)) << 6);
 }
 
 static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
@@ -1133,15 +1133,17 @@ static void suspend_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *m
        if (!mvq->initialized)
                return;
 
-       if (query_virtqueue(ndev, mvq, &attr)) {
-               mlx5_vdpa_warn(&ndev->mvdev, "failed to query virtqueue\n");
-               return;
-       }
        if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY)
                return;
 
        if (modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND))
                mlx5_vdpa_warn(&ndev->mvdev, "modify to suspend failed\n");
+
+       if (query_virtqueue(ndev, mvq, &attr)) {
+               mlx5_vdpa_warn(&ndev->mvdev, "failed to query virtqueue\n");
+               return;
+       }
+       mvq->avail_idx = attr.available_index;
 }
 
 static void suspend_vqs(struct mlx5_vdpa_net *ndev)
@@ -1411,8 +1413,14 @@ static int mlx5_vdpa_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa
        struct mlx5_virtq_attr attr;
        int err;
 
-       if (!mvq->initialized)
-               return -EAGAIN;
+       /* If the virtq object was destroyed, use the value saved at
+        * the last minute of suspend_vq. This caters for userspace
+        * that cares about emulating the index after vq is stopped.
+        */
+       if (!mvq->initialized) {
+               state->avail_index = mvq->avail_idx;
+               return 0;
+       }
 
        err = query_virtqueue(ndev, mvq, &attr);
        if (err) {
@@ -1439,13 +1447,13 @@ static u64 mlx_to_vritio_features(u16 dev_features)
        u64 result = 0;
 
        if (dev_features & MLX5_VIRTIO_NET_F_GUEST_CSUM)
-               result |= BIT(VIRTIO_NET_F_GUEST_CSUM);
+               result |= BIT_ULL(VIRTIO_NET_F_GUEST_CSUM);
        if (dev_features & MLX5_VIRTIO_NET_F_CSUM)
-               result |= BIT(VIRTIO_NET_F_CSUM);
+               result |= BIT_ULL(VIRTIO_NET_F_CSUM);
        if (dev_features & MLX5_VIRTIO_NET_F_HOST_TSO6)
-               result |= BIT(VIRTIO_NET_F_HOST_TSO6);
+               result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO6);
        if (dev_features & MLX5_VIRTIO_NET_F_HOST_TSO4)
-               result |= BIT(VIRTIO_NET_F_HOST_TSO4);
+               result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO4);
 
        return result;
 }
@@ -1459,15 +1467,15 @@ static u64 mlx5_vdpa_get_features(struct vdpa_device *vdev)
        dev_features = MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, device_features_bits_mask);
        ndev->mvdev.mlx_features = mlx_to_vritio_features(dev_features);
        if (MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, virtio_version_1_0))
-               ndev->mvdev.mlx_features |= BIT(VIRTIO_F_VERSION_1);
-       ndev->mvdev.mlx_features |= BIT(VIRTIO_F_ACCESS_PLATFORM);
+               ndev->mvdev.mlx_features |= BIT_ULL(VIRTIO_F_VERSION_1);
+       ndev->mvdev.mlx_features |= BIT_ULL(VIRTIO_F_ACCESS_PLATFORM);
        print_features(mvdev, ndev->mvdev.mlx_features, false);
        return ndev->mvdev.mlx_features;
 }
 
 static int verify_min_features(struct mlx5_vdpa_dev *mvdev, u64 features)
 {
-       if (!(features & BIT(VIRTIO_F_ACCESS_PLATFORM)))
+       if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)))
                return -EOPNOTSUPP;
 
        return 0;
index 620465c..1ab1f5c 100644 (file)
@@ -990,7 +990,7 @@ static long vfio_pci_ioctl(void *device_data,
                case VFIO_PCI_ERR_IRQ_INDEX:
                        if (pci_is_pcie(vdev->pdev))
                                break;
-               /* fall through */
+                       fallthrough;
                default:
                        return -EINVAL;
                }
index c992973..5fbf0c1 100644 (file)
@@ -2439,7 +2439,7 @@ static void *vfio_iommu_type1_open(unsigned long arg)
                break;
        case VFIO_TYPE1_NESTING_IOMMU:
                iommu->nesting = true;
-               /* fall through */
+               fallthrough;
        case VFIO_TYPE1v2_IOMMU:
                iommu->v2 = true;
                break;
index 1f0ca6e..0fd3f87 100644 (file)
@@ -149,7 +149,7 @@ EXPORT_SYMBOL_GPL(vhost_iotlb_free);
  * vhost_iotlb_itree_first - return the first overlapped range
  * @iotlb: the IOTLB
  * @start: start of IOVA range
- * @end: end of IOVA range
+ * @last: last byte in IOVA range
  */
 struct vhost_iotlb_map *
 vhost_iotlb_itree_first(struct vhost_iotlb *iotlb, u64 start, u64 last)
@@ -159,10 +159,10 @@ vhost_iotlb_itree_first(struct vhost_iotlb *iotlb, u64 start, u64 last)
 EXPORT_SYMBOL_GPL(vhost_iotlb_itree_first);
 
 /**
- * vhost_iotlb_itree_first - return the next overlapped range
- * @iotlb: the IOTLB
+ * vhost_iotlb_itree_next - return the next overlapped range
+ * @map: the starting map node
  * @start: start of IOVA range
- * @end: end of IOVA range
+ * @last: last byte IOVA range
  */
 struct vhost_iotlb_map *
 vhost_iotlb_itree_next(struct vhost_iotlb_map *map, u64 start, u64 last)
index 3fab94f..62a9bb0 100644 (file)
@@ -353,8 +353,6 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
        struct vdpa_callback cb;
        struct vhost_virtqueue *vq;
        struct vhost_vring_state s;
-       u64 __user *featurep = argp;
-       u64 features;
        u32 idx;
        long r;
 
@@ -381,18 +379,6 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
 
                vq->last_avail_idx = vq_state.avail_index;
                break;
-       case VHOST_GET_BACKEND_FEATURES:
-               features = VHOST_VDPA_BACKEND_FEATURES;
-               if (copy_to_user(featurep, &features, sizeof(features)))
-                       return -EFAULT;
-               return 0;
-       case VHOST_SET_BACKEND_FEATURES:
-               if (copy_from_user(&features, featurep, sizeof(features)))
-                       return -EFAULT;
-               if (features & ~VHOST_VDPA_BACKEND_FEATURES)
-                       return -EOPNOTSUPP;
-               vhost_set_backend_features(&v->vdev, features);
-               return 0;
        }
 
        r = vhost_vring_ioctl(&v->vdev, cmd, argp);
@@ -440,8 +426,20 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep,
        struct vhost_vdpa *v = filep->private_data;
        struct vhost_dev *d = &v->vdev;
        void __user *argp = (void __user *)arg;
+       u64 __user *featurep = argp;
+       u64 features;
        long r;
 
+       if (cmd == VHOST_SET_BACKEND_FEATURES) {
+               r = copy_from_user(&features, featurep, sizeof(features));
+               if (r)
+                       return r;
+               if (features & ~VHOST_VDPA_BACKEND_FEATURES)
+                       return -EOPNOTSUPP;
+               vhost_set_backend_features(&v->vdev, features);
+               return 0;
+       }
+
        mutex_lock(&d->mutex);
 
        switch (cmd) {
@@ -476,6 +474,10 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep,
        case VHOST_VDPA_SET_CONFIG_CALL:
                r = vhost_vdpa_set_config_call(v, argp);
                break;
+       case VHOST_GET_BACKEND_FEATURES:
+               features = VHOST_VDPA_BACKEND_FEATURES;
+               r = copy_to_user(featurep, &features, sizeof(features));
+               break;
        default:
                r = vhost_dev_ioctl(&v->vdev, cmd, argp);
                if (r == -ENOIOCTLCMD)
@@ -563,6 +565,9 @@ static int vhost_vdpa_map(struct vhost_vdpa *v,
                              perm_to_iommu_flags(perm));
        }
 
+       if (r)
+               vhost_iotlb_del_range(dev->iotlb, iova, iova + size - 1);
+
        return r;
 }
 
@@ -590,21 +595,19 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v,
        struct vhost_dev *dev = &v->vdev;
        struct vhost_iotlb *iotlb = dev->iotlb;
        struct page **page_list;
-       unsigned long list_size = PAGE_SIZE / sizeof(struct page *);
+       struct vm_area_struct **vmas;
        unsigned int gup_flags = FOLL_LONGTERM;
-       unsigned long npages, cur_base, map_pfn, last_pfn = 0;
-       unsigned long locked, lock_limit, pinned, i;
+       unsigned long map_pfn, last_pfn = 0;
+       unsigned long npages, lock_limit;
+       unsigned long i, nmap = 0;
        u64 iova = msg->iova;
+       long pinned;
        int ret = 0;
 
        if (vhost_iotlb_itree_first(iotlb, msg->iova,
                                    msg->iova + msg->size - 1))
                return -EEXIST;
 
-       page_list = (struct page **) __get_free_page(GFP_KERNEL);
-       if (!page_list)
-               return -ENOMEM;
-
        if (msg->perm & VHOST_ACCESS_WO)
                gup_flags |= FOLL_WRITE;
 
@@ -612,61 +615,86 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v,
        if (!npages)
                return -EINVAL;
 
+       page_list = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
+       vmas = kvmalloc_array(npages, sizeof(struct vm_area_struct *),
+                             GFP_KERNEL);
+       if (!page_list || !vmas) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
        mmap_read_lock(dev->mm);
 
-       locked = atomic64_add_return(npages, &dev->mm->pinned_vm);
        lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-
-       if (locked > lock_limit) {
+       if (npages + atomic64_read(&dev->mm->pinned_vm) > lock_limit) {
                ret = -ENOMEM;
-               goto out;
+               goto unlock;
        }
 
-       cur_base = msg->uaddr & PAGE_MASK;
-       iova &= PAGE_MASK;
+       pinned = pin_user_pages(msg->uaddr & PAGE_MASK, npages, gup_flags,
+                               page_list, vmas);
+       if (npages != pinned) {
+               if (pinned < 0) {
+                       ret = pinned;
+               } else {
+                       unpin_user_pages(page_list, pinned);
+                       ret = -ENOMEM;
+               }
+               goto unlock;
+       }
 
-       while (npages) {
-               pinned = min_t(unsigned long, npages, list_size);
-               ret = pin_user_pages(cur_base, pinned,
-                                    gup_flags, page_list, NULL);
-               if (ret != pinned)
-                       goto out;
-
-               if (!last_pfn)
-                       map_pfn = page_to_pfn(page_list[0]);
-
-               for (i = 0; i < ret; i++) {
-                       unsigned long this_pfn = page_to_pfn(page_list[i]);
-                       u64 csize;
-
-                       if (last_pfn && (this_pfn != last_pfn + 1)) {
-                               /* Pin a contiguous chunk of memory */
-                               csize = (last_pfn - map_pfn + 1) << PAGE_SHIFT;
-                               if (vhost_vdpa_map(v, iova, csize,
-                                                  map_pfn << PAGE_SHIFT,
-                                                  msg->perm))
-                                       goto out;
-                               map_pfn = this_pfn;
-                               iova += csize;
+       iova &= PAGE_MASK;
+       map_pfn = page_to_pfn(page_list[0]);
+
+       /* One more iteration to avoid extra vdpa_map() call out of loop. */
+       for (i = 0; i <= npages; i++) {
+               unsigned long this_pfn;
+               u64 csize;
+
+               /* The last chunk may have no valid PFN next to it */
+               this_pfn = i < npages ? page_to_pfn(page_list[i]) : -1UL;
+
+               if (last_pfn && (this_pfn == -1UL ||
+                                this_pfn != last_pfn + 1)) {
+                       /* Pin a contiguous chunk of memory */
+                       csize = last_pfn - map_pfn + 1;
+                       ret = vhost_vdpa_map(v, iova, csize << PAGE_SHIFT,
+                                            map_pfn << PAGE_SHIFT,
+                                            msg->perm);
+                       if (ret) {
+                               /*
+                                * Unpin the rest chunks of memory on the
+                                * flight with no corresponding vdpa_map()
+                                * calls having been made yet. On the other
+                                * hand, vdpa_unmap() in the failure path
+                                * is in charge of accounting the number of
+                                * pinned pages for its own.
+                                * This asymmetrical pattern of accounting
+                                * is for efficiency to pin all pages at
+                                * once, while there is no other callsite
+                                * of vdpa_map() than here above.
+                                */
+                               unpin_user_pages(&page_list[nmap],
+                                                npages - nmap);
+                               goto out;
                        }
-
-                       last_pfn = this_pfn;
+                       atomic64_add(csize, &dev->mm->pinned_vm);
+                       nmap += csize;
+                       iova += csize << PAGE_SHIFT;
+                       map_pfn = this_pfn;
                }
-
-               cur_base += ret << PAGE_SHIFT;
-               npages -= ret;
+               last_pfn = this_pfn;
        }
 
-       /* Pin the rest chunk */
-       ret = vhost_vdpa_map(v, iova, (last_pfn - map_pfn + 1) << PAGE_SHIFT,
-                            map_pfn << PAGE_SHIFT, msg->perm);
+       WARN_ON(nmap != npages);
 out:
-       if (ret) {
+       if (ret)
                vhost_vdpa_unmap(v, msg->iova, msg->size);
-               atomic64_sub(npages, &dev->mm->pinned_vm);
-       }
+unlock:
        mmap_read_unlock(dev->mm);
-       free_page((unsigned long)page_list);
+free:
+       kvfree(vmas);
+       kvfree(page_list);
        return ret;
 }
 
@@ -808,6 +836,7 @@ static int vhost_vdpa_open(struct inode *inode, struct file *filep)
 
 err_init_iotlb:
        vhost_dev_cleanup(&v->vdev);
+       kfree(vqs);
 err:
        atomic_dec(&v->opened);
        return r;
index 5857d4e..9ad45e1 100644 (file)
@@ -1290,6 +1290,11 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
                         vring_used_t __user *used)
 
 {
+       /* If an IOTLB device is present, the vring addresses are
+        * GIOVAs. Access validation occurs at prefetch time. */
+       if (vq->iotlb)
+               return true;
+
        return access_ok(desc, vhost_get_desc_size(vq, num)) &&
               access_ok(avail, vhost_get_avail_size(vq, num)) &&
               access_ok(used, vhost_get_used_size(vq, num));
@@ -1365,6 +1370,20 @@ bool vhost_log_access_ok(struct vhost_dev *dev)
 }
 EXPORT_SYMBOL_GPL(vhost_log_access_ok);
 
+static bool vq_log_used_access_ok(struct vhost_virtqueue *vq,
+                                 void __user *log_base,
+                                 bool log_used,
+                                 u64 log_addr)
+{
+       /* If an IOTLB device is present, log_addr is a GIOVA that
+        * will never be logged by log_used(). */
+       if (vq->iotlb)
+               return true;
+
+       return !log_used || log_access_ok(log_base, log_addr,
+                                         vhost_get_used_size(vq, vq->num));
+}
+
 /* Verify access for write logging. */
 /* Caller should have vq mutex and device mutex */
 static bool vq_log_access_ok(struct vhost_virtqueue *vq,
@@ -1372,8 +1391,7 @@ static bool vq_log_access_ok(struct vhost_virtqueue *vq,
 {
        return vq_memory_access_ok(log_base, vq->umem,
                                   vhost_has_feature(vq, VHOST_F_LOG_ALL)) &&
-               (!vq->log_used || log_access_ok(log_base, vq->log_addr,
-                                 vhost_get_used_size(vq, vq->num)));
+               vq_log_used_access_ok(vq, log_base, vq->log_used, vq->log_addr);
 }
 
 /* Can we start vq? */
@@ -1383,10 +1401,6 @@ bool vhost_vq_access_ok(struct vhost_virtqueue *vq)
        if (!vq_log_access_ok(vq, vq->log_base))
                return false;
 
-       /* Access validation occurs at prefetch time with IOTLB */
-       if (vq->iotlb)
-               return true;
-
        return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used);
 }
 EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
@@ -1516,10 +1530,9 @@ static long vhost_vring_set_addr(struct vhost_dev *d,
                        return -EINVAL;
 
                /* Also validate log access for used ring if enabled. */
-               if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
-                       !log_access_ok(vq->log_base, a.log_guest_addr,
-                               sizeof *vq->used +
-                               vq->num * sizeof *vq->used->ring))
+               if (!vq_log_used_access_ok(vq, vq->log_base,
+                               a.flags & (0x1 << VHOST_VRING_F_LOG),
+                               a.log_guest_addr))
                        return -EINVAL;
        }
 
@@ -2537,7 +2550,7 @@ void vhost_disable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
        if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
                r = vhost_update_used_flags(vq);
                if (r)
-                       vq_err(vq, "Failed to enable notification at %p: %d\n",
+                       vq_err(vq, "Failed to disable notification at %p: %d\n",
                               &vq->used->flags, r);
        }
 }
index ddc7f5f..8ec1942 100644 (file)
@@ -681,7 +681,7 @@ static int adp8860_probe(struct i2c_client *client,
        switch (ADP8860_MANID(reg_val)) {
        case ADP8863_MANUFID:
                data->gdwn_dis = !!pdata->gdwn_dis;
-               /* fall through */
+               fallthrough;
        case ADP8860_MANUFID:
                data->en_ambl_sens = !!pdata->en_ambl_sens;
                break;
index 5e850cc..39deb22 100644 (file)
@@ -22,52 +22,6 @@ config VGA_CONSOLE
 
          Say Y.
 
-config VGACON_SOFT_SCROLLBACK
-       bool "Enable Scrollback Buffer in System RAM"
-       depends on VGA_CONSOLE
-       default n
-       help
-        The scrollback buffer of the standard VGA console is located in
-        the VGA RAM.  The size of this RAM is fixed and is quite small.
-        If you require a larger scrollback buffer, this can be placed in
-        System RAM which is dynamically allocated during initialization.
-        Placing the scrollback buffer in System RAM will slightly slow
-        down the console.
-
-        If you want this feature, say 'Y' here and enter the amount of
-        RAM to allocate for this buffer.  If unsure, say 'N'.
-
-config VGACON_SOFT_SCROLLBACK_SIZE
-       int "Scrollback Buffer Size (in KB)"
-       depends on VGACON_SOFT_SCROLLBACK
-       range 1 1024
-       default "64"
-       help
-         Enter the amount of System RAM to allocate for scrollback
-         buffers of VGA consoles. Each 64KB will give you approximately
-         16 80x25 screenfuls of scrollback buffer.
-
-config VGACON_SOFT_SCROLLBACK_PERSISTENT_ENABLE_BY_DEFAULT
-       bool "Persistent Scrollback History for each console by default"
-       depends on VGACON_SOFT_SCROLLBACK
-       default n
-       help
-         Say Y here if the scrollback history should persist by default when
-         switching between consoles. Otherwise, the scrollback history will be
-         flushed each time the console is switched. This feature can also be
-         enabled using the boot command line parameter
-         'vgacon.scrollback_persistent=1'.
-
-         This feature might break your tool of choice to flush the scrollback
-         buffer, e.g. clear(1) will work fine but Debian's clear_console(1)
-         will be broken, which might cause security issues.
-         You can use the escape sequence \e[3J instead if this feature is
-         activated.
-
-         Note that a buffer of VGACON_SOFT_SCROLLBACK_SIZE is taken for each
-         created tty device.
-         So if you use a RAM-constrained system, say N here.
-
 config MDA_CONSOLE
        depends on !M68K && !PARISC && ISA
        tristate "MDA text console (dual-headed)"
index 72f146d..cd51b7a 100644 (file)
 
 #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
 
-/* borrowed from fbcon.c */
-#define REFCOUNT(fd)   (((int *)(fd))[-1])
-#define FNTSIZE(fd)    (((int *)(fd))[-2])
-#define FNTCHARCNT(fd) (((int *)(fd))[-3])
-#define FONT_EXTRA_WORDS 3
-
 static unsigned char *font_data[MAX_NR_CONSOLES];
 
 static struct newport_regs *npregs;
@@ -522,6 +516,7 @@ static int newport_set_font(int unit, struct console_font *op)
        FNTSIZE(new_data) = size;
        FNTCHARCNT(new_data) = op->charcount;
        REFCOUNT(new_data) = 0; /* usage counter */
+       FNTSUM(new_data) = 0;
 
        p = new_data;
        for (i = 0; i < op->charcount; i++) {
index a52bb37..17876f0 100644 (file)
@@ -165,214 +165,6 @@ static inline void vga_set_mem_top(struct vc_data *c)
        write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
 }
 
-#ifdef CONFIG_VGACON_SOFT_SCROLLBACK
-/* software scrollback */
-struct vgacon_scrollback_info {
-       void *data;
-       int tail;
-       int size;
-       int rows;
-       int cnt;
-       int cur;
-       int save;
-       int restore;
-};
-
-static struct vgacon_scrollback_info *vgacon_scrollback_cur;
-static struct vgacon_scrollback_info vgacon_scrollbacks[MAX_NR_CONSOLES];
-static bool scrollback_persistent = \
-       IS_ENABLED(CONFIG_VGACON_SOFT_SCROLLBACK_PERSISTENT_ENABLE_BY_DEFAULT);
-module_param_named(scrollback_persistent, scrollback_persistent, bool, 0000);
-MODULE_PARM_DESC(scrollback_persistent, "Enable persistent scrollback for all vga consoles");
-
-static void vgacon_scrollback_reset(int vc_num, size_t reset_size)
-{
-       struct vgacon_scrollback_info *scrollback = &vgacon_scrollbacks[vc_num];
-
-       if (scrollback->data && reset_size > 0)
-               memset(scrollback->data, 0, reset_size);
-
-       scrollback->cnt  = 0;
-       scrollback->tail = 0;
-       scrollback->cur  = 0;
-}
-
-static void vgacon_scrollback_init(int vc_num)
-{
-       int pitch = vga_video_num_columns * 2;
-       size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024;
-       int rows = size / pitch;
-       void *data;
-
-       data = kmalloc_array(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024,
-                            GFP_NOWAIT);
-
-       vgacon_scrollbacks[vc_num].data = data;
-       vgacon_scrollback_cur = &vgacon_scrollbacks[vc_num];
-
-       vgacon_scrollback_cur->rows = rows - 1;
-       vgacon_scrollback_cur->size = rows * pitch;
-
-       vgacon_scrollback_reset(vc_num, size);
-}
-
-static void vgacon_scrollback_switch(int vc_num)
-{
-       if (!scrollback_persistent)
-               vc_num = 0;
-
-       if (!vgacon_scrollbacks[vc_num].data) {
-               vgacon_scrollback_init(vc_num);
-       } else {
-               if (scrollback_persistent) {
-                       vgacon_scrollback_cur = &vgacon_scrollbacks[vc_num];
-               } else {
-                       size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024;
-
-                       vgacon_scrollback_reset(vc_num, size);
-               }
-       }
-}
-
-static void vgacon_scrollback_startup(void)
-{
-       vgacon_scrollback_cur = &vgacon_scrollbacks[0];
-       vgacon_scrollback_init(0);
-}
-
-static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
-{
-       void *p;
-
-       if (!vgacon_scrollback_cur->data || !vgacon_scrollback_cur->size ||
-           c->vc_num != fg_console)
-               return;
-
-       p = (void *) (c->vc_origin + t * c->vc_size_row);
-
-       while (count--) {
-               if ((vgacon_scrollback_cur->tail + c->vc_size_row) >
-                   vgacon_scrollback_cur->size)
-                       vgacon_scrollback_cur->tail = 0;
-
-               scr_memcpyw(vgacon_scrollback_cur->data +
-                           vgacon_scrollback_cur->tail,
-                           p, c->vc_size_row);
-
-               vgacon_scrollback_cur->cnt++;
-               p += c->vc_size_row;
-               vgacon_scrollback_cur->tail += c->vc_size_row;
-
-               if (vgacon_scrollback_cur->tail >= vgacon_scrollback_cur->size)
-                       vgacon_scrollback_cur->tail = 0;
-
-               if (vgacon_scrollback_cur->cnt > vgacon_scrollback_cur->rows)
-                       vgacon_scrollback_cur->cnt = vgacon_scrollback_cur->rows;
-
-               vgacon_scrollback_cur->cur = vgacon_scrollback_cur->cnt;
-       }
-}
-
-static void vgacon_restore_screen(struct vc_data *c)
-{
-       c->vc_origin = c->vc_visible_origin;
-       vgacon_scrollback_cur->save = 0;
-
-       if (!vga_is_gfx && !vgacon_scrollback_cur->restore) {
-               scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
-                           c->vc_screenbuf_size > vga_vram_size ?
-                           vga_vram_size : c->vc_screenbuf_size);
-               vgacon_scrollback_cur->restore = 1;
-               vgacon_scrollback_cur->cur = vgacon_scrollback_cur->cnt;
-       }
-}
-
-static void vgacon_scrolldelta(struct vc_data *c, int lines)
-{
-       int start, end, count, soff;
-
-       if (!lines) {
-               vgacon_restore_screen(c);
-               return;
-       }
-
-       if (!vgacon_scrollback_cur->data)
-               return;
-
-       if (!vgacon_scrollback_cur->save) {
-               vgacon_cursor(c, CM_ERASE);
-               vgacon_save_screen(c);
-               c->vc_origin = (unsigned long)c->vc_screenbuf;
-               vgacon_scrollback_cur->save = 1;
-       }
-
-       vgacon_scrollback_cur->restore = 0;
-       start = vgacon_scrollback_cur->cur + lines;
-       end = start + abs(lines);
-
-       if (start < 0)
-               start = 0;
-
-       if (start > vgacon_scrollback_cur->cnt)
-               start = vgacon_scrollback_cur->cnt;
-
-       if (end < 0)
-               end = 0;
-
-       if (end > vgacon_scrollback_cur->cnt)
-               end = vgacon_scrollback_cur->cnt;
-
-       vgacon_scrollback_cur->cur = start;
-       count = end - start;
-       soff = vgacon_scrollback_cur->tail -
-               ((vgacon_scrollback_cur->cnt - end) * c->vc_size_row);
-       soff -= count * c->vc_size_row;
-
-       if (soff < 0)
-               soff += vgacon_scrollback_cur->size;
-
-       count = vgacon_scrollback_cur->cnt - start;
-
-       if (count > c->vc_rows)
-               count = c->vc_rows;
-
-       if (count) {
-               int copysize;
-
-               int diff = c->vc_rows - count;
-               void *d = (void *) c->vc_visible_origin;
-               void *s = (void *) c->vc_screenbuf;
-
-               count *= c->vc_size_row;
-               /* how much memory to end of buffer left? */
-               copysize = min(count, vgacon_scrollback_cur->size - soff);
-               scr_memcpyw(d, vgacon_scrollback_cur->data + soff, copysize);
-               d += copysize;
-               count -= copysize;
-
-               if (count) {
-                       scr_memcpyw(d, vgacon_scrollback_cur->data, count);
-                       d += count;
-               }
-
-               if (diff)
-                       scr_memcpyw(d, s, diff * c->vc_size_row);
-       } else
-               vgacon_cursor(c, CM_MOVE);
-}
-
-static void vgacon_flush_scrollback(struct vc_data *c)
-{
-       size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024;
-
-       vgacon_scrollback_reset(c->vc_num, size);
-}
-#else
-#define vgacon_scrollback_startup(...) do { } while (0)
-#define vgacon_scrollback_init(...)    do { } while (0)
-#define vgacon_scrollback_update(...)  do { } while (0)
-#define vgacon_scrollback_switch(...)  do { } while (0)
-
 static void vgacon_restore_screen(struct vc_data *c)
 {
        if (c->vc_origin != c->vc_visible_origin)
@@ -386,11 +178,6 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines)
        vga_set_mem_top(c);
 }
 
-static void vgacon_flush_scrollback(struct vc_data *c)
-{
-}
-#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
-
 static const char *vgacon_startup(void)
 {
        const char *display_desc = NULL;
@@ -573,10 +360,7 @@ static const char *vgacon_startup(void)
        vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
        vgacon_yres = vga_scan_lines;
 
-       if (!vga_init_done) {
-               vgacon_scrollback_startup();
-               vga_init_done = true;
-       }
+       vga_init_done = true;
 
        return display_desc;
 }
@@ -869,7 +653,6 @@ static int vgacon_switch(struct vc_data *c)
                        vgacon_doresize(c, c->vc_cols, c->vc_rows);
        }
 
-       vgacon_scrollback_switch(c->vc_num);
        return 0;               /* Redrawing not needed */
 }
 
@@ -1386,7 +1169,6 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
        oldo = c->vc_origin;
        delta = lines * c->vc_size_row;
        if (dir == SM_UP) {
-               vgacon_scrollback_update(c, t, lines);
                if (c->vc_scr_end + delta >= vga_vram_end) {
                        scr_memcpyw((u16 *) vga_vram_base,
                                    (u16 *) (oldo + delta),
@@ -1450,7 +1232,6 @@ const struct consw vga_con = {
        .con_save_screen = vgacon_save_screen,
        .con_build_attr = vgacon_build_attr,
        .con_invert_region = vgacon_invert_region,
-       .con_flush_scrollback = vgacon_flush_scrollback,
 };
 EXPORT_SYMBOL(vga_con);
 
index b2c9dd4..402e854 100644 (file)
@@ -272,6 +272,26 @@ config FB_PM2_FIFO_DISCONNECT
        help
          Support the Permedia2 FIFO disconnect feature.
 
+config FB_ARMCLCD
+       tristate "ARM PrimeCell PL110 support"
+       depends on ARM || ARM64 || COMPILE_TEST
+       depends on FB && ARM_AMBA && HAS_IOMEM
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       select FB_MODE_HELPERS if OF
+       select VIDEOMODE_HELPERS if OF
+       select BACKLIGHT_CLASS_DEVICE if OF
+       help
+         This framebuffer device driver is for the ARM PrimeCell PL110
+         Colour LCD controller.  ARM PrimeCells provide the building
+         blocks for System on a Chip devices.
+
+         If you want to compile this as a module (=code which can be
+         inserted into and removed from the running kernel), say M
+         here and read <file:Documentation/kbuild/modules.rst>.  The module
+         will be called amba-clcd.
+
 config FB_ACORN
        bool "Acorn VIDC support"
        depends on (FB = y) && ARM && ARCH_ACORN
index cad4fb6..a0705b9 100644 (file)
@@ -75,6 +75,7 @@ obj-$(CONFIG_FB_HIT)              += hitfb.o
 obj-$(CONFIG_FB_ATMEL)           += atmel_lcdfb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
+obj-$(CONFIG_FB_ARMCLCD)         += amba-clcd.o
 obj-$(CONFIG_FB_GOLDFISH)         += goldfishfb.o
 obj-$(CONFIG_FB_68328)            += 68328fb.o
 obj-$(CONFIG_FB_GBE)              += gbefb.o
index 09a9ad9..bcc92ae 100644 (file)
@@ -857,7 +857,7 @@ static void acornfb_parse_dram(char *opt)
                case 'M':
                case 'm':
                        size *= 1024;
-                       /* Fall through */
+                       fallthrough;
                case 'K':
                case 'k':
                        size *= 1024;
diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c
new file mode 100644 (file)
index 0000000..b7682de
--- /dev/null
@@ -0,0 +1,986 @@
+/*
+ *  linux/drivers/video/amba-clcd.c
+ *
+ * Copyright (C) 2001 ARM Limited, by David A Rusling
+ * Updated to 2.5, Deep Blue Solutions Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ *  ARM PrimeCell PL110 Color LCD Controller
+ */
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/backlight.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <video/display_timing.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
+
+#define to_clcd(info)  container_of(info, struct clcd_fb, fb)
+
+/* This is limited to 16 characters when displayed by X startup */
+static const char *clcd_name = "CLCD FB";
+
+/*
+ * Unfortunately, the enable/disable functions may be called either from
+ * process or IRQ context, and we _need_ to delay.  This is _not_ good.
+ */
+static inline void clcdfb_sleep(unsigned int ms)
+{
+       if (in_atomic()) {
+               mdelay(ms);
+       } else {
+               msleep(ms);
+       }
+}
+
+static inline void clcdfb_set_start(struct clcd_fb *fb)
+{
+       unsigned long ustart = fb->fb.fix.smem_start;
+       unsigned long lstart;
+
+       ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
+       lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
+
+       writel(ustart, fb->regs + CLCD_UBAS);
+       writel(lstart, fb->regs + CLCD_LBAS);
+}
+
+static void clcdfb_disable(struct clcd_fb *fb)
+{
+       u32 val;
+
+       if (fb->board->disable)
+               fb->board->disable(fb);
+
+       if (fb->panel->backlight) {
+               fb->panel->backlight->props.power = FB_BLANK_POWERDOWN;
+               backlight_update_status(fb->panel->backlight);
+       }
+
+       val = readl(fb->regs + fb->off_cntl);
+       if (val & CNTL_LCDPWR) {
+               val &= ~CNTL_LCDPWR;
+               writel(val, fb->regs + fb->off_cntl);
+
+               clcdfb_sleep(20);
+       }
+       if (val & CNTL_LCDEN) {
+               val &= ~CNTL_LCDEN;
+               writel(val, fb->regs + fb->off_cntl);
+       }
+
+       /*
+        * Disable CLCD clock source.
+        */
+       if (fb->clk_enabled) {
+               fb->clk_enabled = false;
+               clk_disable(fb->clk);
+       }
+}
+
+static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
+{
+       /*
+        * Enable the CLCD clock source.
+        */
+       if (!fb->clk_enabled) {
+               fb->clk_enabled = true;
+               clk_enable(fb->clk);
+       }
+
+       /*
+        * Bring up by first enabling..
+        */
+       cntl |= CNTL_LCDEN;
+       writel(cntl, fb->regs + fb->off_cntl);
+
+       clcdfb_sleep(20);
+
+       /*
+        * and now apply power.
+        */
+       cntl |= CNTL_LCDPWR;
+       writel(cntl, fb->regs + fb->off_cntl);
+
+       /*
+        * Turn on backlight
+        */
+       if (fb->panel->backlight) {
+               fb->panel->backlight->props.power = FB_BLANK_UNBLANK;
+               backlight_update_status(fb->panel->backlight);
+       }
+
+       /*
+        * finally, enable the interface.
+        */
+       if (fb->board->enable)
+               fb->board->enable(fb);
+}
+
+static int
+clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
+{
+       u32 caps;
+       int ret = 0;
+
+       if (fb->panel->caps && fb->board->caps)
+               caps = fb->panel->caps & fb->board->caps;
+       else {
+               /* Old way of specifying what can be used */
+               caps = fb->panel->cntl & CNTL_BGR ?
+                       CLCD_CAP_BGR : CLCD_CAP_RGB;
+               /* But mask out 444 modes as they weren't supported */
+               caps &= ~CLCD_CAP_444;
+       }
+
+       /* Only TFT panels can do RGB888/BGR888 */
+       if (!(fb->panel->cntl & CNTL_LCDTFT))
+               caps &= ~CLCD_CAP_888;
+
+       memset(&var->transp, 0, sizeof(var->transp));
+
+       var->red.msb_right = 0;
+       var->green.msb_right = 0;
+       var->blue.msb_right = 0;
+
+       switch (var->bits_per_pixel) {
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               /* If we can't do 5551, reject */
+               caps &= CLCD_CAP_5551;
+               if (!caps) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               var->red.length         = var->bits_per_pixel;
+               var->red.offset         = 0;
+               var->green.length       = var->bits_per_pixel;
+               var->green.offset       = 0;
+               var->blue.length        = var->bits_per_pixel;
+               var->blue.offset        = 0;
+               break;
+
+       case 16:
+               /* If we can't do 444, 5551 or 565, reject */
+               if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               /*
+                * Green length can be 4, 5 or 6 depending whether
+                * we're operating in 444, 5551 or 565 mode.
+                */
+               if (var->green.length == 4 && caps & CLCD_CAP_444)
+                       caps &= CLCD_CAP_444;
+               if (var->green.length == 5 && caps & CLCD_CAP_5551)
+                       caps &= CLCD_CAP_5551;
+               else if (var->green.length == 6 && caps & CLCD_CAP_565)
+                       caps &= CLCD_CAP_565;
+               else {
+                       /*
+                        * PL110 officially only supports RGB555,
+                        * but may be wired up to allow RGB565.
+                        */
+                       if (caps & CLCD_CAP_565) {
+                               var->green.length = 6;
+                               caps &= CLCD_CAP_565;
+                       } else if (caps & CLCD_CAP_5551) {
+                               var->green.length = 5;
+                               caps &= CLCD_CAP_5551;
+                       } else {
+                               var->green.length = 4;
+                               caps &= CLCD_CAP_444;
+                       }
+               }
+
+               if (var->green.length >= 5) {
+                       var->red.length = 5;
+                       var->blue.length = 5;
+               } else {
+                       var->red.length = 4;
+                       var->blue.length = 4;
+               }
+               break;
+       case 32:
+               /* If we can't do 888, reject */
+               caps &= CLCD_CAP_888;
+               if (!caps) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       /*
+        * >= 16bpp displays have separate colour component bitfields
+        * encoded in the pixel data.  Calculate their position from
+        * the bitfield length defined above.
+        */
+       if (ret == 0 && var->bits_per_pixel >= 16) {
+               bool bgr, rgb;
+
+               bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0;
+               rgb = caps & CLCD_CAP_RGB && var->red.offset == 0;
+
+               if (!bgr && !rgb)
+                       /*
+                        * The requested format was not possible, try just
+                        * our capabilities.  One of BGR or RGB must be
+                        * supported.
+                        */
+                       bgr = caps & CLCD_CAP_BGR;
+
+               if (bgr) {
+                       var->blue.offset = 0;
+                       var->green.offset = var->blue.offset + var->blue.length;
+                       var->red.offset = var->green.offset + var->green.length;
+               } else {
+                       var->red.offset = 0;
+                       var->green.offset = var->red.offset + var->red.length;
+                       var->blue.offset = var->green.offset + var->green.length;
+               }
+       }
+
+       return ret;
+}
+
+static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct clcd_fb *fb = to_clcd(info);
+       int ret = -EINVAL;
+
+       if (fb->board->check)
+               ret = fb->board->check(fb, var);
+
+       if (ret == 0 &&
+           var->xres_virtual * var->bits_per_pixel / 8 *
+           var->yres_virtual > fb->fb.fix.smem_len)
+               ret = -EINVAL;
+
+       if (ret == 0)
+               ret = clcdfb_set_bitfields(fb, var);
+
+       return ret;
+}
+
+static int clcdfb_set_par(struct fb_info *info)
+{
+       struct clcd_fb *fb = to_clcd(info);
+       struct clcd_regs regs;
+
+       fb->fb.fix.line_length = fb->fb.var.xres_virtual *
+                                fb->fb.var.bits_per_pixel / 8;
+
+       if (fb->fb.var.bits_per_pixel <= 8)
+               fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+       else
+               fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+
+       fb->board->decode(fb, &regs);
+
+       clcdfb_disable(fb);
+
+       writel(regs.tim0, fb->regs + CLCD_TIM0);
+       writel(regs.tim1, fb->regs + CLCD_TIM1);
+       writel(regs.tim2, fb->regs + CLCD_TIM2);
+       writel(regs.tim3, fb->regs + CLCD_TIM3);
+
+       clcdfb_set_start(fb);
+
+       clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
+
+       fb->clcd_cntl = regs.cntl;
+
+       clcdfb_enable(fb, regs.cntl);
+
+#ifdef DEBUG
+       printk(KERN_INFO
+              "CLCD: Registers set to\n"
+              "  %08x %08x %08x %08x\n"
+              "  %08x %08x %08x %08x\n",
+               readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
+               readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
+               readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
+               readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl));
+#endif
+
+       return 0;
+}
+
+static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
+{
+       unsigned int mask = (1 << bf->length) - 1;
+
+       return (val >> (16 - bf->length) & mask) << bf->offset;
+}
+
+/*
+ *  Set a single color register. The values supplied have a 16 bit
+ *  magnitude.  Return != 0 for invalid regno.
+ */
+static int
+clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
+                unsigned int blue, unsigned int transp, struct fb_info *info)
+{
+       struct clcd_fb *fb = to_clcd(info);
+
+       if (regno < 16)
+               fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
+                                 convert_bitfield(blue, &fb->fb.var.blue) |
+                                 convert_bitfield(green, &fb->fb.var.green) |
+                                 convert_bitfield(red, &fb->fb.var.red);
+
+       if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
+               int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
+               u32 val, mask, newval;
+
+               newval  = (red >> 11)  & 0x001f;
+               newval |= (green >> 6) & 0x03e0;
+               newval |= (blue >> 1)  & 0x7c00;
+
+               /*
+                * 3.2.11: if we're configured for big endian
+                * byte order, the palette entries are swapped.
+                */
+               if (fb->clcd_cntl & CNTL_BEBO)
+                       regno ^= 1;
+
+               if (regno & 1) {
+                       newval <<= 16;
+                       mask = 0x0000ffff;
+               } else {
+                       mask = 0xffff0000;
+               }
+
+               val = readl(fb->regs + hw_reg) & mask;
+               writel(val | newval, fb->regs + hw_reg);
+       }
+
+       return regno > 255;
+}
+
+/*
+ *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+ *  and powerdown modes on hardware that supports disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ */
+static int clcdfb_blank(int blank_mode, struct fb_info *info)
+{
+       struct clcd_fb *fb = to_clcd(info);
+
+       if (blank_mode != 0) {
+               clcdfb_disable(fb);
+       } else {
+               clcdfb_enable(fb, fb->clcd_cntl);
+       }
+       return 0;
+}
+
+static int clcdfb_mmap(struct fb_info *info,
+                      struct vm_area_struct *vma)
+{
+       struct clcd_fb *fb = to_clcd(info);
+       unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
+       int ret = -EINVAL;
+
+       len = info->fix.smem_len;
+
+       if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
+           fb->board->mmap)
+               ret = fb->board->mmap(fb, vma);
+
+       return ret;
+}
+
+static const struct fb_ops clcdfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = clcdfb_check_var,
+       .fb_set_par     = clcdfb_set_par,
+       .fb_setcolreg   = clcdfb_setcolreg,
+       .fb_blank       = clcdfb_blank,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+       .fb_mmap        = clcdfb_mmap,
+};
+
+static int clcdfb_register(struct clcd_fb *fb)
+{
+       int ret;
+
+       /*
+        * ARM PL111 always has IENB at 0x1c; it's only PL110
+        * which is reversed on some platforms.
+        */
+       if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) {
+               fb->off_ienb = CLCD_PL111_IENB;
+               fb->off_cntl = CLCD_PL111_CNTL;
+       } else {
+               fb->off_ienb = CLCD_PL110_IENB;
+               fb->off_cntl = CLCD_PL110_CNTL;
+       }
+
+       fb->clk = clk_get(&fb->dev->dev, NULL);
+       if (IS_ERR(fb->clk)) {
+               ret = PTR_ERR(fb->clk);
+               goto out;
+       }
+
+       ret = clk_prepare(fb->clk);
+       if (ret)
+               goto free_clk;
+
+       fb->fb.device           = &fb->dev->dev;
+
+       fb->fb.fix.mmio_start   = fb->dev->res.start;
+       fb->fb.fix.mmio_len     = resource_size(&fb->dev->res);
+
+       fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
+       if (!fb->regs) {
+               printk(KERN_ERR "CLCD: unable to remap registers\n");
+               ret = -ENOMEM;
+               goto clk_unprep;
+       }
+
+       fb->fb.fbops            = &clcdfb_ops;
+       fb->fb.flags            = FBINFO_FLAG_DEFAULT;
+       fb->fb.pseudo_palette   = fb->cmap;
+
+       strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
+       fb->fb.fix.type         = FB_TYPE_PACKED_PIXELS;
+       fb->fb.fix.type_aux     = 0;
+       fb->fb.fix.xpanstep     = 0;
+       fb->fb.fix.ypanstep     = 0;
+       fb->fb.fix.ywrapstep    = 0;
+       fb->fb.fix.accel        = FB_ACCEL_NONE;
+
+       fb->fb.var.xres         = fb->panel->mode.xres;
+       fb->fb.var.yres         = fb->panel->mode.yres;
+       fb->fb.var.xres_virtual = fb->panel->mode.xres;
+       fb->fb.var.yres_virtual = fb->panel->mode.yres;
+       fb->fb.var.bits_per_pixel = fb->panel->bpp;
+       fb->fb.var.grayscale    = fb->panel->grayscale;
+       fb->fb.var.pixclock     = fb->panel->mode.pixclock;
+       fb->fb.var.left_margin  = fb->panel->mode.left_margin;
+       fb->fb.var.right_margin = fb->panel->mode.right_margin;
+       fb->fb.var.upper_margin = fb->panel->mode.upper_margin;
+       fb->fb.var.lower_margin = fb->panel->mode.lower_margin;
+       fb->fb.var.hsync_len    = fb->panel->mode.hsync_len;
+       fb->fb.var.vsync_len    = fb->panel->mode.vsync_len;
+       fb->fb.var.sync         = fb->panel->mode.sync;
+       fb->fb.var.vmode        = fb->panel->mode.vmode;
+       fb->fb.var.activate     = FB_ACTIVATE_NOW;
+       fb->fb.var.nonstd       = 0;
+       fb->fb.var.height       = fb->panel->height;
+       fb->fb.var.width        = fb->panel->width;
+       fb->fb.var.accel_flags  = 0;
+
+       fb->fb.monspecs.hfmin   = 0;
+       fb->fb.monspecs.hfmax   = 100000;
+       fb->fb.monspecs.vfmin   = 0;
+       fb->fb.monspecs.vfmax   = 400;
+       fb->fb.monspecs.dclkmin = 1000000;
+       fb->fb.monspecs.dclkmax = 100000000;
+
+       /*
+        * Make sure that the bitfields are set appropriately.
+        */
+       clcdfb_set_bitfields(fb, &fb->fb.var);
+
+       /*
+        * Allocate colourmap.
+        */
+       ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
+       if (ret)
+               goto unmap;
+
+       /*
+        * Ensure interrupts are disabled.
+        */
+       writel(0, fb->regs + fb->off_ienb);
+
+       fb_set_var(&fb->fb, &fb->fb.var);
+
+       dev_info(&fb->dev->dev, "%s hardware, %s display\n",
+                fb->board->name, fb->panel->mode.name);
+
+       ret = register_framebuffer(&fb->fb);
+       if (ret == 0)
+               goto out;
+
+       printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
+
+       fb_dealloc_cmap(&fb->fb.cmap);
+ unmap:
+       iounmap(fb->regs);
+ clk_unprep:
+       clk_unprepare(fb->clk);
+ free_clk:
+       clk_put(fb->clk);
+ out:
+       return ret;
+}
+
+#ifdef CONFIG_OF
+static int clcdfb_of_get_dpi_panel_mode(struct device_node *node,
+               struct clcd_panel *clcd_panel)
+{
+       int err;
+       struct display_timing timing;
+       struct videomode video;
+
+       err = of_get_display_timing(node, "panel-timing", &timing);
+       if (err) {
+               pr_err("%pOF: problems parsing panel-timing (%d)\n", node, err);
+               return err;
+       }
+
+       videomode_from_timing(&timing, &video);
+
+       err = fb_videomode_from_videomode(&video, &clcd_panel->mode);
+       if (err)
+               return err;
+
+       /* Set up some inversion flags */
+       if (timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+               clcd_panel->tim2 |= TIM2_IPC;
+       else if (!(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE))
+               /*
+                * To preserve backwards compatibility, the IPC (inverted
+                * pixel clock) flag needs to be set on any display that
+                * doesn't explicitly specify that the pixel clock is
+                * active on the negative or positive edge.
+                */
+               clcd_panel->tim2 |= TIM2_IPC;
+
+       if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
+               clcd_panel->tim2 |= TIM2_IHS;
+
+       if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
+               clcd_panel->tim2 |= TIM2_IVS;
+
+       if (timing.flags & DISPLAY_FLAGS_DE_LOW)
+               clcd_panel->tim2 |= TIM2_IOE;
+
+       return 0;
+}
+
+static int clcdfb_snprintf_mode(char *buf, int size, struct fb_videomode *mode)
+{
+       return snprintf(buf, size, "%ux%u@%u", mode->xres, mode->yres,
+                       mode->refresh);
+}
+
+static int clcdfb_of_get_backlight(struct device *dev,
+                                  struct clcd_panel *clcd_panel)
+{
+       struct backlight_device *backlight;
+
+       /* Look up the optional backlight device */
+       backlight = devm_of_find_backlight(dev);
+       if (IS_ERR(backlight))
+               return PTR_ERR(backlight);
+
+       clcd_panel->backlight = backlight;
+       return 0;
+}
+
+static int clcdfb_of_get_mode(struct device *dev, struct device_node *panel,
+                             struct clcd_panel *clcd_panel)
+{
+       int err;
+       struct fb_videomode *mode;
+       char *name;
+       int len;
+
+       /* Only directly connected DPI panels supported for now */
+       if (of_device_is_compatible(panel, "panel-dpi"))
+               err = clcdfb_of_get_dpi_panel_mode(panel, clcd_panel);
+       else
+               err = -ENOENT;
+       if (err)
+               return err;
+       mode = &clcd_panel->mode;
+
+       len = clcdfb_snprintf_mode(NULL, 0, mode);
+       name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
+       clcdfb_snprintf_mode(name, len + 1, mode);
+       mode->name = name;
+
+       return 0;
+}
+
+static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
+{
+       static struct {
+               unsigned int part;
+               u32 r0, g0, b0;
+               u32 caps;
+       } panels[] = {
+               { 0x110, 1,  7, 13, CLCD_CAP_5551 },
+               { 0x110, 0,  8, 16, CLCD_CAP_888 },
+               { 0x110, 16, 8, 0,  CLCD_CAP_888 },
+               { 0x111, 4, 14, 20, CLCD_CAP_444 },
+               { 0x111, 3, 11, 19, CLCD_CAP_444 | CLCD_CAP_5551 },
+               { 0x111, 3, 10, 19, CLCD_CAP_444 | CLCD_CAP_5551 |
+                                   CLCD_CAP_565 },
+               { 0x111, 0,  8, 16, CLCD_CAP_444 | CLCD_CAP_5551 |
+                                   CLCD_CAP_565 | CLCD_CAP_888 },
+       };
+       int i;
+
+       /* Bypass pixel clock divider */
+       fb->panel->tim2 |= TIM2_BCD;
+
+       /* TFT display, vert. comp. interrupt at the start of the back porch */
+       fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
+
+       fb->panel->caps = 0;
+
+       /* Match the setup with known variants */
+       for (i = 0; i < ARRAY_SIZE(panels) && !fb->panel->caps; i++) {
+               if (amba_part(fb->dev) != panels[i].part)
+                       continue;
+               if (g0 != panels[i].g0)
+                       continue;
+               if (r0 == panels[i].r0 && b0 == panels[i].b0)
+                       fb->panel->caps = panels[i].caps;
+       }
+
+       /*
+        * If we actually physically connected the R lines to B and
+        * vice versa
+        */
+       if (r0 != 0 && b0 == 0)
+               fb->panel->bgr_connection = true;
+
+       return fb->panel->caps ? 0 : -EINVAL;
+}
+
+static int clcdfb_of_init_display(struct clcd_fb *fb)
+{
+       struct device_node *endpoint, *panel;
+       int err;
+       unsigned int bpp;
+       u32 max_bandwidth;
+       u32 tft_r0b0g0[3];
+
+       fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL);
+       if (!fb->panel)
+               return -ENOMEM;
+
+       /*
+        * Fetch the panel endpoint.
+        */
+       endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node, NULL);
+       if (!endpoint)
+               return -ENODEV;
+
+       panel = of_graph_get_remote_port_parent(endpoint);
+       if (!panel)
+               return -ENODEV;
+
+       err = clcdfb_of_get_backlight(&fb->dev->dev, fb->panel);
+       if (err)
+               return err;
+
+       err = clcdfb_of_get_mode(&fb->dev->dev, panel, fb->panel);
+       if (err)
+               return err;
+
+       err = of_property_read_u32(fb->dev->dev.of_node, "max-memory-bandwidth",
+                       &max_bandwidth);
+       if (!err) {
+               /*
+                * max_bandwidth is in bytes per second and pixclock in
+                * pico-seconds, so the maximum allowed bits per pixel is
+                *   8 * max_bandwidth / (PICOS2KHZ(pixclock) * 1000)
+                * Rearrange this calculation to avoid overflow and then ensure
+                * result is a valid format.
+                */
+               bpp = max_bandwidth / (1000 / 8)
+                       / PICOS2KHZ(fb->panel->mode.pixclock);
+               bpp = rounddown_pow_of_two(bpp);
+               if (bpp > 32)
+                       bpp = 32;
+       } else
+               bpp = 32;
+       fb->panel->bpp = bpp;
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       fb->panel->cntl |= CNTL_BEBO;
+#endif
+       fb->panel->width = -1;
+       fb->panel->height = -1;
+
+       if (of_property_read_u32_array(endpoint,
+                       "arm,pl11x,tft-r0g0b0-pads",
+                       tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) != 0)
+               return -ENOENT;
+
+       return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0],
+                                       tft_r0b0g0[1],  tft_r0b0g0[2]);
+}
+
+static int clcdfb_of_vram_setup(struct clcd_fb *fb)
+{
+       int err;
+       struct device_node *memory;
+       u64 size;
+
+       err = clcdfb_of_init_display(fb);
+       if (err)
+               return err;
+
+       memory = of_parse_phandle(fb->dev->dev.of_node, "memory-region", 0);
+       if (!memory)
+               return -ENODEV;
+
+       fb->fb.screen_base = of_iomap(memory, 0);
+       if (!fb->fb.screen_base)
+               return -ENOMEM;
+
+       fb->fb.fix.smem_start = of_translate_address(memory,
+                       of_get_address(memory, 0, &size, NULL));
+       fb->fb.fix.smem_len = size;
+
+       return 0;
+}
+
+static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+       unsigned long off, user_size, kernel_size;
+
+
+       off = vma->vm_pgoff << PAGE_SHIFT;
+       user_size = vma->vm_end - vma->vm_start;
+       kernel_size = fb->fb.fix.smem_len;
+
+       if (off >= kernel_size || user_size > (kernel_size - off))
+               return -ENXIO;
+
+       return remap_pfn_range(vma, vma->vm_start,
+                       __phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff,
+                       user_size,
+                       pgprot_writecombine(vma->vm_page_prot));
+}
+
+static void clcdfb_of_vram_remove(struct clcd_fb *fb)
+{
+       iounmap(fb->fb.screen_base);
+}
+
+static int clcdfb_of_dma_setup(struct clcd_fb *fb)
+{
+       unsigned long framesize;
+       dma_addr_t dma;
+       int err;
+
+       err = clcdfb_of_init_display(fb);
+       if (err)
+               return err;
+
+       framesize = PAGE_ALIGN(fb->panel->mode.xres * fb->panel->mode.yres *
+                       fb->panel->bpp / 8);
+       fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize,
+                       &dma, GFP_KERNEL);
+       if (!fb->fb.screen_base)
+               return -ENOMEM;
+
+       fb->fb.fix.smem_start = dma;
+       fb->fb.fix.smem_len = framesize;
+
+       return 0;
+}
+
+static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+       return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
+                          fb->fb.fix.smem_start, fb->fb.fix.smem_len);
+}
+
+static void clcdfb_of_dma_remove(struct clcd_fb *fb)
+{
+       dma_free_coherent(&fb->dev->dev, fb->fb.fix.smem_len,
+                       fb->fb.screen_base, fb->fb.fix.smem_start);
+}
+
+static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
+{
+       struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board),
+                       GFP_KERNEL);
+       struct device_node *node = dev->dev.of_node;
+
+       if (!board)
+               return NULL;
+
+       board->name = of_node_full_name(node);
+       board->caps = CLCD_CAP_ALL;
+       board->check = clcdfb_check;
+       board->decode = clcdfb_decode;
+       if (of_find_property(node, "memory-region", NULL)) {
+               board->setup = clcdfb_of_vram_setup;
+               board->mmap = clcdfb_of_vram_mmap;
+               board->remove = clcdfb_of_vram_remove;
+       } else {
+               board->setup = clcdfb_of_dma_setup;
+               board->mmap = clcdfb_of_dma_mmap;
+               board->remove = clcdfb_of_dma_remove;
+       }
+
+       return board;
+}
+#else
+static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
+{
+       return NULL;
+}
+#endif
+
+static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
+{
+       struct clcd_board *board = dev_get_platdata(&dev->dev);
+       struct clcd_fb *fb;
+       int ret;
+
+       if (!board)
+               board = clcdfb_of_get_board(dev);
+
+       if (!board)
+               return -EINVAL;
+
+       ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
+       if (ret)
+               goto out;
+
+       ret = amba_request_regions(dev, NULL);
+       if (ret) {
+               printk(KERN_ERR "CLCD: unable to reserve regs region\n");
+               goto out;
+       }
+
+       fb = kzalloc(sizeof(*fb), GFP_KERNEL);
+       if (!fb) {
+               ret = -ENOMEM;
+               goto free_region;
+       }
+
+       fb->dev = dev;
+       fb->board = board;
+
+       dev_info(&fb->dev->dev, "PL%03x designer %02x rev%u at 0x%08llx\n",
+               amba_part(dev), amba_manf(dev), amba_rev(dev),
+               (unsigned long long)dev->res.start);
+
+       ret = fb->board->setup(fb);
+       if (ret)
+               goto free_fb;
+
+       ret = clcdfb_register(fb);
+       if (ret == 0) {
+               amba_set_drvdata(dev, fb);
+               goto out;
+       }
+
+       fb->board->remove(fb);
+ free_fb:
+       kfree(fb);
+ free_region:
+       amba_release_regions(dev);
+ out:
+       return ret;
+}
+
+static int clcdfb_remove(struct amba_device *dev)
+{
+       struct clcd_fb *fb = amba_get_drvdata(dev);
+
+       clcdfb_disable(fb);
+       unregister_framebuffer(&fb->fb);
+       if (fb->fb.cmap.len)
+               fb_dealloc_cmap(&fb->fb.cmap);
+       iounmap(fb->regs);
+       clk_unprepare(fb->clk);
+       clk_put(fb->clk);
+
+       fb->board->remove(fb);
+
+       kfree(fb);
+
+       amba_release_regions(dev);
+
+       return 0;
+}
+
+static const struct amba_id clcdfb_id_table[] = {
+       {
+               .id     = 0x00041110,
+               .mask   = 0x000ffffe,
+       },
+       { 0, 0 },
+};
+
+MODULE_DEVICE_TABLE(amba, clcdfb_id_table);
+
+static struct amba_driver clcd_driver = {
+       .drv            = {
+               .name   = "clcd-pl11x",
+       },
+       .probe          = clcdfb_probe,
+       .remove         = clcdfb_remove,
+       .id_table       = clcdfb_id_table,
+};
+
+static int __init amba_clcdfb_init(void)
+{
+       if (fb_get_options("ambafb", NULL))
+               return -ENODEV;
+
+       return amba_driver_register(&clcd_driver);
+}
+
+module_init(amba_clcdfb_init);
+
+static void __exit amba_clcdfb_exit(void)
+{
+       amba_driver_unregister(&clcd_driver);
+}
+
+module_exit(amba_clcdfb_exit);
+
+MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
+MODULE_LICENSE("GPL");
index 6f78389..ae3d8e8 100644 (file)
@@ -419,7 +419,7 @@ static int arcfb_ioctl(struct fb_info *info,
                        schedule();
                        finish_wait(&arcfb_waitq, &wait);
                }
-               /* fall through */
+                       fallthrough;
 
                case FBIO_GETCONTROL2:
                {
index 1e25219..bfd2f00 100644 (file)
@@ -508,7 +508,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
        case 32:
                var->transp.offset = 24;
                var->transp.length = 8;
-               /* fall through */
+               fallthrough;
        case 24:
                if (pdata->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
                        /* RGB:888 mode */
@@ -633,7 +633,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
                case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
                case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
                case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
-               case 15: /* fall through */
+               case 15:
                case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
                case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
                case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
index 7c4483c..f3d8123 100644 (file)
@@ -1208,11 +1208,11 @@ static void radeon_pm_enable_dll_m10(struct radeonfb_info *rinfo)
        case 1:
                if (mc & 0x4)
                        break;
-               /* fall through */
+               fallthrough;
        case 2:
                dll_sleep_mask |= MDLL_R300_RDCK__MRDCKB_SLEEP;
                dll_reset_mask |= MDLL_R300_RDCK__MRDCKB_RESET;
-               /* fall through */
+               fallthrough;
        case 0:
                dll_sleep_mask |= MDLL_R300_RDCK__MRDCKA_SLEEP;
                dll_reset_mask |= MDLL_R300_RDCK__MRDCKA_RESET;
@@ -1221,7 +1221,7 @@ static void radeon_pm_enable_dll_m10(struct radeonfb_info *rinfo)
        case 1:
                if (!(mc & 0x4))
                        break;
-               /* fall through */
+               fallthrough;
        case 2:
                dll_sleep_mask |= MDLL_R300_RDCK__MRDCKD_SLEEP;
                dll_reset_mask |= MDLL_R300_RDCK__MRDCKD_RESET;
index 3df64a9..15a9ee7 100644 (file)
@@ -1476,11 +1476,11 @@ static void init_vgachip(struct fb_info *info)
                mdelay(100);
                /* mode */
                vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
-               /* fall through */
+               fallthrough;
        case BT_GD5480:
                /* from Klaus' NetBSD driver: */
                vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
-               /* fall through */
+               fallthrough;
        case BT_ALPINE:
                /* put blitter into 542x compat */
                vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
index 9c4f1be..2df56bd 100644 (file)
@@ -49,6 +49,8 @@
 #include <linux/cuda.h>
 #ifdef CONFIG_PPC_PMAC
 #include <asm/prom.h>
+#endif
+#ifdef CONFIG_BOOTX_TEXT
 #include <asm/btext.h>
 #endif
 
@@ -713,7 +715,7 @@ static int controlfb_blank(int blank_mode, struct fb_info *info)
                        break;
                case FB_BLANK_POWERDOWN:
                        ctrl &= ~0x33;
-                       /* fall through */
+                       fallthrough;
                case FB_BLANK_NORMAL:
                        ctrl |= 0x400;
                        break;
index 4e6cbc2..9725ecd 100644 (file)
@@ -234,7 +234,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
 }
 
 static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-                      int softback_lines, int fg, int bg)
+                      int fg, int bg)
 {
        struct fb_cursor cursor;
        struct fbcon_ops *ops = info->fbcon_par;
@@ -247,15 +247,6 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
 
        cursor.set = 0;
 
-       if (softback_lines) {
-               if (y + softback_lines >= vc->vc_rows) {
-                       mode = CM_ERASE;
-                       ops->cursor_flash = 0;
-                       return;
-               } else
-                       y += softback_lines;
-       }
-
        c = scr_readw((u16 *) vc->vc_pos);
        attribute = get_attribute(info, c);
        src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
index 8a31fc2..8c7bd0a 100644 (file)
@@ -122,12 +122,6 @@ static int logo_lines;
 /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
    enums.  */
 static int logo_shown = FBCON_LOGO_CANSHOW;
-/* Software scrollback */
-static int fbcon_softback_size = 32768;
-static unsigned long softback_buf, softback_curr;
-static unsigned long softback_in;
-static unsigned long softback_top, softback_end;
-static int softback_lines;
 /* console mappings */
 static int first_fb_vc;
 static int last_fb_vc = MAX_NR_CONSOLES - 1;
@@ -167,8 +161,6 @@ static int margin_color;
 
 static const struct consw fb_con;
 
-#define CM_SOFTBACK    (8)
-
 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
 
 static int fbcon_set_origin(struct vc_data *);
@@ -373,18 +365,6 @@ static int get_color(struct vc_data *vc, struct fb_info *info,
        return color;
 }
 
-static void fbcon_update_softback(struct vc_data *vc)
-{
-       int l = fbcon_softback_size / vc->vc_size_row;
-
-       if (l > 5)
-               softback_end = softback_buf + l * vc->vc_size_row;
-       else
-               /* Smaller scrollback makes no sense, and 0 would screw
-                  the operation totally */
-               softback_top = 0;
-}
-
 static void fb_flashcursor(struct work_struct *work)
 {
        struct fb_info *info = container_of(work, struct fb_info, queue);
@@ -414,7 +394,7 @@ static void fb_flashcursor(struct work_struct *work)
        c = scr_readw((u16 *) vc->vc_pos);
        mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
                CM_ERASE : CM_DRAW;
-       ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
+       ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
        console_unlock();
 }
@@ -471,13 +451,7 @@ static int __init fb_console_setup(char *this_opt)
                }
                
                if (!strncmp(options, "scrollback:", 11)) {
-                       options += 11;
-                       if (*options) {
-                               fbcon_softback_size = simple_strtoul(options, &options, 0);
-                               if (*options == 'k' || *options == 'K') {
-                                       fbcon_softback_size *= 1024;
-                               }
-                       }
+                       pr_warn("Ignoring scrollback size option\n");
                        continue;
                }
                
@@ -1022,31 +996,6 @@ static const char *fbcon_startup(void)
 
        set_blitting_type(vc, info);
 
-       if (info->fix.type != FB_TYPE_TEXT) {
-               if (fbcon_softback_size) {
-                       if (!softback_buf) {
-                               softback_buf =
-                                   (unsigned long)
-                                   kvmalloc(fbcon_softback_size,
-                                           GFP_KERNEL);
-                               if (!softback_buf) {
-                                       fbcon_softback_size = 0;
-                                       softback_top = 0;
-                               }
-                       }
-               } else {
-                       if (softback_buf) {
-                               kvfree((void *) softback_buf);
-                               softback_buf = 0;
-                               softback_top = 0;
-                       }
-               }
-               if (softback_buf)
-                       softback_in = softback_top = softback_curr =
-                           softback_buf;
-               softback_lines = 0;
-       }
-
        /* Setup default font */
        if (!p->fontdata && !vc->vc_font.data) {
                if (!fontname[0] || !(font = find_font(fontname)))
@@ -1220,9 +1169,6 @@ static void fbcon_init(struct vc_data *vc, int init)
        if (logo)
                fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
 
-       if (vc == svc && softback_buf)
-               fbcon_update_softback(vc);
-
        if (ops->rotate_font && ops->rotate_font(info, vc)) {
                ops->rotate = FB_ROTATE_UR;
                set_blitting_type(vc, info);
@@ -1385,7 +1331,6 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
        struct fbcon_ops *ops = info->fbcon_par;
-       int y;
        int c = scr_readw((u16 *) vc->vc_pos);
 
        ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
@@ -1399,16 +1344,8 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
                fbcon_add_cursor_timer(info);
 
        ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
-       if (mode & CM_SOFTBACK) {
-               mode &= ~CM_SOFTBACK;
-               y = softback_lines;
-       } else {
-               if (softback_lines)
-                       fbcon_set_origin(vc);
-               y = 0;
-       }
 
-       ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
+       ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
 }
 
@@ -1479,8 +1416,6 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
 
        if (con_is_visible(vc)) {
                update_screen(vc);
-               if (softback_buf)
-                       fbcon_update_softback(vc);
        }
 }
 
@@ -1618,99 +1553,6 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
        scrollback_current = 0;
 }
 
-static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p,
-                                 long delta)
-{
-       int count = vc->vc_rows;
-       unsigned short *d, *s;
-       unsigned long n;
-       int line = 0;
-
-       d = (u16 *) softback_curr;
-       if (d == (u16 *) softback_in)
-               d = (u16 *) vc->vc_origin;
-       n = softback_curr + delta * vc->vc_size_row;
-       softback_lines -= delta;
-       if (delta < 0) {
-               if (softback_curr < softback_top && n < softback_buf) {
-                       n += softback_end - softback_buf;
-                       if (n < softback_top) {
-                               softback_lines -=
-                                   (softback_top - n) / vc->vc_size_row;
-                               n = softback_top;
-                       }
-               } else if (softback_curr >= softback_top
-                          && n < softback_top) {
-                       softback_lines -=
-                           (softback_top - n) / vc->vc_size_row;
-                       n = softback_top;
-               }
-       } else {
-               if (softback_curr > softback_in && n >= softback_end) {
-                       n += softback_buf - softback_end;
-                       if (n > softback_in) {
-                               n = softback_in;
-                               softback_lines = 0;
-                       }
-               } else if (softback_curr <= softback_in && n > softback_in) {
-                       n = softback_in;
-                       softback_lines = 0;
-               }
-       }
-       if (n == softback_curr)
-               return;
-       softback_curr = n;
-       s = (u16 *) softback_curr;
-       if (s == (u16 *) softback_in)
-               s = (u16 *) vc->vc_origin;
-       while (count--) {
-               unsigned short *start;
-               unsigned short *le;
-               unsigned short c;
-               int x = 0;
-               unsigned short attr = 1;
-
-               start = s;
-               le = advance_row(s, 1);
-               do {
-                       c = scr_readw(s);
-                       if (attr != (c & 0xff00)) {
-                               attr = c & 0xff00;
-                               if (s > start) {
-                                       fbcon_putcs(vc, start, s - start,
-                                                   line, x);
-                                       x += s - start;
-                                       start = s;
-                               }
-                       }
-                       if (c == scr_readw(d)) {
-                               if (s > start) {
-                                       fbcon_putcs(vc, start, s - start,
-                                                   line, x);
-                                       x += s - start + 1;
-                                       start = s + 1;
-                               } else {
-                                       x++;
-                                       start++;
-                               }
-                       }
-                       s++;
-                       d++;
-               } while (s < le);
-               if (s > start)
-                       fbcon_putcs(vc, start, s - start, line, x);
-               line++;
-               if (d == (u16 *) softback_end)
-                       d = (u16 *) softback_buf;
-               if (d == (u16 *) softback_in)
-                       d = (u16 *) vc->vc_origin;
-               if (s == (u16 *) softback_end)
-                       s = (u16 *) softback_buf;
-               if (s == (u16 *) softback_in)
-                       s = (u16 *) vc->vc_origin;
-       }
-}
-
 static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
                              int line, int count, int dy)
 {
@@ -1850,31 +1692,6 @@ static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p,
        }
 }
 
-static inline void fbcon_softback_note(struct vc_data *vc, int t,
-                                      int count)
-{
-       unsigned short *p;
-
-       if (vc->vc_num != fg_console)
-               return;
-       p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
-
-       while (count) {
-               scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row);
-               count--;
-               p = advance_row(p, 1);
-               softback_in += vc->vc_size_row;
-               if (softback_in == softback_end)
-                       softback_in = softback_buf;
-               if (softback_in == softback_top) {
-                       softback_top += vc->vc_size_row;
-                       if (softback_top == softback_end)
-                               softback_top = softback_buf;
-               }
-       }
-       softback_curr = softback_in;
-}
-
 static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
                enum con_scroll dir, unsigned int count)
 {
@@ -1897,8 +1714,6 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
        case SM_UP:
                if (count > vc->vc_rows)        /* Maximum realistic size */
                        count = vc->vc_rows;
-               if (softback_top)
-                       fbcon_softback_note(vc, t, count);
                if (logo_shown >= 0)
                        goto redraw_up;
                switch (p->scrollmode) {
@@ -2191,6 +2006,9 @@ static void updatescrollmode(struct fbcon_display *p,
        }
 }
 
+#define PITCH(w) (((w) + 7) >> 3)
+#define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */
+
 static int fbcon_resize(struct vc_data *vc, unsigned int width, 
                        unsigned int height, unsigned int user)
 {
@@ -2200,6 +2018,24 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
        struct fb_var_screeninfo var = info->var;
        int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
 
+       if (p->userfont && FNTSIZE(vc->vc_font.data)) {
+               int size;
+               int pitch = PITCH(vc->vc_font.width);
+
+               /*
+                * If user font, ensure that a possible change to user font
+                * height or width will not allow a font data out-of-bounds access.
+                * NOTE: must use original charcount in calculation as font
+                * charcount can change and cannot be used to determine the
+                * font data allocated size.
+                */
+               if (pitch <= 0)
+                       return -EINVAL;
+               size = CALC_FONTSZ(vc->vc_font.height, pitch, FNTCHARCNT(vc->vc_font.data));
+               if (size > FNTSIZE(vc->vc_font.data))
+                       return -EINVAL;
+       }
+
        virt_w = FBCON_SWAP(ops->rotate, width, height);
        virt_h = FBCON_SWAP(ops->rotate, height, width);
        virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,
@@ -2248,14 +2084,6 @@ static int fbcon_switch(struct vc_data *vc)
        info = registered_fb[con2fb_map[vc->vc_num]];
        ops = info->fbcon_par;
 
-       if (softback_top) {
-               if (softback_lines)
-                       fbcon_set_origin(vc);
-               softback_top = softback_curr = softback_in = softback_buf;
-               softback_lines = 0;
-               fbcon_update_softback(vc);
-       }
-
        if (logo_shown >= 0) {
                struct vc_data *conp2 = vc_cons[logo_shown].d;
 
@@ -2471,6 +2299,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
 
        if (font->width <= 8) {
                j = vc->vc_font.height;
+               if (font->charcount * j > FNTSIZE(fontdata))
+                       return -EINVAL;
+
                for (i = 0; i < font->charcount; i++) {
                        memcpy(data, fontdata, j);
                        memset(data + j, 0, 32 - j);
@@ -2479,6 +2310,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
                }
        } else if (font->width <= 16) {
                j = vc->vc_font.height * 2;
+               if (font->charcount * j > FNTSIZE(fontdata))
+                       return -EINVAL;
+
                for (i = 0; i < font->charcount; i++) {
                        memcpy(data, fontdata, j);
                        memset(data + j, 0, 64 - j);
@@ -2486,6 +2320,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
                        fontdata += j;
                }
        } else if (font->width <= 24) {
+               if (font->charcount * (vc->vc_font.height * sizeof(u32)) > FNTSIZE(fontdata))
+                       return -EINVAL;
+
                for (i = 0; i < font->charcount; i++) {
                        for (j = 0; j < vc->vc_font.height; j++) {
                                *data++ = fontdata[0];
@@ -2498,6 +2335,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
                }
        } else {
                j = vc->vc_font.height * 4;
+               if (font->charcount * j > FNTSIZE(fontdata))
+                       return -EINVAL;
+
                for (i = 0; i < font->charcount; i++) {
                        memcpy(data, fontdata, j);
                        memset(data + j, 0, 128 - j);
@@ -2579,9 +2419,6 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
        int cnt;
        char *old_data = NULL;
 
-       if (con_is_visible(vc) && softback_lines)
-               fbcon_set_origin(vc);
-
        resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
        if (p->userfont)
                old_data = vc->vc_font.data;
@@ -2607,8 +2444,6 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
                cols /= w;
                rows /= h;
                vc_resize(vc, cols, rows);
-               if (con_is_visible(vc) && softback_buf)
-                       fbcon_update_softback(vc);
        } else if (con_is_visible(vc)
                   && vc->vc_mode == KD_TEXT) {
                fbcon_clear_margins(vc, 0);
@@ -2652,7 +2487,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
        int size;
        int i, csum;
        u8 *new_data, *data = font->data;
-       int pitch = (font->width+7) >> 3;
+       int pitch = PITCH(font->width);
 
        /* Is there a reason why fbconsole couldn't handle any charcount >256?
         * If not this check should be changed to charcount < 256 */
@@ -2668,7 +2503,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
        if (fbcon_invalid_charcount(info, charcount))
                return -EINVAL;
 
-       size = h * pitch * charcount;
+       size = CALC_FONTSZ(h, pitch, charcount);
 
        new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER);
 
@@ -2767,19 +2602,7 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
 
 static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
 {
-       unsigned long p;
-       int line;
-       
-       if (vc->vc_num != fg_console || !softback_lines)
-               return (u16 *) (vc->vc_origin + offset);
-       line = offset / vc->vc_size_row;
-       if (line >= softback_lines)
-               return (u16 *) (vc->vc_origin + offset -
-                               softback_lines * vc->vc_size_row);
-       p = softback_curr + offset;
-       if (p >= softback_end)
-               p += softback_buf - softback_end;
-       return (u16 *) p;
+       return (u16 *) (vc->vc_origin + offset);
 }
 
 static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
@@ -2793,22 +2616,7 @@ static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
 
                x = offset % vc->vc_cols;
                y = offset / vc->vc_cols;
-               if (vc->vc_num == fg_console)
-                       y += softback_lines;
-               ret = pos + (vc->vc_cols - x) * 2;
-       } else if (vc->vc_num == fg_console && softback_lines) {
-               unsigned long offset = pos - softback_curr;
-
-               if (pos < softback_curr)
-                       offset += softback_end - softback_buf;
-               offset /= 2;
-               x = offset % vc->vc_cols;
-               y = offset / vc->vc_cols;
                ret = pos + (vc->vc_cols - x) * 2;
-               if (ret == softback_end)
-                       ret = softback_buf;
-               if (ret == softback_in)
-                       ret = vc->vc_origin;
        } else {
                /* Should not happen */
                x = y = 0;
@@ -2836,106 +2644,11 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
                        a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
                            (((a) & 0x0700) << 4);
                scr_writew(a, p++);
-               if (p == (u16 *) softback_end)
-                       p = (u16 *) softback_buf;
-               if (p == (u16 *) softback_in)
-                       p = (u16 *) vc->vc_origin;
        }
 }
 
-static void fbcon_scrolldelta(struct vc_data *vc, int lines)
-{
-       struct fb_info *info = registered_fb[con2fb_map[fg_console]];
-       struct fbcon_ops *ops = info->fbcon_par;
-       struct fbcon_display *disp = &fb_display[fg_console];
-       int offset, limit, scrollback_old;
-
-       if (softback_top) {
-               if (vc->vc_num != fg_console)
-                       return;
-               if (vc->vc_mode != KD_TEXT || !lines)
-                       return;
-               if (logo_shown >= 0) {
-                       struct vc_data *conp2 = vc_cons[logo_shown].d;
-
-                       if (conp2->vc_top == logo_lines
-                           && conp2->vc_bottom == conp2->vc_rows)
-                               conp2->vc_top = 0;
-                       if (logo_shown == vc->vc_num) {
-                               unsigned long p, q;
-                               int i;
-
-                               p = softback_in;
-                               q = vc->vc_origin +
-                                   logo_lines * vc->vc_size_row;
-                               for (i = 0; i < logo_lines; i++) {
-                                       if (p == softback_top)
-                                               break;
-                                       if (p == softback_buf)
-                                               p = softback_end;
-                                       p -= vc->vc_size_row;
-                                       q -= vc->vc_size_row;
-                                       scr_memcpyw((u16 *) q, (u16 *) p,
-                                                   vc->vc_size_row);
-                               }
-                               softback_in = softback_curr = p;
-                               update_region(vc, vc->vc_origin,
-                                             logo_lines * vc->vc_cols);
-                       }
-                       logo_shown = FBCON_LOGO_CANSHOW;
-               }
-               fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
-               fbcon_redraw_softback(vc, disp, lines);
-               fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
-               return;
-       }
-
-       if (!scrollback_phys_max)
-               return;
-
-       scrollback_old = scrollback_current;
-       scrollback_current -= lines;
-       if (scrollback_current < 0)
-               scrollback_current = 0;
-       else if (scrollback_current > scrollback_max)
-               scrollback_current = scrollback_max;
-       if (scrollback_current == scrollback_old)
-               return;
-
-       if (fbcon_is_inactive(vc, info))
-               return;
-
-       fbcon_cursor(vc, CM_ERASE);
-
-       offset = disp->yscroll - scrollback_current;
-       limit = disp->vrows;
-       switch (disp->scrollmode) {
-       case SCROLL_WRAP_MOVE:
-               info->var.vmode |= FB_VMODE_YWRAP;
-               break;
-       case SCROLL_PAN_MOVE:
-       case SCROLL_PAN_REDRAW:
-               limit -= vc->vc_rows;
-               info->var.vmode &= ~FB_VMODE_YWRAP;
-               break;
-       }
-       if (offset < 0)
-               offset += limit;
-       else if (offset >= limit)
-               offset -= limit;
-
-       ops->var.xoffset = 0;
-       ops->var.yoffset = offset * vc->vc_font.height;
-       ops->update_start(info);
-
-       if (!scrollback_current)
-               fbcon_cursor(vc, CM_DRAW);
-}
-
 static int fbcon_set_origin(struct vc_data *vc)
 {
-       if (softback_lines)
-               fbcon_scrolldelta(vc, softback_lines);
        return 0;
 }
 
@@ -2999,8 +2712,6 @@ static void fbcon_modechanged(struct fb_info *info)
 
                fbcon_set_palette(vc, color_table);
                update_screen(vc);
-               if (softback_buf)
-                       fbcon_update_softback(vc);
        }
 }
 
@@ -3411,7 +3122,6 @@ static const struct consw fb_con = {
        .con_font_default       = fbcon_set_def_font,
        .con_font_copy          = fbcon_copy_font,
        .con_set_palette        = fbcon_set_palette,
-       .con_scrolldelta        = fbcon_scrolldelta,
        .con_set_origin         = fbcon_set_origin,
        .con_invert_region      = fbcon_invert_region,
        .con_screen_pos         = fbcon_screen_pos,
@@ -3646,9 +3356,6 @@ static void fbcon_exit(void)
        }
 #endif
 
-       kvfree((void *)softback_buf);
-       softback_buf = 0UL;
-
        for_each_registered_fb(i) {
                int pending = 0;
 
index 20dea85..9315b36 100644 (file)
@@ -62,7 +62,7 @@ struct fbcon_ops {
        void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
                              int color, int bottom_only);
        void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode,
-                      int softback_lines, int fg, int bg);
+                      int fg, int bg);
        int  (*update_start)(struct fb_info *info);
        int  (*rotate_font)(struct fb_info *info, struct vc_data *vc);
        struct fb_var_screeninfo var;  /* copy of the current fb_var_screeninfo */
@@ -152,13 +152,6 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
 #define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
 #define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
 
-/* Font */
-#define REFCOUNT(fd)   (((int *)(fd))[-1])
-#define FNTSIZE(fd)    (((int *)(fd))[-2])
-#define FNTCHARCNT(fd) (((int *)(fd))[-3])
-#define FNTSUM(fd)     (((int *)(fd))[-4])
-#define FONT_EXTRA_WORDS 4
-
     /*
      *  Scroll Method
      */
index 5b17713..bbd869e 100644 (file)
@@ -219,7 +219,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
 }
 
 static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-                      int softback_lines, int fg, int bg)
+                      int fg, int bg)
 {
        struct fb_cursor cursor;
        struct fbcon_ops *ops = info->fbcon_par;
@@ -236,15 +236,6 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
 
        cursor.set = 0;
 
-       if (softback_lines) {
-               if (y + softback_lines >= vc->vc_rows) {
-                       mode = CM_ERASE;
-                       ops->cursor_flash = 0;
-                       return;
-               } else
-                       y += softback_lines;
-       }
-
        c = scr_readw((u16 *) vc->vc_pos);
        attribute = get_attribute(info, c);
        src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
index 894d01a..a34cbe8 100644 (file)
@@ -202,7 +202,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
 }
 
 static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-                     int softback_lines, int fg, int bg)
+                     int fg, int bg)
 {
        struct fb_cursor cursor;
        struct fbcon_ops *ops = info->fbcon_par;
@@ -219,15 +219,6 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
 
        cursor.set = 0;
 
-       if (softback_lines) {
-               if (y + softback_lines >= vc->vc_rows) {
-                       mode = CM_ERASE;
-                       ops->cursor_flash = 0;
-                       return;
-               } else
-                       y += softback_lines;
-       }
-
        c = scr_readw((u16 *) vc->vc_pos);
        attribute = get_attribute(info, c);
        src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
index c0d4452..ac72d4f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/fb.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
+#include <linux/font.h>
 #include <asm/types.h>
 #include "fbcon.h"
 #include "fbcon_rotate.h"
index 01b87f2..199cbc7 100644 (file)
@@ -249,7 +249,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
 }
 
 static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-                     int softback_lines, int fg, int bg)
+                     int fg, int bg)
 {
        struct fb_cursor cursor;
        struct fbcon_ops *ops = info->fbcon_par;
@@ -267,15 +267,6 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
 
        cursor.set = 0;
 
-       if (softback_lines) {
-               if (y + softback_lines >= vc->vc_rows) {
-                       mode = CM_ERASE;
-                       ops->cursor_flash = 0;
-                       return;
-               } else
-                       y += softback_lines;
-       }
-
        c = scr_readw((u16 *) vc->vc_pos);
        attribute = get_attribute(info, c);
        src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
index da7c88f..6815bfb 100644 (file)
@@ -1306,7 +1306,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
        case FBIOGET_CON2FBMAP:
        case FBIOPUT_CON2FBMAP:
                arg = (unsigned long) compat_ptr(arg);
-               /* fall through */
+               fallthrough;
        case FBIOBLANK:
                ret = do_fb_ioctl(info, cmd, arg);
                break;
index 1dfaff0..628fe5e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/fb.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
+#include <linux/font.h>
 #include <asm/types.h>
 #include "fbcon.h"
 
@@ -80,7 +81,7 @@ static void tile_clear_margins(struct vc_data *vc, struct fb_info *info,
 }
 
 static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
-                       int softback_lines, int fg, int bg)
+                       int fg, int bg)
 {
        struct fb_tilecursor cursor;
        int use_sw = vc->vc_cursor_type & CUR_SW;
index 67ebfe5..a547c21 100644 (file)
@@ -1287,7 +1287,7 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
                dev_warn(info->dev,
                         "MFB_SET_PIXFMT value of 0x%08x is deprecated.\n",
                         MFB_SET_PIXFMT_OLD);
-               /* fall through */
+               fallthrough;
        case MFB_SET_PIXFMT:
                if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
                        return -EFAULT;
@@ -1297,7 +1297,7 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
                dev_warn(info->dev,
                         "MFB_GET_PIXFMT value of 0x%08x is deprecated.\n",
                         MFB_GET_PIXFMT_OLD);
-               /* fall through */
+               fallthrough;
        case MFB_GET_PIXFMT:
                pix_fmt = ad->pix_fmt;
                if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
index 13ded3a..e5475ae 100644 (file)
@@ -534,7 +534,7 @@ static int gxt4500_setcolreg(unsigned int reg, unsigned int red,
                        break;
                case DFA_PIX_32BIT:
                        val |= (reg << 24);
-                       /* fall through */
+                       fallthrough;
                case DFA_PIX_24BIT:
                        val |= (reg << 16) | (reg << 8);
                        break;
index e4c3c8b..02411d8 100644 (file)
@@ -648,13 +648,13 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
                ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
                if (!ret)
                        break;
-               /* Fallthrough */
+               fallthrough;
        case VERSION_WIN8:
        case VERSION_WIN8_1:
                ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
                if (!ret)
                        break;
-               /* Fallthrough */
+               fallthrough;
        case VERSION_WS2008:
        case VERSION_WIN7:
                ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
index c65ec73..e6f35f8 100644 (file)
@@ -430,7 +430,7 @@ static int i740fb_decode_var(const struct fb_var_screeninfo *var,
                break;
        case 9 ... 15:
                bpp = 15;
-               /* fall through */
+               fallthrough;
        case 16:
                if ((1000000 / var->pixclock) > DACSPEED16) {
                        dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n",
index 01c75c0..39ebbe0 100644 (file)
@@ -90,8 +90,6 @@ static int var_to_pixfmt(struct fb_var_screeninfo *var)
                        else
                                return PIXFMT_BGR888UNPACK;
                }
-
-               /* fall through */
        }
 
        return -EINVAL;
index 8335da4..9b0a324 100644 (file)
@@ -896,7 +896,7 @@ void NVCalcStateExt(struct nvidia_par *par,
                if (!par->FlatPanel)
                        state->control = NV_RD32(par->PRAMDAC0, 0x0580) &
                                0xeffffeff;
-               /* fallthrough */
+               fallthrough;
        case NV_ARCH_10:
        case NV_ARCH_20:
        case NV_ARCH_30:
index 5cd0f5f..4501e84 100644 (file)
@@ -141,7 +141,7 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
                out_le32(par->cmap_adr + 0x58,
                         in_le32(par->cmap_adr + 0x58) & ~0x20);
-               /* fall through */
+               fallthrough;
        case cmap_r128:
                /* Set palette index & data */
                out_8(par->cmap_adr + 0xb0, regno);
@@ -211,7 +211,7 @@ static int offb_blank(int blank, struct fb_info *info)
                                /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
                                out_le32(par->cmap_adr + 0x58,
                                         in_le32(par->cmap_adr + 0x58) & ~0x20);
-                               /* fall through */
+                               fallthrough;
                        case cmap_r128:
                                /* Set palette index & data */
                                out_8(par->cmap_adr + 0xb0, i);
index fa73acf..7317c9a 100644 (file)
@@ -328,13 +328,13 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
                        lcdc.bpp = 12;
                        break;
                }
-               /* fallthrough */
+               fallthrough;
        case OMAPFB_COLOR_YUV422:
                if (lcdc.ext_mode) {
                        lcdc.bpp = 16;
                        break;
                }
-               /* fallthrough */
+               fallthrough;
        default:
                /* FIXME: other BPPs.
                 * bpp1: code  0,     size 256
index 0cbcc74..3d090d2 100644 (file)
@@ -253,7 +253,7 @@ static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
                if (fbdev->ctrl->setcolreg)
                        r = fbdev->ctrl->setcolreg(regno, red, green, blue,
                                                        transp, update_hw_pal);
-               /* Fallthrough */
+               fallthrough;
        case OMAPFB_COLOR_RGB565:
        case OMAPFB_COLOR_RGB444:
                if (r != 0)
@@ -443,7 +443,7 @@ static int set_color_mode(struct omapfb_plane_struct *plane,
                return 0;
        case 12:
                var->bits_per_pixel = 16;
-               /* fall through */
+               fallthrough;
        case 16:
                if (plane->fbdev->panel->bpp == 12)
                        plane->color_mode = OMAPFB_COLOR_RGB444;
@@ -1531,27 +1531,27 @@ static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
        case OMAPFB_ACTIVE:
                for (i = 0; i < fbdev->mem_desc.region_cnt; i++)
                        unregister_framebuffer(fbdev->fb_info[i]);
-               /* fall through */
+               fallthrough;
        case 7:
                omapfb_unregister_sysfs(fbdev);
-               /* fall through */
+               fallthrough;
        case 6:
                if (fbdev->panel->disable)
                        fbdev->panel->disable(fbdev->panel);
-               /* fall through */
+               fallthrough;
        case 5:
                omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
-               /* fall through */
+               fallthrough;
        case 4:
                planes_cleanup(fbdev);
-               /* fall through */
+               fallthrough;
        case 3:
                ctrl_cleanup(fbdev);
-               /* fall through */
+               fallthrough;
        case 2:
                if (fbdev->panel->cleanup)
                        fbdev->panel->cleanup(fbdev->panel);
-               /* fall through */
+               fallthrough;
        case 1:
                dev_set_drvdata(fbdev->dev, NULL);
                kfree(fbdev);
@@ -1854,7 +1854,7 @@ static int __init omapfb_setup(char *options)
                        case 'm':
                        case 'M':
                                vram *= 1024;
-                               /* Fall through */
+                               fallthrough;
                        case 'k':
                        case 'K':
                                vram *= 1024;
index 3920a0d..b2d6e6d 100644 (file)
@@ -1861,7 +1861,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
                if (color_mode == OMAP_DSS_COLOR_YUV2 ||
                        color_mode == OMAP_DSS_COLOR_UYVY)
                        width = width >> 1;
-               /* fall through */
+               fallthrough;
        case OMAP_DSS_ROT_90:
        case OMAP_DSS_ROT_270:
                *offset1 = 0;
@@ -1884,7 +1884,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
                if (color_mode == OMAP_DSS_COLOR_YUV2 ||
                        color_mode == OMAP_DSS_COLOR_UYVY)
                        width = width >> 1;
-               /* fall through */
+               fallthrough;
        case OMAP_DSS_ROT_90 + 4:
        case OMAP_DSS_ROT_270 + 4:
                *offset1 = 0;
index f40be68..ea8c88a 100644 (file)
@@ -760,7 +760,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
                        r = -ENODEV;
                        break;
                }
-               /* FALLTHROUGH */
+               fallthrough;
 
        case OMAPFB_WAITFORVSYNC:
                DBG("ioctl WAITFORVSYNC\n");
index 836e7b1..a3decc7 100644 (file)
@@ -882,7 +882,7 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
                                / (var->bits_per_pixel >> 2);
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                screen_width = fix->line_length / (var->bits_per_pixel >> 3);
                break;
index c7c98d8..0642555 100644 (file)
@@ -233,10 +233,10 @@ static u32 to3264(u32 timing, int bpp, int is64)
        switch (bpp) {
        case 24:
                timing *= 3;
-               /* fall through */
+               fallthrough;
        case 8:
                timing >>= 1;
-               /* fall through */
+               fallthrough;
        case 16:
                timing >>= 1;
        case 32:
index eedfbd3..47e6a1d 100644 (file)
@@ -60,8 +60,6 @@ static int determine_best_pix_fmt(struct fb_var_screeninfo *var)
                        else
                                return PIX_FMT_BGR1555;
                }
-
-               /* fall through */
        }
 
        /*
@@ -87,8 +85,6 @@ static int determine_best_pix_fmt(struct fb_var_screeninfo *var)
                        else
                                return PIX_FMT_BGR888UNPACK;
                }
-
-               /* fall through */
        }
 
        return -EINVAL;
index a53d24f..f1551e0 100644 (file)
@@ -1614,7 +1614,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
                 */
                if (old_state != C_DISABLE_PM)
                        break;
-               /* fall through */
+               fallthrough;
 
        case C_ENABLE:
                /*
index 9b34938..ce55b9d 100644 (file)
@@ -1093,7 +1093,7 @@ static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                break;
        case 9 ... 15:
                var->green.length = 5;
-               /* fall through */
+               fallthrough;
        case 16:
                var->bits_per_pixel = 16;
                /* The Riva128 supports RGB555 only */
index 9dc9250..ba316bd 100644 (file)
@@ -284,7 +284,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
                /* 666 with one bit alpha/transparency */
                var->transp.offset      = 18;
                var->transp.length      = 1;
-               /* fall through */
+               fallthrough;
        case 18:
                var->bits_per_pixel     = 32;
 
@@ -312,7 +312,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
        case 25:
                var->transp.length      = var->bits_per_pixel - 24;
                var->transp.offset      = 24;
-               /* fall through */
+               fallthrough;
        case 24:
                /* our 24bpp is unpacked, so 32bpp */
                var->bits_per_pixel     = 32;
@@ -809,7 +809,7 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
        case FB_BLANK_POWERDOWN:
                wincon &= ~WINCONx_ENWIN;
                sfb->enabled &= ~(1 << index);
-               /* fall through - to FB_BLANK_NORMAL */
+               fallthrough;    /* to FB_BLANK_NORMAL */
 
        case FB_BLANK_NORMAL:
                /* disable the DMA and display 0x0 (black) */
index bda6cc3..e31cf63 100644 (file)
@@ -935,7 +935,7 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
                 */
                if (old_state != C_DISABLE_PM)
                        break;
-               /* fall through */
+               fallthrough;
 
        case C_ENABLE:
                /*
index 3fd87ae..a2442aa 100644 (file)
@@ -1860,7 +1860,7 @@ static int savage_init_hw(struct savagefb_par *par)
                if ((vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6))
                        RamSavage4[1] = 8;
 
-               /*FALLTHROUGH*/
+               fallthrough;
 
        case S3_SAVAGE2000:
                videoRam = RamSavage4[(config1 & 0xE0) >> 5] * 1024;
index 8a27d12..c104342 100644 (file)
@@ -1594,7 +1594,7 @@ sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
        case V4L2_PIX_FMT_NV12:
        case V4L2_PIX_FMT_NV21:
                info->fix.ypanstep = 2;
-               /* Fall through */
+               fallthrough;
        case V4L2_PIX_FMT_NV16:
        case V4L2_PIX_FMT_NV61:
                info->fix.xpanstep = 2;
@@ -2085,7 +2085,7 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
        case V4L2_PIX_FMT_NV12:
        case V4L2_PIX_FMT_NV21:
                info->fix.ypanstep = 2;
-               /* Fall through */
+               fallthrough;
        case V4L2_PIX_FMT_NV16:
        case V4L2_PIX_FMT_NV61:
                info->fix.xpanstep = 2;
index ac14096..03c736f 100644 (file)
@@ -1739,7 +1739,7 @@ static int        sisfb_ioctl(struct fb_info *info, unsigned int cmd,
                if(ivideo->warncount++ < 10)
                        printk(KERN_INFO
                                "sisfb: Deprecated ioctl call received - update your application!\n");
-               /* fall through */
+               fallthrough;
           case SISFB_GET_INFO:  /* For communication with X driver */
                ivideo->sisfb_infoblock.sisfb_id         = SISFB_ID;
                ivideo->sisfb_infoblock.sisfb_version    = VER_MAJOR;
@@ -1793,7 +1793,7 @@ static int        sisfb_ioctl(struct fb_info *info, unsigned int cmd,
                if(ivideo->warncount++ < 10)
                        printk(KERN_INFO
                                "sisfb: Deprecated ioctl call received - update your application!\n");
-               /* fall through */
+               fallthrough;
           case SISFB_GET_VBRSTATUS:
                if(sisfb_CheckVBRetrace(ivideo))
                        return put_user((u32)1, argp);
@@ -1804,7 +1804,7 @@ static int        sisfb_ioctl(struct fb_info *info, unsigned int cmd,
                if(ivideo->warncount++ < 10)
                        printk(KERN_INFO
                                "sisfb: Deprecated ioctl call received - update your application!\n");
-               /* fall through */
+               fallthrough;
           case SISFB_GET_AUTOMAXIMIZE:
                if(ivideo->sisfb_max)
                        return put_user((u32)1, argp);
@@ -1815,7 +1815,7 @@ static int        sisfb_ioctl(struct fb_info *info, unsigned int cmd,
                if(ivideo->warncount++ < 10)
                        printk(KERN_INFO
                                "sisfb: Deprecated ioctl call received - update your application!\n");
-               /* fall through */
+               fallthrough;
           case SISFB_SET_AUTOMAXIMIZE:
                if(get_user(gpu32, argp))
                        return -EFAULT;
index 3dd1b1d..6a52eba 100644 (file)
@@ -1005,7 +1005,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
        case FB_BLANK_POWERDOWN:
                ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
                sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);
-               /* fall through */
+               fallthrough;
 
        case FB_BLANK_NORMAL:
                ctrl |= SM501_DC_CRT_CONTROL_BLANK;
index de953dd..2658656 100644 (file)
@@ -999,7 +999,7 @@ stifb_blank(int blank_mode, struct fb_info *info)
        case S9000_ID_HCRX:
                HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
                break;
-       case S9000_ID_A1659A:   /* fall through */
+       case S9000_ID_A1659A:
        case S9000_ID_TIMBER:
        case CRX24_OVERLAY_PLANES:
        default:
@@ -1157,7 +1157,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
                        dev_name);
                   goto out_err0;
                }
-               /* fall through */
+               fallthrough;
        case S9000_ID_ARTIST:
        case S9000_ID_HCRX:
        case S9000_ID_TIMBER:
index f73e26c..f056d80 100644 (file)
@@ -523,7 +523,7 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        case 32:
                var->transp.offset = 24;
                var->transp.length = 8;
-               /* fall through */
+               fallthrough;
        case 24:
                var->red.offset = 16;
                var->green.offset = 8;
index a20eeb8..578d354 100644 (file)
@@ -1121,7 +1121,7 @@ static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *i
         char oldop = setop(0);
         char oldsr = setsr(0);
         char oldmask = selectmask();
-        const char *cdat = image->data;
+       const unsigned char *cdat = image->data;
        u32 dx = image->dx;
         char __iomem *where;
         int y;
index 3fea01d..4a86940 100644 (file)
@@ -744,7 +744,7 @@ static void set_lcd_output_path(int set_iga, int output_interface)
                    viaparinfo->chip_info->gfx_chip_name))
                        viafb_write_reg_mask(CR97, VIACR, 0x84,
                                       BIT7 + BIT2 + BIT1 + BIT0);
-               /* fall through */
+               fallthrough;
        case INTERFACE_DVP0:
        case INTERFACE_DVP1:
        case INTERFACE_DFP_HIGH:
index 00307b8..5ec5144 100644 (file)
@@ -677,7 +677,7 @@ static void xenfb_backend_changed(struct xenbus_device *dev,
        case XenbusStateClosed:
                if (dev->state == XenbusStateClosed)
                        break;
-               /* fall through - Missed the backend's CLOSING state. */
+               fallthrough;    /* Missed the backend's CLOSING state */
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;
index 9673eb1..f22ebe8 100644 (file)
@@ -234,7 +234,7 @@ static long sc1200wdt_ioctl(struct file *file, unsigned int cmd,
                        return -EINVAL;
                timeout = new_timeout;
                sc1200wdt_write_data(WDTO, timeout);
-               /* fall through - and return the new timeout */
+               fallthrough;    /* and return the new timeout */
 
        case WDIOC_GETTIMEOUT:
                return put_user(timeout * 60, p);
index 184a06a..c006278 100644 (file)
@@ -332,7 +332,7 @@ static long wdrtas_ioctl(struct file *file, unsigned int cmd,
                        wdrtas_interval = i;
                else
                        wdrtas_interval = wdrtas_get_interval(i);
-               /* fallthrough */
+               fallthrough;
 
        case WDIOC_GETTIMEOUT:
                return put_user(wdrtas_interval, argp);
index ea6c1e7..41645fe 100644 (file)
@@ -325,4 +325,14 @@ config XEN_HAVE_VPMU
 config XEN_FRONT_PGDIR_SHBUF
        tristate
 
+config XEN_UNPOPULATED_ALLOC
+       bool "Use unpopulated memory ranges for guest mappings"
+       depends on X86 && ZONE_DEVICE
+       default XEN_BACKEND || XEN_GNTDEV || XEN_DOM0
+       help
+         Use unpopulated memory ranges in order to create mappings for guest
+         memory regions, including grant maps and foreign pages. This avoids
+         having to balloon out RAM regions in order to obtain physical memory
+         space to create such mappings.
+
 endmenu
index c25c9a6..babdca8 100644 (file)
@@ -41,3 +41,4 @@ xen-gntdev-$(CONFIG_XEN_GNTDEV_DMABUF)        += gntdev-dmabuf.o
 xen-gntalloc-y                         := gntalloc.o
 xen-privcmd-y                          := privcmd.o privcmd-buf.o
 obj-$(CONFIG_XEN_FRONT_PGDIR_SHBUF)    += xen-front-pgdir-shbuf.o
+obj-$(CONFIG_XEN_UNPOPULATED_ALLOC)    += unpopulated-alloc.o
index 37ffccd..51427c7 100644 (file)
@@ -653,7 +653,7 @@ void free_xenballooned_pages(int nr_pages, struct page **pages)
 }
 EXPORT_SYMBOL(free_xenballooned_pages);
 
-#ifdef CONFIG_XEN_PV
+#if defined(CONFIG_XEN_PV) && !defined(CONFIG_XEN_UNPOPULATED_ALLOC)
 static void __init balloon_add_region(unsigned long start_pfn,
                                      unsigned long pages)
 {
@@ -707,7 +707,7 @@ static int __init balloon_init(void)
        register_sysctl_table(xen_root);
 #endif
 
-#ifdef CONFIG_XEN_PV
+#if defined(CONFIG_XEN_PV) && !defined(CONFIG_XEN_UNPOPULATED_ALLOC)
        {
                int i;
 
index 140c7bf..6f02c18 100644 (file)
@@ -92,6 +92,8 @@ static bool (*pirq_needs_eoi)(unsigned irq);
 /* Xen will never allocate port zero for any purpose. */
 #define VALID_EVTCHN(chn)      ((chn) != 0)
 
+static struct irq_info *legacy_info_ptrs[NR_IRQS_LEGACY];
+
 static struct irq_chip xen_dynamic_chip;
 static struct irq_chip xen_percpu_chip;
 static struct irq_chip xen_pirq_chip;
@@ -156,7 +158,18 @@ int get_evtchn_to_irq(evtchn_port_t evtchn)
 /* Get info for IRQ */
 struct irq_info *info_for_irq(unsigned irq)
 {
-       return irq_get_handler_data(irq);
+       if (irq < nr_legacy_irqs())
+               return legacy_info_ptrs[irq];
+       else
+               return irq_get_chip_data(irq);
+}
+
+static void set_info_for_irq(unsigned int irq, struct irq_info *info)
+{
+       if (irq < nr_legacy_irqs())
+               legacy_info_ptrs[irq] = info;
+       else
+               irq_set_chip_data(irq, info);
 }
 
 /* Constructors for packed IRQ information. */
@@ -377,7 +390,7 @@ static void xen_irq_init(unsigned irq)
        info->type = IRQT_UNBOUND;
        info->refcnt = -1;
 
-       irq_set_handler_data(irq, info);
+       set_info_for_irq(irq, info);
 
        list_add_tail(&info->list, &xen_irq_list_head);
 }
@@ -426,14 +439,14 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi)
 
 static void xen_free_irq(unsigned irq)
 {
-       struct irq_info *info = irq_get_handler_data(irq);
+       struct irq_info *info = info_for_irq(irq);
 
        if (WARN_ON(!info))
                return;
 
        list_del(&info->list);
 
-       irq_set_handler_data(irq, NULL);
+       set_info_for_irq(irq, NULL);
 
        WARN_ON(info->refcnt > 0);
 
@@ -603,7 +616,7 @@ EXPORT_SYMBOL_GPL(xen_irq_from_gsi);
 static void __unbind_from_irq(unsigned int irq)
 {
        evtchn_port_t evtchn = evtchn_from_irq(irq);
-       struct irq_info *info = irq_get_handler_data(irq);
+       struct irq_info *info = info_for_irq(irq);
 
        if (info->refcnt > 0) {
                info->refcnt--;
@@ -1108,7 +1121,7 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
 
 void unbind_from_irqhandler(unsigned int irq, void *dev_id)
 {
-       struct irq_info *info = irq_get_handler_data(irq);
+       struct irq_info *info = info_for_irq(irq);
 
        if (WARN_ON(!info))
                return;
@@ -1142,7 +1155,7 @@ int evtchn_make_refcounted(evtchn_port_t evtchn)
        if (irq == -1)
                return -ENOENT;
 
-       info = irq_get_handler_data(irq);
+       info = info_for_irq(irq);
 
        if (!info)
                return -ENOENT;
@@ -1170,7 +1183,7 @@ int evtchn_get(evtchn_port_t evtchn)
        if (irq == -1)
                goto done;
 
-       info = irq_get_handler_data(irq);
+       info = info_for_irq(irq);
 
        if (!info)
                goto done;
index 8d06bf1..523dcdf 100644 (file)
@@ -801,7 +801,7 @@ int gnttab_alloc_pages(int nr_pages, struct page **pages)
 {
        int ret;
 
-       ret = alloc_xenballooned_pages(nr_pages, pages);
+       ret = xen_alloc_unpopulated_pages(nr_pages, pages);
        if (ret < 0)
                return ret;
 
@@ -836,7 +836,7 @@ EXPORT_SYMBOL_GPL(gnttab_pages_clear_private);
 void gnttab_free_pages(int nr_pages, struct page **pages)
 {
        gnttab_pages_clear_private(nr_pages, pages);
-       free_xenballooned_pages(nr_pages, pages);
+       xen_free_unpopulated_pages(nr_pages, pages);
 }
 EXPORT_SYMBOL_GPL(gnttab_free_pages);
 
index 63abe6c..b0c73c5 100644 (file)
@@ -424,7 +424,7 @@ static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs)
        if (pages == NULL)
                return -ENOMEM;
 
-       rc = alloc_xenballooned_pages(numpgs, pages);
+       rc = xen_alloc_unpopulated_pages(numpgs, pages);
        if (rc != 0) {
                pr_warn("%s Could not alloc %d pfns rc:%d\n", __func__,
                        numpgs, rc);
@@ -895,7 +895,7 @@ static void privcmd_close(struct vm_area_struct *vma)
 
        rc = xen_unmap_domain_gfn_range(vma, numgfns, pages);
        if (rc == 0)
-               free_xenballooned_pages(numpgs, pages);
+               xen_free_unpopulated_pages(numpgs, pages);
        else
                pr_crit("unable to unmap MFN range: leaking %d pages. rc=%d\n",
                        numpgs, rc);
index b43b559..72d725a 100644 (file)
@@ -1263,7 +1263,7 @@ static void pvcalls_front_changed(struct xenbus_device *dev,
                if (dev->state == XenbusStateClosed)
                        break;
                /* Missed the backend's CLOSING state */
-               /* fall through */
+               fallthrough;
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;
diff --git a/drivers/xen/unpopulated-alloc.c b/drivers/xen/unpopulated-alloc.c
new file mode 100644 (file)
index 0000000..3b98dc9
--- /dev/null
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/errno.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/memremap.h>
+#include <linux/slab.h>
+
+#include <asm/page.h>
+
+#include <xen/page.h>
+#include <xen/xen.h>
+
+static DEFINE_MUTEX(list_lock);
+static LIST_HEAD(page_list);
+static unsigned int list_count;
+
+static int fill_list(unsigned int nr_pages)
+{
+       struct dev_pagemap *pgmap;
+       void *vaddr;
+       unsigned int i, alloc_pages = round_up(nr_pages, PAGES_PER_SECTION);
+       int ret;
+
+       pgmap = kzalloc(sizeof(*pgmap), GFP_KERNEL);
+       if (!pgmap)
+               return -ENOMEM;
+
+       pgmap->type = MEMORY_DEVICE_GENERIC;
+       pgmap->res.name = "Xen scratch";
+       pgmap->res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+
+       ret = allocate_resource(&iomem_resource, &pgmap->res,
+                               alloc_pages * PAGE_SIZE, 0, -1,
+                               PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL);
+       if (ret < 0) {
+               pr_err("Cannot allocate new IOMEM resource\n");
+               kfree(pgmap);
+               return ret;
+       }
+
+#ifdef CONFIG_XEN_HAVE_PVMMU
+        /*
+         * memremap will build page tables for the new memory so
+         * the p2m must contain invalid entries so the correct
+         * non-present PTEs will be written.
+         *
+         * If a failure occurs, the original (identity) p2m entries
+         * are not restored since this region is now known not to
+         * conflict with any devices.
+         */
+       if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+               xen_pfn_t pfn = PFN_DOWN(pgmap->res.start);
+
+               for (i = 0; i < alloc_pages; i++) {
+                       if (!set_phys_to_machine(pfn + i, INVALID_P2M_ENTRY)) {
+                               pr_warn("set_phys_to_machine() failed, no memory added\n");
+                               release_resource(&pgmap->res);
+                               kfree(pgmap);
+                               return -ENOMEM;
+                       }
+                }
+       }
+#endif
+
+       vaddr = memremap_pages(pgmap, NUMA_NO_NODE);
+       if (IS_ERR(vaddr)) {
+               pr_err("Cannot remap memory range\n");
+               release_resource(&pgmap->res);
+               kfree(pgmap);
+               return PTR_ERR(vaddr);
+       }
+
+       for (i = 0; i < alloc_pages; i++) {
+               struct page *pg = virt_to_page(vaddr + PAGE_SIZE * i);
+
+               BUG_ON(!virt_addr_valid(vaddr + PAGE_SIZE * i));
+               list_add(&pg->lru, &page_list);
+               list_count++;
+       }
+
+       return 0;
+}
+
+/**
+ * xen_alloc_unpopulated_pages - alloc unpopulated pages
+ * @nr_pages: Number of pages
+ * @pages: pages returned
+ * @return 0 on success, error otherwise
+ */
+int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages)
+{
+       unsigned int i;
+       int ret = 0;
+
+       mutex_lock(&list_lock);
+       if (list_count < nr_pages) {
+               ret = fill_list(nr_pages - list_count);
+               if (ret)
+                       goto out;
+       }
+
+       for (i = 0; i < nr_pages; i++) {
+               struct page *pg = list_first_entry_or_null(&page_list,
+                                                          struct page,
+                                                          lru);
+
+               BUG_ON(!pg);
+               list_del(&pg->lru);
+               list_count--;
+               pages[i] = pg;
+
+#ifdef CONFIG_XEN_HAVE_PVMMU
+               if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+                       ret = xen_alloc_p2m_entry(page_to_pfn(pg));
+                       if (ret < 0) {
+                               unsigned int j;
+
+                               for (j = 0; j <= i; j++) {
+                                       list_add(&pages[j]->lru, &page_list);
+                                       list_count++;
+                               }
+                               goto out;
+                       }
+               }
+#endif
+       }
+
+out:
+       mutex_unlock(&list_lock);
+       return ret;
+}
+EXPORT_SYMBOL(xen_alloc_unpopulated_pages);
+
+/**
+ * xen_free_unpopulated_pages - return unpopulated pages
+ * @nr_pages: Number of pages
+ * @pages: pages to return
+ */
+void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages)
+{
+       unsigned int i;
+
+       mutex_lock(&list_lock);
+       for (i = 0; i < nr_pages; i++) {
+               list_add(&pages[i]->lru, &page_list);
+               list_count++;
+       }
+       mutex_unlock(&list_lock);
+}
+EXPORT_SYMBOL(xen_free_unpopulated_pages);
+
+#ifdef CONFIG_XEN_PV
+static int __init init(void)
+{
+       unsigned int i;
+
+       if (!xen_domain())
+               return -ENODEV;
+
+       if (!xen_pv_domain())
+               return 0;
+
+       /*
+        * Initialize with pages from the extra memory regions (see
+        * arch/x86/xen/setup.c).
+        */
+       for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
+               unsigned int j;
+
+               for (j = 0; j < xen_extra_mem[i].n_pfns; j++) {
+                       struct page *pg =
+                               pfn_to_page(xen_extra_mem[i].start_pfn + j);
+
+                       list_add(&pg->lru, &page_list);
+                       list_count++;
+               }
+       }
+
+       return 0;
+}
+subsys_initcall(init);
+#endif
index 7457213..f914b72 100644 (file)
@@ -229,7 +229,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
        case ACPI_NOTIFY_BUS_CHECK:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                        "\nReceived BUS CHECK notification for device\n"));
-               /* Fall Through */
+               fallthrough;
        case ACPI_NOTIFY_DEVICE_CHECK:
                if (event == ACPI_NOTIFY_DEVICE_CHECK)
                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
index f211558..b500466 100644 (file)
@@ -545,7 +545,7 @@ static void xen_pcibk_frontend_changed(struct xenbus_device *xdev,
                xenbus_switch_state(xdev, XenbusStateClosed);
                if (xenbus_dev_is_online(xdev))
                        break;
-               /* fall through - if not online */
+               fallthrough;    /* if not online */
        case XenbusStateUnknown:
                dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
                device_unregister(&xdev->dev);
index 75c0a2e..1e8cfd8 100644 (file)
@@ -1185,7 +1185,7 @@ static void scsiback_frontend_changed(struct xenbus_device *dev,
                xenbus_switch_state(dev, XenbusStateClosed);
                if (xenbus_dev_is_online(dev))
                        break;
-               /* fall through - if not online */
+               fallthrough;    /* if not online */
        case XenbusStateUnknown:
                device_unregister(&dev->dev);
                break;
index 786fbb7..2690318 100644 (file)
@@ -379,8 +379,14 @@ int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr,
        int i, j;
 
        for (i = 0; i < nr_pages; i++) {
-               err = gnttab_grant_foreign_access(dev->otherend_id,
-                                                 virt_to_gfn(vaddr), 0);
+               unsigned long gfn;
+
+               if (is_vmalloc_addr(vaddr))
+                       gfn = pfn_to_gfn(vmalloc_to_pfn(vaddr));
+               else
+                       gfn = virt_to_gfn(vaddr);
+
+               err = gnttab_grant_foreign_access(dev->otherend_id, gfn, 0);
                if (err < 0) {
                        xenbus_dev_fatal(dev, err,
                                         "granting access to ring page");
@@ -615,7 +621,7 @@ static int xenbus_map_ring_hvm(struct xenbus_device *dev,
        bool leaked = false;
        unsigned int nr_pages = XENBUS_PAGES(nr_grefs);
 
-       err = alloc_xenballooned_pages(nr_pages, node->hvm.pages);
+       err = xen_alloc_unpopulated_pages(nr_pages, node->hvm.pages);
        if (err)
                goto out_err;
 
@@ -656,7 +662,7 @@ static int xenbus_map_ring_hvm(struct xenbus_device *dev,
                         addr, nr_pages);
  out_free_ballooned_pages:
        if (!leaked)
-               free_xenballooned_pages(nr_pages, node->hvm.pages);
+               xen_free_unpopulated_pages(nr_pages, node->hvm.pages);
  out_err:
        return err;
 }
@@ -852,7 +858,7 @@ static int xenbus_unmap_ring_hvm(struct xenbus_device *dev, void *vaddr)
                               info.addrs);
        if (!rv) {
                vunmap(vaddr);
-               free_xenballooned_pages(nr_pages, node->hvm.pages);
+               xen_free_unpopulated_pages(nr_pages, node->hvm.pages);
        }
        else
                WARN(1, "Leaking %p, size %u page(s)\n", vaddr, nr_pages);
index 1537908..4809446 100644 (file)
@@ -401,12 +401,12 @@ static void xenbus_reset_frontend(char *fe, char *be, int be_state)
        case XenbusStateConnected:
                xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosing);
                xenbus_reset_wait_for_backend(be, XenbusStateClosing);
-               /* fall through */
+               fallthrough;
 
        case XenbusStateClosing:
                xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosed);
                xenbus_reset_wait_for_backend(be, XenbusStateClosed);
-               /* fall through */
+               fallthrough;
 
        case XenbusStateClosed:
                xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateInitialising);
index 7b1077f..34742c6 100644 (file)
@@ -232,7 +232,7 @@ int __init xen_xlate_map_ballooned_pages(xen_pfn_t **gfns, void **virt,
                kfree(pages);
                return -ENOMEM;
        }
-       rc = alloc_xenballooned_pages(nr_pages, pages);
+       rc = xen_alloc_unpopulated_pages(nr_pages, pages);
        if (rc) {
                pr_warn("%s Couldn't balloon alloc %ld pages rc:%d\n", __func__,
                        nr_pages, rc);
@@ -249,7 +249,7 @@ int __init xen_xlate_map_ballooned_pages(xen_pfn_t **gfns, void **virt,
        if (!vaddr) {
                pr_warn("%s Couldn't map %ld pages rc:%d\n", __func__,
                        nr_pages, rc);
-               free_xenballooned_pages(nr_pages, pages);
+               xen_free_unpopulated_pages(nr_pages, pages);
                kfree(pages);
                kfree(pfns);
                return -ENOMEM;
index 47c7338..1b99286 100644 (file)
@@ -181,7 +181,7 @@ static int __init amiga_zorro_probe(struct platform_device *pdev)
                z->resource.name = z->name;
                r = zorro_find_parent_resource(pdev, z);
                error = request_resource(r, &z->resource);
-               if (error)
+               if (error && !(z->rom.er_Type & ERTF_MEMLIST))
                        dev_err(&bus->dev,
                                "Address space collision on device %s %pR\n",
                                z->name, &z->resource);
index 92cd1d8..3576123 100644 (file)
@@ -213,7 +213,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
                break;
        default:
                WARN_ONCE(1, "unknown lock status code: %d\n", status);
-               /* fall through */
+               fallthrough;
        case P9_LOCK_ERROR:
        case P9_LOCK_GRACE:
                res = -ENOLCK;
index 1c7b0e3..d72ee2c 100644 (file)
@@ -37,7 +37,6 @@ obj-$(CONFIG_FS_DAX)          += dax.o
 obj-$(CONFIG_FS_ENCRYPTION)    += crypto/
 obj-$(CONFIG_FS_VERITY)                += verity/
 obj-$(CONFIG_FILE_LOCKING)      += locks.o
-obj-$(CONFIG_COMPAT)           += compat.o
 obj-$(CONFIG_BINFMT_AOUT)      += binfmt_aout.o
 obj-$(CONFIG_BINFMT_EM86)      += binfmt_em86.o
 obj-$(CONFIG_BINFMT_MISC)      += binfmt_misc.o
index 30d526f..05e9634 100644 (file)
@@ -18,11 +18,11 @@ static inline unsigned int adfs_readval(unsigned char *p, int len)
 
        switch (len) {
        case 4:         val |= p[3] << 24;
-                       /* fall through */
+               fallthrough;
        case 3:         val |= p[2] << 16;
-                       /* fall through */
+               fallthrough;
        case 2:         val |= p[1] << 8;
-                       /* fall through */
+               fallthrough;
        default:        val |= p[0];
        }
        return val;
@@ -32,11 +32,11 @@ static inline void adfs_writeval(unsigned char *p, int len, unsigned int val)
 {
        switch (len) {
        case 4:         p[3] = val >> 24;
-                       /* fall through */
+               fallthrough;
        case 3:         p[2] = val >> 16;
-                       /* fall through */
+               fallthrough;
        case 2:         p[1] = val >> 8;
-                       /* fall through */
+               fallthrough;
        default:        p[0] = val;
        }
 }
index f708c45..29f11e1 100644 (file)
@@ -420,24 +420,51 @@ affs_mode_to_prot(struct inode *inode)
        u32 prot = AFFS_I(inode)->i_protect;
        umode_t mode = inode->i_mode;
 
+       /*
+        * First, clear all RWED bits for owner, group, other.
+        * Then, recalculate them afresh.
+        *
+        * We'll always clear the delete-inhibit bit for the owner, as that is
+        * the classic single-user mode AmigaOS protection bit and we need to
+        * stay compatible with all scenarios.
+        *
+        * Since multi-user AmigaOS is an extension, we'll only set the
+        * delete-allow bit if any of the other bits in the same user class
+        * (group/other) are used.
+        */
+       prot &= ~(FIBF_NOEXECUTE | FIBF_NOREAD
+                 | FIBF_NOWRITE | FIBF_NODELETE
+                 | FIBF_GRP_EXECUTE | FIBF_GRP_READ
+                 | FIBF_GRP_WRITE   | FIBF_GRP_DELETE
+                 | FIBF_OTR_EXECUTE | FIBF_OTR_READ
+                 | FIBF_OTR_WRITE   | FIBF_OTR_DELETE);
+
+       /* Classic single-user AmigaOS flags. These are inverted. */
        if (!(mode & 0100))
                prot |= FIBF_NOEXECUTE;
        if (!(mode & 0400))
                prot |= FIBF_NOREAD;
        if (!(mode & 0200))
                prot |= FIBF_NOWRITE;
+
+       /* Multi-user extended flags. Not inverted. */
        if (mode & 0010)
                prot |= FIBF_GRP_EXECUTE;
        if (mode & 0040)
                prot |= FIBF_GRP_READ;
        if (mode & 0020)
                prot |= FIBF_GRP_WRITE;
+       if (mode & 0070)
+               prot |= FIBF_GRP_DELETE;
+
        if (mode & 0001)
                prot |= FIBF_OTR_EXECUTE;
        if (mode & 0004)
                prot |= FIBF_OTR_READ;
        if (mode & 0002)
                prot |= FIBF_OTR_WRITE;
+       if (mode & 0007)
+               prot |= FIBF_OTR_DELETE;
 
        AFFS_I(inode)->i_protect = prot;
 }
index a26a0f9..d91b013 100644 (file)
@@ -429,6 +429,24 @@ static int affs_write_begin(struct file *file, struct address_space *mapping,
        return ret;
 }
 
+static int affs_write_end(struct file *file, struct address_space *mapping,
+                         loff_t pos, unsigned int len, unsigned int copied,
+                         struct page *page, void *fsdata)
+{
+       struct inode *inode = mapping->host;
+       int ret;
+
+       ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
+
+       /* Clear Archived bit on file writes, as AmigaOS would do */
+       if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {
+               AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;
+               mark_inode_dirty(inode);
+       }
+
+       return ret;
+}
+
 static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,affs_get_block);
@@ -438,7 +456,7 @@ const struct address_space_operations affs_aops = {
        .readpage = affs_readpage,
        .writepage = affs_writepage,
        .write_begin = affs_write_begin,
-       .write_end = generic_write_end,
+       .write_end = affs_write_end,
        .direct_IO = affs_direct_IO,
        .bmap = _affs_bmap
 };
@@ -795,6 +813,12 @@ done:
        if (tmp > inode->i_size)
                inode->i_size = AFFS_I(inode)->mmu_private = tmp;
 
+       /* Clear Archived bit on file writes, as AmigaOS would do */
+       if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {
+               AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;
+               mark_inode_dirty(inode);
+       }
+
 err_first_bh:
        unlock_page(page);
        put_page(page);
index a346cf7..0444121 100644 (file)
@@ -93,7 +93,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
        case ST_ROOT:
                inode->i_uid = sbi->s_uid;
                inode->i_gid = sbi->s_gid;
-               /* fall through */
+               fallthrough;
        case ST_USERDIR:
                if (be32_to_cpu(tail->stype) == ST_USERDIR ||
                    affs_test_opt(sbi->s_flags, SF_SETMODE)) {
index 47107c6..a100cd9 100644 (file)
@@ -474,7 +474,7 @@ got_root:
        case MUFS_INTLFFS:
        case MUFS_DCFFS:
                affs_set_opt(sbi->s_flags, SF_MUFS);
-               /* fall thru */
+               fallthrough;
        case FS_INTLFFS:
        case FS_DCFFS:
                affs_set_opt(sbi->s_flags, SF_INTL);
@@ -486,7 +486,7 @@ got_root:
                break;
        case MUFS_OFS:
                affs_set_opt(sbi->s_flags, SF_MUFS);
-               /* fall through */
+               fallthrough;
        case FS_OFS:
                affs_set_opt(sbi->s_flags, SF_OFS);
                sb->s_flags |= SB_NOEXEC;
@@ -494,7 +494,7 @@ got_root:
        case MUFS_DCOFS:
        case MUFS_INTLOFS:
                affs_set_opt(sbi->s_flags, SF_MUFS);
-               /* fall through */
+               fallthrough;
        case FS_DCOFS:
        case FS_INTLOFS:
                affs_set_opt(sbi->s_flags, SF_INTL);
index bef4138..a4e9e6e 100644 (file)
@@ -252,7 +252,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
                call->unmarshall++;
 
                /* extract the FID array and its count in two steps */
-               /* fall through */
+               fallthrough;
        case 1:
                _debug("extract FID count");
                ret = afs_extract_data(call, true);
@@ -271,7 +271,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
                afs_extract_to_buf(call, call->count * 3 * 4);
                call->unmarshall++;
 
-               /* Fall through */
+               fallthrough;
        case 2:
                _debug("extract FID array");
                ret = afs_extract_data(call, true);
@@ -297,7 +297,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
                call->unmarshall++;
 
                /* extract the callback array and its count in two steps */
-               /* fall through */
+               fallthrough;
        case 3:
                _debug("extract CB count");
                ret = afs_extract_data(call, true);
@@ -312,7 +312,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
                iov_iter_discard(&call->def_iter, READ, call->count2 * 3 * 4);
                call->unmarshall++;
 
-               /* Fall through */
+               fallthrough;
        case 4:
                _debug("extract discard %zu/%u",
                       iov_iter_count(call->iter), call->count2 * 3 * 4);
@@ -391,7 +391,7 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
                afs_extract_to_buf(call, 11 * sizeof(__be32));
                call->unmarshall++;
 
-               /* Fall through */
+               fallthrough;
        case 1:
                _debug("extract UUID");
                ret = afs_extract_data(call, false);
@@ -503,7 +503,7 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
                afs_extract_to_buf(call, 11 * sizeof(__be32));
                call->unmarshall++;
 
-               /* Fall through */
+               fallthrough;
        case 1:
                _debug("extract UUID");
                ret = afs_extract_data(call, false);
@@ -618,7 +618,7 @@ static int afs_deliver_yfs_cb_callback(struct afs_call *call)
                call->unmarshall++;
 
                /* extract the FID array and its count in two steps */
-               /* Fall through */
+               fallthrough;
        case 1:
                _debug("extract FID count");
                ret = afs_extract_data(call, true);
@@ -637,7 +637,7 @@ static int afs_deliver_yfs_cb_callback(struct afs_call *call)
                afs_extract_to_buf(call, size);
                call->unmarshall++;
 
-               /* Fall through */
+               fallthrough;
        case 2:
                _debug("extract FID array");
                ret = afs_extract_data(call, false);
index 6f6ed16..371d148 100644 (file)
@@ -311,7 +311,7 @@ int afs_page_filler(void *data, struct page *page)
        case -ENOBUFS:
                _debug("cache said ENOBUFS");
 
-               /* fall through */
+               fallthrough;
        default:
        go_on:
                req = kzalloc(struct_size(req, array, 1), GFP_KERNEL);
index ffb8575..cb3054c 100644 (file)
@@ -376,7 +376,6 @@ again:
                spin_unlock(&vnode->lock);
                return;
 
-               /* Fall through */
        default:
                /* Looks like a lock request was withdrawn. */
                spin_unlock(&vnode->lock);
index 5d9ef51..e7e98ad 100644 (file)
@@ -161,8 +161,8 @@ responded:
                }
        }
 
-       rtt_us = rxrpc_kernel_get_srtt(call->net->socket, call->rxcall);
-       if (rtt_us < server->probe.rtt) {
+       if (rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us) &&
+           rtt_us < server->probe.rtt) {
                server->probe.rtt = rtt_us;
                server->rtt = rtt_us;
                alist->preferred = index;
index acb4d0c..1d95ed9 100644 (file)
@@ -320,7 +320,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
                        call->tmp_u = htonl(0);
                        afs_extract_to_tmp(call);
                }
-               /* Fall through */
+               fallthrough;
 
                /* extract the returned data length */
        case 1:
@@ -348,7 +348,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
                call->bvec[0].bv_page = req->pages[req->index];
                iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size);
                ASSERTCMP(size, <=, PAGE_SIZE);
-               /* Fall through */
+               fallthrough;
 
                /* extract the returned data */
        case 2:
@@ -375,7 +375,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
                /* Discard any excess data the server gave us */
                afs_extract_discard(call, req->actual_len - req->len);
                call->unmarshall = 3;
-               /* Fall through */
+               fallthrough;
 
        case 3:
                _debug("extract discard %zu/%llu",
@@ -388,7 +388,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
        no_more_data:
                call->unmarshall = 4;
                afs_extract_to_buf(call, (21 + 3 + 6) * 4);
-               /* Fall through */
+               fallthrough;
 
                /* extract the metadata */
        case 4:
@@ -1343,7 +1343,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
        case 0:
                call->unmarshall++;
                afs_extract_to_buf(call, 12 * 4);
-               /* Fall through */
+               fallthrough;
 
                /* extract the returned status record */
        case 1:
@@ -1356,7 +1356,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                xdr_decode_AFSFetchVolumeStatus(&bp, &op->volstatus.vs);
                call->unmarshall++;
                afs_extract_to_tmp(call);
-               /* Fall through */
+               fallthrough;
 
                /* extract the volume name length */
        case 2:
@@ -1371,7 +1371,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                size = (call->count + 3) & ~3; /* It's padded */
                afs_extract_to_buf(call, size);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the volume name */
        case 3:
@@ -1385,7 +1385,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                _debug("volname '%s'", p);
                afs_extract_to_tmp(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the offline message length */
        case 4:
@@ -1400,7 +1400,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                size = (call->count + 3) & ~3; /* It's padded */
                afs_extract_to_buf(call, size);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the offline message */
        case 5:
@@ -1415,7 +1415,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
 
                afs_extract_to_tmp(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the message of the day length */
        case 6:
@@ -1430,7 +1430,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                size = (call->count + 3) & ~3; /* It's padded */
                afs_extract_to_buf(call, size);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the message of the day */
        case 7:
@@ -1682,7 +1682,7 @@ static int afs_deliver_fs_get_capabilities(struct afs_call *call)
        case 0:
                afs_extract_to_tmp(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* Extract the capabilities word count */
        case 1:
@@ -1696,7 +1696,7 @@ static int afs_deliver_fs_get_capabilities(struct afs_call *call)
                call->count2 = count;
                afs_extract_discard(call, count * sizeof(__be32));
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* Extract capabilities words */
        case 2:
@@ -1776,7 +1776,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
        case 0:
                afs_extract_to_tmp(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* Extract the file status count and array in two steps */
        case 1:
@@ -1794,7 +1794,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
                call->unmarshall++;
        more_counts:
                afs_extract_to_buf(call, 21 * sizeof(__be32));
-               /* Fall through */
+               fallthrough;
 
        case 2:
                _debug("extract status array %u", call->count);
@@ -1824,7 +1824,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
                call->count = 0;
                call->unmarshall++;
                afs_extract_to_tmp(call);
-               /* Fall through */
+               fallthrough;
 
                /* Extract the callback count and array in two steps */
        case 3:
@@ -1841,7 +1841,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
                call->unmarshall++;
        more_cbs:
                afs_extract_to_buf(call, 3 * sizeof(__be32));
-               /* Fall through */
+               fallthrough;
 
        case 4:
                _debug("extract CB array");
@@ -1870,7 +1870,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
 
                afs_extract_to_buf(call, 6 * sizeof(__be32));
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
        case 5:
                ret = afs_extract_data(call, false);
@@ -1974,7 +1974,7 @@ static int afs_deliver_fs_fetch_acl(struct afs_call *call)
        case 0:
                afs_extract_to_tmp(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the returned data length */
        case 1:
@@ -1992,7 +1992,7 @@ static int afs_deliver_fs_fetch_acl(struct afs_call *call)
                acl->size = call->count2;
                afs_extract_begin(call, acl->data, size);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the returned data */
        case 2:
@@ -2002,7 +2002,7 @@ static int afs_deliver_fs_fetch_acl(struct afs_call *call)
 
                afs_extract_to_buf(call, (21 + 6) * 4);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the metadata */
        case 3:
index 1d13d2e..0fe8844 100644 (file)
@@ -810,14 +810,32 @@ void afs_evict_inode(struct inode *inode)
 
 static void afs_setattr_success(struct afs_operation *op)
 {
-       struct inode *inode = &op->file[0].vnode->vfs_inode;
+       struct afs_vnode_param *vp = &op->file[0];
+       struct inode *inode = &vp->vnode->vfs_inode;
+       loff_t old_i_size = i_size_read(inode);
+
+       op->setattr.old_i_size = old_i_size;
+       afs_vnode_commit_status(op, vp);
+       /* inode->i_size has now been changed. */
+
+       if (op->setattr.attr->ia_valid & ATTR_SIZE) {
+               loff_t size = op->setattr.attr->ia_size;
+               if (size > old_i_size)
+                       pagecache_isize_extended(inode, old_i_size, size);
+       }
+}
+
+static void afs_setattr_edit_file(struct afs_operation *op)
+{
+       struct afs_vnode_param *vp = &op->file[0];
+       struct inode *inode = &vp->vnode->vfs_inode;
 
-       afs_vnode_commit_status(op, &op->file[0]);
        if (op->setattr.attr->ia_valid & ATTR_SIZE) {
-               loff_t i_size = inode->i_size, size = op->setattr.attr->ia_size;
-               if (size > i_size)
-                       pagecache_isize_extended(inode, i_size, size);
-               truncate_pagecache(inode, size);
+               loff_t size = op->setattr.attr->ia_size;
+               loff_t i_size = op->setattr.old_i_size;
+
+               if (size < i_size)
+                       truncate_pagecache(inode, size);
        }
 }
 
@@ -825,6 +843,7 @@ static const struct afs_operation_ops afs_setattr_operation = {
        .issue_afs_rpc  = afs_fs_setattr,
        .issue_yfs_rpc  = yfs_fs_setattr,
        .success        = afs_setattr_success,
+       .edit_dir       = afs_setattr_edit_file,
 };
 
 /*
@@ -863,11 +882,16 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
        if (S_ISREG(vnode->vfs_inode.i_mode))
                filemap_write_and_wait(vnode->vfs_inode.i_mapping);
 
+       /* Prevent any new writebacks from starting whilst we do this. */
+       down_write(&vnode->validate_lock);
+
        op = afs_alloc_operation(((attr->ia_valid & ATTR_FILE) ?
                                  afs_file_key(attr->ia_file) : NULL),
                                 vnode->volume);
-       if (IS_ERR(op))
-               return PTR_ERR(op);
+       if (IS_ERR(op)) {
+               ret = PTR_ERR(op);
+               goto out_unlock;
+       }
 
        afs_op_set_vnode(op, 0, vnode);
        op->setattr.attr = attr;
@@ -880,5 +904,10 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
        op->file[0].update_ctime = 1;
 
        op->ops = &afs_setattr_operation;
-       return afs_do_sync_operation(op);
+       ret = afs_do_sync_operation(op);
+
+out_unlock:
+       up_write(&vnode->validate_lock);
+       _leave(" = %d", ret);
+       return ret;
 }
index 792ac71..e5f0446 100644 (file)
@@ -401,22 +401,24 @@ struct afs_vlserver {
 #define AFS_VLSERVER_FL_PROBED 0               /* The VL server has been probed */
 #define AFS_VLSERVER_FL_PROBING        1               /* VL server is being probed */
 #define AFS_VLSERVER_FL_IS_YFS 2               /* Server is YFS not AFS */
+#define AFS_VLSERVER_FL_RESPONDING 3           /* VL server is responding */
        rwlock_t                lock;           /* Lock on addresses */
        atomic_t                usage;
+       unsigned int            rtt;            /* Server's current RTT in uS */
 
        /* Probe state */
        wait_queue_head_t       probe_wq;
        atomic_t                probe_outstanding;
        spinlock_t              probe_lock;
        struct {
-               unsigned int    rtt;            /* RTT as ktime/64 */
+               unsigned int    rtt;            /* RTT in uS */
                u32             abort_code;
                short           error;
-               bool            have_result;
-               bool            responded:1;
-               bool            is_yfs:1;
-               bool            not_yfs:1;
-               bool            local_failure:1;
+               unsigned short  flags;
+#define AFS_VLSERVER_PROBE_RESPONDED           0x01 /* At least once response (may be abort) */
+#define AFS_VLSERVER_PROBE_IS_YFS              0x02 /* The peer appears to be YFS */
+#define AFS_VLSERVER_PROBE_NOT_YFS             0x04 /* The peer appears not to be YFS */
+#define AFS_VLSERVER_PROBE_LOCAL_FAILURE       0x08 /* A local failure prevented a probe */
        } probe;
 
        u16                     port;
@@ -810,6 +812,7 @@ struct afs_operation {
                } store;
                struct {
                        struct iattr    *attr;
+                       loff_t          old_i_size;
                } setattr;
                struct afs_acl  *acl;
                struct yfs_acl  *yacl;
index 5334f1b..1d1a8de 100644 (file)
@@ -120,42 +120,42 @@ void afs_prioritise_error(struct afs_error *e, int error, u32 abort_code)
                if (e->error == -ETIMEDOUT ||
                    e->error == -ETIME)
                        return;
-               /* Fall through */
+               fallthrough;
        case -ETIMEDOUT:
        case -ETIME:
                if (e->error == -ENOMEM ||
                    e->error == -ENONET)
                        return;
-               /* Fall through */
+               fallthrough;
        case -ENOMEM:
        case -ENONET:
                if (e->error == -ERFKILL)
                        return;
-               /* Fall through */
+               fallthrough;
        case -ERFKILL:
                if (e->error == -EADDRNOTAVAIL)
                        return;
-               /* Fall through */
+               fallthrough;
        case -EADDRNOTAVAIL:
                if (e->error == -ENETUNREACH)
                        return;
-               /* Fall through */
+               fallthrough;
        case -ENETUNREACH:
                if (e->error == -EHOSTUNREACH)
                        return;
-               /* Fall through */
+               fallthrough;
        case -EHOSTUNREACH:
                if (e->error == -EHOSTDOWN)
                        return;
-               /* Fall through */
+               fallthrough;
        case -EHOSTDOWN:
                if (e->error == -ECONNREFUSED)
                        return;
-               /* Fall through */
+               fallthrough;
        case -ECONNREFUSED:
                if (e->error == -ECONNRESET)
                        return;
-               /* Fall through */
+               fallthrough;
        case -ECONNRESET: /* Responded, but call expired. */
                if (e->responded)
                        return;
index e817fc7..e8babb6 100644 (file)
@@ -310,6 +310,11 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
                                   alist->preferred == i ? '>' : '-',
                                   &alist->addrs[i].transport);
        }
+       seq_printf(m, " info: fl=%lx rtt=%d\n", vlserver->flags, vlserver->rtt);
+       seq_printf(m, " probe: fl=%x e=%d ac=%d out=%d\n",
+                  vlserver->probe.flags, vlserver->probe.error,
+                  vlserver->probe.abort_code,
+                  atomic_read(&vlserver->probe_outstanding));
        return 0;
 }
 
index 6a0935c..d83f13c 100644 (file)
@@ -281,7 +281,7 @@ bool afs_select_fileserver(struct afs_operation *op)
        case -ETIME:
                if (op->error != -EDESTADDRREQ)
                        goto iterate_address;
-               /* Fall through */
+               fallthrough;
        case -ERFKILL:
        case -EADDRNOTAVAIL:
        case -ENETUNREACH:
index 8fc8fb4..8be709c 100644 (file)
@@ -568,7 +568,7 @@ static void afs_deliver_to_call(struct afs_call *call)
                case -EIO:
                        pr_err("kAFS: Call %u in bad state %u\n",
                               call->debug_id, state);
-                       /* Fall through */
+                       fallthrough;
                case -ENODATA:
                case -EBADMSG:
                case -EMSGSIZE:
@@ -669,7 +669,7 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
                ret = call->ret0;
                call->ret0 = 0;
 
-               /* Fall through */
+               fallthrough;
        case -ECONNABORTED:
                ac->responded = true;
                break;
@@ -872,7 +872,7 @@ void afs_send_empty_reply(struct afs_call *call)
                _debug("oom");
                rxrpc_kernel_abort_call(net->socket, call->rxcall,
                                        RX_USER_ABORT, -ENOMEM, "KOO");
-               /* Fall through */
+               fallthrough;
        default:
                _leave(" [error]");
                return;
index 8fea54e..38b2ba1 100644 (file)
@@ -21,6 +21,7 @@ struct afs_vlserver *afs_alloc_vlserver(const char *name, size_t name_len,
                rwlock_init(&vlserver->lock);
                init_waitqueue_head(&vlserver->probe_wq);
                spin_lock_init(&vlserver->probe_lock);
+               vlserver->rtt = UINT_MAX;
                vlserver->name_len = name_len;
                vlserver->port = port;
                memcpy(vlserver->name, name, name_len);
index e3aa013..d1c7068 100644 (file)
 #include "internal.h"
 #include "protocol_yfs.h"
 
-static bool afs_vl_probe_done(struct afs_vlserver *server)
+
+/*
+ * Handle the completion of a set of probes.
+ */
+static void afs_finished_vl_probe(struct afs_vlserver *server)
 {
-       if (!atomic_dec_and_test(&server->probe_outstanding))
-               return false;
+       if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)) {
+               server->rtt = UINT_MAX;
+               clear_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags);
+       }
 
-       wake_up_var(&server->probe_outstanding);
        clear_bit_unlock(AFS_VLSERVER_FL_PROBING, &server->flags);
        wake_up_bit(&server->flags, AFS_VLSERVER_FL_PROBING);
-       return true;
+}
+
+/*
+ * Handle the completion of a probe RPC call.
+ */
+static void afs_done_one_vl_probe(struct afs_vlserver *server, bool wake_up)
+{
+       if (atomic_dec_and_test(&server->probe_outstanding)) {
+               afs_finished_vl_probe(server);
+               wake_up = true;
+       }
+
+       if (wake_up)
+               wake_up_all(&server->probe_wq);
 }
 
 /*
@@ -45,15 +63,20 @@ void afs_vlserver_probe_result(struct afs_call *call)
                server->probe.error = 0;
                goto responded;
        case -ECONNABORTED:
-               if (!server->probe.responded) {
+               if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)) {
                        server->probe.abort_code = call->abort_code;
                        server->probe.error = ret;
                }
                goto responded;
        case -ENOMEM:
        case -ENONET:
-               server->probe.local_failure = true;
-               afs_io_error(call, afs_io_error_vl_probe_fail);
+       case -EKEYEXPIRED:
+       case -EKEYREVOKED:
+       case -EKEYREJECTED:
+               server->probe.flags |= AFS_VLSERVER_PROBE_LOCAL_FAILURE;
+               if (server->probe.error == 0)
+                       server->probe.error = ret;
+               trace_afs_io_error(call->debug_id, ret, afs_io_error_vl_probe_fail);
                goto out;
        case -ECONNRESET: /* Responded, but call expired. */
        case -ERFKILL:
@@ -67,12 +90,12 @@ void afs_vlserver_probe_result(struct afs_call *call)
        default:
                clear_bit(index, &alist->responded);
                set_bit(index, &alist->failed);
-               if (!server->probe.responded &&
+               if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED) &&
                    (server->probe.error == 0 ||
                     server->probe.error == -ETIMEDOUT ||
                     server->probe.error == -ETIME))
                        server->probe.error = ret;
-               afs_io_error(call, afs_io_error_vl_probe_fail);
+               trace_afs_io_error(call->debug_id, ret, afs_io_error_vl_probe_fail);
                goto out;
        }
 
@@ -81,39 +104,36 @@ responded:
        clear_bit(index, &alist->failed);
 
        if (call->service_id == YFS_VL_SERVICE) {
-               server->probe.is_yfs = true;
+               server->probe.flags |= AFS_VLSERVER_PROBE_IS_YFS;
                set_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags);
                alist->addrs[index].srx_service = call->service_id;
        } else {
-               server->probe.not_yfs = true;
-               if (!server->probe.is_yfs) {
+               server->probe.flags |= AFS_VLSERVER_PROBE_NOT_YFS;
+               if (!(server->probe.flags & AFS_VLSERVER_PROBE_IS_YFS)) {
                        clear_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags);
                        alist->addrs[index].srx_service = call->service_id;
                }
        }
 
-       rtt_us = rxrpc_kernel_get_srtt(call->net->socket, call->rxcall);
-       if (rtt_us < server->probe.rtt) {
+       if (rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us) &&
+           rtt_us < server->probe.rtt) {
                server->probe.rtt = rtt_us;
+               server->rtt = rtt_us;
                alist->preferred = index;
-               have_result = true;
        }
 
        smp_wmb(); /* Set rtt before responded. */
-       server->probe.responded = true;
+       server->probe.flags |= AFS_VLSERVER_PROBE_RESPONDED;
        set_bit(AFS_VLSERVER_FL_PROBED, &server->flags);
+       set_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags);
+       have_result = true;
 out:
        spin_unlock(&server->probe_lock);
 
        _debug("probe [%u][%u] %pISpc rtt=%u ret=%d",
               server_index, index, &alist->addrs[index].transport, rtt_us, ret);
 
-       have_result |= afs_vl_probe_done(server);
-       if (have_result) {
-               server->probe.have_result = true;
-               wake_up_var(&server->probe.have_result);
-               wake_up_all(&server->probe_wq);
-       }
+       afs_done_one_vl_probe(server, have_result);
 }
 
 /*
@@ -151,11 +171,10 @@ static bool afs_do_probe_vlserver(struct afs_net *net,
                        in_progress = true;
                } else {
                        afs_prioritise_error(_e, PTR_ERR(call), ac.abort_code);
+                       afs_done_one_vl_probe(server, false);
                }
        }
 
-       if (!in_progress)
-               afs_vl_probe_done(server);
        return in_progress;
 }
 
@@ -193,7 +212,7 @@ int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist,
 {
        struct wait_queue_entry *waits;
        struct afs_vlserver *server;
-       unsigned int rtt = UINT_MAX;
+       unsigned int rtt = UINT_MAX, rtt_s;
        bool have_responders = false;
        int pref = -1, i;
 
@@ -205,7 +224,7 @@ int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist,
                        server = vllist->servers[i].server;
                        if (!test_bit(AFS_VLSERVER_FL_PROBING, &server->flags))
                                __clear_bit(i, &untried);
-                       if (server->probe.responded)
+                       if (server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)
                                have_responders = true;
                }
        }
@@ -231,7 +250,7 @@ int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist,
                for (i = 0; i < vllist->nr_servers; i++) {
                        if (test_bit(i, &untried)) {
                                server = vllist->servers[i].server;
-                               if (server->probe.responded)
+                               if (server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)
                                        goto stop;
                                if (test_bit(AFS_VLSERVER_FL_PROBING, &server->flags))
                                        still_probing = true;
@@ -249,10 +268,11 @@ stop:
        for (i = 0; i < vllist->nr_servers; i++) {
                if (test_bit(i, &untried)) {
                        server = vllist->servers[i].server;
-                       if (server->probe.responded &&
-                           server->probe.rtt < rtt) {
+                       rtt_s = READ_ONCE(server->rtt);
+                       if (test_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags) &&
+                           rtt_s < rtt) {
                                pref = i;
-                               rtt = server->probe.rtt;
+                               rtt = rtt_s;
                        }
 
                        remove_wait_queue(&server->probe_wq, &waits[i]);
index f405ca8..c0458c9 100644 (file)
@@ -192,7 +192,8 @@ pick_server:
        for (i = 0; i < vc->server_list->nr_servers; i++) {
                struct afs_vlserver *s = vc->server_list->servers[i].server;
 
-               if (!test_bit(i, &vc->untried) || !s->probe.responded)
+               if (!test_bit(i, &vc->untried) ||
+                   !test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags))
                        continue;
                if (s->probe.rtt < rtt) {
                        vc->index = i;
@@ -262,10 +263,14 @@ no_more_servers:
        for (i = 0; i < vc->server_list->nr_servers; i++) {
                struct afs_vlserver *s = vc->server_list->servers[i].server;
 
+               if (test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags))
+                       e.responded = true;
                afs_prioritise_error(&e, READ_ONCE(s->probe.error),
                                     s->probe.abort_code);
        }
 
+       error = e.error;
+
 failed_set_error:
        vc->error = error;
 failed:
index fd82850..dc93273 100644 (file)
@@ -196,7 +196,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
 
                /* Extract the returned uuid, uniquifier, nentries and
                 * blkaddrs size */
-               /* Fall through */
+               fallthrough;
        case 1:
                ret = afs_extract_data(call, true);
                if (ret < 0)
@@ -221,7 +221,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
                count = min(call->count, 4U);
                afs_extract_to_buf(call, count * sizeof(__be32));
 
-               /* Fall through - and extract entries */
+               fallthrough;    /* and extract entries */
        case 2:
                ret = afs_extract_data(call, call->count > 4);
                if (ret < 0)
@@ -324,7 +324,7 @@ static int afs_deliver_vl_get_capabilities(struct afs_call *call)
                afs_extract_to_tmp(call);
                call->unmarshall++;
 
-               /* Fall through - and extract the capabilities word count */
+               fallthrough;    /* and extract the capabilities word count */
        case 1:
                ret = afs_extract_data(call, true);
                if (ret < 0)
@@ -337,7 +337,7 @@ static int afs_deliver_vl_get_capabilities(struct afs_call *call)
                call->unmarshall++;
                afs_extract_discard(call, count * sizeof(__be32));
 
-               /* Fall through - and extract capabilities words */
+               fallthrough;    /* and extract capabilities words */
        case 2:
                ret = afs_extract_data(call, false);
                if (ret < 0)
@@ -436,7 +436,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
                /* Extract the returned uuid, uniquifier, fsEndpoints count and
                 * either the first fsEndpoint type or the volEndpoints
                 * count if there are no fsEndpoints. */
-               /* Fall through */
+               fallthrough;
        case 1:
                ret = afs_extract_data(call, true);
                if (ret < 0)
@@ -475,7 +475,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
                afs_extract_to_buf(call, size);
                call->unmarshall = 2;
 
-               /* Fall through - and extract fsEndpoints[] entries */
+               fallthrough;    /* and extract fsEndpoints[] entries */
        case 2:
                ret = afs_extract_data(call, true);
                if (ret < 0)
@@ -526,7 +526,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
                 * extract the type of the next endpoint when we extract the
                 * data of the current one, but this is the first...
                 */
-               /* Fall through */
+               fallthrough;
        case 3:
                ret = afs_extract_data(call, true);
                if (ret < 0)
@@ -552,7 +552,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
                afs_extract_to_buf(call, size);
                call->unmarshall = 4;
 
-               /* Fall through - and extract volEndpoints[] entries */
+               fallthrough;    /* and extract volEndpoints[] entries */
        case 4:
                ret = afs_extract_data(call, true);
                if (ret < 0)
@@ -587,7 +587,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
                afs_extract_discard(call, 0);
                call->unmarshall = 5;
 
-               /* Fall through - Done */
+               fallthrough;    /* Done */
        case 5:
                ret = afs_extract_data(call, false);
                if (ret < 0)
@@ -663,7 +663,7 @@ static int afs_deliver_yfsvl_get_cell_name(struct afs_call *call)
                afs_extract_to_tmp(call);
                call->unmarshall++;
 
-               /* Fall through - and extract the cell name length */
+               fallthrough;    /* and extract the cell name length */
        case 1:
                ret = afs_extract_data(call, true);
                if (ret < 0)
@@ -685,7 +685,7 @@ static int afs_deliver_yfsvl_get_cell_name(struct afs_call *call)
                afs_extract_begin(call, cell_name, namesz);
                call->unmarshall++;
 
-               /* Fall through - and extract cell name */
+               fallthrough;    /* and extract cell name */
        case 2:
                ret = afs_extract_data(call, true);
                if (ret < 0)
@@ -694,7 +694,7 @@ static int afs_deliver_yfsvl_get_cell_name(struct afs_call *call)
                afs_extract_discard(call, call->count2);
                call->unmarshall++;
 
-               /* Fall through - and extract padding */
+               fallthrough;    /* and extract padding */
        case 3:
                ret = afs_extract_data(call, false);
                if (ret < 0)
index a121c24..da12abd 100644 (file)
@@ -609,7 +609,7 @@ no_more:
 
        default:
                pr_notice("kAFS: Unexpected error from FS.StoreData %d\n", ret);
-               /* Fall through */
+               fallthrough;
        case -EACCES:
        case -EPERM:
        case -ENOKEY:
@@ -738,11 +738,21 @@ static int afs_writepages_region(struct address_space *mapping,
 int afs_writepages(struct address_space *mapping,
                   struct writeback_control *wbc)
 {
+       struct afs_vnode *vnode = AFS_FS_I(mapping->host);
        pgoff_t start, end, next;
        int ret;
 
        _enter("");
 
+       /* We have to be careful as we can end up racing with setattr()
+        * truncating the pagecache since the caller doesn't take a lock here
+        * to prevent it.
+        */
+       if (wbc->sync_mode == WB_SYNC_ALL)
+               down_read(&vnode->validate_lock);
+       else if (!down_read_trylock(&vnode->validate_lock))
+               return 0;
+
        if (wbc->range_cyclic) {
                start = mapping->writeback_index;
                end = -1;
@@ -762,6 +772,7 @@ int afs_writepages(struct address_space *mapping,
                ret = afs_writepages_region(mapping, wbc, start, end, &next);
        }
 
+       up_read(&vnode->validate_lock);
        _leave(" = %d", ret);
        return ret;
 }
index 8c24fdc..3b1239b 100644 (file)
@@ -373,7 +373,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
                req->offset = req->pos & (PAGE_SIZE - 1);
                afs_extract_to_tmp64(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the returned data length */
        case 1:
@@ -401,7 +401,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
                call->bvec[0].bv_page = req->pages[req->index];
                iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size);
                ASSERTCMP(size, <=, PAGE_SIZE);
-               /* Fall through */
+               fallthrough;
 
                /* extract the returned data */
        case 2:
@@ -428,7 +428,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
                /* Discard any excess data the server gave us */
                afs_extract_discard(call, req->actual_len - req->len);
                call->unmarshall = 3;
-               /* Fall through */
+               fallthrough;
 
        case 3:
                _debug("extract discard %zu/%llu",
@@ -444,7 +444,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
                                   sizeof(struct yfs_xdr_YFSFetchStatus) +
                                   sizeof(struct yfs_xdr_YFSCallBack) +
                                   sizeof(struct yfs_xdr_YFSVolSync));
-               /* Fall through */
+               fallthrough;
 
                /* extract the metadata */
        case 4:
@@ -461,7 +461,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
                req->file_size = vp->scb.status.size;
 
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
        case 5:
                break;
@@ -1262,7 +1262,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
        case 0:
                call->unmarshall++;
                afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSFetchVolumeStatus));
-               /* Fall through */
+               fallthrough;
 
                /* extract the returned status record */
        case 1:
@@ -1275,7 +1275,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                xdr_decode_YFSFetchVolumeStatus(&bp, &op->volstatus.vs);
                call->unmarshall++;
                afs_extract_to_tmp(call);
-               /* Fall through */
+               fallthrough;
 
                /* extract the volume name length */
        case 2:
@@ -1290,7 +1290,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                size = (call->count + 3) & ~3; /* It's padded */
                afs_extract_to_buf(call, size);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the volume name */
        case 3:
@@ -1304,7 +1304,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                _debug("volname '%s'", p);
                afs_extract_to_tmp(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the offline message length */
        case 4:
@@ -1319,7 +1319,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                size = (call->count + 3) & ~3; /* It's padded */
                afs_extract_to_buf(call, size);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the offline message */
        case 5:
@@ -1334,7 +1334,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
 
                afs_extract_to_tmp(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the message of the day length */
        case 6:
@@ -1349,7 +1349,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                size = (call->count + 3) & ~3; /* It's padded */
                afs_extract_to_buf(call, size);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the message of the day */
        case 7:
@@ -1363,7 +1363,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
                _debug("motd '%s'", p);
 
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
        case 8:
                break;
@@ -1622,7 +1622,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
        case 0:
                afs_extract_to_tmp(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* Extract the file status count and array in two steps */
        case 1:
@@ -1640,7 +1640,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
                call->unmarshall++;
        more_counts:
                afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSFetchStatus));
-               /* Fall through */
+               fallthrough;
 
        case 2:
                _debug("extract status array %u", call->count);
@@ -1670,7 +1670,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
                call->count = 0;
                call->unmarshall++;
                afs_extract_to_tmp(call);
-               /* Fall through */
+               fallthrough;
 
                /* Extract the callback count and array in two steps */
        case 3:
@@ -1687,7 +1687,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
                call->unmarshall++;
        more_cbs:
                afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSCallBack));
-               /* Fall through */
+               fallthrough;
 
        case 4:
                _debug("extract CB array");
@@ -1716,7 +1716,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
 
                afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSVolSync));
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
        case 5:
                ret = afs_extract_data(call, false);
@@ -1727,7 +1727,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
                xdr_decode_YFSVolSync(&bp, &op->volsync);
 
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
        case 6:
                break;
@@ -1804,7 +1804,7 @@ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
        case 0:
                afs_extract_to_tmp(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* Extract the file ACL length */
        case 1:
@@ -1826,7 +1826,7 @@ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
                        afs_extract_discard(call, size);
                }
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* Extract the file ACL */
        case 2:
@@ -1836,7 +1836,7 @@ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
 
                afs_extract_to_tmp(call);
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* Extract the volume ACL length */
        case 3:
@@ -1858,7 +1858,7 @@ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
                        afs_extract_discard(call, size);
                }
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* Extract the volume ACL */
        case 4:
@@ -1871,7 +1871,7 @@ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
                                   sizeof(struct yfs_xdr_YFSFetchStatus) +
                                   sizeof(struct yfs_xdr_YFSVolSync));
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
                /* extract the metadata */
        case 5:
@@ -1886,7 +1886,7 @@ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
                xdr_decode_YFSVolSync(&bp, &op->volsync);
 
                call->unmarshall++;
-               /* Fall through */
+               fallthrough;
 
        case 6:
                break;
index 5736bff..c45c20d 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1489,12 +1489,8 @@ static ssize_t aio_setup_rw(int rw, const struct iocb *iocb,
                *iovec = NULL;
                return ret;
        }
-#ifdef CONFIG_COMPAT
-       if (compat)
-               return compat_import_iovec(rw, buf, len, UIO_FASTIOV, iovec,
-                               iter);
-#endif
-       return import_iovec(rw, buf, len, UIO_FASTIOV, iovec, iter);
+
+       return __import_iovec(rw, buf, len, UIO_FASTIOV, iovec, iter, compat);
 }
 
 static inline void aio_rw_done(struct kiocb *req, ssize_t ret)
@@ -1511,7 +1507,7 @@ static inline void aio_rw_done(struct kiocb *req, ssize_t ret)
                 * may be already running. Just fail this IO with EINTR.
                 */
                ret = -EINTR;
-               /*FALLTHRU*/
+               fallthrough;
        default:
                req->ki_complete(req, ret, 0);
        }
index 74c886f..5ced859 100644 (file)
@@ -53,7 +53,7 @@ static int autofs_write(struct autofs_sb_info *sbi,
 
        mutex_lock(&sbi->pipe_mutex);
        while (bytes) {
-               wr = kernel_write(file, data, bytes, &file->f_pos);
+               wr = __kernel_write(file, data, bytes, NULL);
                if (wr <= 0)
                        break;
                data += wr;
index f2f9086..b9c658e 100644 (file)
@@ -576,7 +576,7 @@ static int load_flat_file(struct linux_binprm *bprm,
                        goto err;
                }
 
-               len = data_len + extra;
+               len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
                len = PAGE_ALIGN(len);
                realdatastart = vm_mmap(NULL, 0, len,
                        PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
@@ -590,7 +590,9 @@ static int load_flat_file(struct linux_binprm *bprm,
                        vm_munmap(textpos, text_len);
                        goto err;
                }
-               datapos = ALIGN(realdatastart, FLAT_DATA_ALIGN);
+               datapos = ALIGN(realdatastart +
+                               MAX_SHARED_LIBS * sizeof(unsigned long),
+                               FLAT_DATA_ALIGN);
 
                pr_debug("Allocated data+bss+stack (%u bytes): %lx\n",
                         data_len + bss_len + stack_len, datapos);
@@ -620,7 +622,7 @@ static int load_flat_file(struct linux_binprm *bprm,
                memp_size = len;
        } else {
 
-               len = text_len + data_len + extra;
+               len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(u32);
                len = PAGE_ALIGN(len);
                textpos = vm_mmap(NULL, 0, len,
                        PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
@@ -635,7 +637,9 @@ static int load_flat_file(struct linux_binprm *bprm,
                }
 
                realdatastart = textpos + ntohl(hdr->data_start);
-               datapos = ALIGN(realdatastart, FLAT_DATA_ALIGN);
+               datapos = ALIGN(realdatastart +
+                               MAX_SHARED_LIBS * sizeof(u32),
+                               FLAT_DATA_ALIGN);
 
                reloc = (__be32 __user *)
                        (datapos + (ntohl(hdr->reloc_start) - text_len));
@@ -652,9 +656,8 @@ static int load_flat_file(struct linux_binprm *bprm,
                                         (text_len + full_data
                                                  - sizeof(struct flat_hdr)),
                                         0);
-                       if (datapos != realdatastart)
-                               memmove((void *)datapos, (void *)realdatastart,
-                                               full_data);
+                       memmove((void *) datapos, (void *) realdatastart,
+                                       full_data);
 #else
                        /*
                         * This is used on MMU systems mainly for testing.
@@ -710,7 +713,8 @@ static int load_flat_file(struct linux_binprm *bprm,
                if (IS_ERR_VALUE(result)) {
                        ret = result;
                        pr_err("Unable to read code+data+bss, errno %d\n", ret);
-                       vm_munmap(textpos, text_len + data_len + extra);
+                       vm_munmap(textpos, text_len + data_len + extra +
+                               MAX_SHARED_LIBS * sizeof(u32));
                        goto err;
                }
        }
index 613920c..ea8aaf3 100644 (file)
@@ -1798,7 +1798,6 @@ static struct btrfs_block_group *btrfs_create_block_group_cache(
 
        cache->fs_info = fs_info;
        cache->full_stripe_len = btrfs_full_stripe_len(fs_info, start);
-       set_free_space_tree_thresholds(cache);
 
        cache->discard_index = BTRFS_DISCARD_INDEX_UNUSED;
 
@@ -1912,6 +1911,8 @@ static int read_one_block_group(struct btrfs_fs_info *info,
        if (ret < 0)
                goto error;
 
+       set_free_space_tree_thresholds(cache);
+
        if (need_clear) {
                /*
                 * When we mount with old space cache, we need to
@@ -2132,6 +2133,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used,
                return -ENOMEM;
 
        cache->length = size;
+       set_free_space_tree_thresholds(cache);
        cache->used = bytes_used;
        cache->flags = type;
        cache->last_byte_to_unpin = (u64)-1;
index 70e49d8..cd392da 100644 (file)
@@ -68,7 +68,7 @@ const char *btrfs_super_csum_driver(u16 csum_type)
                btrfs_csums[csum_type].name;
 }
 
-size_t __const btrfs_get_num_csums(void)
+size_t __attribute_const__ btrfs_get_num_csums(void)
 {
        return ARRAY_SIZE(btrfs_csums);
 }
@@ -1297,6 +1297,8 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
        btrfs_tree_read_unlock_blocking(eb);
        free_extent_buffer(eb);
 
+       btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb_rewin),
+                                      eb_rewin, btrfs_header_level(eb_rewin));
        btrfs_tree_read_lock(eb_rewin);
        __tree_mod_log_rewind(fs_info, eb_rewin, time_seq, tm);
        WARN_ON(btrfs_header_nritems(eb_rewin) >
@@ -1370,7 +1372,6 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
 
        if (!eb)
                return NULL;
-       btrfs_tree_read_lock(eb);
        if (old_root) {
                btrfs_set_header_bytenr(eb, eb->start);
                btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV);
@@ -1378,6 +1379,9 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
                btrfs_set_header_level(eb, old_root->level);
                btrfs_set_header_generation(eb, old_generation);
        }
+       btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb), eb,
+                                      btrfs_header_level(eb));
+       btrfs_tree_read_lock(eb);
        if (tm)
                __tree_mod_log_rewind(fs_info, eb, time_seq, tm);
        else
index 9c7e466..9a72896 100644 (file)
@@ -2262,7 +2262,7 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
 int btrfs_super_csum_size(const struct btrfs_super_block *s);
 const char *btrfs_super_csum_name(u16 csum_type);
 const char *btrfs_super_csum_driver(u16 csum_type);
-size_t __const btrfs_get_num_csums(void);
+size_t __attribute_const__ btrfs_get_num_csums(void);
 
 
 /*
@@ -2518,7 +2518,7 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
                                    u64 bytenr, u64 num_bytes);
 int btrfs_exclude_logged_extents(struct extent_buffer *eb);
 int btrfs_cross_ref_exist(struct btrfs_root *root,
-                         u64 objectid, u64 offset, u64 bytenr);
+                         u64 objectid, u64 offset, u64 bytenr, bool strict);
 struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
                                             struct btrfs_root *root,
                                             u64 parent, u64 root_objectid,
@@ -2934,7 +2934,7 @@ struct extent_map *btrfs_get_extent_fiemap(struct btrfs_inode *inode,
                                           u64 start, u64 len);
 noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
                              u64 *orig_start, u64 *orig_block_len,
-                             u64 *ram_bytes);
+                             u64 *ram_bytes, bool strict);
 
 void __btrfs_del_delalloc_inode(struct btrfs_root *root,
                                struct btrfs_inode *inode);
index db93909..e4a1c6a 100644 (file)
@@ -599,6 +599,37 @@ static void btrfs_rm_dev_replace_unblocked(struct btrfs_fs_info *fs_info)
        wake_up(&fs_info->dev_replace.replace_wait);
 }
 
+/*
+ * When finishing the device replace, before swapping the source device with the
+ * target device we must update the chunk allocation state in the target device,
+ * as it is empty because replace works by directly copying the chunks and not
+ * through the normal chunk allocation path.
+ */
+static int btrfs_set_target_alloc_state(struct btrfs_device *srcdev,
+                                       struct btrfs_device *tgtdev)
+{
+       struct extent_state *cached_state = NULL;
+       u64 start = 0;
+       u64 found_start;
+       u64 found_end;
+       int ret = 0;
+
+       lockdep_assert_held(&srcdev->fs_info->chunk_mutex);
+
+       while (!find_first_extent_bit(&srcdev->alloc_state, start,
+                                     &found_start, &found_end,
+                                     CHUNK_ALLOCATED, &cached_state)) {
+               ret = set_extent_bits(&tgtdev->alloc_state, found_start,
+                                     found_end, CHUNK_ALLOCATED);
+               if (ret)
+                       break;
+               start = found_end + 1;
+       }
+
+       free_extent_state(cached_state);
+       return ret;
+}
+
 static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
                                       int scrub_ret)
 {
@@ -673,8 +704,14 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
        dev_replace->time_stopped = ktime_get_real_seconds();
        dev_replace->item_needs_writeback = 1;
 
-       /* replace old device with new one in mapping tree */
+       /*
+        * Update allocation state in the new device and replace the old device
+        * with the new one in the mapping tree.
+        */
        if (!scrub_ret) {
+               scrub_ret = btrfs_set_target_alloc_state(src_device, tgt_device);
+               if (scrub_ret)
+                       goto error;
                btrfs_dev_replace_update_device_in_mapping_tree(fs_info,
                                                                src_device,
                                                                tgt_device);
@@ -685,6 +722,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
                                 btrfs_dev_name(src_device),
                                 src_device->devid,
                                 rcu_str_deref(tgt_device->name), scrub_ret);
+error:
                up_write(&dev_replace->rwsem);
                mutex_unlock(&fs_info->chunk_mutex);
                mutex_unlock(&fs_info->fs_devices->device_list_mutex);
@@ -745,7 +783,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
        /* replace the sysfs entry */
        btrfs_sysfs_remove_devices_dir(fs_info->fs_devices, src_device);
        btrfs_sysfs_update_devid(tgt_device);
-       btrfs_rm_dev_replace_free_srcdev(src_device);
+       if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &src_device->dev_state))
+               btrfs_scratch_superblocks(fs_info, src_device->bdev,
+                                         src_device->name->str);
 
        /* write back the superblocks */
        trans = btrfs_start_transaction(root, 0);
@@ -754,6 +794,8 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
 
        mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
 
+       btrfs_rm_dev_replace_free_srcdev(src_device);
+
        return 0;
 }
 
index 9ae25f6..9f72b09 100644 (file)
@@ -636,16 +636,15 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
        csum_tree_block(eb, result);
 
        if (memcmp_extent_buffer(eb, result, 0, csum_size)) {
-               u32 val;
-               u32 found = 0;
-
-               memcpy(&found, result, csum_size);
+               u8 val[BTRFS_CSUM_SIZE] = { 0 };
 
                read_extent_buffer(eb, &val, 0, csum_size);
                btrfs_warn_rl(fs_info,
-               "%s checksum verify failed on %llu wanted %x found %x level %d",
+       "%s checksum verify failed on %llu wanted " CSUM_FMT " found " CSUM_FMT " level %d",
                              fs_info->sb->s_id, eb->start,
-                             val, found, btrfs_header_level(eb));
+                             CSUM_FMT_VALUE(csum_size, val),
+                             CSUM_FMT_VALUE(csum_size, result),
+                             btrfs_header_level(eb));
                ret = -EUCLEAN;
                goto err;
        }
@@ -3418,6 +3417,8 @@ fail_block_groups:
        btrfs_put_block_group_cache(fs_info);
 
 fail_tree_roots:
+       if (fs_info->data_reloc_root)
+               btrfs_drop_and_free_fs_root(fs_info, fs_info->data_reloc_root);
        free_root_pointers(fs_info, true);
        invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
 
@@ -4551,6 +4552,7 @@ static void btrfs_cleanup_bg_io(struct btrfs_block_group *cache)
                cache->io_ctl.inode = NULL;
                iput(inode);
        }
+       ASSERT(cache->io_ctl.pages == NULL);
        btrfs_put_block_group(cache);
 }
 
index de6fe17..780b9c9 100644 (file)
@@ -400,12 +400,11 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
                        if (type == BTRFS_SHARED_BLOCK_REF_KEY) {
                                ASSERT(eb->fs_info);
                                /*
-                                * Every shared one has parent tree
-                                * block, which must be aligned to
-                                * nodesize.
+                                * Every shared one has parent tree block,
+                                * which must be aligned to sector size.
                                 */
                                if (offset &&
-                                   IS_ALIGNED(offset, eb->fs_info->nodesize))
+                                   IS_ALIGNED(offset, eb->fs_info->sectorsize))
                                        return type;
                        }
                } else if (is_data == BTRFS_REF_TYPE_DATA) {
@@ -414,12 +413,11 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
                        if (type == BTRFS_SHARED_DATA_REF_KEY) {
                                ASSERT(eb->fs_info);
                                /*
-                                * Every shared one has parent tree
-                                * block, which must be aligned to
-                                * nodesize.
+                                * Every shared one has parent tree block,
+                                * which must be aligned to sector size.
                                 */
                                if (offset &&
-                                   IS_ALIGNED(offset, eb->fs_info->nodesize))
+                                   IS_ALIGNED(offset, eb->fs_info->sectorsize))
                                        return type;
                        }
                } else {
@@ -429,8 +427,9 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
        }
 
        btrfs_print_leaf((struct extent_buffer *)eb);
-       btrfs_err(eb->fs_info, "eb %llu invalid extent inline ref type %d",
-                 eb->start, type);
+       btrfs_err(eb->fs_info,
+                 "eb %llu iref 0x%lx invalid extent inline ref type %d",
+                 eb->start, (unsigned long)iref, type);
        WARN_ON(1);
 
        return BTRFS_REF_TYPE_INVALID;
@@ -2306,7 +2305,8 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
 
 static noinline int check_committed_ref(struct btrfs_root *root,
                                        struct btrfs_path *path,
-                                       u64 objectid, u64 offset, u64 bytenr)
+                                       u64 objectid, u64 offset, u64 bytenr,
+                                       bool strict)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_root *extent_root = fs_info->extent_root;
@@ -2348,9 +2348,13 @@ static noinline int check_committed_ref(struct btrfs_root *root,
            btrfs_extent_inline_ref_size(BTRFS_EXTENT_DATA_REF_KEY))
                goto out;
 
-       /* If extent created before last snapshot => it's definitely shared */
-       if (btrfs_extent_generation(leaf, ei) <=
-           btrfs_root_last_snapshot(&root->root_item))
+       /*
+        * If extent created before last snapshot => it's shared unless the
+        * snapshot has been deleted. Use the heuristic if strict is false.
+        */
+       if (!strict &&
+           (btrfs_extent_generation(leaf, ei) <=
+            btrfs_root_last_snapshot(&root->root_item)))
                goto out;
 
        iref = (struct btrfs_extent_inline_ref *)(ei + 1);
@@ -2375,7 +2379,7 @@ out:
 }
 
 int btrfs_cross_ref_exist(struct btrfs_root *root, u64 objectid, u64 offset,
-                         u64 bytenr)
+                         u64 bytenr, bool strict)
 {
        struct btrfs_path *path;
        int ret;
@@ -2386,7 +2390,7 @@ int btrfs_cross_ref_exist(struct btrfs_root *root, u64 objectid, u64 offset,
 
        do {
                ret = check_committed_ref(root, path, objectid,
-                                         offset, bytenr);
+                                         offset, bytenr, strict);
                if (ret && ret != -ENOENT)
                        goto out;
 
@@ -4522,7 +4526,7 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                return ERR_PTR(-EUCLEAN);
        }
 
-       btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level);
+       btrfs_set_buffer_lockdep_class(owner, buf, level);
        btrfs_tree_lock(buf);
        btrfs_clean_tree_block(buf);
        clear_bit(EXTENT_BUFFER_STALE, &buf->bflags);
index 6def411..a940edb 100644 (file)
@@ -5655,9 +5655,9 @@ void read_extent_buffer(const struct extent_buffer *eb, void *dstv,
        }
 }
 
-int read_extent_buffer_to_user(const struct extent_buffer *eb,
-                              void __user *dstv,
-                              unsigned long start, unsigned long len)
+int read_extent_buffer_to_user_nofault(const struct extent_buffer *eb,
+                                      void __user *dstv,
+                                      unsigned long start, unsigned long len)
 {
        size_t cur;
        size_t offset;
@@ -5677,7 +5677,7 @@ int read_extent_buffer_to_user(const struct extent_buffer *eb,
 
                cur = min(len, (PAGE_SIZE - offset));
                kaddr = page_address(page);
-               if (copy_to_user(dst, kaddr + offset, cur)) {
+               if (copy_to_user_nofault(dst, kaddr + offset, cur)) {
                        ret = -EFAULT;
                        break;
                }
index 00a88f2..30794ae 100644 (file)
@@ -241,9 +241,9 @@ int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
 void read_extent_buffer(const struct extent_buffer *eb, void *dst,
                        unsigned long start,
                        unsigned long len);
-int read_extent_buffer_to_user(const struct extent_buffer *eb,
-                              void __user *dst, unsigned long start,
-                              unsigned long len);
+int read_extent_buffer_to_user_nofault(const struct extent_buffer *eb,
+                                      void __user *dst, unsigned long start,
+                                      unsigned long len);
 void write_extent_buffer_fsid(const struct extent_buffer *eb, const void *src);
 void write_extent_buffer_chunk_tree_uuid(const struct extent_buffer *eb,
                const void *src);
index bb824c7..4507c3d 100644 (file)
@@ -1571,7 +1571,7 @@ static int check_can_nocow(struct btrfs_inode *inode, loff_t pos,
        }
 
        ret = can_nocow_extent(&inode->vfs_inode, lockstart, &num_bytes,
-                       NULL, NULL, NULL);
+                       NULL, NULL, NULL, false);
        if (ret <= 0) {
                ret = 0;
                if (!nowait)
index ef0fd7a..dc82fd0 100644 (file)
@@ -1186,7 +1186,6 @@ static int __btrfs_wait_cache_io(struct btrfs_root *root,
        ret = update_cache_item(trans, root, inode, path, offset,
                                io_ctl->entries, io_ctl->bitmaps);
 out:
-       io_ctl_free(io_ctl);
        if (ret) {
                invalidate_inode_pages2(inode->i_mapping);
                BTRFS_I(inode)->generation = 0;
@@ -1347,6 +1346,7 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
         * them out later
         */
        io_ctl_drop_pages(io_ctl);
+       io_ctl_free(io_ctl);
 
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
                             i_size_read(inode) - 1, &cached_state);
index 8b1f5c8..6b9faf3 100644 (file)
@@ -22,6 +22,10 @@ void set_free_space_tree_thresholds(struct btrfs_block_group *cache)
        size_t bitmap_size;
        u64 num_bitmaps, total_bitmap_size;
 
+       if (WARN_ON(cache->length == 0))
+               btrfs_warn(cache->fs_info, "block group %llu length is zero",
+                          cache->start);
+
        /*
         * We convert to bitmaps when the disk space required for using extents
         * exceeds that required for using bitmaps.
index 51fcd82..9570458 100644 (file)
@@ -1610,7 +1610,7 @@ next_slot:
                                goto out_check;
                        ret = btrfs_cross_ref_exist(root, ino,
                                                    found_key.offset -
-                                                   extent_offset, disk_bytenr);
+                                                   extent_offset, disk_bytenr, false);
                        if (ret) {
                                /*
                                 * ret could be -EIO if the above fails to read
@@ -2161,11 +2161,8 @@ static blk_status_t btrfs_submit_bio_start(void *private_data, struct bio *bio,
                                    u64 bio_offset)
 {
        struct inode *inode = private_data;
-       blk_status_t ret = 0;
 
-       ret = btrfs_csum_one_bio(BTRFS_I(inode), bio, 0, 0);
-       BUG_ON(ret); /* -ENOMEM */
-       return 0;
+       return btrfs_csum_one_bio(BTRFS_I(inode), bio, 0, 0);
 }
 
 /*
@@ -6953,6 +6950,8 @@ static struct extent_map *btrfs_new_extent_direct(struct btrfs_inode *inode,
  * @orig_start:        (optional) Return the original file offset of the file extent
  * @orig_len:  (optional) Return the original on-disk length of the file extent
  * @ram_bytes: (optional) Return the ram_bytes of the file extent
+ * @strict:    if true, omit optimizations that might force us into unnecessary
+ *             cow. e.g., don't trust generation number.
  *
  * This function will flush ordered extents in the range to ensure proper
  * nocow checks for (nowait == false) case.
@@ -6967,7 +6966,7 @@ static struct extent_map *btrfs_new_extent_direct(struct btrfs_inode *inode,
  */
 noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
                              u64 *orig_start, u64 *orig_block_len,
-                             u64 *ram_bytes)
+                             u64 *ram_bytes, bool strict)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_path *path;
@@ -7045,8 +7044,9 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
         * Do the same check as in btrfs_cross_ref_exist but without the
         * unnecessary search.
         */
-       if (btrfs_file_extent_generation(leaf, fi) <=
-           btrfs_root_last_snapshot(&root->root_item))
+       if (!strict &&
+           (btrfs_file_extent_generation(leaf, fi) <=
+            btrfs_root_last_snapshot(&root->root_item)))
                goto out;
 
        backref_offset = btrfs_file_extent_offset(leaf, fi);
@@ -7082,7 +7082,8 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
         */
 
        ret = btrfs_cross_ref_exist(root, btrfs_ino(BTRFS_I(inode)),
-                                   key.offset - backref_offset, disk_bytenr);
+                                   key.offset - backref_offset, disk_bytenr,
+                                   strict);
        if (ret) {
                ret = 0;
                goto out;
@@ -7303,7 +7304,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
                block_start = em->block_start + (start - em->start);
 
                if (can_nocow_extent(inode, start, &len, &orig_start,
-                                    &orig_block_len, &ram_bytes) == 1 &&
+                                    &orig_block_len, &ram_bytes, false) == 1 &&
                    btrfs_inc_nocow_writers(fs_info, block_start)) {
                        struct extent_map *em2;
 
@@ -7619,10 +7620,8 @@ static blk_status_t btrfs_submit_bio_start_direct_io(void *private_data,
                                    struct bio *bio, u64 offset)
 {
        struct inode *inode = private_data;
-       blk_status_t ret;
-       ret = btrfs_csum_one_bio(BTRFS_I(inode), bio, offset, 1);
-       BUG_ON(ret); /* -ENOMEM */
-       return 0;
+
+       return btrfs_csum_one_bio(BTRFS_I(inode), bio, offset, 1);
 }
 
 static void btrfs_end_dio_bio(struct bio *bio)
@@ -10136,7 +10135,7 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
                free_extent_map(em);
                em = NULL;
 
-               ret = can_nocow_extent(inode, start, &len, NULL, NULL, NULL);
+               ret = can_nocow_extent(inode, start, &len, NULL, NULL, NULL, true);
                if (ret < 0) {
                        goto out;
                } else if (ret) {
index bd3511c..2d9109d 100644 (file)
@@ -2086,9 +2086,14 @@ static noinline int copy_to_sk(struct btrfs_path *path,
                sh.len = item_len;
                sh.transid = found_transid;
 
-               /* copy search result header */
-               if (copy_to_user(ubuf + *sk_offset, &sh, sizeof(sh))) {
-                       ret = -EFAULT;
+               /*
+                * Copy search result header. If we fault then loop again so we
+                * can fault in the pages and -EFAULT there if there's a
+                * problem. Otherwise we'll fault and then copy the buffer in
+                * properly this next time through
+                */
+               if (copy_to_user_nofault(ubuf + *sk_offset, &sh, sizeof(sh))) {
+                       ret = 0;
                        goto out;
                }
 
@@ -2096,10 +2101,14 @@ static noinline int copy_to_sk(struct btrfs_path *path,
 
                if (item_len) {
                        char __user *up = ubuf + *sk_offset;
-                       /* copy the item */
-                       if (read_extent_buffer_to_user(leaf, up,
-                                                      item_off, item_len)) {
-                               ret = -EFAULT;
+                       /*
+                        * Copy the item, same behavior as above, but reset the
+                        * * sk_offset so we copy the full thing again.
+                        */
+                       if (read_extent_buffer_to_user_nofault(leaf, up,
+                                               item_off, item_len)) {
+                               ret = 0;
+                               *sk_offset -= sizeof(sh);
                                goto out;
                        }
 
@@ -2184,6 +2193,11 @@ static noinline int search_ioctl(struct inode *inode,
        key.offset = sk->min_offset;
 
        while (1) {
+               ret = fault_in_pages_writeable(ubuf + sk_offset,
+                                              *buf_size - sk_offset);
+               if (ret)
+                       break;
+
                ret = btrfs_search_forward(root, &key, path, sk->min_transid);
                if (ret != 0) {
                        if (ret > 0)
index 61f44e7..80567c1 100644 (file)
@@ -95,9 +95,10 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
                         * offset is supposed to be a tree block which
                         * must be aligned to nodesize.
                         */
-                       if (!IS_ALIGNED(offset, eb->fs_info->nodesize))
-                               pr_info("\t\t\t(parent %llu is NOT ALIGNED to nodesize %llu)\n",
-                                       offset, (unsigned long long)eb->fs_info->nodesize);
+                       if (!IS_ALIGNED(offset, eb->fs_info->sectorsize))
+                               pr_info(
+                       "\t\t\t(parent %llu not aligned to sectorsize %u)\n",
+                                       offset, eb->fs_info->sectorsize);
                        break;
                case BTRFS_EXTENT_DATA_REF_KEY:
                        dref = (struct btrfs_extent_data_ref *)(&iref->offset);
@@ -112,8 +113,9 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
                         * must be aligned to nodesize.
                         */
                        if (!IS_ALIGNED(offset, eb->fs_info->nodesize))
-                               pr_info("\t\t\t(parent %llu is NOT ALIGNED to nodesize %llu)\n",
-                                    offset, (unsigned long long)eb->fs_info->nodesize);
+                               pr_info(
+                       "\t\t\t(parent %llu not aligned to sectorsize %u)\n",
+                                    offset, eb->fs_info->sectorsize);
                        break;
                default:
                        pr_cont("(extent %llu has INVALID ref type %d)\n",
index 5a6cb9d..354ab99 100644 (file)
@@ -3716,50 +3716,84 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
        return 0;
 }
 
+static void scrub_workers_put(struct btrfs_fs_info *fs_info)
+{
+       if (refcount_dec_and_mutex_lock(&fs_info->scrub_workers_refcnt,
+                                       &fs_info->scrub_lock)) {
+               struct btrfs_workqueue *scrub_workers = NULL;
+               struct btrfs_workqueue *scrub_wr_comp = NULL;
+               struct btrfs_workqueue *scrub_parity = NULL;
+
+               scrub_workers = fs_info->scrub_workers;
+               scrub_wr_comp = fs_info->scrub_wr_completion_workers;
+               scrub_parity = fs_info->scrub_parity_workers;
+
+               fs_info->scrub_workers = NULL;
+               fs_info->scrub_wr_completion_workers = NULL;
+               fs_info->scrub_parity_workers = NULL;
+               mutex_unlock(&fs_info->scrub_lock);
+
+               btrfs_destroy_workqueue(scrub_workers);
+               btrfs_destroy_workqueue(scrub_wr_comp);
+               btrfs_destroy_workqueue(scrub_parity);
+       }
+}
+
 /*
  * get a reference count on fs_info->scrub_workers. start worker if necessary
  */
 static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
                                                int is_dev_replace)
 {
+       struct btrfs_workqueue *scrub_workers = NULL;
+       struct btrfs_workqueue *scrub_wr_comp = NULL;
+       struct btrfs_workqueue *scrub_parity = NULL;
        unsigned int flags = WQ_FREEZABLE | WQ_UNBOUND;
        int max_active = fs_info->thread_pool_size;
+       int ret = -ENOMEM;
 
-       lockdep_assert_held(&fs_info->scrub_lock);
+       if (refcount_inc_not_zero(&fs_info->scrub_workers_refcnt))
+               return 0;
 
-       if (refcount_read(&fs_info->scrub_workers_refcnt) == 0) {
-               ASSERT(fs_info->scrub_workers == NULL);
-               fs_info->scrub_workers = btrfs_alloc_workqueue(fs_info, "scrub",
-                               flags, is_dev_replace ? 1 : max_active, 4);
-               if (!fs_info->scrub_workers)
-                       goto fail_scrub_workers;
-
-               ASSERT(fs_info->scrub_wr_completion_workers == NULL);
-               fs_info->scrub_wr_completion_workers =
-                       btrfs_alloc_workqueue(fs_info, "scrubwrc", flags,
-                                             max_active, 2);
-               if (!fs_info->scrub_wr_completion_workers)
-                       goto fail_scrub_wr_completion_workers;
+       scrub_workers = btrfs_alloc_workqueue(fs_info, "scrub", flags,
+                                             is_dev_replace ? 1 : max_active, 4);
+       if (!scrub_workers)
+               goto fail_scrub_workers;
 
-               ASSERT(fs_info->scrub_parity_workers == NULL);
-               fs_info->scrub_parity_workers =
-                       btrfs_alloc_workqueue(fs_info, "scrubparity", flags,
+       scrub_wr_comp = btrfs_alloc_workqueue(fs_info, "scrubwrc", flags,
                                              max_active, 2);
-               if (!fs_info->scrub_parity_workers)
-                       goto fail_scrub_parity_workers;
+       if (!scrub_wr_comp)
+               goto fail_scrub_wr_completion_workers;
 
+       scrub_parity = btrfs_alloc_workqueue(fs_info, "scrubparity", flags,
+                                            max_active, 2);
+       if (!scrub_parity)
+               goto fail_scrub_parity_workers;
+
+       mutex_lock(&fs_info->scrub_lock);
+       if (refcount_read(&fs_info->scrub_workers_refcnt) == 0) {
+               ASSERT(fs_info->scrub_workers == NULL &&
+                      fs_info->scrub_wr_completion_workers == NULL &&
+                      fs_info->scrub_parity_workers == NULL);
+               fs_info->scrub_workers = scrub_workers;
+               fs_info->scrub_wr_completion_workers = scrub_wr_comp;
+               fs_info->scrub_parity_workers = scrub_parity;
                refcount_set(&fs_info->scrub_workers_refcnt, 1);
-       } else {
-               refcount_inc(&fs_info->scrub_workers_refcnt);
+               mutex_unlock(&fs_info->scrub_lock);
+               return 0;
        }
-       return 0;
+       /* Other thread raced in and created the workers for us */
+       refcount_inc(&fs_info->scrub_workers_refcnt);
+       mutex_unlock(&fs_info->scrub_lock);
 
+       ret = 0;
+       btrfs_destroy_workqueue(scrub_parity);
 fail_scrub_parity_workers:
-       btrfs_destroy_workqueue(fs_info->scrub_wr_completion_workers);
+       btrfs_destroy_workqueue(scrub_wr_comp);
 fail_scrub_wr_completion_workers:
-       btrfs_destroy_workqueue(fs_info->scrub_workers);
+       btrfs_destroy_workqueue(scrub_workers);
 fail_scrub_workers:
-       return -ENOMEM;
+       return ret;
 }
 
 int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
@@ -3770,9 +3804,6 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
        int ret;
        struct btrfs_device *dev;
        unsigned int nofs_flag;
-       struct btrfs_workqueue *scrub_workers = NULL;
-       struct btrfs_workqueue *scrub_wr_comp = NULL;
-       struct btrfs_workqueue *scrub_parity = NULL;
 
        if (btrfs_fs_closing(fs_info))
                return -EAGAIN;
@@ -3819,13 +3850,17 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
        if (IS_ERR(sctx))
                return PTR_ERR(sctx);
 
+       ret = scrub_workers_get(fs_info, is_dev_replace);
+       if (ret)
+               goto out_free_ctx;
+
        mutex_lock(&fs_info->fs_devices->device_list_mutex);
        dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL, true);
        if (!dev || (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) &&
                     !is_dev_replace)) {
                mutex_unlock(&fs_info->fs_devices->device_list_mutex);
                ret = -ENODEV;
-               goto out_free_ctx;
+               goto out;
        }
 
        if (!is_dev_replace && !readonly &&
@@ -3834,7 +3869,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
                btrfs_err_in_rcu(fs_info, "scrub: device %s is not writable",
                                rcu_str_deref(dev->name));
                ret = -EROFS;
-               goto out_free_ctx;
+               goto out;
        }
 
        mutex_lock(&fs_info->scrub_lock);
@@ -3843,7 +3878,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
                mutex_unlock(&fs_info->scrub_lock);
                mutex_unlock(&fs_info->fs_devices->device_list_mutex);
                ret = -EIO;
-               goto out_free_ctx;
+               goto out;
        }
 
        down_read(&fs_info->dev_replace.rwsem);
@@ -3854,17 +3889,10 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
                mutex_unlock(&fs_info->scrub_lock);
                mutex_unlock(&fs_info->fs_devices->device_list_mutex);
                ret = -EINPROGRESS;
-               goto out_free_ctx;
+               goto out;
        }
        up_read(&fs_info->dev_replace.rwsem);
 
-       ret = scrub_workers_get(fs_info, is_dev_replace);
-       if (ret) {
-               mutex_unlock(&fs_info->scrub_lock);
-               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
-               goto out_free_ctx;
-       }
-
        sctx->readonly = readonly;
        dev->scrub_ctx = sctx;
        mutex_unlock(&fs_info->fs_devices->device_list_mutex);
@@ -3917,24 +3945,14 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
 
        mutex_lock(&fs_info->scrub_lock);
        dev->scrub_ctx = NULL;
-       if (refcount_dec_and_test(&fs_info->scrub_workers_refcnt)) {
-               scrub_workers = fs_info->scrub_workers;
-               scrub_wr_comp = fs_info->scrub_wr_completion_workers;
-               scrub_parity = fs_info->scrub_parity_workers;
-
-               fs_info->scrub_workers = NULL;
-               fs_info->scrub_wr_completion_workers = NULL;
-               fs_info->scrub_parity_workers = NULL;
-       }
        mutex_unlock(&fs_info->scrub_lock);
 
-       btrfs_destroy_workqueue(scrub_workers);
-       btrfs_destroy_workqueue(scrub_wr_comp);
-       btrfs_destroy_workqueue(scrub_parity);
+       scrub_workers_put(fs_info);
        scrub_put_ctx(sctx);
 
        return ret;
-
+out:
+       scrub_workers_put(fs_info);
 out_free_ctx:
        scrub_free_ctx(sctx);
 
index e529ddb..25967ec 100644 (file)
@@ -625,6 +625,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
                        } else if (strncmp(args[0].from, "lzo", 3) == 0) {
                                compress_type = "lzo";
                                info->compress_type = BTRFS_COMPRESS_LZO;
+                               info->compress_level = 0;
                                btrfs_set_opt(info->mount_opt, COMPRESS);
                                btrfs_clear_opt(info->mount_opt, NODATACOW);
                                btrfs_clear_opt(info->mount_opt, NODATASUM);
index c8df2ed..5be3006 100644 (file)
@@ -1170,10 +1170,12 @@ int btrfs_sysfs_remove_devices_dir(struct btrfs_fs_devices *fs_devices,
                                          disk_kobj->name);
                }
 
-               kobject_del(&one_device->devid_kobj);
-               kobject_put(&one_device->devid_kobj);
+               if (one_device->devid_kobj.state_initialized) {
+                       kobject_del(&one_device->devid_kobj);
+                       kobject_put(&one_device->devid_kobj);
 
-               wait_for_completion(&one_device->kobj_unregister);
+                       wait_for_completion(&one_device->kobj_unregister);
+               }
 
                return 0;
        }
@@ -1186,10 +1188,12 @@ int btrfs_sysfs_remove_devices_dir(struct btrfs_fs_devices *fs_devices,
                        sysfs_remove_link(fs_devices->devices_kobj,
                                          disk_kobj->name);
                }
-               kobject_del(&one_device->devid_kobj);
-               kobject_put(&one_device->devid_kobj);
+               if (one_device->devid_kobj.state_initialized) {
+                       kobject_del(&one_device->devid_kobj);
+                       kobject_put(&one_device->devid_kobj);
 
-               wait_for_completion(&one_device->kobj_unregister);
+                       wait_for_completion(&one_device->kobj_unregister);
+               }
        }
 
        return 0;
index 20c6ac1..d2fc292 100644 (file)
@@ -1636,6 +1636,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        pending->snap = btrfs_get_new_fs_root(fs_info, objectid, pending->anon_dev);
        if (IS_ERR(pending->snap)) {
                ret = PTR_ERR(pending->snap);
+               pending->snap = NULL;
                btrfs_abort_transaction(trans, ret);
                goto fail;
        }
index 517b443..7b1fee6 100644 (file)
@@ -984,7 +984,7 @@ static int check_inode_item(struct extent_buffer *leaf,
        /* Note for ROOT_TREE_DIR_ITEM, mkfs could set its transid 0 */
        if (btrfs_inode_transid(leaf, iitem) > super_gen + 1) {
                inode_item_err(leaf, slot,
-                       "invalid inode generation: has %llu expect [0, %llu]",
+                       "invalid inode transid: has %llu expect [0, %llu]",
                               btrfs_inode_transid(leaf, iitem), super_gen + 1);
                return -EUCLEAN;
        }
index 696dd86..39da9db 100644 (file)
@@ -3449,11 +3449,13 @@ fail:
        btrfs_free_path(path);
 out_unlock:
        mutex_unlock(&dir->log_mutex);
-       if (ret == -ENOSPC) {
+       if (err == -ENOSPC) {
                btrfs_set_log_full_commit(trans);
-               ret = 0;
-       } else if (ret < 0)
-               btrfs_abort_transaction(trans, ret);
+               err = 0;
+       } else if (err < 0 && err != -ENOENT) {
+               /* ENOENT can be returned if the entry hasn't been fsynced yet */
+               btrfs_abort_transaction(trans, err);
+       }
 
        btrfs_end_log_trans(root);
 
index ee96c58..1997a7d 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/sched.h>
+#include <linux/sched/mm.h>
 #include <linux/bio.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
@@ -1998,9 +1999,9 @@ static u64 btrfs_num_devices(struct btrfs_fs_info *fs_info)
        return num_devices;
 }
 
-static void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
-                                     struct block_device *bdev,
-                                     const char *device_path)
+void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
+                              struct block_device *bdev,
+                              const char *device_path)
 {
        struct btrfs_super_block *disk_super;
        int copy_num;
@@ -2223,11 +2224,7 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev)
        struct btrfs_fs_info *fs_info = srcdev->fs_info;
        struct btrfs_fs_devices *fs_devices = srcdev->fs_devices;
 
-       if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &srcdev->dev_state)) {
-               /* zero out the old super if it is writable */
-               btrfs_scratch_superblocks(fs_info, srcdev->bdev,
-                                         srcdev->name->str);
-       }
+       mutex_lock(&uuid_mutex);
 
        btrfs_close_bdev(srcdev);
        synchronize_rcu();
@@ -2257,6 +2254,7 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev)
                close_fs_devices(fs_devices);
                free_fs_devices(fs_devices);
        }
+       mutex_unlock(&uuid_mutex);
 }
 
 void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
@@ -4462,6 +4460,7 @@ int btrfs_uuid_scan_kthread(void *data)
                        goto skip;
                }
 update_tree:
+               btrfs_release_path(path);
                if (!btrfs_is_empty_uuid(root_item.uuid)) {
                        ret = btrfs_uuid_tree_add(trans, root_item.uuid,
                                                  BTRFS_UUID_KEY_SUBVOL,
@@ -4486,6 +4485,7 @@ update_tree:
                }
 
 skip:
+               btrfs_release_path(path);
                if (trans) {
                        ret = btrfs_end_transaction(trans);
                        trans = NULL;
@@ -4493,7 +4493,6 @@ skip:
                                break;
                }
 
-               btrfs_release_path(path);
                if (key.offset < (u64)-1) {
                        key.offset++;
                } else if (key.type < BTRFS_ROOT_ITEM_KEY) {
@@ -6483,8 +6482,17 @@ static struct btrfs_device *add_missing_dev(struct btrfs_fs_devices *fs_devices,
                                            u64 devid, u8 *dev_uuid)
 {
        struct btrfs_device *device;
+       unsigned int nofs_flag;
 
+       /*
+        * We call this under the chunk_mutex, so we want to use NOFS for this
+        * allocation, however we don't want to change btrfs_alloc_device() to
+        * always do NOFS because we use it in a lot of other GFP_KERNEL safe
+        * places.
+        */
+       nofs_flag = memalloc_nofs_save();
        device = btrfs_alloc_device(NULL, &devid, dev_uuid);
+       memalloc_nofs_restore(nofs_flag);
        if (IS_ERR(device))
                return device;
 
index 5eea939..302c923 100644 (file)
@@ -573,6 +573,9 @@ void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);
 void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info);
 bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
                                        struct btrfs_device *failing_dev);
+void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
+                              struct block_device *bdev,
+                              const char *device_path);
 
 int btrfs_bg_type_to_factor(u64 flags);
 const char *btrfs_bg_type_to_raid_name(u64 flags);
index d468ed9..50bbc99 100644 (file)
@@ -1958,7 +1958,7 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
                 */
                set_buffer_new(bh);
                set_buffer_unwritten(bh);
-               /* FALLTHRU */
+               fallthrough;
        case IOMAP_MAPPED:
                if ((iomap->flags & IOMAP_F_NEW) ||
                    offset >= i_size_read(inode))
index 55ccccf..034b3f4 100644 (file)
@@ -887,8 +887,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
        int have = ci->i_snap_caps;
 
        if ((have & mask) == mask) {
-               dout("__ceph_caps_issued_mask ino 0x%lx snap issued %s"
-                    " (mask %s)\n", ci->vfs_inode.i_ino,
+               dout("__ceph_caps_issued_mask ino 0x%llx snap issued %s"
+                    " (mask %s)\n", ceph_ino(&ci->vfs_inode),
                     ceph_cap_string(have),
                     ceph_cap_string(mask));
                return 1;
@@ -899,8 +899,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
                if (!__cap_is_valid(cap))
                        continue;
                if ((cap->issued & mask) == mask) {
-                       dout("__ceph_caps_issued_mask ino 0x%lx cap %p issued %s"
-                            " (mask %s)\n", ci->vfs_inode.i_ino, cap,
+                       dout("__ceph_caps_issued_mask ino 0x%llx cap %p issued %s"
+                            " (mask %s)\n", ceph_ino(&ci->vfs_inode), cap,
                             ceph_cap_string(cap->issued),
                             ceph_cap_string(mask));
                        if (touch)
@@ -911,8 +911,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
                /* does a combination of caps satisfy mask? */
                have |= cap->issued;
                if ((have & mask) == mask) {
-                       dout("__ceph_caps_issued_mask ino 0x%lx combo issued %s"
-                            " (mask %s)\n", ci->vfs_inode.i_ino,
+                       dout("__ceph_caps_issued_mask ino 0x%llx combo issued %s"
+                            " (mask %s)\n", ceph_ino(&ci->vfs_inode),
                             ceph_cap_string(cap->issued),
                             ceph_cap_string(mask));
                        if (touch) {
@@ -2872,7 +2872,7 @@ int ceph_get_caps(struct file *filp, int need, int want,
                        struct cap_wait cw;
                        DEFINE_WAIT_FUNC(wait, woken_wake_function);
 
-                       cw.ino = inode->i_ino;
+                       cw.ino = ceph_ino(inode);
                        cw.tgid = current->tgid;
                        cw.need = need;
                        cw.want = want;
index 97539b4..3e3fcda 100644 (file)
@@ -202,7 +202,7 @@ static int caps_show_cb(struct inode *inode, struct ceph_cap *cap, void *p)
 {
        struct seq_file *s = p;
 
-       seq_printf(s, "0x%-17lx%-17s%-17s\n", inode->i_ino,
+       seq_printf(s, "0x%-17llx%-17s%-17s\n", ceph_ino(inode),
                   ceph_cap_string(cap->issued),
                   ceph_cap_string(cap->implemented));
        return 0;
@@ -247,7 +247,7 @@ static int caps_show(struct seq_file *s, void *p)
 
        spin_lock(&mdsc->caps_list_lock);
        list_for_each_entry(cw, &mdsc->cap_wait_list, list) {
-               seq_printf(s, "%-13d0x%-17lx%-17s%-17s\n", cw->tgid, cw->ino,
+               seq_printf(s, "%-13d0x%-17llx%-17s%-17s\n", cw->tgid, cw->ino,
                                ceph_cap_string(cw->need),
                                ceph_cap_string(cw->want));
        }
index 060bdcc..d72e4a1 100644 (file)
@@ -259,9 +259,7 @@ static int __dcache_readdir(struct file *file,  struct dir_context *ctx,
                             dentry, dentry, d_inode(dentry));
                        ctx->pos = di->offset;
                        if (!dir_emit(ctx, dentry->d_name.name,
-                                     dentry->d_name.len,
-                                     ceph_translate_ino(dentry->d_sb,
-                                                        d_inode(dentry)->i_ino),
+                                     dentry->d_name.len, ceph_present_inode(d_inode(dentry)),
                                      d_inode(dentry)->i_mode >> 12)) {
                                dput(dentry);
                                err = 0;
@@ -324,18 +322,21 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
        /* always start with . and .. */
        if (ctx->pos == 0) {
                dout("readdir off 0 -> '.'\n");
-               if (!dir_emit(ctx, ".", 1, 
-                           ceph_translate_ino(inode->i_sb, inode->i_ino),
+               if (!dir_emit(ctx, ".", 1, ceph_present_inode(inode),
                            inode->i_mode >> 12))
                        return 0;
                ctx->pos = 1;
        }
        if (ctx->pos == 1) {
-               ino_t ino = parent_ino(file->f_path.dentry);
+               u64 ino;
+               struct dentry *dentry = file->f_path.dentry;
+
+               spin_lock(&dentry->d_lock);
+               ino = ceph_present_inode(dentry->d_parent->d_inode);
+               spin_unlock(&dentry->d_lock);
+
                dout("readdir off 1 -> '..'\n");
-               if (!dir_emit(ctx, "..", 2,
-                           ceph_translate_ino(inode->i_sb, ino),
-                           inode->i_mode >> 12))
+               if (!dir_emit(ctx, "..", 2, ino, inode->i_mode >> 12))
                        return 0;
                ctx->pos = 2;
        }
@@ -507,9 +508,6 @@ more:
        }
        for (; i < rinfo->dir_nr; i++) {
                struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i;
-               struct ceph_vino vino;
-               ino_t ino;
-               u32 ftype;
 
                BUG_ON(rde->offset < ctx->pos);
 
@@ -519,13 +517,10 @@ more:
                     rde->name_len, rde->name, &rde->inode.in);
 
                BUG_ON(!rde->inode.in);
-               ftype = le32_to_cpu(rde->inode.in->mode) >> 12;
-               vino.ino = le64_to_cpu(rde->inode.in->ino);
-               vino.snap = le64_to_cpu(rde->inode.in->snapid);
-               ino = ceph_vino_to_ino(vino);
 
                if (!dir_emit(ctx, rde->name, rde->name_len,
-                             ceph_translate_ino(inode->i_sb, ino), ftype)) {
+                             ceph_present_ino(inode->i_sb, le64_to_cpu(rde->inode.in->ino)),
+                             le32_to_cpu(rde->inode.in->mode) >> 12)) {
                        dout("filldir stopping us...\n");
                        return 0;
                }
@@ -1161,7 +1156,7 @@ retry:
 
        if (try_async && op == CEPH_MDS_OP_UNLINK &&
            (req->r_dir_caps = get_caps_for_async_unlink(dir, dentry))) {
-               dout("async unlink on %lu/%.*s caps=%s", dir->i_ino,
+               dout("async unlink on %llu/%.*s caps=%s", ceph_ino(dir),
                     dentry->d_name.len, dentry->d_name.name,
                     ceph_cap_string(req->r_dir_caps));
                set_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags);
@@ -1745,7 +1740,7 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
                        case -ENOENT:
                                if (d_really_is_negative(dentry))
                                        valid = 1;
-                               /* Fallthrough */
+                               fallthrough;
                        default:
                                break;
                        }
index d51c3f2..3f4c993 100644 (file)
@@ -252,7 +252,7 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
        case S_IFREG:
                ceph_fscache_register_inode_cookie(inode);
                ceph_fscache_file_set_cookie(inode, file);
-               /* fall through */
+               fallthrough;
        case S_IFDIR:
                ret = ceph_init_file_info(inode, file, fmode,
                                                S_ISDIR(inode->i_mode));
@@ -630,8 +630,8 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
        } else {
                struct dentry *dn;
 
-               dout("%s d_adding new inode 0x%llx to 0x%lx/%s\n", __func__,
-                       vino.ino, dir->i_ino, dentry->d_name.name);
+               dout("%s d_adding new inode 0x%llx to 0x%llx/%s\n", __func__,
+                       vino.ino, ceph_ino(dir), dentry->d_name.name);
                ceph_dir_clear_ordered(dir);
                ceph_init_inode_acls(inode, as_ctx);
                if (inode->i_state & I_NEW) {
@@ -2507,6 +2507,7 @@ const struct file_operations ceph_file_fops = {
        .mmap = ceph_mmap,
        .fsync = ceph_fsync,
        .lock = ceph_lock,
+       .setlease = simple_nosetlease,
        .flock = ceph_flock,
        .splice_read = generic_file_splice_read,
        .splice_write = iter_file_splice_write,
index 357c937..d163fa9 100644 (file)
@@ -41,8 +41,10 @@ static void ceph_inode_work(struct work_struct *work);
  */
 static int ceph_set_ino_cb(struct inode *inode, void *data)
 {
-       ceph_inode(inode)->i_vino = *(struct ceph_vino *)data;
-       inode->i_ino = ceph_vino_to_ino(*(struct ceph_vino *)data);
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       ci->i_vino = *(struct ceph_vino *)data;
+       inode->i_ino = ceph_vino_to_ino_t(ci->i_vino);
        inode_set_iversion_raw(inode, 0);
        return 0;
 }
@@ -50,17 +52,14 @@ static int ceph_set_ino_cb(struct inode *inode, void *data)
 struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino)
 {
        struct inode *inode;
-       ino_t t = ceph_vino_to_ino(vino);
 
-       inode = iget5_locked(sb, t, ceph_ino_compare, ceph_set_ino_cb, &vino);
+       inode = iget5_locked(sb, (unsigned long)vino.ino, ceph_ino_compare,
+                            ceph_set_ino_cb, &vino);
        if (!inode)
                return ERR_PTR(-ENOMEM);
-       if (inode->i_state & I_NEW)
-               dout("get_inode created new inode %p %llx.%llx ino %llx\n",
-                    inode, ceph_vinop(inode), (u64)inode->i_ino);
 
-       dout("get_inode on %lu=%llx.%llx got %p\n", inode->i_ino, vino.ino,
-            vino.snap, inode);
+       dout("get_inode on %llu=%llx.%llx got %p new %d\n", ceph_present_inode(inode),
+            ceph_vinop(inode), inode, !!(inode->i_state & I_NEW));
        return inode;
 }
 
@@ -2378,7 +2377,7 @@ int ceph_getattr(const struct path *path, struct kstat *stat,
        }
 
        generic_fillattr(inode, stat);
-       stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino);
+       stat->ino = ceph_present_inode(inode);
 
        /*
         * btime on newly-allocated inodes is 0, so if this is still set to
index bc9e959..6588006 100644 (file)
@@ -372,7 +372,7 @@ struct ceph_quotarealm_inode {
 
 struct cap_wait {
        struct list_head        list;
-       unsigned long           ino;
+       u64                     ino;
        pid_t                   tgid;
        int                     need;
        int                     want;
index 198ddde..cc2c4d4 100644 (file)
@@ -23,12 +23,12 @@ static inline bool ceph_has_realms_with_quotas(struct inode *inode)
 {
        struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        struct super_block *sb = mdsc->fsc->sb;
+       struct inode *root = d_inode(sb->s_root);
 
        if (atomic64_read(&mdsc->quotarealms_count) > 0)
                return true;
        /* if root is the real CephFS root, we don't have quota realms */
-       if (sb->s_root->d_inode &&
-           (sb->s_root->d_inode->i_ino == CEPH_INO_ROOT))
+       if (root && ceph_ino(root) == CEPH_INO_ROOT)
                return false;
        /* otherwise, we can't know for sure */
        return true;
index 4c3c964..a3995eb 100644 (file)
@@ -457,15 +457,7 @@ ceph_vino(const struct inode *inode)
        return ceph_inode(inode)->i_vino;
 }
 
-/*
- * ino_t is <64 bits on many architectures, blech.
- *
- *               i_ino (kernel inode)   st_ino (userspace)
- * i386          32                     32
- * x86_64+ino32  64                     32
- * x86_64        64                     64
- */
-static inline u32 ceph_ino_to_ino32(__u64 vino)
+static inline u32 ceph_ino_to_ino32(u64 vino)
 {
        u32 ino = vino & 0xffffffff;
        ino ^= vino >> 32;
@@ -475,34 +467,17 @@ static inline u32 ceph_ino_to_ino32(__u64 vino)
 }
 
 /*
- * kernel i_ino value
+ * Inode numbers in cephfs are 64 bits, but inode->i_ino is 32-bits on
+ * some arches. We generally do not use this value inside the ceph driver, but
+ * we do want to set it to something, so that generic vfs code has an
+ * appropriate value for tracepoints and the like.
  */
-static inline ino_t ceph_vino_to_ino(struct ceph_vino vino)
+static inline ino_t ceph_vino_to_ino_t(struct ceph_vino vino)
 {
-#if BITS_PER_LONG == 32
-       return ceph_ino_to_ino32(vino.ino);
-#else
+       if (sizeof(ino_t) == sizeof(u32))
+               return ceph_ino_to_ino32(vino.ino);
        return (ino_t)vino.ino;
-#endif
-}
-
-/*
- * user-visible ino (stat, filldir)
- */
-#if BITS_PER_LONG == 32
-static inline ino_t ceph_translate_ino(struct super_block *sb, ino_t ino)
-{
-       return ino;
-}
-#else
-static inline ino_t ceph_translate_ino(struct super_block *sb, ino_t ino)
-{
-       if (ceph_test_mount_opt(ceph_sb_to_client(sb), INO32))
-               ino = ceph_ino_to_ino32(ino);
-       return ino;
 }
-#endif
-
 
 /* for printf-style formatting */
 #define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap
@@ -511,11 +486,34 @@ static inline u64 ceph_ino(struct inode *inode)
 {
        return ceph_inode(inode)->i_vino.ino;
 }
+
 static inline u64 ceph_snap(struct inode *inode)
 {
        return ceph_inode(inode)->i_vino.snap;
 }
 
+/**
+ * ceph_present_ino - format an inode number for presentation to userland
+ * @sb: superblock where the inode lives
+ * @ino: inode number to (possibly) convert
+ *
+ * If the user mounted with the ino32 option, then the 64-bit value needs
+ * to be converted to something that can fit inside 32 bits. Note that
+ * internal kernel code never uses this value, so this is entirely for
+ * userland consumption.
+ */
+static inline u64 ceph_present_ino(struct super_block *sb, u64 ino)
+{
+       if (unlikely(ceph_test_mount_opt(ceph_sb_to_client(sb), INO32)))
+               return ceph_ino_to_ino32(ino);
+       return ino;
+}
+
+static inline u64 ceph_present_inode(struct inode *inode)
+{
+       return ceph_present_ino(inode->i_sb, ceph_ino(inode));
+}
+
 static inline int ceph_ino_compare(struct inode *inode, void *data)
 {
        struct ceph_vino *pvino = (struct ceph_vino *)data;
@@ -524,11 +522,16 @@ static inline int ceph_ino_compare(struct inode *inode, void *data)
                ci->i_vino.snap == pvino->snap;
 }
 
+
 static inline struct inode *ceph_find_inode(struct super_block *sb,
                                            struct ceph_vino vino)
 {
-       ino_t t = ceph_vino_to_ino(vino);
-       return ilookup5(sb, t, ceph_ino_compare, &vino);
+       /*
+        * NB: The hashval will be run through the fs/inode.c hash function
+        * anyway, so there is no need to squash the inode number down to
+        * 32-bits first. Just use low-order bits on arches with 32-bit long.
+        */
+       return ilookup5(sb, (unsigned long)vino.ino, ceph_ino_compare, &vino);
 }
 
 
index b296964..b565d83 100644 (file)
@@ -2031,4 +2031,19 @@ static inline bool is_smb1_server(struct TCP_Server_Info *server)
        return strcmp(server->vals->version_string, SMB1_VERSION_STRING) == 0;
 }
 
+static inline bool is_tcon_dfs(struct cifs_tcon *tcon)
+{
+       /*
+        * For SMB1, see MS-CIFS 2.4.55 SMB_COM_TREE_CONNECT_ANDX (0x75) and MS-CIFS 3.3.4.4 DFS
+        * Subsystem Notifies That a Share Is a DFS Share.
+        *
+        * For SMB2+, see MS-SMB2 2.2.10 SMB2 TREE_CONNECT Response and MS-SMB2 3.3.4.14 Server
+        * Application Updates a Share.
+        */
+       if (!tcon || !tcon->ses || !tcon->ses->server)
+               return false;
+       return is_smb1_server(tcon->ses->server) ? tcon->Flags & SMB_SHARE_IS_IN_DFS :
+               tcon->share_flags & (SHI1005_FLAGS_DFS | SHI1005_FLAGS_DFS_ROOT);
+}
+
 #endif /* _CIFS_GLOB_H */
index 0e763d2..0496934 100644 (file)
@@ -581,7 +581,7 @@ should_set_ext_sec_flag(enum securityEnum sectype)
                if (global_secflags &
                    (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
                        return true;
-               /* Fallthrough */
+               fallthrough;
        default:
                return false;
        }
index a275ee3..a5731dd 100644 (file)
@@ -1378,25 +1378,25 @@ static int cifs_parse_security_flavors(char *value,
                return 1;
        case Opt_sec_krb5i:
                vol->sign = true;
-               /* Fallthrough */
+               fallthrough;
        case Opt_sec_krb5:
                vol->sectype = Kerberos;
                break;
        case Opt_sec_ntlmsspi:
                vol->sign = true;
-               /* Fallthrough */
+               fallthrough;
        case Opt_sec_ntlmssp:
                vol->sectype = RawNTLMSSP;
                break;
        case Opt_sec_ntlmi:
                vol->sign = true;
-               /* Fallthrough */
+               fallthrough;
        case Opt_ntlm:
                vol->sectype = NTLM;
                break;
        case Opt_sec_ntlmv2i:
                vol->sign = true;
-               /* Fallthrough */
+               fallthrough;
        case Opt_sec_ntlmv2:
                vol->sectype = NTLMv2;
                break;
@@ -2187,7 +2187,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                vol->password = NULL;
                                break;
                        }
-                       /* Fallthrough - to Opt_pass below.*/
+                       fallthrough;    /* to Opt_pass below */
                case Opt_pass:
                        /* Obtain the value string */
                        value = strchr(data, '=');
@@ -4909,7 +4909,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
                if (!tcon)
                        continue;
                /* Make sure that requests go through new root servers */
-               if (tcon->share_flags & (SHI1005_FLAGS_DFS | SHI1005_FLAGS_DFS_ROOT)) {
+               if (is_tcon_dfs(tcon)) {
                        put_root_ses(root_ses);
                        set_root_ses(cifs_sb, ses, &root_ses);
                }
index 3989d08..1f75b25 100644 (file)
@@ -1017,6 +1017,8 @@ handle_mnt_opt:
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
                rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true,
                                       full_path, fid);
+               if (rc == -EREMOTE)
+                       rc = 0;
                if (rc) {
                        cifs_dbg(FYI, "%s: Get mode from SID failed. rc=%d\n",
                                 __func__, rc);
@@ -1025,6 +1027,8 @@ handle_mnt_opt:
        } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false,
                                       full_path, fid);
+               if (rc == -EREMOTE)
+                       rc = 0;
                if (rc) {
                        cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n",
                                 __func__, rc);
index 69cd585..de56436 100644 (file)
@@ -798,7 +798,7 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
                        if ((server->sec_kerberos || server->sec_mskerberos) &&
                            (global_secflags & CIFSSEC_MAY_KRB5))
                                return Kerberos;
-                       /* Fallthrough */
+                       fallthrough;
                default:
                        return Unspecified;
                }
@@ -815,7 +815,7 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
                default:
                        break;
                }
-               /* Fallthrough - to attempt LANMAN authentication next */
+               fallthrough;    /* to attempt LANMAN authentication next */
        case CIFS_NEGFLAVOR_LANMAN:
                switch (requested) {
                case LANMAN:
@@ -823,7 +823,7 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
                case Unspecified:
                        if (global_secflags & CIFSSEC_MAY_LANMAN)
                                return LANMAN;
-                       /* Fallthrough */
+                       fallthrough;
                default:
                        return Unspecified;
                }
index 32f90dc..d44df8f 100644 (file)
@@ -1208,7 +1208,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
        rqst[1].rq_iov = si_iov;
        rqst[1].rq_nvec = 1;
 
-       len = sizeof(ea) + ea_name_len + ea_value_len + 1;
+       len = sizeof(*ea) + ea_name_len + ea_value_len + 1;
        ea = kzalloc(len, GFP_KERNEL);
        if (ea == NULL) {
                rc = -ENOMEM;
index 667d70a..96c172d 100644 (file)
@@ -1101,7 +1101,7 @@ smb2_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
                if ((server->sec_kerberos || server->sec_mskerberos) &&
                        (global_secflags & CIFSSEC_MAY_KRB5))
                        return Kerberos;
-               /* Fallthrough */
+               fallthrough;
        default:
                return Unspecified;
        }
diff --git a/fs/compat.c b/fs/compat.c
deleted file mode 100644 (file)
index 436d228..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  linux/fs/compat.c
- *
- *  Kernel compatibililty routines for e.g. 32 bit syscall support
- *  on 64 bit kernels.
- *
- *  Copyright (C) 2002       Stephen Rothwell, IBM Corporation
- *  Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
- *  Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
- *  Copyright (C) 2001,2002  Andi Kleen, SuSE Labs 
- *  Copyright (C) 2003       Pavel Machek (pavel@ucw.cz)
- */
-
-#include <linux/compat.h>
-#include <linux/nfs4_mount.h>
-#include <linux/syscalls.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include "internal.h"
-
-struct compat_nfs_string {
-       compat_uint_t len;
-       compat_uptr_t data;
-};
-
-static inline void compat_nfs_string(struct nfs_string *dst,
-                                    struct compat_nfs_string *src)
-{
-       dst->data = compat_ptr(src->data);
-       dst->len = src->len;
-}
-
-struct compat_nfs4_mount_data_v1 {
-       compat_int_t version;
-       compat_int_t flags;
-       compat_int_t rsize;
-       compat_int_t wsize;
-       compat_int_t timeo;
-       compat_int_t retrans;
-       compat_int_t acregmin;
-       compat_int_t acregmax;
-       compat_int_t acdirmin;
-       compat_int_t acdirmax;
-       struct compat_nfs_string client_addr;
-       struct compat_nfs_string mnt_path;
-       struct compat_nfs_string hostname;
-       compat_uint_t host_addrlen;
-       compat_uptr_t host_addr;
-       compat_int_t proto;
-       compat_int_t auth_flavourlen;
-       compat_uptr_t auth_flavours;
-};
-
-static int do_nfs4_super_data_conv(void *raw_data)
-{
-       int version = *(compat_uint_t *) raw_data;
-
-       if (version == 1) {
-               struct compat_nfs4_mount_data_v1 *raw = raw_data;
-               struct nfs4_mount_data *real = raw_data;
-
-               /* copy the fields backwards */
-               real->auth_flavours = compat_ptr(raw->auth_flavours);
-               real->auth_flavourlen = raw->auth_flavourlen;
-               real->proto = raw->proto;
-               real->host_addr = compat_ptr(raw->host_addr);
-               real->host_addrlen = raw->host_addrlen;
-               compat_nfs_string(&real->hostname, &raw->hostname);
-               compat_nfs_string(&real->mnt_path, &raw->mnt_path);
-               compat_nfs_string(&real->client_addr, &raw->client_addr);
-               real->acdirmax = raw->acdirmax;
-               real->acdirmin = raw->acdirmin;
-               real->acregmax = raw->acregmax;
-               real->acregmin = raw->acregmin;
-               real->retrans = raw->retrans;
-               real->timeo = raw->timeo;
-               real->wsize = raw->wsize;
-               real->rsize = raw->rsize;
-               real->flags = raw->flags;
-               real->version = raw->version;
-       }
-
-       return 0;
-}
-
-#define NFS4_NAME      "nfs4"
-
-COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
-                      const char __user *, dir_name,
-                      const char __user *, type, compat_ulong_t, flags,
-                      const void __user *, data)
-{
-       char *kernel_type;
-       void *options;
-       char *kernel_dev;
-       int retval;
-
-       kernel_type = copy_mount_string(type);
-       retval = PTR_ERR(kernel_type);
-       if (IS_ERR(kernel_type))
-               goto out;
-
-       kernel_dev = copy_mount_string(dev_name);
-       retval = PTR_ERR(kernel_dev);
-       if (IS_ERR(kernel_dev))
-               goto out1;
-
-       options = copy_mount_options(data);
-       retval = PTR_ERR(options);
-       if (IS_ERR(options))
-               goto out2;
-
-       if (kernel_type && options) {
-               if (!strcmp(kernel_type, NFS4_NAME)) {
-                       retval = -EINVAL;
-                       if (do_nfs4_super_data_conv(options))
-                               goto out3;
-               }
-       }
-
-       retval = do_mount(kernel_dev, dir_name, kernel_type, flags, options);
-
- out3:
-       kfree(options);
- out2:
-       kfree(kernel_dev);
- out1:
-       kfree(kernel_type);
- out:
-       return retval;
-}
index cb73365..ca22737 100644 (file)
@@ -1688,11 +1688,11 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence)
        switch (whence) {
                case 1:
                        offset += file->f_pos;
-                       /* fall through */
+                       fallthrough;
                case 0:
                        if (offset >= 0)
                                break;
-                       /* fall through */
+                       fallthrough;
                default:
                        return -EINVAL;
        }
index 9212325..4ef3f71 100644 (file)
@@ -343,9 +343,11 @@ void fscrypt_msg(const struct inode *inode, const char *level,
        va_start(args, fmt);
        vaf.fmt = fmt;
        vaf.va = &args;
-       if (inode)
+       if (inode && inode->i_ino)
                printk("%sfscrypt (%s, inode %lu): %pV\n",
                       level, inode->i_sb->s_id, inode->i_ino, &vaf);
+       else if (inode)
+               printk("%sfscrypt (%s): %pV\n", level, inode->i_sb->s_id, &vaf);
        else
                printk("%sfscrypt: %pV\n", level, &vaf);
        va_end(args);
index 011830f..1fbe6c2 100644 (file)
@@ -61,15 +61,6 @@ struct fscrypt_nokey_name {
  */
 #define FSCRYPT_NOKEY_NAME_MAX offsetofend(struct fscrypt_nokey_name, sha256)
 
-static void fscrypt_do_sha256(const u8 *data, unsigned int data_len, u8 *result)
-{
-       struct sha256_state sctx;
-
-       sha256_init(&sctx);
-       sha256_update(&sctx, data, data_len);
-       sha256_final(&sctx, result);
-}
-
 static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
 {
        if (str->len == 1 && str->name[0] == '.')
@@ -242,11 +233,11 @@ static int base64_decode(const char *src, int len, u8 *dst)
        return cp - dst;
 }
 
-bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
-                                 u32 max_len, u32 *encrypted_len_ret)
+bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
+                                 u32 orig_len, u32 max_len,
+                                 u32 *encrypted_len_ret)
 {
-       const struct fscrypt_info *ci = inode->i_crypt_info;
-       int padding = 4 << (fscrypt_policy_flags(&ci->ci_policy) &
+       int padding = 4 << (fscrypt_policy_flags(policy) &
                            FSCRYPT_POLICY_FLAGS_PAD_MASK);
        u32 encrypted_len;
 
@@ -260,8 +251,6 @@ bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
 
 /**
  * fscrypt_fname_alloc_buffer() - allocate a buffer for presented filenames
- * @inode: inode of the parent directory (for regular filenames)
- *        or of the symlink (for symlink targets)
  * @max_encrypted_len: maximum length of encrypted filenames the buffer will be
  *                    used to present
  * @crypto_str: (output) buffer to allocate
@@ -271,8 +260,7 @@ bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
  *
  * Return: 0 on success, -errno on failure
  */
-int fscrypt_fname_alloc_buffer(const struct inode *inode,
-                              u32 max_encrypted_len,
+int fscrypt_fname_alloc_buffer(u32 max_encrypted_len,
                               struct fscrypt_str *crypto_str)
 {
        const u32 max_encoded_len = BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX);
@@ -369,9 +357,9 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
        } else {
                memcpy(nokey_name.bytes, iname->name, sizeof(nokey_name.bytes));
                /* Compute strong hash of remaining part of name. */
-               fscrypt_do_sha256(&iname->name[sizeof(nokey_name.bytes)],
-                                 iname->len - sizeof(nokey_name.bytes),
-                                 nokey_name.sha256);
+               sha256(&iname->name[sizeof(nokey_name.bytes)],
+                      iname->len - sizeof(nokey_name.bytes),
+                      nokey_name.sha256);
                size = FSCRYPT_NOKEY_NAME_MAX;
        }
        oname->len = base64_encode((const u8 *)&nokey_name, size, oname->name);
@@ -394,9 +382,9 @@ EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
  * directory's encryption key, then @iname is the plaintext, so we encrypt it to
  * get the disk_name.
  *
- * Else, for keyless @lookup operations, @iname is the presented ciphertext, so
- * we decode it to get the fscrypt_nokey_name.  Non-@lookup operations will be
- * impossible in this case, so we fail them with ENOKEY.
+ * Else, for keyless @lookup operations, @iname should be a no-key name, so we
+ * decode it to get the struct fscrypt_nokey_name.  Non-@lookup operations will
+ * be impossible in this case, so we fail them with ENOKEY.
  *
  * If successful, fscrypt_free_filename() must be called later to clean up.
  *
@@ -421,7 +409,8 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
                return ret;
 
        if (fscrypt_has_encryption_key(dir)) {
-               if (!fscrypt_fname_encrypted_size(dir, iname->len,
+               if (!fscrypt_fname_encrypted_size(&dir->i_crypt_info->ci_policy,
+                                                 iname->len,
                                                  dir->i_sb->s_cop->max_namelen,
                                                  &fname->crypto_buf.len))
                        return -ENAMETOOLONG;
@@ -440,7 +429,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
        }
        if (!lookup)
                return -ENOKEY;
-       fname->is_ciphertext_name = true;
+       fname->is_nokey_name = true;
 
        /*
         * We don't have the key and we are doing a lookup; decode the
@@ -499,7 +488,7 @@ bool fscrypt_match_name(const struct fscrypt_name *fname,
 {
        const struct fscrypt_nokey_name *nokey_name =
                (const void *)fname->crypto_buf.name;
-       u8 sha256[SHA256_DIGEST_SIZE];
+       u8 digest[SHA256_DIGEST_SIZE];
 
        if (likely(fname->disk_name.name)) {
                if (de_name_len != fname->disk_name.len)
@@ -510,9 +499,9 @@ bool fscrypt_match_name(const struct fscrypt_name *fname,
                return false;
        if (memcmp(de_name, nokey_name->bytes, sizeof(nokey_name->bytes)))
                return false;
-       fscrypt_do_sha256(&de_name[sizeof(nokey_name->bytes)],
-                         de_name_len - sizeof(nokey_name->bytes), sha256);
-       return !memcmp(sha256, nokey_name->sha256, sizeof(sha256));
+       sha256(&de_name[sizeof(nokey_name->bytes)],
+              de_name_len - sizeof(nokey_name->bytes), digest);
+       return !memcmp(digest, nokey_name->sha256, sizeof(digest));
 }
 EXPORT_SYMBOL_GPL(fscrypt_match_name);
 
@@ -541,7 +530,7 @@ EXPORT_SYMBOL_GPL(fscrypt_fname_siphash);
  * Validate dentries in encrypted directories to make sure we aren't potentially
  * caching stale dentries after a key has been added.
  */
-static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
+int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct dentry *dir;
        int err;
@@ -549,17 +538,17 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
 
        /*
         * Plaintext names are always valid, since fscrypt doesn't support
-        * reverting to ciphertext names without evicting the directory's inode
+        * reverting to no-key names without evicting the directory's inode
         * -- which implies eviction of the dentries in the directory.
         */
-       if (!(dentry->d_flags & DCACHE_ENCRYPTED_NAME))
+       if (!(dentry->d_flags & DCACHE_NOKEY_NAME))
                return 1;
 
        /*
-        * Ciphertext name; valid if the directory's key is still unavailable.
+        * No-key name; valid if the directory's key is still unavailable.
         *
-        * Although fscrypt forbids rename() on ciphertext names, we still must
-        * use dget_parent() here rather than use ->d_parent directly.  That's
+        * Although fscrypt forbids rename() on no-key names, we still must use
+        * dget_parent() here rather than use ->d_parent directly.  That's
         * because a corrupted fs image may contain directory hard links, which
         * the VFS handles by moving the directory's dentry tree in the dcache
         * each time ->lookup() finds the directory and it already has a dentry
@@ -580,6 +569,7 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
 
        return valid;
 }
+EXPORT_SYMBOL_GPL(fscrypt_d_revalidate);
 
 const struct dentry_operations fscrypt_d_ops = {
        .d_revalidate = fscrypt_d_revalidate,
index 8117a61..4f5806a 100644 (file)
@@ -97,7 +97,6 @@ static inline const u8 *fscrypt_context_nonce(const union fscrypt_context *ctx)
        return NULL;
 }
 
-#undef fscrypt_policy
 union fscrypt_policy {
        u8 version;
        struct fscrypt_policy_v1 v1;
@@ -292,8 +291,9 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
 /* fname.c */
 int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
                          u8 *out, unsigned int olen);
-bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
-                                 u32 max_len, u32 *encrypted_len_ret);
+bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
+                                 u32 orig_len, u32 max_len,
+                                 u32 *encrypted_len_ret);
 extern const struct dentry_operations fscrypt_d_ops;
 
 /* hkdf.c */
@@ -572,6 +572,9 @@ int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key);
 int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
                               const struct fscrypt_master_key *mk);
 
+void fscrypt_hash_inode_number(struct fscrypt_info *ci,
+                              const struct fscrypt_master_key *mk);
+
 /* keysetup_v1.c */
 
 void fscrypt_put_direct_key(struct fscrypt_direct_key *dk);
@@ -590,5 +593,6 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u,
 int fscrypt_policy_from_context(union fscrypt_policy *policy_u,
                                const union fscrypt_context *ctx_u,
                                int ctx_size);
+const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir);
 
 #endif /* _FSCRYPT_PRIVATE_H */
index 09fb8aa..20b0df4 100644 (file)
@@ -60,8 +60,8 @@ int __fscrypt_prepare_link(struct inode *inode, struct inode *dir,
        if (err)
                return err;
 
-       /* ... in case we looked up ciphertext name before key was added */
-       if (dentry->d_flags & DCACHE_ENCRYPTED_NAME)
+       /* ... in case we looked up no-key name before key was added */
+       if (dentry->d_flags & DCACHE_NOKEY_NAME)
                return -ENOKEY;
 
        if (!fscrypt_has_permitted_context(dir, inode))
@@ -85,9 +85,8 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (err)
                return err;
 
-       /* ... in case we looked up ciphertext name(s) before key was added */
-       if ((old_dentry->d_flags | new_dentry->d_flags) &
-           DCACHE_ENCRYPTED_NAME)
+       /* ... in case we looked up no-key name(s) before key was added */
+       if ((old_dentry->d_flags | new_dentry->d_flags) & DCACHE_NOKEY_NAME)
                return -ENOKEY;
 
        if (old_dir != new_dir) {
@@ -114,9 +113,9 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
        if (err && err != -ENOENT)
                return err;
 
-       if (fname->is_ciphertext_name) {
+       if (fname->is_nokey_name) {
                spin_lock(&dentry->d_lock);
-               dentry->d_flags |= DCACHE_ENCRYPTED_NAME;
+               dentry->d_flags |= DCACHE_NOKEY_NAME;
                spin_unlock(&dentry->d_lock);
                d_set_d_op(dentry, &fscrypt_d_ops);
        }
@@ -166,26 +165,51 @@ int fscrypt_prepare_setflags(struct inode *inode,
        return 0;
 }
 
-int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
-                             unsigned int max_len,
-                             struct fscrypt_str *disk_link)
+/**
+ * fscrypt_prepare_symlink() - prepare to create a possibly-encrypted symlink
+ * @dir: directory in which the symlink is being created
+ * @target: plaintext symlink target
+ * @len: length of @target excluding null terminator
+ * @max_len: space the filesystem has available to store the symlink target
+ * @disk_link: (out) the on-disk symlink target being prepared
+ *
+ * This function computes the size the symlink target will require on-disk,
+ * stores it in @disk_link->len, and validates it against @max_len.  An
+ * encrypted symlink may be longer than the original.
+ *
+ * Additionally, @disk_link->name is set to @target if the symlink will be
+ * unencrypted, but left NULL if the symlink will be encrypted.  For encrypted
+ * symlinks, the filesystem must call fscrypt_encrypt_symlink() to create the
+ * on-disk target later.  (The reason for the two-step process is that some
+ * filesystems need to know the size of the symlink target before creating the
+ * inode, e.g. to determine whether it will be a "fast" or "slow" symlink.)
+ *
+ * Return: 0 on success, -ENAMETOOLONG if the symlink target is too long,
+ * -ENOKEY if the encryption key is missing, or another -errno code if a problem
+ * occurred while setting up the encryption key.
+ */
+int fscrypt_prepare_symlink(struct inode *dir, const char *target,
+                           unsigned int len, unsigned int max_len,
+                           struct fscrypt_str *disk_link)
 {
-       int err;
+       const union fscrypt_policy *policy;
 
        /*
         * To calculate the size of the encrypted symlink target we need to know
         * the amount of NUL padding, which is determined by the flags set in
         * the encryption policy which will be inherited from the directory.
-        * The easiest way to get access to this is to just load the directory's
-        * fscrypt_info, since we'll need it to create the dir_entry anyway.
-        *
-        * Note: in test_dummy_encryption mode, @dir may be unencrypted.
         */
-       err = fscrypt_get_encryption_info(dir);
-       if (err)
-               return err;
-       if (!fscrypt_has_encryption_key(dir))
-               return -ENOKEY;
+       policy = fscrypt_policy_to_inherit(dir);
+       if (policy == NULL) {
+               /* Not encrypted */
+               disk_link->name = (unsigned char *)target;
+               disk_link->len = len + 1;
+               if (disk_link->len > max_len)
+                       return -ENAMETOOLONG;
+               return 0;
+       }
+       if (IS_ERR(policy))
+               return PTR_ERR(policy);
 
        /*
         * Calculate the size of the encrypted symlink and verify it won't
@@ -198,7 +222,7 @@ int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
         * counting it (even though it is meaningless for ciphertext) is simpler
         * for now since filesystems will assume it is there and subtract it.
         */
-       if (!fscrypt_fname_encrypted_size(dir, len,
+       if (!fscrypt_fname_encrypted_size(policy, len,
                                          max_len - sizeof(struct fscrypt_symlink_data),
                                          &disk_link->len))
                return -ENAMETOOLONG;
@@ -207,7 +231,7 @@ int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
        disk_link->name = NULL;
        return 0;
 }
-EXPORT_SYMBOL_GPL(__fscrypt_prepare_symlink);
+EXPORT_SYMBOL_GPL(fscrypt_prepare_symlink);
 
 int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
                              unsigned int len, struct fscrypt_str *disk_link)
@@ -217,9 +241,13 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
        struct fscrypt_symlink_data *sd;
        unsigned int ciphertext_len;
 
-       err = fscrypt_require_key(inode);
-       if (err)
-               return err;
+       /*
+        * fscrypt_prepare_new_inode() should have already set up the new
+        * symlink inode's encryption key.  We don't wait until now to do it,
+        * since we may be in a filesystem transaction now.
+        */
+       if (WARN_ON_ONCE(!fscrypt_has_encryption_key(inode)))
+               return -ENOKEY;
 
        if (disk_link->name) {
                /* filesystem-provided buffer */
@@ -319,7 +347,7 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
        if (cstr.len + sizeof(*sd) - 1 > max_size)
                return ERR_PTR(-EUCLEAN);
 
-       err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
+       err = fscrypt_fname_alloc_buffer(cstr.len, &pstr);
        if (err)
                return ERR_PTR(err);
 
index faa2554..89bffa8 100644 (file)
@@ -106,7 +106,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
        crypto_cfg.data_unit_size = sb->s_blocksize;
        crypto_cfg.dun_bytes = fscrypt_get_dun_bytes(ci);
        num_devs = fscrypt_get_num_devices(sb);
-       devs = kmalloc_array(num_devs, sizeof(*devs), GFP_NOFS);
+       devs = kmalloc_array(num_devs, sizeof(*devs), GFP_KERNEL);
        if (!devs)
                return -ENOMEM;
        fscrypt_get_devices(sb, num_devs, devs);
@@ -135,9 +135,8 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
        struct fscrypt_blk_crypto_key *blk_key;
        int err;
        int i;
-       unsigned int flags;
 
-       blk_key = kzalloc(struct_size(blk_key, devs, num_devs), GFP_NOFS);
+       blk_key = kzalloc(struct_size(blk_key, devs, num_devs), GFP_KERNEL);
        if (!blk_key)
                return -ENOMEM;
 
@@ -166,10 +165,8 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
                }
                queue_refs++;
 
-               flags = memalloc_nofs_save();
                err = blk_crypto_start_using_key(&blk_key->base,
                                                 blk_key->devs[i]);
-               memalloc_nofs_restore(flags);
                if (err) {
                        fscrypt_err(inode,
                                    "error %d starting to use blk-crypto", err);
index e74f239..53cc552 100644 (file)
@@ -817,6 +817,7 @@ static int check_for_busy_inodes(struct super_block *sb,
        struct list_head *pos;
        size_t busy_count = 0;
        unsigned long ino;
+       char ino_str[50] = "";
 
        spin_lock(&mk->mk_decrypted_inodes_lock);
 
@@ -838,11 +839,15 @@ static int check_for_busy_inodes(struct super_block *sb,
        }
        spin_unlock(&mk->mk_decrypted_inodes_lock);
 
+       /* If the inode is currently being created, ino may still be 0. */
+       if (ino)
+               snprintf(ino_str, sizeof(ino_str), ", including ino %lu", ino);
+
        fscrypt_warn(NULL,
-                    "%s: %zu inode(s) still busy after removing key with %s %*phN, including ino %lu",
+                    "%s: %zu inode(s) still busy after removing key with %s %*phN%s",
                     sb->s_id, busy_count, master_key_spec_type(&mk->mk_spec),
                     master_key_spec_len(&mk->mk_spec), (u8 *)&mk->mk_spec.u,
-                    ino);
+                    ino_str);
        return -EBUSY;
 }
 
index fea6226..d3c3e5d 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <crypto/skcipher.h>
 #include <linux/key.h>
+#include <linux/random.h>
 
 #include "fscrypt_private.h"
 
@@ -222,6 +223,16 @@ int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
        return 0;
 }
 
+void fscrypt_hash_inode_number(struct fscrypt_info *ci,
+                              const struct fscrypt_master_key *mk)
+{
+       WARN_ON(ci->ci_inode->i_ino == 0);
+       WARN_ON(!mk->mk_ino_hash_key_initialized);
+
+       ci->ci_hashed_ino = (u32)siphash_1u64(ci->ci_inode->i_ino,
+                                             &mk->mk_ino_hash_key);
+}
+
 static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci,
                                            struct fscrypt_master_key *mk)
 {
@@ -254,13 +265,20 @@ unlock:
                        return err;
        }
 
-       ci->ci_hashed_ino = (u32)siphash_1u64(ci->ci_inode->i_ino,
-                                             &mk->mk_ino_hash_key);
+       /*
+        * New inodes may not have an inode number assigned yet.
+        * Hashing their inode number is delayed until later.
+        */
+       if (ci->ci_inode->i_ino == 0)
+               WARN_ON(!(ci->ci_inode->i_state & I_CREATING));
+       else
+               fscrypt_hash_inode_number(ci, mk);
        return 0;
 }
 
 static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
-                                    struct fscrypt_master_key *mk)
+                                    struct fscrypt_master_key *mk,
+                                    bool need_dirhash_key)
 {
        int err;
 
@@ -306,7 +324,7 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
                return err;
 
        /* Derive a secret dirhash key for directories that need it. */
-       if (S_ISDIR(ci->ci_inode->i_mode) && IS_CASEFOLDED(ci->ci_inode)) {
+       if (need_dirhash_key) {
                err = fscrypt_derive_dirhash_key(ci, mk);
                if (err)
                        return err;
@@ -326,6 +344,7 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
  * key being removed with a new inode starting to use it.
  */
 static int setup_file_encryption_key(struct fscrypt_info *ci,
+                                    bool need_dirhash_key,
                                     struct key **master_key_ret)
 {
        struct key *key;
@@ -400,7 +419,7 @@ static int setup_file_encryption_key(struct fscrypt_info *ci,
                err = fscrypt_setup_v1_file_key(ci, mk->mk_secret.raw);
                break;
        case FSCRYPT_POLICY_V2:
-               err = fscrypt_setup_v2_file_key(ci, mk);
+               err = fscrypt_setup_v2_file_key(ci, mk, need_dirhash_key);
                break;
        default:
                WARN_ON(1);
@@ -454,57 +473,28 @@ static void put_crypt_info(struct fscrypt_info *ci)
        kmem_cache_free(fscrypt_info_cachep, ci);
 }
 
-int fscrypt_get_encryption_info(struct inode *inode)
+static int
+fscrypt_setup_encryption_info(struct inode *inode,
+                             const union fscrypt_policy *policy,
+                             const u8 nonce[FSCRYPT_FILE_NONCE_SIZE],
+                             bool need_dirhash_key)
 {
        struct fscrypt_info *crypt_info;
-       union fscrypt_context ctx;
        struct fscrypt_mode *mode;
        struct key *master_key = NULL;
        int res;
 
-       if (fscrypt_has_encryption_key(inode))
-               return 0;
-
        res = fscrypt_initialize(inode->i_sb->s_cop->flags);
        if (res)
                return res;
 
-       res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
-       if (res < 0) {
-               const union fscrypt_context *dummy_ctx =
-                       fscrypt_get_dummy_context(inode->i_sb);
-
-               if (IS_ENCRYPTED(inode) || !dummy_ctx) {
-                       fscrypt_warn(inode,
-                                    "Error %d getting encryption context",
-                                    res);
-                       return res;
-               }
-               /* Fake up a context for an unencrypted directory */
-               res = fscrypt_context_size(dummy_ctx);
-               memcpy(&ctx, dummy_ctx, res);
-       }
-
-       crypt_info = kmem_cache_zalloc(fscrypt_info_cachep, GFP_NOFS);
+       crypt_info = kmem_cache_zalloc(fscrypt_info_cachep, GFP_KERNEL);
        if (!crypt_info)
                return -ENOMEM;
 
        crypt_info->ci_inode = inode;
-
-       res = fscrypt_policy_from_context(&crypt_info->ci_policy, &ctx, res);
-       if (res) {
-               fscrypt_warn(inode,
-                            "Unrecognized or corrupt encryption context");
-               goto out;
-       }
-
-       memcpy(crypt_info->ci_nonce, fscrypt_context_nonce(&ctx),
-              FSCRYPT_FILE_NONCE_SIZE);
-
-       if (!fscrypt_supported_policy(&crypt_info->ci_policy, inode)) {
-               res = -EINVAL;
-               goto out;
-       }
+       crypt_info->ci_policy = *policy;
+       memcpy(crypt_info->ci_nonce, nonce, FSCRYPT_FILE_NONCE_SIZE);
 
        mode = select_encryption_mode(&crypt_info->ci_policy, inode);
        if (IS_ERR(mode)) {
@@ -514,13 +504,14 @@ int fscrypt_get_encryption_info(struct inode *inode)
        WARN_ON(mode->ivsize > FSCRYPT_MAX_IV_SIZE);
        crypt_info->ci_mode = mode;
 
-       res = setup_file_encryption_key(crypt_info, &master_key);
+       res = setup_file_encryption_key(crypt_info, need_dirhash_key,
+                                       &master_key);
        if (res)
                goto out;
 
        /*
-        * Multiple tasks may race to set ->i_crypt_info, so use
-        * cmpxchg_release().  This pairs with the smp_load_acquire() in
+        * For existing inodes, multiple tasks may race to set ->i_crypt_info.
+        * So use cmpxchg_release().  This pairs with the smp_load_acquire() in
         * fscrypt_get_info().  I.e., here we publish ->i_crypt_info with a
         * RELEASE barrier so that other tasks can ACQUIRE it.
         */
@@ -550,14 +541,113 @@ out:
                up_read(&mk->mk_secret_sem);
                key_put(master_key);
        }
+       put_crypt_info(crypt_info);
+       return res;
+}
+
+/**
+ * fscrypt_get_encryption_info() - set up an inode's encryption key
+ * @inode: the inode to set up the key for.  Must be encrypted.
+ *
+ * Set up ->i_crypt_info, if it hasn't already been done.
+ *
+ * Note: unless ->i_crypt_info is already set, this isn't %GFP_NOFS-safe.  So
+ * generally this shouldn't be called from within a filesystem transaction.
+ *
+ * Return: 0 if ->i_crypt_info was set or was already set, *or* if the
+ *        encryption key is unavailable.  (Use fscrypt_has_encryption_key() to
+ *        distinguish these cases.)  Also can return another -errno code.
+ */
+int fscrypt_get_encryption_info(struct inode *inode)
+{
+       int res;
+       union fscrypt_context ctx;
+       union fscrypt_policy policy;
+
+       if (fscrypt_has_encryption_key(inode))
+               return 0;
+
+       res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
+       if (res < 0) {
+               fscrypt_warn(inode, "Error %d getting encryption context", res);
+               return res;
+       }
+
+       res = fscrypt_policy_from_context(&policy, &ctx, res);
+       if (res) {
+               fscrypt_warn(inode,
+                            "Unrecognized or corrupt encryption context");
+               return res;
+       }
+
+       if (!fscrypt_supported_policy(&policy, inode))
+               return -EINVAL;
+
+       res = fscrypt_setup_encryption_info(inode, &policy,
+                                           fscrypt_context_nonce(&ctx),
+                                           IS_CASEFOLDED(inode) &&
+                                           S_ISDIR(inode->i_mode));
        if (res == -ENOKEY)
                res = 0;
-       put_crypt_info(crypt_info);
        return res;
 }
 EXPORT_SYMBOL(fscrypt_get_encryption_info);
 
 /**
+ * fscrypt_prepare_new_inode() - prepare to create a new inode in a directory
+ * @dir: a possibly-encrypted directory
+ * @inode: the new inode.  ->i_mode must be set already.
+ *        ->i_ino doesn't need to be set yet.
+ * @encrypt_ret: (output) set to %true if the new inode will be encrypted
+ *
+ * If the directory is encrypted, set up its ->i_crypt_info in preparation for
+ * encrypting the name of the new file.  Also, if the new inode will be
+ * encrypted, set up its ->i_crypt_info and set *encrypt_ret=true.
+ *
+ * This isn't %GFP_NOFS-safe, and therefore it should be called before starting
+ * any filesystem transaction to create the inode.  For this reason, ->i_ino
+ * isn't required to be set yet, as the filesystem may not have set it yet.
+ *
+ * This doesn't persist the new inode's encryption context.  That still needs to
+ * be done later by calling fscrypt_set_context().
+ *
+ * Return: 0 on success, -ENOKEY if the encryption key is missing, or another
+ *        -errno code
+ */
+int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
+                             bool *encrypt_ret)
+{
+       const union fscrypt_policy *policy;
+       u8 nonce[FSCRYPT_FILE_NONCE_SIZE];
+
+       policy = fscrypt_policy_to_inherit(dir);
+       if (policy == NULL)
+               return 0;
+       if (IS_ERR(policy))
+               return PTR_ERR(policy);
+
+       if (WARN_ON_ONCE(inode->i_mode == 0))
+               return -EINVAL;
+
+       /*
+        * Only regular files, directories, and symlinks are encrypted.
+        * Special files like device nodes and named pipes aren't.
+        */
+       if (!S_ISREG(inode->i_mode) &&
+           !S_ISDIR(inode->i_mode) &&
+           !S_ISLNK(inode->i_mode))
+               return 0;
+
+       *encrypt_ret = true;
+
+       get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE);
+       return fscrypt_setup_encryption_info(inode, policy, nonce,
+                                            IS_CASEFOLDED(dir) &&
+                                            S_ISDIR(inode->i_mode));
+}
+EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode);
+
+/**
  * fscrypt_put_encryption_info() - free most of an inode's fscrypt data
  * @inode: an inode being evicted
  *
index a3cb525..2762c53 100644 (file)
@@ -60,7 +60,7 @@ static int derive_key_aes(const u8 *master_key,
                goto out;
        }
        crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
-       req = skcipher_request_alloc(tfm, GFP_NOFS);
+       req = skcipher_request_alloc(tfm, GFP_KERNEL);
        if (!req) {
                res = -ENOMEM;
                goto out;
@@ -99,7 +99,7 @@ find_and_lock_process_key(const char *prefix,
        const struct user_key_payload *ukp;
        const struct fscrypt_key *payload;
 
-       description = kasprintf(GFP_NOFS, "%s%*phN", prefix,
+       description = kasprintf(GFP_KERNEL, "%s%*phN", prefix,
                                FSCRYPT_KEY_DESCRIPTOR_SIZE, descriptor);
        if (!description)
                return ERR_PTR(-ENOMEM);
@@ -228,7 +228,7 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key)
                return dk;
 
        /* Nope, allocate one. */
-       dk = kzalloc(sizeof(*dk), GFP_NOFS);
+       dk = kzalloc(sizeof(*dk), GFP_KERNEL);
        if (!dk)
                return ERR_PTR(-ENOMEM);
        refcount_set(&dk->dk_refcount, 1);
@@ -272,7 +272,7 @@ static int setup_v1_file_key_derived(struct fscrypt_info *ci,
         * This cannot be a stack buffer because it will be passed to the
         * scatterlist crypto API during derive_key_aes().
         */
-       derived_key = kmalloc(ci->ci_mode->keysize, GFP_NOFS);
+       derived_key = kmalloc(ci->ci_mode->keysize, GFP_KERNEL);
        if (!derived_key)
                return -ENOMEM;
 
index 2d73fd3..4441d99 100644 (file)
@@ -32,6 +32,14 @@ bool fscrypt_policies_equal(const union fscrypt_policy *policy1,
        return !memcmp(policy1, policy2, fscrypt_policy_size(policy1));
 }
 
+static const union fscrypt_policy *
+fscrypt_get_dummy_policy(struct super_block *sb)
+{
+       if (!sb->s_cop->get_dummy_policy)
+               return NULL;
+       return sb->s_cop->get_dummy_policy(sb);
+}
+
 static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode)
 {
        if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
@@ -192,10 +200,15 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy,
                                          32, 32))
                return false;
 
+       /*
+        * IV_INO_LBLK_32 hashes the inode number, so in principle it can
+        * support any ino_bits.  However, currently the inode number is gotten
+        * from inode::i_ino which is 'unsigned long'.  So for now the
+        * implementation limit is 32 bits.
+        */
        if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) &&
-           /* This uses hashed inode numbers, so ino_bits doesn't matter. */
            !supported_iv_ino_lblk_policy(policy, inode, "IV_INO_LBLK_32",
-                                         INT_MAX, 32))
+                                         32, 32))
                return false;
 
        if (memchr_inv(policy->__reserved, 0, sizeof(policy->__reserved))) {
@@ -231,18 +244,19 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u,
 }
 
 /**
- * fscrypt_new_context_from_policy() - create a new fscrypt_context from
- *                                    an fscrypt_policy
+ * fscrypt_new_context() - create a new fscrypt_context
  * @ctx_u: output context
  * @policy_u: input policy
+ * @nonce: nonce to use
  *
  * Create an fscrypt_context for an inode that is being assigned the given
- * encryption policy.  A new nonce is randomly generated.
+ * encryption policy.  @nonce must be a new random nonce.
  *
  * Return: the size of the new context in bytes.
  */
-static int fscrypt_new_context_from_policy(union fscrypt_context *ctx_u,
-                                          const union fscrypt_policy *policy_u)
+static int fscrypt_new_context(union fscrypt_context *ctx_u,
+                              const union fscrypt_policy *policy_u,
+                              const u8 nonce[FSCRYPT_FILE_NONCE_SIZE])
 {
        memset(ctx_u, 0, sizeof(*ctx_u));
 
@@ -260,7 +274,7 @@ static int fscrypt_new_context_from_policy(union fscrypt_context *ctx_u,
                memcpy(ctx->master_key_descriptor,
                       policy->master_key_descriptor,
                       sizeof(ctx->master_key_descriptor));
-               get_random_bytes(ctx->nonce, sizeof(ctx->nonce));
+               memcpy(ctx->nonce, nonce, FSCRYPT_FILE_NONCE_SIZE);
                return sizeof(*ctx);
        }
        case FSCRYPT_POLICY_V2: {
@@ -276,7 +290,7 @@ static int fscrypt_new_context_from_policy(union fscrypt_context *ctx_u,
                memcpy(ctx->master_key_identifier,
                       policy->master_key_identifier,
                       sizeof(ctx->master_key_identifier));
-               get_random_bytes(ctx->nonce, sizeof(ctx->nonce));
+               memcpy(ctx->nonce, nonce, FSCRYPT_FILE_NONCE_SIZE);
                return sizeof(*ctx);
        }
        }
@@ -372,6 +386,7 @@ static int fscrypt_get_policy(struct inode *inode, union fscrypt_policy *policy)
 static int set_encryption_policy(struct inode *inode,
                                 const union fscrypt_policy *policy)
 {
+       u8 nonce[FSCRYPT_FILE_NONCE_SIZE];
        union fscrypt_context ctx;
        int ctxsize;
        int err;
@@ -409,7 +424,8 @@ static int set_encryption_policy(struct inode *inode,
                return -EINVAL;
        }
 
-       ctxsize = fscrypt_new_context_from_policy(&ctx, policy);
+       get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE);
+       ctxsize = fscrypt_new_context(&ctx, policy, nonce);
 
        return inode->i_sb->s_cop->set_context(inode, &ctx, ctxsize, NULL);
 }
@@ -620,86 +636,99 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
 }
 EXPORT_SYMBOL(fscrypt_has_permitted_context);
 
+/*
+ * Return the encryption policy that new files in the directory will inherit, or
+ * NULL if none, or an ERR_PTR() on error.  If the directory is encrypted, also
+ * ensure that its key is set up, so that the new filename can be encrypted.
+ */
+const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir)
+{
+       int err;
+
+       if (IS_ENCRYPTED(dir)) {
+               err = fscrypt_require_key(dir);
+               if (err)
+                       return ERR_PTR(err);
+               return &dir->i_crypt_info->ci_policy;
+       }
+
+       return fscrypt_get_dummy_policy(dir->i_sb);
+}
+
 /**
- * fscrypt_inherit_context() - Sets a child context from its parent
- * @parent: Parent inode from which the context is inherited.
- * @child:  Child inode that inherits the context from @parent.
- * @fs_data:  private data given by FS.
- * @preload:  preload child i_crypt_info if true
+ * fscrypt_set_context() - Set the fscrypt context of a new inode
+ * @inode: a new inode
+ * @fs_data: private data given by FS and passed to ->set_context()
+ *
+ * This should be called after fscrypt_prepare_new_inode(), generally during a
+ * filesystem transaction.  Everything here must be %GFP_NOFS-safe.
  *
  * Return: 0 on success, -errno on failure
  */
-int fscrypt_inherit_context(struct inode *parent, struct inode *child,
-                                               void *fs_data, bool preload)
+int fscrypt_set_context(struct inode *inode, void *fs_data)
 {
+       struct fscrypt_info *ci = inode->i_crypt_info;
        union fscrypt_context ctx;
        int ctxsize;
-       struct fscrypt_info *ci;
-       int res;
-
-       res = fscrypt_get_encryption_info(parent);
-       if (res < 0)
-               return res;
 
-       ci = fscrypt_get_info(parent);
-       if (ci == NULL)
+       /* fscrypt_prepare_new_inode() should have set up the key already. */
+       if (WARN_ON_ONCE(!ci))
                return -ENOKEY;
 
-       ctxsize = fscrypt_new_context_from_policy(&ctx, &ci->ci_policy);
-
        BUILD_BUG_ON(sizeof(ctx) != FSCRYPT_SET_CONTEXT_MAX_SIZE);
-       res = parent->i_sb->s_cop->set_context(child, &ctx, ctxsize, fs_data);
-       if (res)
-               return res;
-       return preload ? fscrypt_get_encryption_info(child): 0;
+       ctxsize = fscrypt_new_context(&ctx, &ci->ci_policy, ci->ci_nonce);
+
+       /*
+        * This may be the first time the inode number is available, so do any
+        * delayed key setup that requires the inode number.
+        */
+       if (ci->ci_policy.version == FSCRYPT_POLICY_V2 &&
+           (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) {
+               const struct fscrypt_master_key *mk =
+                       ci->ci_master_key->payload.data[0];
+
+               fscrypt_hash_inode_number(ci, mk);
+       }
+
+       return inode->i_sb->s_cop->set_context(inode, &ctx, ctxsize, fs_data);
 }
-EXPORT_SYMBOL(fscrypt_inherit_context);
+EXPORT_SYMBOL_GPL(fscrypt_set_context);
 
 /**
  * fscrypt_set_test_dummy_encryption() - handle '-o test_dummy_encryption'
  * @sb: the filesystem on which test_dummy_encryption is being specified
- * @arg: the argument to the test_dummy_encryption option.
- *      If no argument was specified, then @arg->from == NULL.
- * @dummy_ctx: the filesystem's current dummy context (input/output, see below)
+ * @arg: the argument to the test_dummy_encryption option.  May be NULL.
+ * @dummy_policy: the filesystem's current dummy policy (input/output, see
+ *               below)
  *
  * Handle the test_dummy_encryption mount option by creating a dummy encryption
- * context, saving it in @dummy_ctx, and adding the corresponding dummy
- * encryption key to the filesystem.  If the @dummy_ctx is already set, then
+ * policy, saving it in @dummy_policy, and adding the corresponding dummy
+ * encryption key to the filesystem.  If the @dummy_policy is already set, then
  * instead validate that it matches @arg.  Don't support changing it via
  * remount, as that is difficult to do safely.
  *
- * The reason we use an fscrypt_context rather than an fscrypt_policy is because
- * we mustn't generate a new nonce each time we access a dummy-encrypted
- * directory, as that would change the way filenames are encrypted.
- *
- * Return: 0 on success (dummy context set, or the same context is already set);
- *         -EEXIST if a different dummy context is already set;
+ * Return: 0 on success (dummy policy set, or the same policy is already set);
+ *         -EEXIST if a different dummy policy is already set;
  *         or another -errno value.
  */
-int fscrypt_set_test_dummy_encryption(struct super_block *sb,
-                                     const substring_t *arg,
-                                     struct fscrypt_dummy_context *dummy_ctx)
+int fscrypt_set_test_dummy_encryption(struct super_block *sb, const char *arg,
+                                     struct fscrypt_dummy_policy *dummy_policy)
 {
-       const char *argstr = "v2";
-       const char *argstr_to_free = NULL;
        struct fscrypt_key_specifier key_spec = { 0 };
        int version;
-       union fscrypt_context *ctx = NULL;
+       union fscrypt_policy *policy = NULL;
        int err;
 
-       if (arg->from) {
-               argstr = argstr_to_free = match_strdup(arg);
-               if (!argstr)
-                       return -ENOMEM;
-       }
+       if (!arg)
+               arg = "v2";
 
-       if (!strcmp(argstr, "v1")) {
-               version = FSCRYPT_CONTEXT_V1;
+       if (!strcmp(arg, "v1")) {
+               version = FSCRYPT_POLICY_V1;
                key_spec.type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
                memset(key_spec.u.descriptor, 0x42,
                       FSCRYPT_KEY_DESCRIPTOR_SIZE);
-       } else if (!strcmp(argstr, "v2")) {
-               version = FSCRYPT_CONTEXT_V2;
+       } else if (!strcmp(arg, "v2")) {
+               version = FSCRYPT_POLICY_V2;
                key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
                /* key_spec.u.identifier gets filled in when adding the key */
        } else {
@@ -707,21 +736,8 @@ int fscrypt_set_test_dummy_encryption(struct super_block *sb,
                goto out;
        }
 
-       if (dummy_ctx->ctx) {
-               /*
-                * Note: if we ever make test_dummy_encryption support
-                * specifying other encryption settings, such as the encryption
-                * modes, we'll need to compare those settings here.
-                */
-               if (dummy_ctx->ctx->version == version)
-                       err = 0;
-               else
-                       err = -EEXIST;
-               goto out;
-       }
-
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (!ctx) {
+       policy = kzalloc(sizeof(*policy), GFP_KERNEL);
+       if (!policy) {
                err = -ENOMEM;
                goto out;
        }
@@ -730,18 +746,18 @@ int fscrypt_set_test_dummy_encryption(struct super_block *sb,
        if (err)
                goto out;
 
-       ctx->version = version;
-       switch (ctx->version) {
-       case FSCRYPT_CONTEXT_V1:
-               ctx->v1.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
-               ctx->v1.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
-               memcpy(ctx->v1.master_key_descriptor, key_spec.u.descriptor,
+       policy->version = version;
+       switch (policy->version) {
+       case FSCRYPT_POLICY_V1:
+               policy->v1.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
+               policy->v1.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
+               memcpy(policy->v1.master_key_descriptor, key_spec.u.descriptor,
                       FSCRYPT_KEY_DESCRIPTOR_SIZE);
                break;
-       case FSCRYPT_CONTEXT_V2:
-               ctx->v2.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
-               ctx->v2.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
-               memcpy(ctx->v2.master_key_identifier, key_spec.u.identifier,
+       case FSCRYPT_POLICY_V2:
+               policy->v2.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
+               policy->v2.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
+               memcpy(policy->v2.master_key_identifier, key_spec.u.identifier,
                       FSCRYPT_KEY_IDENTIFIER_SIZE);
                break;
        default:
@@ -749,12 +765,19 @@ int fscrypt_set_test_dummy_encryption(struct super_block *sb,
                err = -EINVAL;
                goto out;
        }
-       dummy_ctx->ctx = ctx;
-       ctx = NULL;
+
+       if (dummy_policy->policy) {
+               if (fscrypt_policies_equal(policy, dummy_policy->policy))
+                       err = 0;
+               else
+                       err = -EEXIST;
+               goto out;
+       }
+       dummy_policy->policy = policy;
+       policy = NULL;
        err = 0;
 out:
-       kfree(ctx);
-       kfree(argstr_to_free);
+       kfree(policy);
        return err;
 }
 EXPORT_SYMBOL_GPL(fscrypt_set_test_dummy_encryption);
@@ -771,10 +794,16 @@ EXPORT_SYMBOL_GPL(fscrypt_set_test_dummy_encryption);
 void fscrypt_show_test_dummy_encryption(struct seq_file *seq, char sep,
                                        struct super_block *sb)
 {
-       const union fscrypt_context *ctx = fscrypt_get_dummy_context(sb);
+       const union fscrypt_policy *policy = fscrypt_get_dummy_policy(sb);
+       int vers;
 
-       if (!ctx)
+       if (!policy)
                return;
-       seq_printf(seq, "%ctest_dummy_encryption=v%d", sep, ctx->version);
+
+       vers = policy->version;
+       if (vers == FSCRYPT_POLICY_V1) /* Handle numbering quirk */
+               vers = 1;
+
+       seq_printf(seq, "%ctest_dummy_encryption=v%d", sep, vers);
 }
 EXPORT_SYMBOL_GPL(fscrypt_show_test_dummy_encryption);
index 95341af..994ab66 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1367,7 +1367,7 @@ static vm_fault_t dax_iomap_pte_fault(struct vm_fault *vmf, pfn_t *pfnp,
                        ret = dax_load_hole(&xas, mapping, &entry, vmf);
                        goto finish_iomap;
                }
-               /*FALLTHRU*/
+               fallthrough;
        default:
                WARN_ON_ONCE(1);
                error = -EIO;
index b167d2d..a768a09 100644 (file)
@@ -177,7 +177,7 @@ static int open_proxy_open(struct inode *inode, struct file *filp)
                goto out;
 
        if (!fops_get(real_fops)) {
-#ifdef MODULE
+#ifdef CONFIG_MODULES
                if (real_fops->owner &&
                    real_fops->owner->state == MODULE_STATE_GOING)
                        goto out;
@@ -312,7 +312,7 @@ static int full_proxy_open(struct inode *inode, struct file *filp)
                goto out;
 
        if (!fops_get(real_fops)) {
-#ifdef MODULE
+#ifdef CONFIG_MODULES
                if (real_fops->owner &&
                    real_fops->owner->state == MODULE_STATE_GOING)
                        goto out;
index 18d8159..002123e 100644 (file)
@@ -5817,7 +5817,7 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
                break;
        case -EAGAIN:
                error = 0;
-               /* fall through */
+               fallthrough;
        default:
                __put_lkb(ls, lkb);
                goto out;
index 28bb568..15880a6 100644 (file)
@@ -141,6 +141,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
 
        name[len + EFI_VARIABLE_GUID_LEN+1] = '\0';
 
+       /* replace invalid slashes like kobject_set_name_vargs does for /sys/firmware/efi/vars. */
+       strreplace(name, '/', '!');
+
        inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0,
                                   is_removable);
        if (!inode)
index 7d40d78..ae32554 100644 (file)
@@ -359,7 +359,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
                return z_erofs_extent_lookback(m, m->delta[0]);
        case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
                map->m_flags &= ~EROFS_MAP_ZIPPED;
-               /* fallthrough */
+               fallthrough;
        case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
                map->m_la = (lcn << lclusterbits) | m->clusterofs;
                break;
@@ -416,7 +416,7 @@ int z_erofs_map_blocks_iter(struct inode *inode,
        case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
                if (endoff >= m.clusterofs)
                        map->m_flags &= ~EROFS_MAP_ZIPPED;
-               /* fallthrough */
+               fallthrough;
        case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
                if (endoff >= m.clusterofs) {
                        map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
@@ -433,7 +433,7 @@ int z_erofs_map_blocks_iter(struct inode *inode,
                end = (m.lcn << lclusterbits) | m.clusterofs;
                map->m_flags |= EROFS_MAP_FULL_MAPPED;
                m.delta[0] = 1;
-               /* fallthrough */
+               fallthrough;
        case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
                /* get the correspoinding first chunk */
                err = z_erofs_extent_lookback(&m, m.delta[0]);
index e0decff..4df6112 100644 (file)
@@ -218,8 +218,7 @@ struct eventpoll {
        struct file *file;
 
        /* used to optimize loop detection check */
-       struct list_head visited_list_link;
-       int visited;
+       u64 gen;
 
 #ifdef CONFIG_NET_RX_BUSY_POLL
        /* used to track busy poll napi_id */
@@ -274,6 +273,8 @@ static long max_user_watches __read_mostly;
  */
 static DEFINE_MUTEX(epmutex);
 
+static u64 loop_check_gen = 0;
+
 /* Used to check for epoll file descriptor inclusion loops */
 static struct nested_calls poll_loop_ncalls;
 
@@ -283,9 +284,6 @@ static struct kmem_cache *epi_cache __read_mostly;
 /* Slab cache used to allocate "struct eppoll_entry" */
 static struct kmem_cache *pwq_cache __read_mostly;
 
-/* Visited nodes during ep_loop_check(), so we can unset them when we finish */
-static LIST_HEAD(visited_list);
-
 /*
  * List of files with newly added links, where we may need to limit the number
  * of emanating paths. Protected by the epmutex.
@@ -1450,7 +1448,7 @@ static int reverse_path_check(void)
 
 static int ep_create_wakeup_source(struct epitem *epi)
 {
-       const char *name;
+       struct name_snapshot n;
        struct wakeup_source *ws;
 
        if (!epi->ep->ws) {
@@ -1459,8 +1457,9 @@ static int ep_create_wakeup_source(struct epitem *epi)
                        return -ENOMEM;
        }
 
-       name = epi->ffd.file->f_path.dentry->d_name.name;
-       ws = wakeup_source_register(NULL, name);
+       take_dentry_name_snapshot(&n, epi->ffd.file->f_path.dentry);
+       ws = wakeup_source_register(NULL, n.name.name);
+       release_dentry_name_snapshot(&n);
 
        if (!ws)
                return -ENOMEM;
@@ -1522,6 +1521,22 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
                RCU_INIT_POINTER(epi->ws, NULL);
        }
 
+       /* Add the current item to the list of active epoll hook for this file */
+       spin_lock(&tfile->f_lock);
+       list_add_tail_rcu(&epi->fllink, &tfile->f_ep_links);
+       spin_unlock(&tfile->f_lock);
+
+       /*
+        * Add the current item to the RB tree. All RB tree operations are
+        * protected by "mtx", and ep_insert() is called with "mtx" held.
+        */
+       ep_rbtree_insert(ep, epi);
+
+       /* now check if we've created too many backpaths */
+       error = -EINVAL;
+       if (full_check && reverse_path_check())
+               goto error_remove_epi;
+
        /* Initialize the poll table using the queue callback */
        epq.epi = epi;
        init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);
@@ -1544,22 +1559,6 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
        if (epi->nwait < 0)
                goto error_unregister;
 
-       /* Add the current item to the list of active epoll hook for this file */
-       spin_lock(&tfile->f_lock);
-       list_add_tail_rcu(&epi->fllink, &tfile->f_ep_links);
-       spin_unlock(&tfile->f_lock);
-
-       /*
-        * Add the current item to the RB tree. All RB tree operations are
-        * protected by "mtx", and ep_insert() is called with "mtx" held.
-        */
-       ep_rbtree_insert(ep, epi);
-
-       /* now check if we've created too many backpaths */
-       error = -EINVAL;
-       if (full_check && reverse_path_check())
-               goto error_remove_epi;
-
        /* We have to drop the new item inside our item list to keep track of it */
        write_lock_irq(&ep->lock);
 
@@ -1588,6 +1587,8 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
 
        return 0;
 
+error_unregister:
+       ep_unregister_pollwait(ep, epi);
 error_remove_epi:
        spin_lock(&tfile->f_lock);
        list_del_rcu(&epi->fllink);
@@ -1595,9 +1596,6 @@ error_remove_epi:
 
        rb_erase_cached(&epi->rbn, &ep->rbr);
 
-error_unregister:
-       ep_unregister_pollwait(ep, epi);
-
        /*
         * We need to do this because an event could have been arrived on some
         * allocated wait queue. Note that we don't care about the ep->ovflist
@@ -1972,13 +1970,12 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
        struct epitem *epi;
 
        mutex_lock_nested(&ep->mtx, call_nests + 1);
-       ep->visited = 1;
-       list_add(&ep->visited_list_link, &visited_list);
+       ep->gen = loop_check_gen;
        for (rbp = rb_first_cached(&ep->rbr); rbp; rbp = rb_next(rbp)) {
                epi = rb_entry(rbp, struct epitem, rbn);
                if (unlikely(is_file_epoll(epi->ffd.file))) {
                        ep_tovisit = epi->ffd.file->private_data;
-                       if (ep_tovisit->visited)
+                       if (ep_tovisit->gen == loop_check_gen)
                                continue;
                        error = ep_call_nested(&poll_loop_ncalls,
                                        ep_loop_check_proc, epi->ffd.file,
@@ -1995,9 +1992,9 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
                         * during ep_insert().
                         */
                        if (list_empty(&epi->ffd.file->f_tfile_llink)) {
-                               get_file(epi->ffd.file);
-                               list_add(&epi->ffd.file->f_tfile_llink,
-                                        &tfile_check_list);
+                               if (get_file_rcu(epi->ffd.file))
+                                       list_add(&epi->ffd.file->f_tfile_llink,
+                                                &tfile_check_list);
                        }
                }
        }
@@ -2019,18 +2016,8 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
  */
 static int ep_loop_check(struct eventpoll *ep, struct file *file)
 {
-       int ret;
-       struct eventpoll *ep_cur, *ep_next;
-
-       ret = ep_call_nested(&poll_loop_ncalls,
+       return ep_call_nested(&poll_loop_ncalls,
                              ep_loop_check_proc, file, ep, current);
-       /* clear visited list */
-       list_for_each_entry_safe(ep_cur, ep_next, &visited_list,
-                                                       visited_list_link) {
-               ep_cur->visited = 0;
-               list_del(&ep_cur->visited_list_link);
-       }
-       return ret;
 }
 
 static void clear_tfile_check_list(void)
@@ -2195,11 +2182,13 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
                goto error_tgt_fput;
        if (op == EPOLL_CTL_ADD) {
                if (!list_empty(&f.file->f_ep_links) ||
+                               ep->gen == loop_check_gen ||
                                                is_file_epoll(tf.file)) {
                        mutex_unlock(&ep->mtx);
                        error = epoll_mutex_lock(&epmutex, 0, nonblock);
                        if (error)
                                goto error_tgt_fput;
+                       loop_check_gen++;
                        full_check = 1;
                        if (is_file_epoll(tf.file)) {
                                error = -ELOOP;
@@ -2263,6 +2252,7 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
 error_tgt_fput:
        if (full_check) {
                clear_tfile_check_list();
+               loop_check_gen++;
                mutex_unlock(&epmutex);
        }
 
index 03d0824..5a2f119 100644 (file)
@@ -17,7 +17,6 @@
 #include "exfat_raw.h"
 #include "exfat_fs.h"
 
-#define EXFAT_CACHE_VALID      0
 #define EXFAT_MAX_CACHE                16
 
 struct exfat_cache {
@@ -61,16 +60,6 @@ void exfat_cache_shutdown(void)
        kmem_cache_destroy(exfat_cachep);
 }
 
-void exfat_cache_init_inode(struct inode *inode)
-{
-       struct exfat_inode_info *ei = EXFAT_I(inode);
-
-       spin_lock_init(&ei->cache_lru_lock);
-       ei->nr_caches = 0;
-       ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
-       INIT_LIST_HEAD(&ei->cache_lru);
-}
-
 static inline struct exfat_cache *exfat_cache_alloc(void)
 {
        return kmem_cache_alloc(exfat_cachep, GFP_NOFS);
index 95d717f..c013fe9 100644 (file)
@@ -248,6 +248,8 @@ struct exfat_sb_info {
        struct rcu_head rcu;
 };
 
+#define EXFAT_CACHE_VALID      0
+
 /*
  * EXFAT file system inode in-memory data
  */
@@ -428,7 +430,6 @@ extern const struct dentry_operations exfat_utf8_dentry_ops;
 /* cache.c */
 int exfat_cache_init(void);
 void exfat_cache_shutdown(void);
-void exfat_cache_init_inode(struct inode *inode);
 void exfat_cache_inval_inode(struct inode *inode);
 int exfat_get_cluster(struct inode *inode, unsigned int cluster,
                unsigned int *fclus, unsigned int *dclus,
index 7f90204..a6de17c 100644 (file)
@@ -611,8 +611,6 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
        ei->i_crtime = info->crtime;
        inode->i_atime = info->atime;
 
-       exfat_cache_init_inode(inode);
-
        return 0;
 }
 
index e73f20f..c94ac23 100644 (file)
@@ -578,7 +578,8 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 
        i_pos = exfat_make_i_pos(&info);
        inode = exfat_build_inode(sb, &info, i_pos);
-       if (IS_ERR(inode))
+       err = PTR_ERR_OR_ZERO(inode);
+       if (err)
                goto unlock;
 
        inode_inc_iversion(inode);
@@ -745,10 +746,9 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry,
 
        i_pos = exfat_make_i_pos(&info);
        inode = exfat_build_inode(sb, &info, i_pos);
-       if (IS_ERR(inode)) {
-               err = PTR_ERR(inode);
+       err = PTR_ERR_OR_ZERO(inode);
+       if (err)
                goto unlock;
-       }
 
        i_mode = inode->i_mode;
        alias = d_find_alias(inode);
@@ -890,10 +890,9 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 
        i_pos = exfat_make_i_pos(&info);
        inode = exfat_build_inode(sb, &info, i_pos);
-       if (IS_ERR(inode)) {
-               err = PTR_ERR(inode);
+       err = PTR_ERR_OR_ZERO(inode);
+       if (err)
                goto unlock;
-       }
 
        inode_inc_iversion(inode);
        inode->i_mtime = inode->i_atime = inode->i_ctime =
index 3b6a165..60b941b 100644 (file)
@@ -376,7 +376,6 @@ static int exfat_read_root(struct inode *inode)
        inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
                current_time(inode);
        exfat_truncate_atime(&inode->i_atime);
-       exfat_cache_init_inode(inode);
        return 0;
 }
 
@@ -763,6 +762,10 @@ static void exfat_inode_init_once(void *foo)
 {
        struct exfat_inode_info *ei = (struct exfat_inode_info *)foo;
 
+       spin_lock_init(&ei->cache_lru_lock);
+       ei->nr_caches = 0;
+       ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
+       INIT_LIST_HEAD(&ei->cache_lru);
        INIT_HLIST_NODE(&ei->i_hash_fat);
        inode_init_once(&ei->vfs_inode);
 }
index 60378dd..96044f5 100644 (file)
@@ -93,8 +93,10 @@ static vm_fault_t ext2_dax_fault(struct vm_fault *vmf)
        struct inode *inode = file_inode(vmf->vma->vm_file);
        struct ext2_inode_info *ei = EXT2_I(inode);
        vm_fault_t ret;
+       bool write = (vmf->flags & FAULT_FLAG_WRITE) &&
+               (vmf->vma->vm_flags & VM_SHARED);
 
-       if (vmf->flags & FAULT_FLAG_WRITE) {
+       if (write) {
                sb_start_pagefault(inode->i_sb);
                file_update_time(vmf->vma->vm_file);
        }
@@ -103,7 +105,7 @@ static vm_fault_t ext2_dax_fault(struct vm_fault *vmf)
        ret = dax_iomap_fault(vmf, PE_SIZE_PTE, NULL, NULL, &ext2_iomap_ops);
 
        up_read(&ei->dax_sem);
-       if (vmf->flags & FAULT_FLAG_WRITE)
+       if (write)
                sb_end_pagefault(inode->i_sb);
        return ret;
 }
index 80662e1..415c21f 100644 (file)
@@ -1241,7 +1241,7 @@ do_indirects:
                                mark_inode_dirty(inode);
                                ext2_free_branches(inode, &nr, &nr+1, 1);
                        }
-                       /* fall through */
+                       fallthrough;
                case EXT2_IND_BLOCK:
                        nr = i_data[EXT2_DIND_BLOCK];
                        if (nr) {
@@ -1249,7 +1249,7 @@ do_indirects:
                                mark_inode_dirty(inode);
                                ext2_free_branches(inode, &nr, &nr+1, 2);
                        }
-                       /* fall through */
+                       fallthrough;
                case EXT2_DIND_BLOCK:
                        nr = i_data[EXT2_TIND_BLOCK];
                        if (nr) {
index dda8605..7fab2b3 100644 (file)
@@ -587,7 +587,7 @@ static int parse_options(char *options, struct super_block *sb,
                case Opt_xip:
                        ext2_msg(sb, KERN_INFO, "use dax instead of xip");
                        set_opt(opts->s_mount_opt, XIP);
-                       /* Fall through */
+                       fallthrough;
                case Opt_dax:
 #ifdef CONFIG_FS_DAX
                        ext2_msg(sb, KERN_WARNING,
index 1d82336..efe77cf 100644 (file)
@@ -148,7 +148,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
        }
 
        if (IS_ENCRYPTED(inode)) {
-               err = fscrypt_fname_alloc_buffer(inode, EXT4_NAME_LEN, &fstr);
+               err = fscrypt_fname_alloc_buffer(EXT4_NAME_LEN, &fstr);
                if (err < 0)
                        return err;
        }
index 523e00d..f9a692c 100644 (file)
@@ -1401,7 +1401,7 @@ struct ext4_super_block {
 #define EXT4_MF_FS_ABORTED             0x0002  /* Fatal error detected */
 
 #ifdef CONFIG_FS_ENCRYPTION
-#define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_ctx.ctx != NULL)
+#define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_policy.policy != NULL)
 #else
 #define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
 #endif
@@ -1596,8 +1596,8 @@ struct ext4_sb_info {
        atomic_t s_warning_count;
        atomic_t s_msg_count;
 
-       /* Encryption context for '-o test_dummy_encryption' */
-       struct fscrypt_dummy_context s_dummy_enc_ctx;
+       /* Encryption policy for '-o test_dummy_encryption' */
+       struct fscrypt_dummy_policy s_dummy_enc_policy;
 
        /*
         * Barrier between writepages ops and changing any inode's JOURNAL_DATA
index df25d38..698ca4a 100644 (file)
@@ -742,6 +742,53 @@ not_found:
        return 1;
 }
 
+static int ext4_xattr_credits_for_new_inode(struct inode *dir, mode_t mode,
+                                           bool encrypt)
+{
+       struct super_block *sb = dir->i_sb;
+       int nblocks = 0;
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
+       struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT);
+
+       if (IS_ERR(p))
+               return PTR_ERR(p);
+       if (p) {
+               int acl_size = p->a_count * sizeof(ext4_acl_entry);
+
+               nblocks += (S_ISDIR(mode) ? 2 : 1) *
+                       __ext4_xattr_set_credits(sb, NULL /* inode */,
+                                                NULL /* block_bh */, acl_size,
+                                                true /* is_create */);
+               posix_acl_release(p);
+       }
+#endif
+
+#ifdef CONFIG_SECURITY
+       {
+               int num_security_xattrs = 1;
+
+#ifdef CONFIG_INTEGRITY
+               num_security_xattrs++;
+#endif
+               /*
+                * We assume that security xattrs are never more than 1k.
+                * In practice they are under 128 bytes.
+                */
+               nblocks += num_security_xattrs *
+                       __ext4_xattr_set_credits(sb, NULL /* inode */,
+                                                NULL /* block_bh */, 1024,
+                                                true /* is_create */);
+       }
+#endif
+       if (encrypt)
+               nblocks += __ext4_xattr_set_credits(sb,
+                                                   NULL /* inode */,
+                                                   NULL /* block_bh */,
+                                                   FSCRYPT_SET_CONTEXT_MAX_SIZE,
+                                                   true /* is_create */);
+       return nblocks;
+}
+
 /*
  * There are two policies for allocating an inode.  If the new inode is
  * a directory, then a forward search is made for a block group with both
@@ -772,7 +819,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
        ext4_group_t i;
        ext4_group_t flex_group;
        struct ext4_group_info *grp;
-       int encrypt = 0;
+       bool encrypt = false;
 
        /* Cannot create files in a deleted directory */
        if (!dir || !dir->i_nlink)
@@ -784,59 +831,6 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
        if (unlikely(ext4_forced_shutdown(sbi)))
                return ERR_PTR(-EIO);
 
-       if ((IS_ENCRYPTED(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) &&
-           (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) &&
-           !(i_flags & EXT4_EA_INODE_FL)) {
-               err = fscrypt_get_encryption_info(dir);
-               if (err)
-                       return ERR_PTR(err);
-               if (!fscrypt_has_encryption_key(dir))
-                       return ERR_PTR(-ENOKEY);
-               encrypt = 1;
-       }
-
-       if (!handle && sbi->s_journal && !(i_flags & EXT4_EA_INODE_FL)) {
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
-               struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT);
-
-               if (IS_ERR(p))
-                       return ERR_CAST(p);
-               if (p) {
-                       int acl_size = p->a_count * sizeof(ext4_acl_entry);
-
-                       nblocks += (S_ISDIR(mode) ? 2 : 1) *
-                               __ext4_xattr_set_credits(sb, NULL /* inode */,
-                                       NULL /* block_bh */, acl_size,
-                                       true /* is_create */);
-                       posix_acl_release(p);
-               }
-#endif
-
-#ifdef CONFIG_SECURITY
-               {
-                       int num_security_xattrs = 1;
-
-#ifdef CONFIG_INTEGRITY
-                       num_security_xattrs++;
-#endif
-                       /*
-                        * We assume that security xattrs are never
-                        * more than 1k.  In practice they are under
-                        * 128 bytes.
-                        */
-                       nblocks += num_security_xattrs *
-                               __ext4_xattr_set_credits(sb, NULL /* inode */,
-                                       NULL /* block_bh */, 1024,
-                                       true /* is_create */);
-               }
-#endif
-               if (encrypt)
-                       nblocks += __ext4_xattr_set_credits(sb,
-                                       NULL /* inode */, NULL /* block_bh */,
-                                       FSCRYPT_SET_CONTEXT_MAX_SIZE,
-                                       true /* is_create */);
-       }
-
        ngroups = ext4_get_groups_count(sb);
        trace_ext4_request_inode(dir, mode);
        inode = new_inode(sb);
@@ -866,10 +860,25 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
        else
                ei->i_projid = make_kprojid(&init_user_ns, EXT4_DEF_PROJID);
 
+       if (!(i_flags & EXT4_EA_INODE_FL)) {
+               err = fscrypt_prepare_new_inode(dir, inode, &encrypt);
+               if (err)
+                       goto out;
+       }
+
        err = dquot_initialize(inode);
        if (err)
                goto out;
 
+       if (!handle && sbi->s_journal && !(i_flags & EXT4_EA_INODE_FL)) {
+               ret2 = ext4_xattr_credits_for_new_inode(dir, mode, encrypt);
+               if (ret2 < 0) {
+                       err = ret2;
+                       goto out;
+               }
+               nblocks += ret2;
+       }
+
        if (!goal)
                goal = sbi->s_inode_goal;
 
@@ -1162,7 +1171,7 @@ got:
         * prevent its deduplication.
         */
        if (encrypt) {
-               err = fscrypt_inherit_context(dir, inode, handle, true);
+               err = fscrypt_set_context(inode, handle);
                if (err)
                        goto fail_free_drop;
        }
index 3a196d8..bf59646 100644 (file)
@@ -4901,7 +4901,7 @@ static void __ext4_update_other_inode_time(struct super_block *sb,
            (inode->i_state & I_DIRTY_TIME)) {
                struct ext4_inode_info  *ei = EXT4_I(inode);
 
-               inode->i_state &= ~(I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED);
+               inode->i_state &= ~I_DIRTY_TIME;
                spin_unlock(&inode->i_lock);
 
                spin_lock(&ei->i_raw_lock);
index 153a9fb..0d74615 100644 (file)
@@ -663,8 +663,7 @@ static struct stats dx_show_leaf(struct inode *dir,
 
                                        /* Directory is encrypted */
                                        res = fscrypt_fname_alloc_buffer(
-                                               dir, len,
-                                               &fname_crypto_str);
+                                               len, &fname_crypto_str);
                                        if (res)
                                                printk(KERN_WARNING "Error "
                                                        "allocating crypto "
@@ -1016,8 +1015,8 @@ static int htree_dirblock_to_tree(struct file *dir_file,
                        brelse(bh);
                        return err;
                }
-               err = fscrypt_fname_alloc_buffer(dir, EXT4_NAME_LEN,
-                                                    &fname_crypto_str);
+               err = fscrypt_fname_alloc_buffer(EXT4_NAME_LEN,
+                                                &fname_crypto_str);
                if (err < 0) {
                        brelse(bh);
                        return err;
index ea425b4..8b27362 100644 (file)
@@ -1104,7 +1104,7 @@ static void ext4_put_super(struct super_block *sb)
                crypto_free_shash(sbi->s_chksum_driver);
        kfree(sbi->s_blockgroup_lock);
        fs_put_dax(sbi->s_daxdev);
-       fscrypt_free_dummy_context(&sbi->s_dummy_enc_ctx);
+       fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
 #ifdef CONFIG_UNICODE
        utf8_unload(sbi->s_encoding);
 #endif
@@ -1392,10 +1392,9 @@ retry:
        return res;
 }
 
-static const union fscrypt_context *
-ext4_get_dummy_context(struct super_block *sb)
+static const union fscrypt_policy *ext4_get_dummy_policy(struct super_block *sb)
 {
-       return EXT4_SB(sb)->s_dummy_enc_ctx.ctx;
+       return EXT4_SB(sb)->s_dummy_enc_policy.policy;
 }
 
 static bool ext4_has_stable_inodes(struct super_block *sb)
@@ -1414,7 +1413,7 @@ static const struct fscrypt_operations ext4_cryptops = {
        .key_prefix             = "ext4:",
        .get_context            = ext4_get_context,
        .set_context            = ext4_set_context,
-       .get_dummy_context      = ext4_get_dummy_context,
+       .get_dummy_policy       = ext4_get_dummy_policy,
        .empty_dir              = ext4_empty_dir,
        .max_namelen            = EXT4_NAME_LEN,
        .has_stable_inodes      = ext4_has_stable_inodes,
@@ -1888,12 +1887,13 @@ static int ext4_set_test_dummy_encryption(struct super_block *sb,
         * needed to allow it to be set or changed during remount.  We do allow
         * it to be specified during remount, but only if there is no change.
         */
-       if (is_remount && !sbi->s_dummy_enc_ctx.ctx) {
+       if (is_remount && !sbi->s_dummy_enc_policy.policy) {
                ext4_msg(sb, KERN_WARNING,
                         "Can't set test_dummy_encryption on remount");
                return -1;
        }
-       err = fscrypt_set_test_dummy_encryption(sb, arg, &sbi->s_dummy_enc_ctx);
+       err = fscrypt_set_test_dummy_encryption(sb, arg->from,
+                                               &sbi->s_dummy_enc_policy);
        if (err) {
                if (err == -EEXIST)
                        ext4_msg(sb, KERN_WARNING,
@@ -4935,7 +4935,7 @@ failed_mount:
        for (i = 0; i < EXT4_MAXQUOTAS; i++)
                kfree(get_qf_name(sb, sbi, i));
 #endif
-       fscrypt_free_dummy_context(&sbi->s_dummy_enc_ctx);
+       fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
        ext4_blkdev_remove(sbi);
        brelse(bh);
 out_fail:
index ed2bca0..73683e5 100644 (file)
@@ -3550,6 +3550,9 @@ static int check_direct_IO(struct inode *inode, struct iov_iter *iter,
        unsigned long align = offset | iov_iter_alignment(iter);
        struct block_device *bdev = inode->i_sb->s_bdev;
 
+       if (iov_iter_rw(iter) == READ && offset >= i_size_read(inode))
+               return 1;
+
        if (align & blocksize_mask) {
                if (bdev)
                        blkbits = blksize_bits(bdev_logical_block_size(bdev));
index 069f498..53fbc4d 100644 (file)
@@ -111,7 +111,7 @@ static int __f2fs_setup_filename(const struct inode *dir,
 #ifdef CONFIG_FS_ENCRYPTION
        fname->crypto_buf = crypt_name->crypto_buf;
 #endif
-       if (crypt_name->is_ciphertext_name) {
+       if (crypt_name->is_nokey_name) {
                /* hash was decoded from the no-key name */
                fname->hash = cpu_to_le32(crypt_name->hash);
        } else {
@@ -537,7 +537,7 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
                        goto put_error;
 
                if (IS_ENCRYPTED(inode)) {
-                       err = fscrypt_inherit_context(dir, inode, page, false);
+                       err = fscrypt_set_context(inode, page);
                        if (err)
                                goto put_error;
                }
@@ -1032,7 +1032,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
                if (err)
                        goto out;
 
-               err = fscrypt_fname_alloc_buffer(inode, F2FS_NAME_LEN, &fstr);
+               err = fscrypt_fname_alloc_buffer(F2FS_NAME_LEN, &fstr);
                if (err < 0)
                        goto out;
        }
index 16322ea..7c089ff 100644 (file)
@@ -138,7 +138,7 @@ struct f2fs_mount_info {
        int fsync_mode;                 /* fsync policy */
        int fs_mode;                    /* fs mode: LFS or ADAPTIVE */
        int bggc_mode;                  /* bggc mode: off, on or sync */
-       struct fscrypt_dummy_context dummy_enc_ctx; /* test dummy encryption */
+       struct fscrypt_dummy_policy dummy_enc_policy; /* test dummy encryption */
        block_t unusable_cap_perc;      /* percentage for cap */
        block_t unusable_cap;           /* Amount of space allowed to be
                                         * unusable when disabling checkpoint
@@ -1315,13 +1315,6 @@ enum fsync_mode {
 #define IS_IO_TRACED_PAGE(page) (0)
 #endif
 
-#ifdef CONFIG_FS_ENCRYPTION
-#define DUMMY_ENCRYPTION_ENABLED(sbi) \
-       (unlikely(F2FS_OPTION(sbi).dummy_enc_ctx.ctx != NULL))
-#else
-#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
-#endif
-
 /* For compression */
 enum compress_algorithm_type {
        COMPRESS_LZO,
@@ -2646,7 +2639,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,
        case FI_NEW_INODE:
                if (set)
                        return;
-               /* fall through */
+               fallthrough;
        case FI_DATA_EXIST:
        case FI_INLINE_DOTS:
        case FI_PIN_FILE:
@@ -4022,22 +4015,6 @@ static inline bool f2fs_lfs_mode(struct f2fs_sb_info *sbi)
        return F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS;
 }
 
-static inline bool f2fs_may_encrypt(struct inode *dir, struct inode *inode)
-{
-#ifdef CONFIG_FS_ENCRYPTION
-       struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
-       umode_t mode = inode->i_mode;
-
-       /*
-        * If the directory encrypted or dummy encryption enabled,
-        * then we should encrypt the inode.
-        */
-       if (IS_ENCRYPTED(dir) || DUMMY_ENCRYPTION_ENABLED(sbi))
-               return (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode));
-#endif
-       return false;
-}
-
 static inline bool f2fs_may_compress(struct inode *inode)
 {
        if (IS_SWAPFILE(inode) || f2fs_is_pinned_file(inode) ||
index 84e4bbc..45f3245 100644 (file)
@@ -28,6 +28,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
        nid_t ino;
        struct inode *inode;
        bool nid_free = false;
+       bool encrypt = false;
        int xattr_size = 0;
        int err;
 
@@ -69,13 +70,17 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
                F2FS_I(inode)->i_projid = make_kprojid(&init_user_ns,
                                                        F2FS_DEF_PROJID);
 
+       err = fscrypt_prepare_new_inode(dir, inode, &encrypt);
+       if (err)
+               goto fail_drop;
+
        err = dquot_initialize(inode);
        if (err)
                goto fail_drop;
 
        set_inode_flag(inode, FI_NEW_INODE);
 
-       if (f2fs_may_encrypt(dir, inode))
+       if (encrypt)
                f2fs_set_encrypted_inode(inode);
 
        if (f2fs_sb_has_extra_attr(sbi)) {
index 9bbaa26..cb1b5b6 100644 (file)
@@ -618,10 +618,10 @@ pgoff_t f2fs_get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs)
        switch (dn->max_level) {
        case 3:
                base += 2 * indirect_blks;
-               /* fall through */
+               fallthrough;
        case 2:
                base += 2 * direct_blks;
-               /* fall through */
+               fallthrough;
        case 1:
                base += direct_index;
                break;
@@ -2373,6 +2373,9 @@ static int __f2fs_build_free_nids(struct f2fs_sb_info *sbi,
        if (unlikely(nid >= nm_i->max_nid))
                nid = 0;
 
+       if (unlikely(nid % NAT_ENTRY_PER_BLOCK))
+               nid = NAT_BLOCK_OFFSET(nid) * NAT_ENTRY_PER_BLOCK;
+
        /* Enough entries */
        if (nm_i->nid_cnt[FREE_NID] >= NAT_ENTRY_PER_BLOCK)
                return 0;
index a65d357..e247a5e 100644 (file)
@@ -799,7 +799,7 @@ static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
 
                if (__is_large_section(sbi)) {
                        unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
-                       unsigned short valid_blocks =
+                       block_t valid_blocks =
                                get_valid_blocks(sbi, segno, true);
 
                        f2fs_bug_on(sbi, unlikely(!valid_blocks ||
@@ -815,7 +815,7 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
                enum dirty_type dirty_type)
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
-       unsigned short valid_blocks;
+       block_t valid_blocks;
 
        if (test_and_clear_bit(segno, dirty_i->dirty_segmap[dirty_type]))
                dirty_i->nr_dirty[dirty_type]--;
@@ -4316,8 +4316,8 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi)
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
        struct free_segmap_info *free_i = FREE_I(sbi);
        unsigned int segno = 0, offset = 0, secno;
-       unsigned short valid_blocks;
-       unsigned short blks_per_sec = BLKS_PER_SEC(sbi);
+       block_t valid_blocks;
+       block_t blks_per_sec = BLKS_PER_SEC(sbi);
 
        while (1) {
                /* find dirty segment based on free segmap */
index dfa072f..bef2be3 100644 (file)
@@ -433,12 +433,12 @@ static int f2fs_set_test_dummy_encryption(struct super_block *sb,
         * needed to allow it to be set or changed during remount.  We do allow
         * it to be specified during remount, but only if there is no change.
         */
-       if (is_remount && !F2FS_OPTION(sbi).dummy_enc_ctx.ctx) {
+       if (is_remount && !F2FS_OPTION(sbi).dummy_enc_policy.policy) {
                f2fs_warn(sbi, "Can't set test_dummy_encryption on remount");
                return -EINVAL;
        }
        err = fscrypt_set_test_dummy_encryption(
-               sb, arg, &F2FS_OPTION(sbi).dummy_enc_ctx);
+               sb, arg->from, &F2FS_OPTION(sbi).dummy_enc_policy);
        if (err) {
                if (err == -EEXIST)
                        f2fs_warn(sbi,
@@ -1275,7 +1275,7 @@ static void f2fs_put_super(struct super_block *sb)
        for (i = 0; i < MAXQUOTAS; i++)
                kfree(F2FS_OPTION(sbi).s_qf_names[i]);
 #endif
-       fscrypt_free_dummy_context(&F2FS_OPTION(sbi).dummy_enc_ctx);
+       fscrypt_free_dummy_policy(&F2FS_OPTION(sbi).dummy_enc_policy);
        destroy_percpu_info(sbi);
        for (i = 0; i < NR_PAGE_TYPE; i++)
                kvfree(sbi->write_io[i]);
@@ -2482,10 +2482,9 @@ static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
                                ctx, len, fs_data, XATTR_CREATE);
 }
 
-static const union fscrypt_context *
-f2fs_get_dummy_context(struct super_block *sb)
+static const union fscrypt_policy *f2fs_get_dummy_policy(struct super_block *sb)
 {
-       return F2FS_OPTION(F2FS_SB(sb)).dummy_enc_ctx.ctx;
+       return F2FS_OPTION(F2FS_SB(sb)).dummy_enc_policy.policy;
 }
 
 static bool f2fs_has_stable_inodes(struct super_block *sb)
@@ -2523,7 +2522,7 @@ static const struct fscrypt_operations f2fs_cryptops = {
        .key_prefix             = "f2fs:",
        .get_context            = f2fs_get_context,
        .set_context            = f2fs_set_context,
-       .get_dummy_context      = f2fs_get_dummy_context,
+       .get_dummy_policy       = f2fs_get_dummy_policy,
        .empty_dir              = f2fs_empty_dir,
        .max_namelen            = F2FS_NAME_LEN,
        .has_stable_inodes      = f2fs_has_stable_inodes,
@@ -3864,7 +3863,7 @@ free_options:
        for (i = 0; i < MAXQUOTAS; i++)
                kfree(F2FS_OPTION(sbi).s_qf_names[i]);
 #endif
-       fscrypt_free_dummy_context(&F2FS_OPTION(sbi).dummy_enc_ctx);
+       fscrypt_free_dummy_policy(&F2FS_OPTION(sbi).dummy_enc_policy);
        kvfree(options);
 free_sb_buf:
        kfree(raw_super);
index 2e4c0fa..19ac5ba 100644 (file)
@@ -362,7 +362,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
        case F_OFD_SETLK:
        case F_OFD_SETLKW:
 #endif
-               /* Fallthrough */
+               fallthrough;
        case F_SETLK:
        case F_SETLKW:
                if (copy_from_user(&flock, argp, sizeof(flock)))
@@ -771,7 +771,7 @@ static void send_sigio_to_task(struct task_struct *p,
                        if (!do_send_sig_info(signum, &si, p, type))
                                break;
                }
-               /* fall-through - fall back on the old plain SIGIO signal */
+                       fallthrough;    /* fall back on the old plain SIGIO signal */
                case 0:
                        do_send_sig_info(SIGIO, SEND_SIG_PRIV, p, type);
        }
index a605c3d..58b27e4 100644 (file)
@@ -42,7 +42,6 @@
 struct wb_writeback_work {
        long nr_pages;
        struct super_block *sb;
-       unsigned long *older_than_this;
        enum writeback_sync_modes sync_mode;
        unsigned int tagged_writepages:1;
        unsigned int for_kupdate:1;
@@ -144,7 +143,9 @@ static void inode_io_list_del_locked(struct inode *inode,
                                     struct bdi_writeback *wb)
 {
        assert_spin_locked(&wb->list_lock);
+       assert_spin_locked(&inode->i_lock);
 
+       inode->i_state &= ~I_SYNC_QUEUED;
        list_del_init(&inode->i_io_list);
        wb_io_lists_depopulated(wb);
 }
@@ -1122,7 +1123,9 @@ void inode_io_list_del(struct inode *inode)
        struct bdi_writeback *wb;
 
        wb = inode_to_wb_and_lock_list(inode);
+       spin_lock(&inode->i_lock);
        inode_io_list_del_locked(inode, wb);
+       spin_unlock(&inode->i_lock);
        spin_unlock(&wb->list_lock);
 }
 EXPORT_SYMBOL(inode_io_list_del);
@@ -1172,8 +1175,10 @@ void sb_clear_inode_writeback(struct inode *inode)
  * the case then the inode must have been redirtied while it was being written
  * out and we don't reset its dirtied_when.
  */
-static void redirty_tail(struct inode *inode, struct bdi_writeback *wb)
+static void redirty_tail_locked(struct inode *inode, struct bdi_writeback *wb)
 {
+       assert_spin_locked(&inode->i_lock);
+
        if (!list_empty(&wb->b_dirty)) {
                struct inode *tail;
 
@@ -1182,6 +1187,14 @@ static void redirty_tail(struct inode *inode, struct bdi_writeback *wb)
                        inode->dirtied_when = jiffies;
        }
        inode_io_list_move_locked(inode, wb, &wb->b_dirty);
+       inode->i_state &= ~I_SYNC_QUEUED;
+}
+
+static void redirty_tail(struct inode *inode, struct bdi_writeback *wb)
+{
+       spin_lock(&inode->i_lock);
+       redirty_tail_locked(inode, wb);
+       spin_unlock(&inode->i_lock);
 }
 
 /*
@@ -1220,16 +1233,13 @@ static bool inode_dirtied_after(struct inode *inode, unsigned long t)
 #define EXPIRE_DIRTY_ATIME 0x0001
 
 /*
- * Move expired (dirtied before work->older_than_this) dirty inodes from
+ * Move expired (dirtied before dirtied_before) dirty inodes from
  * @delaying_queue to @dispatch_queue.
  */
 static int move_expired_inodes(struct list_head *delaying_queue,
                               struct list_head *dispatch_queue,
-                              int flags,
-                              struct wb_writeback_work *work)
+                              unsigned long dirtied_before)
 {
-       unsigned long *older_than_this = NULL;
-       unsigned long expire_time;
        LIST_HEAD(tmp);
        struct list_head *pos, *node;
        struct super_block *sb = NULL;
@@ -1237,21 +1247,15 @@ static int move_expired_inodes(struct list_head *delaying_queue,
        int do_sb_sort = 0;
        int moved = 0;
 
-       if ((flags & EXPIRE_DIRTY_ATIME) == 0)
-               older_than_this = work->older_than_this;
-       else if (!work->for_sync) {
-               expire_time = jiffies - (dirtytime_expire_interval * HZ);
-               older_than_this = &expire_time;
-       }
        while (!list_empty(delaying_queue)) {
                inode = wb_inode(delaying_queue->prev);
-               if (older_than_this &&
-                   inode_dirtied_after(inode, *older_than_this))
+               if (inode_dirtied_after(inode, dirtied_before))
                        break;
                list_move(&inode->i_io_list, &tmp);
                moved++;
-               if (flags & EXPIRE_DIRTY_ATIME)
-                       set_bit(__I_DIRTY_TIME_EXPIRED, &inode->i_state);
+               spin_lock(&inode->i_lock);
+               inode->i_state |= I_SYNC_QUEUED;
+               spin_unlock(&inode->i_lock);
                if (sb_is_blkdev_sb(inode->i_sb))
                        continue;
                if (sb && sb != inode->i_sb)
@@ -1289,18 +1293,22 @@ out:
  *                                           |
  *                                           +--> dequeue for IO
  */
-static void queue_io(struct bdi_writeback *wb, struct wb_writeback_work *work)
+static void queue_io(struct bdi_writeback *wb, struct wb_writeback_work *work,
+                    unsigned long dirtied_before)
 {
        int moved;
+       unsigned long time_expire_jif = dirtied_before;
 
        assert_spin_locked(&wb->list_lock);
        list_splice_init(&wb->b_more_io, &wb->b_io);
-       moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, 0, work);
+       moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, dirtied_before);
+       if (!work->for_sync)
+               time_expire_jif = jiffies - dirtytime_expire_interval * HZ;
        moved += move_expired_inodes(&wb->b_dirty_time, &wb->b_io,
-                                    EXPIRE_DIRTY_ATIME, work);
+                                    time_expire_jif);
        if (moved)
                wb_io_lists_populated(wb);
-       trace_writeback_queue_io(wb, work, moved);
+       trace_writeback_queue_io(wb, work, dirtied_before, moved);
 }
 
 static int write_inode(struct inode *inode, struct writeback_control *wbc)
@@ -1394,7 +1402,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
                 * writeback is not making progress due to locked
                 * buffers. Skip this inode for now.
                 */
-               redirty_tail(inode, wb);
+               redirty_tail_locked(inode, wb);
                return;
        }
 
@@ -1414,7 +1422,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
                         * retrying writeback of the dirty page/inode
                         * that cannot be performed immediately.
                         */
-                       redirty_tail(inode, wb);
+                       redirty_tail_locked(inode, wb);
                }
        } else if (inode->i_state & I_DIRTY) {
                /*
@@ -1422,10 +1430,11 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
                 * such as delayed allocation during submission or metadata
                 * updates after data IO completion.
                 */
-               redirty_tail(inode, wb);
+               redirty_tail_locked(inode, wb);
        } else if (inode->i_state & I_DIRTY_TIME) {
                inode->dirtied_when = jiffies;
                inode_io_list_move_locked(inode, wb, &wb->b_dirty_time);
+               inode->i_state &= ~I_SYNC_QUEUED;
        } else {
                /* The inode is clean. Remove from writeback lists. */
                inode_io_list_del_locked(inode, wb);
@@ -1472,18 +1481,14 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
        spin_lock(&inode->i_lock);
 
        dirty = inode->i_state & I_DIRTY;
-       if (inode->i_state & I_DIRTY_TIME) {
-               if ((dirty & I_DIRTY_INODE) ||
-                   wbc->sync_mode == WB_SYNC_ALL ||
-                   unlikely(inode->i_state & I_DIRTY_TIME_EXPIRED) ||
-                   unlikely(time_after(jiffies,
-                                       (inode->dirtied_time_when +
-                                        dirtytime_expire_interval * HZ)))) {
-                       dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED;
-                       trace_writeback_lazytime(inode);
-               }
-       } else
-               inode->i_state &= ~I_DIRTY_TIME_EXPIRED;
+       if ((inode->i_state & I_DIRTY_TIME) &&
+           ((dirty & I_DIRTY_INODE) ||
+            wbc->sync_mode == WB_SYNC_ALL || wbc->for_sync ||
+            time_after(jiffies, inode->dirtied_time_when +
+                       dirtytime_expire_interval * HZ))) {
+               dirty |= I_DIRTY_TIME;
+               trace_writeback_lazytime(inode);
+       }
        inode->i_state &= ~dirty;
 
        /*
@@ -1669,8 +1674,8 @@ static long writeback_sb_inodes(struct super_block *sb,
                 */
                spin_lock(&inode->i_lock);
                if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
+                       redirty_tail_locked(inode, wb);
                        spin_unlock(&inode->i_lock);
-                       redirty_tail(inode, wb);
                        continue;
                }
                if ((inode->i_state & I_SYNC) && wbc.sync_mode != WB_SYNC_ALL) {
@@ -1811,7 +1816,7 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
        blk_start_plug(&plug);
        spin_lock(&wb->list_lock);
        if (list_empty(&wb->b_io))
-               queue_io(wb, &work);
+               queue_io(wb, &work, jiffies);
        __writeback_inodes_wb(wb, &work);
        spin_unlock(&wb->list_lock);
        blk_finish_plug(&plug);
@@ -1831,7 +1836,7 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
  * takes longer than a dirty_writeback_interval interval, then leave a
  * one-second gap.
  *
- * older_than_this takes precedence over nr_to_write.  So we'll only write back
+ * dirtied_before takes precedence over nr_to_write.  So we'll only write back
  * all dirty pages if they are all attached to "old" mappings.
  */
 static long wb_writeback(struct bdi_writeback *wb,
@@ -1839,14 +1844,11 @@ static long wb_writeback(struct bdi_writeback *wb,
 {
        unsigned long wb_start = jiffies;
        long nr_pages = work->nr_pages;
-       unsigned long oldest_jif;
+       unsigned long dirtied_before = jiffies;
        struct inode *inode;
        long progress;
        struct blk_plug plug;
 
-       oldest_jif = jiffies;
-       work->older_than_this = &oldest_jif;
-
        blk_start_plug(&plug);
        spin_lock(&wb->list_lock);
        for (;;) {
@@ -1880,14 +1882,14 @@ static long wb_writeback(struct bdi_writeback *wb,
                 * safe.
                 */
                if (work->for_kupdate) {
-                       oldest_jif = jiffies -
+                       dirtied_before = jiffies -
                                msecs_to_jiffies(dirty_expire_interval * 10);
                } else if (work->for_background)
-                       oldest_jif = jiffies;
+                       dirtied_before = jiffies;
 
                trace_writeback_start(wb, work);
                if (list_empty(&wb->b_io))
-                       queue_io(wb, work);
+                       queue_io(wb, work, dirtied_before);
                if (work->sb)
                        progress = writeback_sb_inodes(work->sb, wb, work);
                else
@@ -2182,7 +2184,7 @@ static int __init start_dirtytime_writeback(void)
 __initcall(start_dirtytime_writeback);
 
 int dirtytime_interval_handler(struct ctl_table *table, int write,
-                              void __user *buffer, size_t *lenp, loff_t *ppos)
+                              void *buffer, size_t *lenp, loff_t *ppos)
 {
        int ret;
 
@@ -2289,11 +2291,12 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                inode->i_state |= flags;
 
                /*
-                * If the inode is being synced, just update its dirty state.
-                * The unlocker will place the inode on the appropriate
-                * superblock list, based upon its state.
+                * If the inode is queued for writeback by flush worker, just
+                * update its dirty state. Once the flush worker is done with
+                * the inode it will place it on the appropriate superblock
+                * list, based upon its state.
                 */
-               if (inode->i_state & I_SYNC)
+               if (inode->i_state & I_SYNC_QUEUED)
                        goto out_unlock_inode;
 
                /*
index 7d5c5dd..2834d1a 100644 (file)
@@ -521,7 +521,7 @@ static int legacy_parse_param(struct fs_context *fc, struct fs_parameter *param)
        switch (param->type) {
        case fs_value_is_string:
                len = 1 + param->size;
-               /* Fall through */
+               fallthrough;
        case fs_value_is_flag:
                len += strlen(param->key);
                break;
index 2fa3f24..27a890a 100644 (file)
@@ -412,7 +412,7 @@ SYSCALL_DEFINE5(fsconfig,
                break;
        case FSCONFIG_SET_PATH_EMPTY:
                lookup_flags = LOOKUP_EMPTY;
-               /* fallthru */
+               fallthrough;
        case FSCONFIG_SET_PATH:
                param.type = fs_value_is_filename;
                param.name = getname_flags(_value, lookup_flags, NULL);
index 6611ef3..43c165e 100644 (file)
@@ -3091,11 +3091,10 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        ssize_t ret = 0;
        struct file *file = iocb->ki_filp;
        struct fuse_file *ff = file->private_data;
-       bool async_dio = ff->fc->async_dio;
        loff_t pos = 0;
        struct inode *inode;
        loff_t i_size;
-       size_t count = iov_iter_count(iter);
+       size_t count = iov_iter_count(iter), shortened = 0;
        loff_t offset = iocb->ki_pos;
        struct fuse_io_priv *io;
 
@@ -3103,17 +3102,9 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        inode = file->f_mapping->host;
        i_size = i_size_read(inode);
 
-       if ((iov_iter_rw(iter) == READ) && (offset > i_size))
+       if ((iov_iter_rw(iter) == READ) && (offset >= i_size))
                return 0;
 
-       /* optimization for short read */
-       if (async_dio && iov_iter_rw(iter) != WRITE && offset + count > i_size) {
-               if (offset >= i_size)
-                       return 0;
-               iov_iter_truncate(iter, fuse_round_up(ff->fc, i_size - offset));
-               count = iov_iter_count(iter);
-       }
-
        io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
        if (!io)
                return -ENOMEM;
@@ -3129,15 +3120,22 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
         * By default, we want to optimize all I/Os with async request
         * submission to the client filesystem if supported.
         */
-       io->async = async_dio;
+       io->async = ff->fc->async_dio;
        io->iocb = iocb;
        io->blocking = is_sync_kiocb(iocb);
 
+       /* optimization for short read */
+       if (io->async && !io->write && offset + count > i_size) {
+               iov_iter_truncate(iter, fuse_round_up(ff->fc, i_size - offset));
+               shortened = count - iov_iter_count(iter);
+               count -= shortened;
+       }
+
        /*
         * We cannot asynchronously extend the size of a file.
         * In such case the aio will behave exactly like sync io.
         */
-       if ((offset + count > i_size) && iov_iter_rw(iter) == WRITE)
+       if ((offset + count > i_size) && io->write)
                io->blocking = true;
 
        if (io->async && io->blocking) {
@@ -3155,6 +3153,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        } else {
                ret = __fuse_direct_read(io, iter, &pos);
        }
+       iov_iter_reexpand(iter, iov_iter_count(iter) + shortened);
 
        if (io->async) {
                bool blocking = io->blocking;
index 770f3a7..0f69fbd 100644 (file)
@@ -746,7 +746,7 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
                        }
                        if (n == 0)
                                break;
-               /* fall through - To branching from existing tree */
+                       fallthrough;    /* To branching from existing tree */
                case ALLOC_GROW_DEPTH:
                        if (i > 1 && i < mp->mp_fheight)
                                gfs2_trans_add_meta(ip->i_gl, mp->mp_bh[i-1]);
@@ -757,7 +757,7 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
                                state = ALLOC_DATA;
                        if (n == 0)
                                break;
-               /* fall through - To tree complete, adding data blocks */
+                       fallthrough;    /* To tree complete, adding data blocks */
                case ALLOC_DATA:
                        BUG_ON(n > dblks);
                        BUG_ON(mp->mp_bh[end_of_metadata] == NULL);
index a58333e..3763c9f 100644 (file)
@@ -902,6 +902,36 @@ static void empty_ail1_list(struct gfs2_sbd *sdp)
 }
 
 /**
+ * drain_bd - drain the buf and databuf queue for a failed transaction
+ * @tr: the transaction to drain
+ *
+ * When this is called, we're taking an error exit for a log write that failed
+ * but since we bypassed the after_commit functions, we need to remove the
+ * items from the buf and databuf queue.
+ */
+static void trans_drain(struct gfs2_trans *tr)
+{
+       struct gfs2_bufdata *bd;
+       struct list_head *head;
+
+       if (!tr)
+               return;
+
+       head = &tr->tr_buf;
+       while (!list_empty(head)) {
+               bd = list_first_entry(head, struct gfs2_bufdata, bd_list);
+               list_del_init(&bd->bd_list);
+               kmem_cache_free(gfs2_bufdata_cachep, bd);
+       }
+       head = &tr->tr_databuf;
+       while (!list_empty(head)) {
+               bd = list_first_entry(head, struct gfs2_bufdata, bd_list);
+               list_del_init(&bd->bd_list);
+               kmem_cache_free(gfs2_bufdata_cachep, bd);
+       }
+}
+
+/**
  * gfs2_log_flush - flush incore transaction(s)
  * @sdp: the filesystem
  * @gl: The glock structure to flush.  If NULL, flush the whole incore log
@@ -1005,6 +1035,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
 
 out:
        if (gfs2_withdrawn(sdp)) {
+               trans_drain(tr);
                /**
                 * If the tr_list is empty, we're withdrawing during a log
                 * flush that targets a transaction, but the transaction was
index 4b67d47..6e173ae 100644 (file)
@@ -1599,7 +1599,7 @@ static int gfs2_quota_get_state(struct super_block *sb, struct qc_state *state)
        case GFS2_QUOTA_ON:
                state->s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED;
                state->s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED;
-               /*FALLTHRU*/
+               fallthrough;
        case GFS2_QUOTA_ACCOUNT:
                state->s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED |
                                                  QCI_SYSFILE;
index e1c7eb6..6d4bf7e 100644 (file)
@@ -67,6 +67,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
                tr->tr_reserved += gfs2_struct2blk(sdp, revokes);
        INIT_LIST_HEAD(&tr->tr_databuf);
        INIT_LIST_HEAD(&tr->tr_buf);
+       INIT_LIST_HEAD(&tr->tr_list);
        INIT_LIST_HEAD(&tr->tr_ail1_list);
        INIT_LIST_HEAD(&tr->tr_ail2_list);
 
index 61eec62..0350dc7 100644 (file)
@@ -195,7 +195,7 @@ reread:
        switch (sbi->s_vhdr->signature) {
        case cpu_to_be16(HFSPLUS_VOLHEAD_SIGX):
                set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
-               /*FALLTHRU*/
+               fallthrough;
        case cpu_to_be16(HFSPLUS_VOLHEAD_SIG):
                break;
        case cpu_to_be16(HFSP_WRAP_MAGIC):
index 10517ec..a7cd0f6 100644 (file)
@@ -82,9 +82,6 @@ int may_linkat(struct path *link);
 /*
  * namespace.c
  */
-extern void *copy_mount_options(const void __user *);
-extern char *copy_mount_string(const void __user *);
-
 extern struct vfsmount *lookup_mnt(const struct path *);
 extern int finish_automount(struct vfsmount *, struct path *);
 
index e92c472..414beb5 100644 (file)
@@ -925,6 +925,24 @@ static bool io_wq_worker_cancel(struct io_worker *worker, void *data)
        return match->nr_running && !match->cancel_all;
 }
 
+static inline void io_wqe_remove_pending(struct io_wqe *wqe,
+                                        struct io_wq_work *work,
+                                        struct io_wq_work_node *prev)
+{
+       unsigned int hash = io_get_work_hash(work);
+       struct io_wq_work *prev_work = NULL;
+
+       if (io_wq_is_hashed(work) && work == wqe->hash_tail[hash]) {
+               if (prev)
+                       prev_work = container_of(prev, struct io_wq_work, list);
+               if (prev_work && io_get_work_hash(prev_work) == hash)
+                       wqe->hash_tail[hash] = prev_work;
+               else
+                       wqe->hash_tail[hash] = NULL;
+       }
+       wq_list_del(&wqe->work_list, &work->list, prev);
+}
+
 static void io_wqe_cancel_pending_work(struct io_wqe *wqe,
                                       struct io_cb_cancel_data *match)
 {
@@ -938,8 +956,7 @@ retry:
                work = container_of(node, struct io_wq_work, list);
                if (!match->fn(work, match->data))
                        continue;
-
-               wq_list_del(&wqe->work_list, node, prev);
+               io_wqe_remove_pending(wqe, work, prev);
                spin_unlock_irqrestore(&wqe->lock, flags);
                io_run_cancel(work, wqe);
                match->nr_pending++;
index 91e2cc8..f58b3d6 100644 (file)
@@ -1150,7 +1150,7 @@ static void io_prep_async_work(struct io_kiocb *req)
        io_req_init_async(req);
 
        if (req->flags & REQ_F_ISREG) {
-               if (def->hash_reg_file)
+               if (def->hash_reg_file || (req->ctx->flags & IORING_SETUP_IOPOLL))
                        io_wq_hash_work(&req->work, file_inode(req->file));
        } else {
                if (def->unbound_nonreg_file)
@@ -1746,12 +1746,16 @@ static struct io_kiocb *io_req_find_next(struct io_kiocb *req)
        return __io_req_find_next(req);
 }
 
-static int io_req_task_work_add(struct io_kiocb *req, struct callback_head *cb)
+static int io_req_task_work_add(struct io_kiocb *req, struct callback_head *cb,
+                               bool twa_signal_ok)
 {
        struct task_struct *tsk = req->task;
        struct io_ring_ctx *ctx = req->ctx;
        int ret, notify;
 
+       if (tsk->flags & PF_EXITING)
+               return -ESRCH;
+
        /*
         * SQPOLL kernel thread doesn't need notification, just a wakeup. For
         * all other cases, use TWA_SIGNAL unconditionally to ensure we're
@@ -1759,7 +1763,7 @@ static int io_req_task_work_add(struct io_kiocb *req, struct callback_head *cb)
         * will do the job.
         */
        notify = 0;
-       if (!(ctx->flags & IORING_SETUP_SQPOLL))
+       if (!(ctx->flags & IORING_SETUP_SQPOLL) && twa_signal_ok)
                notify = TWA_SIGNAL;
 
        ret = task_work_add(tsk, cb, notify);
@@ -1786,8 +1790,10 @@ static void __io_req_task_cancel(struct io_kiocb *req, int error)
 static void io_req_task_cancel(struct callback_head *cb)
 {
        struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work);
+       struct io_ring_ctx *ctx = req->ctx;
 
        __io_req_task_cancel(req, -ECANCELED);
+       percpu_ref_put(&ctx->refs);
 }
 
 static void __io_req_task_submit(struct io_kiocb *req)
@@ -1819,7 +1825,7 @@ static void io_req_task_queue(struct io_kiocb *req)
        init_task_work(&req->task_work, io_req_task_submit);
        percpu_ref_get(&req->ctx->refs);
 
-       ret = io_req_task_work_add(req, &req->task_work);
+       ret = io_req_task_work_add(req, &req->task_work, true);
        if (unlikely(ret)) {
                struct task_struct *tsk;
 
@@ -2009,6 +2015,12 @@ static inline unsigned int io_put_rw_kbuf(struct io_kiocb *req)
 
 static inline bool io_run_task_work(void)
 {
+       /*
+        * Not safe to run on exiting task, and the task_work handling will
+        * not add work to such a task.
+        */
+       if (unlikely(current->flags & PF_EXITING))
+               return false;
        if (current->task_works) {
                __set_current_state(TASK_RUNNING);
                task_work_run();
@@ -2048,6 +2060,7 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events,
 
                req = list_first_entry(done, struct io_kiocb, inflight_entry);
                if (READ_ONCE(req->result) == -EAGAIN) {
+                       req->result = 0;
                        req->iopoll_completed = 0;
                        list_move_tail(&req->inflight_entry, &again);
                        continue;
@@ -2281,50 +2294,43 @@ static bool io_resubmit_prep(struct io_kiocb *req, int error)
                goto end_req;
        }
 
-       ret = io_import_iovec(rw, req, &iovec, &iter, false);
-       if (ret < 0)
-               goto end_req;
-       ret = io_setup_async_rw(req, iovec, inline_vecs, &iter, false);
-       if (!ret)
+       if (!req->io) {
+               ret = io_import_iovec(rw, req, &iovec, &iter, false);
+               if (ret < 0)
+                       goto end_req;
+               ret = io_setup_async_rw(req, iovec, inline_vecs, &iter, false);
+               if (!ret)
+                       return true;
+               kfree(iovec);
+       } else {
                return true;
-       kfree(iovec);
+       }
 end_req:
        req_set_fail_links(req);
        io_req_complete(req, ret);
        return false;
 }
-
-static void io_rw_resubmit(struct callback_head *cb)
-{
-       struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work);
-       struct io_ring_ctx *ctx = req->ctx;
-       int err;
-
-       err = io_sq_thread_acquire_mm(ctx, req);
-
-       if (io_resubmit_prep(req, err)) {
-               refcount_inc(&req->refs);
-               io_queue_async_work(req);
-       }
-
-       percpu_ref_put(&ctx->refs);
-}
 #endif
 
 static bool io_rw_reissue(struct io_kiocb *req, long res)
 {
 #ifdef CONFIG_BLOCK
+       umode_t mode = file_inode(req->file)->i_mode;
        int ret;
 
+       if (!S_ISBLK(mode) && !S_ISREG(mode))
+               return false;
        if ((res != -EAGAIN && res != -EOPNOTSUPP) || io_wq_current_is_worker())
                return false;
 
-       init_task_work(&req->task_work, io_rw_resubmit);
-       percpu_ref_get(&req->ctx->refs);
+       ret = io_sq_thread_acquire_mm(req->ctx, req);
 
-       ret = io_req_task_work_add(req, &req->task_work);
-       if (!ret)
+       if (io_resubmit_prep(req, ret)) {
+               refcount_inc(&req->refs);
+               io_queue_async_work(req);
                return true;
+       }
+
 #endif
        return false;
 }
@@ -2563,7 +2569,7 @@ static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
                 * IO with EINTR.
                 */
                ret = -EINTR;
-               /* fall through */
+               fallthrough;
        default:
                kiocb->ki_complete(kiocb, ret, 0);
        }
@@ -2846,13 +2852,8 @@ static ssize_t __io_import_iovec(int rw, struct io_kiocb *req,
                return ret;
        }
 
-#ifdef CONFIG_COMPAT
-       if (req->ctx->compat)
-               return compat_import_iovec(rw, buf, sqe_len, UIO_FASTIOV,
-                                               iovec, iter);
-#endif
-
-       return import_iovec(rw, buf, sqe_len, UIO_FASTIOV, iovec, iter);
+       return __import_iovec(rw, buf, sqe_len, UIO_FASTIOV, iovec, iter,
+                             req->ctx->compat);
 }
 
 static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
@@ -2865,6 +2866,11 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
        return iov_iter_count(&req->io->rw.iter);
 }
 
+static inline loff_t *io_kiocb_ppos(struct kiocb *kiocb)
+{
+       return kiocb->ki_filp->f_mode & FMODE_STREAM ? NULL : &kiocb->ki_pos;
+}
+
 /*
  * For files that don't have ->read_iter() and ->write_iter(), handle them
  * by looping over ->read() or ->write() manually.
@@ -2900,10 +2906,10 @@ static ssize_t loop_rw_iter(int rw, struct file *file, struct kiocb *kiocb,
 
                if (rw == READ) {
                        nr = file->f_op->read(file, iovec.iov_base,
-                                             iovec.iov_len, &kiocb->ki_pos);
+                                             iovec.iov_len, io_kiocb_ppos(kiocb));
                } else {
                        nr = file->f_op->write(file, iovec.iov_base,
-                                              iovec.iov_len, &kiocb->ki_pos);
+                                              iovec.iov_len, io_kiocb_ppos(kiocb));
                }
 
                if (iov_iter_is_bvec(iter))
@@ -2984,14 +2990,15 @@ static inline int io_rw_prep_async(struct io_kiocb *req, int rw,
                                   bool force_nonblock)
 {
        struct io_async_rw *iorw = &req->io->rw;
+       struct iovec *iov;
        ssize_t ret;
 
-       iorw->iter.iov = iorw->fast_iov;
-       ret = __io_import_iovec(rw, req, (struct iovec **) &iorw->iter.iov,
-                               &iorw->iter, !force_nonblock);
+       iorw->iter.iov = iov = iorw->fast_iov;
+       ret = __io_import_iovec(rw, req, &iov, &iorw->iter, !force_nonblock);
        if (unlikely(ret < 0))
                return ret;
 
+       iorw->iter.iov = iov;
        io_req_map_rw(req, iorw->iter.iov, iorw->fast_iov, &iorw->iter);
        return 0;
 }
@@ -3037,6 +3044,7 @@ static int io_async_buf_func(struct wait_queue_entry *wait, unsigned mode,
        if (!wake_page_match(wpq, key))
                return 0;
 
+       req->rw.kiocb.ki_flags &= ~IOCB_WAITQ;
        list_del_init(&wait->entry);
 
        init_task_work(&req->task_work, io_req_task_submit);
@@ -3044,7 +3052,7 @@ static int io_async_buf_func(struct wait_queue_entry *wait, unsigned mode,
 
        /* submit ref gets dropped, acquire a new one */
        refcount_inc(&req->refs);
-       ret = io_req_task_work_add(req, &req->task_work);
+       ret = io_req_task_work_add(req, &req->task_work, true);
        if (unlikely(ret)) {
                struct task_struct *tsk;
 
@@ -3094,6 +3102,7 @@ static bool io_rw_should_retry(struct io_kiocb *req)
        wait->wait.flags = 0;
        INIT_LIST_HEAD(&wait->wait.entry);
        kiocb->ki_flags |= IOCB_WAITQ;
+       kiocb->ki_flags &= ~IOCB_NOWAIT;
        kiocb->ki_waitq = wait;
 
        io_get_req_task(req);
@@ -3118,6 +3127,7 @@ static int io_read(struct io_kiocb *req, bool force_nonblock,
        struct iov_iter __iter, *iter = &__iter;
        ssize_t io_size, ret, ret2;
        size_t iov_count;
+       bool no_async;
 
        if (req->io)
                iter = &req->io->rw.iter;
@@ -3125,6 +3135,7 @@ static int io_read(struct io_kiocb *req, bool force_nonblock,
        ret = io_import_iovec(READ, req, &iovec, iter, !force_nonblock);
        if (ret < 0)
                return ret;
+       iov_count = iov_iter_count(iter);
        io_size = ret;
        req->result = io_size;
        ret = 0;
@@ -3134,11 +3145,11 @@ static int io_read(struct io_kiocb *req, bool force_nonblock,
                kiocb->ki_flags &= ~IOCB_NOWAIT;
 
        /* If the file doesn't support async, just async punt */
-       if (force_nonblock && !io_file_supports_async(req->file, READ))
+       no_async = force_nonblock && !io_file_supports_async(req->file, READ);
+       if (no_async)
                goto copy_iov;
 
-       iov_count = iov_iter_count(iter);
-       ret = rw_verify_area(READ, req->file, &kiocb->ki_pos, iov_count);
+       ret = rw_verify_area(READ, req->file, io_kiocb_ppos(kiocb), iov_count);
        if (unlikely(ret))
                goto out_free;
 
@@ -3150,14 +3161,19 @@ static int io_read(struct io_kiocb *req, bool force_nonblock,
                ret = 0;
                goto out_free;
        } else if (ret == -EAGAIN) {
-               if (!force_nonblock)
+               /* IOPOLL retry should happen for io-wq threads */
+               if (!force_nonblock && !(req->ctx->flags & IORING_SETUP_IOPOLL))
                        goto done;
-               ret = io_setup_async_rw(req, iovec, inline_vecs, iter, false);
-               if (ret)
-                       goto out_free;
-               return -EAGAIN;
+               /* no retry on NONBLOCK marked file */
+               if (req->file->f_flags & O_NONBLOCK)
+                       goto done;
+               /* some cases will consume bytes even on error returns */
+               iov_iter_revert(iter, iov_count - iov_iter_count(iter));
+               ret = 0;
+               goto copy_iov;
        } else if (ret < 0) {
-               goto out_free;
+               /* make sure -ERESTARTSYS -> -EINTR is done */
+               goto done;
        }
 
        /* read it all, or we did blocking attempt. no retry. */
@@ -3172,6 +3188,8 @@ copy_iov:
                ret = ret2;
                goto out_free;
        }
+       if (no_async)
+               return -EAGAIN;
        /* it's copied and will be cleaned with ->io */
        iovec = NULL;
        /* now use our persistent iterator, if we aren't already */
@@ -3241,6 +3259,7 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
        ret = io_import_iovec(WRITE, req, &iovec, iter, !force_nonblock);
        if (ret < 0)
                return ret;
+       iov_count = iov_iter_count(iter);
        io_size = ret;
        req->result = io_size;
 
@@ -3257,8 +3276,7 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
            (req->flags & REQ_F_ISREG))
                goto copy_iov;
 
-       iov_count = iov_iter_count(iter);
-       ret = rw_verify_area(WRITE, req->file, &kiocb->ki_pos, iov_count);
+       ret = rw_verify_area(WRITE, req->file, io_kiocb_ppos(kiocb), iov_count);
        if (unlikely(ret))
                goto out_free;
 
@@ -3290,10 +3308,19 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
         */
        if (ret2 == -EOPNOTSUPP && (kiocb->ki_flags & IOCB_NOWAIT))
                ret2 = -EAGAIN;
+       /* no retry on NONBLOCK marked file */
+       if (ret2 == -EAGAIN && (req->file->f_flags & O_NONBLOCK))
+               goto done;
        if (!force_nonblock || ret2 != -EAGAIN) {
+               /* IOPOLL retry should happen for io-wq threads */
+               if ((req->ctx->flags & IORING_SETUP_IOPOLL) && ret2 == -EAGAIN)
+                       goto copy_iov;
+done:
                kiocb_done(kiocb, ret2, cs);
        } else {
 copy_iov:
+               /* some cases will consume bytes even on error returns */
+               iov_iter_revert(iter, iov_count - iov_iter_count(iter));
                ret = io_setup_async_rw(req, iovec, inline_vecs, iter, false);
                if (!ret)
                        return -EAGAIN;
@@ -3495,8 +3522,6 @@ static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
        const char __user *fname;
        int ret;
 
-       if (unlikely(req->ctx->flags & (IORING_SETUP_IOPOLL|IORING_SETUP_SQPOLL)))
-               return -EINVAL;
        if (unlikely(sqe->ioprio || sqe->buf_index))
                return -EINVAL;
        if (unlikely(req->flags & REQ_F_FIXED_FILE))
@@ -3523,6 +3548,8 @@ static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        u64 flags, mode;
 
+       if (unlikely(req->ctx->flags & (IORING_SETUP_IOPOLL|IORING_SETUP_SQPOLL)))
+               return -EINVAL;
        if (req->flags & REQ_F_NEED_CLEANUP)
                return 0;
        mode = READ_ONCE(sqe->len);
@@ -3537,6 +3564,8 @@ static int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        size_t len;
        int ret;
 
+       if (unlikely(req->ctx->flags & (IORING_SETUP_IOPOLL|IORING_SETUP_SQPOLL)))
+               return -EINVAL;
        if (req->flags & REQ_F_NEED_CLEANUP)
                return 0;
        how = u64_to_user_ptr(READ_ONCE(sqe->addr2));
@@ -3754,7 +3783,7 @@ static int io_epoll_ctl_prep(struct io_kiocb *req,
 #if defined(CONFIG_EPOLL)
        if (sqe->ioprio || sqe->buf_index)
                return -EINVAL;
-       if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
+       if (unlikely(req->ctx->flags & (IORING_SETUP_IOPOLL | IORING_SETUP_SQPOLL)))
                return -EINVAL;
 
        req->epoll.epfd = READ_ONCE(sqe->fd);
@@ -3869,7 +3898,7 @@ static int io_fadvise(struct io_kiocb *req, bool force_nonblock)
 
 static int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
-       if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
+       if (unlikely(req->ctx->flags & (IORING_SETUP_IOPOLL | IORING_SETUP_SQPOLL)))
                return -EINVAL;
        if (sqe->ioprio || sqe->buf_index)
                return -EINVAL;
@@ -4166,8 +4195,9 @@ static int __io_recvmsg_copy_hdr(struct io_kiocb *req,
                                sr->len);
                iomsg->iov = NULL;
        } else {
-               ret = import_iovec(READ, uiov, iov_len, UIO_FASTIOV,
-                                       &iomsg->iov, &iomsg->msg.msg_iter);
+               ret = __import_iovec(READ, uiov, iov_len, UIO_FASTIOV,
+                                    &iomsg->iov, &iomsg->msg.msg_iter,
+                                    false);
                if (ret > 0)
                        ret = 0;
        }
@@ -4207,9 +4237,9 @@ static int __io_compat_recvmsg_copy_hdr(struct io_kiocb *req,
                sr->len = iomsg->iov[0].iov_len;
                iomsg->iov = NULL;
        } else {
-               ret = compat_import_iovec(READ, uiov, len, UIO_FASTIOV,
-                                               &iomsg->iov,
-                                               &iomsg->msg.msg_iter);
+               ret = __import_iovec(READ, (struct iovec __user *)uiov, len,
+                                  UIO_FASTIOV, &iomsg->iov,
+                                  &iomsg->msg.msg_iter, true);
                if (ret < 0)
                        return ret;
        }
@@ -4566,6 +4596,7 @@ struct io_poll_table {
 static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
                           __poll_t mask, task_work_func_t func)
 {
+       bool twa_signal_ok;
        int ret;
 
        /* for instances that support it check for an event match first: */
@@ -4581,12 +4612,20 @@ static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
        percpu_ref_get(&req->ctx->refs);
 
        /*
+        * If we using the signalfd wait_queue_head for this wakeup, then
+        * it's not safe to use TWA_SIGNAL as we could be recursing on the
+        * tsk->sighand->siglock on doing the wakeup. Should not be needed
+        * either, as the normal wakeup will suffice.
+        */
+       twa_signal_ok = (poll->head != &req->task->sighand->signalfd_wqh);
+
+       /*
         * If this fails, then the task is exiting. When a task exits, the
         * work gets canceled, so just cancel this request as well instead
         * of executing it. We can't safely execute it anyway, as we may not
         * have the needed state needed for it anyway.
         */
-       ret = io_req_task_work_add(req, &req->task_work);
+       ret = io_req_task_work_add(req, &req->task_work, twa_signal_ok);
        if (unlikely(ret)) {
                struct task_struct *tsk;
 
@@ -4702,6 +4741,8 @@ static int io_poll_double_wake(struct wait_queue_entry *wait, unsigned mode,
        if (mask && !(mask & poll->events))
                return 0;
 
+       list_del_init(&wait->entry);
+
        if (poll && poll->head) {
                bool done;
 
@@ -4875,12 +4916,20 @@ static bool io_arm_poll_handler(struct io_kiocb *req)
        struct async_poll *apoll;
        struct io_poll_table ipt;
        __poll_t mask, ret;
+       int rw;
 
        if (!req->file || !file_can_poll(req->file))
                return false;
        if (req->flags & REQ_F_POLLED)
                return false;
-       if (!def->pollin && !def->pollout)
+       if (def->pollin)
+               rw = READ;
+       else if (def->pollout)
+               rw = WRITE;
+       else
+               return false;
+       /* if we can't nonblock try, then no point in arming a poll handler */
+       if (!io_file_supports_async(req->file, rw))
                return false;
 
        apoll = kmalloc(sizeof(*apoll), GFP_ATOMIC);
@@ -5369,6 +5418,8 @@ static int io_async_cancel(struct io_kiocb *req)
 static int io_files_update_prep(struct io_kiocb *req,
                                const struct io_uring_sqe *sqe)
 {
+       if (unlikely(req->ctx->flags & IORING_SETUP_SQPOLL))
+               return -EINVAL;
        if (unlikely(req->flags & (REQ_F_FIXED_FILE | REQ_F_BUFFER_SELECT)))
                return -EINVAL;
        if (sqe->ioprio || sqe->rw_flags)
@@ -5419,6 +5470,8 @@ static int io_req_defer_prep(struct io_kiocb *req,
        if (unlikely(ret))
                return ret;
 
+       io_prep_async_work(req);
+
        switch (req->opcode) {
        case IORING_OP_NOP:
                break;
@@ -5616,6 +5669,11 @@ static void __io_clean_op(struct io_kiocb *req)
                        io_put_file(req, req->splice.file_in,
                                    (req->splice.flags & SPLICE_F_FD_IN_FIXED));
                        break;
+               case IORING_OP_OPENAT:
+               case IORING_OP_OPENAT2:
+                       if (req->open.filename)
+                               putname(req->open.filename);
+                       break;
                }
                req->flags &= ~REQ_F_NEED_CLEANUP;
        }
@@ -6293,9 +6351,6 @@ static void io_submit_state_start(struct io_submit_state *state,
                                  struct io_ring_ctx *ctx, unsigned int max_ios)
 {
        blk_start_plug(&state->plug);
-#ifdef CONFIG_BLOCK
-       state->plug.nowait = true;
-#endif
        state->comp.nr = 0;
        INIT_LIST_HEAD(&state->comp.list);
        state->comp.ctx = ctx;
@@ -7305,7 +7360,7 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                table = &ctx->file_data->table[i >> IORING_FILE_TABLE_SHIFT];
                index = i & IORING_FILE_TABLE_MASK;
                if (table->files[index]) {
-                       file = io_file_from_index(ctx, index);
+                       file = table->files[index];
                        err = io_queue_file_removal(data, file);
                        if (err)
                                break;
@@ -7334,6 +7389,7 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                        table->files[index] = file;
                        err = io_sqe_file_register(ctx, file, i);
                        if (err) {
+                               table->files[index] = NULL;
                                fput(file);
                                break;
                        }
@@ -7433,9 +7489,6 @@ static int io_sq_offload_start(struct io_ring_ctx *ctx,
 {
        int ret;
 
-       mmgrab(current->mm);
-       ctx->sqo_mm = current->mm;
-
        if (ctx->flags & IORING_SETUP_SQPOLL) {
                ret = -EPERM;
                if (!capable(CAP_SYS_ADMIN))
@@ -7480,10 +7533,6 @@ static int io_sq_offload_start(struct io_ring_ctx *ctx,
        return 0;
 err:
        io_finish_async(ctx);
-       if (ctx->sqo_mm) {
-               mmdrop(ctx->sqo_mm);
-               ctx->sqo_mm = NULL;
-       }
        return ret;
 }
 
@@ -8000,6 +8049,28 @@ static bool io_match_link(struct io_kiocb *preq, struct io_kiocb *req)
        return false;
 }
 
+static inline bool io_match_files(struct io_kiocb *req,
+                                      struct files_struct *files)
+{
+       return (req->flags & REQ_F_WORK_INITIALIZED) && req->work.files == files;
+}
+
+static bool io_match_link_files(struct io_kiocb *req,
+                               struct files_struct *files)
+{
+       struct io_kiocb *link;
+
+       if (io_match_files(req, files))
+               return true;
+       if (req->flags & REQ_F_LINK_HEAD) {
+               list_for_each_entry(link, &req->link_list, link_list) {
+                       if (io_match_files(link, files))
+                               return true;
+               }
+       }
+       return false;
+}
+
 /*
  * We're looking to cancel 'req' because it's holding on to our files, but
  * 'req' could be a link to another request. See if it is, and cancel that
@@ -8074,12 +8145,38 @@ static void io_attempt_cancel(struct io_ring_ctx *ctx, struct io_kiocb *req)
        io_timeout_remove_link(ctx, req);
 }
 
+static void io_cancel_defer_files(struct io_ring_ctx *ctx,
+                                 struct files_struct *files)
+{
+       struct io_defer_entry *de = NULL;
+       LIST_HEAD(list);
+
+       spin_lock_irq(&ctx->completion_lock);
+       list_for_each_entry_reverse(de, &ctx->defer_list, list) {
+               if (io_match_link_files(de->req, files)) {
+                       list_cut_position(&list, &ctx->defer_list, &de->list);
+                       break;
+               }
+       }
+       spin_unlock_irq(&ctx->completion_lock);
+
+       while (!list_empty(&list)) {
+               de = list_first_entry(&list, struct io_defer_entry, list);
+               list_del_init(&de->list);
+               req_set_fail_links(de->req);
+               io_put_req(de->req);
+               io_req_complete(de->req, -ECANCELED);
+               kfree(de);
+       }
+}
+
 static void io_uring_cancel_files(struct io_ring_ctx *ctx,
                                  struct files_struct *files)
 {
        if (list_empty_careful(&ctx->inflight_list))
                return;
 
+       io_cancel_defer_files(ctx, files);
        /* cancel all at once, should be faster than doing it one by one*/
        io_wq_cancel_cb(ctx->io_wq, io_wq_files_match, files, true);
 
@@ -8108,6 +8205,8 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
                /* cancel this request, or head link requests */
                io_attempt_cancel(ctx, cancel_req);
                io_put_req(cancel_req);
+               /* cancellations _may_ trigger task work */
+               io_run_task_work();
                schedule();
                finish_wait(&ctx->inflight_wait, &wait);
        }
@@ -8313,11 +8412,19 @@ static int io_uring_show_cred(int id, void *p, void *data)
 
 static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
 {
+       bool has_lock;
        int i;
 
-       mutex_lock(&ctx->uring_lock);
+       /*
+        * Avoid ABBA deadlock between the seq lock and the io_uring mutex,
+        * since fdinfo case grabs it in the opposite direction of normal use
+        * cases. If we fail to get the lock, we just don't iterate any
+        * structures that could be going away outside the io_uring mutex.
+        */
+       has_lock = mutex_trylock(&ctx->uring_lock);
+
        seq_printf(m, "UserFiles:\t%u\n", ctx->nr_user_files);
-       for (i = 0; i < ctx->nr_user_files; i++) {
+       for (i = 0; has_lock && i < ctx->nr_user_files; i++) {
                struct fixed_file_table *table;
                struct file *f;
 
@@ -8329,13 +8436,13 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
                        seq_printf(m, "%5u: <none>\n", i);
        }
        seq_printf(m, "UserBufs:\t%u\n", ctx->nr_user_bufs);
-       for (i = 0; i < ctx->nr_user_bufs; i++) {
+       for (i = 0; has_lock && i < ctx->nr_user_bufs; i++) {
                struct io_mapped_ubuf *buf = &ctx->user_bufs[i];
 
                seq_printf(m, "%5u: 0x%llx/%u\n", i, buf->ubuf,
                                                (unsigned int) buf->len);
        }
-       if (!idr_is_empty(&ctx->personality_idr)) {
+       if (has_lock && !idr_is_empty(&ctx->personality_idr)) {
                seq_printf(m, "Personalities:\n");
                idr_for_each(&ctx->personality_idr, io_uring_show_cred, m);
        }
@@ -8350,7 +8457,8 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
                                        req->task->task_works != NULL);
        }
        spin_unlock_irq(&ctx->completion_lock);
-       mutex_unlock(&ctx->uring_lock);
+       if (has_lock)
+               mutex_unlock(&ctx->uring_lock);
 }
 
 static void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
@@ -8533,6 +8641,9 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p,
        ctx->user = user;
        ctx->creds = get_current_cred();
 
+       mmgrab(current->mm);
+       ctx->sqo_mm = current->mm;
+
        /*
         * Account memory _before_ installing the file descriptor. Once
         * the descriptor is installed, it can get closed at any time. Also
index 89f61d9..107ee80 100644 (file)
@@ -127,7 +127,7 @@ iomap_seek_hole_actor(struct inode *inode, loff_t offset, loff_t length,
                                                   SEEK_HOLE);
                if (offset < 0)
                        return length;
-               /* fall through */
+               fallthrough;
        case IOMAP_HOLE:
                *(loff_t *)data = offset;
                return 0;
@@ -175,7 +175,7 @@ iomap_seek_data_actor(struct inode *inode, loff_t offset, loff_t length,
                                                   SEEK_DATA);
                if (offset < 0)
                        return length;
-               /*FALLTHRU*/
+               fallthrough;
        default:
                *(loff_t *)data = offset;
                return 0;
index ab8cdd9..78858f6 100644 (file)
@@ -341,7 +341,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
                        rdev = old_decode_dev(je16_to_cpu(jdev.old_id));
                else
                        rdev = new_decode_dev(je32_to_cpu(jdev.new_id));
-               /* fall through */
+               fallthrough;
 
        case S_IFSOCK:
        case S_IFIFO:
index bccfc40..2f6f0b1 100644 (file)
@@ -1273,7 +1273,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                        dbg_readinode("symlink's target '%s' cached\n", f->target);
                }
 
-               /* fall through... */
+               fallthrough;
 
        case S_IFBLK:
        case S_IFCHR:
index 4d08edf..e0d42e9 100644 (file)
@@ -137,11 +137,11 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
        switch (whence) {
                case 1:
                        offset += file->f_pos;
-                       /* fall through */
+                       fallthrough;
                case 0:
                        if (offset >= 0)
                                break;
-                       /* fall through */
+                       fallthrough;
                default:
                        return -EINVAL;
        }
index 8fc0542..1f84a03 100644 (file)
@@ -1499,7 +1499,7 @@ static void lease_clear_pending(struct file_lock *fl, int arg)
        switch (arg) {
        case F_UNLCK:
                fl->fl_flags &= ~FL_UNLOCK_PENDING;
-               /* fall through */
+               fallthrough;
        case F_RDLCK:
                fl->fl_flags &= ~FL_DOWNGRADE_PENDING;
        }
@@ -2525,7 +2525,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
                cmd = F_SETLKW;
                file_lock->fl_flags |= FL_OFDLCK;
                file_lock->fl_owner = filp;
-               /* Fallthrough */
+               fallthrough;
        case F_SETLKW:
                file_lock->fl_flags |= FL_SLEEP;
        }
@@ -2656,7 +2656,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
                cmd = F_SETLKW64;
                file_lock->fl_flags |= FL_OFDLCK;
                file_lock->fl_owner = filp;
-               /* Fallthrough */
+               fallthrough;
        case F_SETLKW64:
                file_lock->fl_flags |= FL_SLEEP;
        }
index bae0e95..294e05a 100644 (file)
@@ -3072,10 +3072,10 @@ static void shrink_submounts(struct mount *mnt)
        }
 }
 
-void *copy_mount_options(const void __user * data)
+static void *copy_mount_options(const void __user * data)
 {
        char *copy;
-       unsigned size;
+       unsigned left, offset;
 
        if (!data)
                return NULL;
@@ -3084,20 +3084,31 @@ void *copy_mount_options(const void __user * data)
        if (!copy)
                return ERR_PTR(-ENOMEM);
 
-       size = PAGE_SIZE - offset_in_page(data);
+       left = copy_from_user(copy, data, PAGE_SIZE);
 
-       if (copy_from_user(copy, data, size)) {
+       /*
+        * Not all architectures have an exact copy_from_user(). Resort to
+        * byte at a time.
+        */
+       offset = PAGE_SIZE - left;
+       while (left) {
+               char c;
+               if (get_user(c, (const char __user *)data + offset))
+                       break;
+               copy[offset] = c;
+               left--;
+               offset++;
+       }
+
+       if (left == PAGE_SIZE) {
                kfree(copy);
                return ERR_PTR(-EFAULT);
        }
-       if (size != PAGE_SIZE) {
-               if (copy_from_user(copy + size, data + size, PAGE_SIZE - size))
-                       memset(copy + size, 0, PAGE_SIZE - size);
-       }
+
        return copy;
 }
 
-char *copy_mount_string(const void __user *data)
+static char *copy_mount_string(const void __user *data)
 {
        return data ? strndup_user(data, PATH_MAX) : NULL;
 }
index d1a0e2c..08108b6 100644 (file)
@@ -753,7 +753,7 @@ out:
        case -ENODEV:
                /* Our extent block devices are unavailable */
                set_bit(NFS_LSEG_UNAVAILABLE, &lseg->pls_flags);
-               /* Fall through */
+               fallthrough;
        case 0:
                return lseg;
        default:
index a12f42e..cb52db9 100644 (file)
@@ -579,6 +579,9 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
        xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
 
        do {
+               if (entry->label)
+                       entry->label->len = NFS4_MAXLABELLEN;
+
                status = xdr_decode(desc, entry, &stream);
                if (status != 0) {
                        if (status == -EAGAIN)
@@ -1181,7 +1184,7 @@ int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
                        /* A NFSv4 OPEN will revalidate later */
                        if (server->caps & NFS_CAP_ATOMIC_OPEN)
                                goto out;
-                       /* Fallthrough */
+                       fallthrough;
                case S_IFDIR:
                        if (server->flags & NFS_MOUNT_NOCTO)
                                break;
index a13e690..7f5aa04 100644 (file)
@@ -187,7 +187,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
                pnfs_error_mark_layout_for_return(inode, lseg);
                pnfs_set_lo_fail(lseg);
                rpc_wake_up(&tbl->slot_tbl_waitq);
-               /* fall through */
+               fallthrough;
        default:
 reset:
                dprintk("%s Retry through MDS. Error %d\n", __func__,
index 9651455..a163533 100644 (file)
@@ -715,7 +715,7 @@ nfs4_ff_layout_stat_io_end_write(struct rpc_task *task,
 }
 
 static void
-ff_layout_mark_ds_unreachable(struct pnfs_layout_segment *lseg, int idx)
+ff_layout_mark_ds_unreachable(struct pnfs_layout_segment *lseg, u32 idx)
 {
        struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx);
 
@@ -724,7 +724,7 @@ ff_layout_mark_ds_unreachable(struct pnfs_layout_segment *lseg, int idx)
 }
 
 static void
-ff_layout_mark_ds_reachable(struct pnfs_layout_segment *lseg, int idx)
+ff_layout_mark_ds_reachable(struct pnfs_layout_segment *lseg, u32 idx)
 {
        struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx);
 
@@ -734,14 +734,14 @@ ff_layout_mark_ds_reachable(struct pnfs_layout_segment *lseg, int idx)
 
 static struct nfs4_pnfs_ds *
 ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg,
-                            int start_idx, int *best_idx,
+                            u32 start_idx, u32 *best_idx,
                             bool check_device)
 {
        struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg);
        struct nfs4_ff_layout_mirror *mirror;
        struct nfs4_pnfs_ds *ds;
        bool fail_return = false;
-       int idx;
+       u32 idx;
 
        /* mirrors are initially sorted by efficiency */
        for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) {
@@ -766,21 +766,21 @@ ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg,
 
 static struct nfs4_pnfs_ds *
 ff_layout_choose_any_ds_for_read(struct pnfs_layout_segment *lseg,
-                                int start_idx, int *best_idx)
+                                u32 start_idx, u32 *best_idx)
 {
        return ff_layout_choose_ds_for_read(lseg, start_idx, best_idx, false);
 }
 
 static struct nfs4_pnfs_ds *
 ff_layout_choose_valid_ds_for_read(struct pnfs_layout_segment *lseg,
-                                  int start_idx, int *best_idx)
+                                  u32 start_idx, u32 *best_idx)
 {
        return ff_layout_choose_ds_for_read(lseg, start_idx, best_idx, true);
 }
 
 static struct nfs4_pnfs_ds *
 ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg,
-                                 int start_idx, int *best_idx)
+                                 u32 start_idx, u32 *best_idx)
 {
        struct nfs4_pnfs_ds *ds;
 
@@ -791,7 +791,8 @@ ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg,
 }
 
 static struct nfs4_pnfs_ds *
-ff_layout_get_ds_for_read(struct nfs_pageio_descriptor *pgio, int *best_idx)
+ff_layout_get_ds_for_read(struct nfs_pageio_descriptor *pgio,
+                         u32 *best_idx)
 {
        struct pnfs_layout_segment *lseg = pgio->pg_lseg;
        struct nfs4_pnfs_ds *ds;
@@ -837,7 +838,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
        struct nfs_pgio_mirror *pgm;
        struct nfs4_ff_layout_mirror *mirror;
        struct nfs4_pnfs_ds *ds;
-       int ds_idx;
+       u32 ds_idx, i;
 
 retry:
        ff_layout_pg_check_layout(pgio, req);
@@ -863,14 +864,14 @@ retry:
                goto retry;
        }
 
-       mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx);
+       for (i = 0; i < pgio->pg_mirror_count; i++) {
+               mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i);
+               pgm = &pgio->pg_mirrors[i];
+               pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize;
+       }
 
        pgio->pg_mirror_idx = ds_idx;
 
-       /* read always uses only one mirror - idx 0 for pgio layer */
-       pgm = &pgio->pg_mirrors[0];
-       pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize;
-
        if (NFS_SERVER(pgio->pg_inode)->flags &
                        (NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR))
                pgio->pg_maxretrans = io_maxretrans;
@@ -894,7 +895,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
        struct nfs4_ff_layout_mirror *mirror;
        struct nfs_pgio_mirror *pgm;
        struct nfs4_pnfs_ds *ds;
-       int i;
+       u32 i;
 
 retry:
        ff_layout_pg_check_layout(pgio, req);
@@ -1038,7 +1039,7 @@ static void ff_layout_reset_write(struct nfs_pgio_header *hdr, bool retry_pnfs)
 static void ff_layout_resend_pnfs_read(struct nfs_pgio_header *hdr)
 {
        u32 idx = hdr->pgio_mirror_idx + 1;
-       int new_idx = 0;
+       u32 new_idx = 0;
 
        if (ff_layout_choose_any_ds_for_read(hdr->lseg, idx + 1, &new_idx))
                ff_layout_send_layouterror(hdr->lseg);
@@ -1075,7 +1076,7 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
                                           struct nfs4_state *state,
                                           struct nfs_client *clp,
                                           struct pnfs_layout_segment *lseg,
-                                          int idx)
+                                          u32 idx)
 {
        struct pnfs_layout_hdr *lo = lseg->pls_layout;
        struct inode *inode = lo->plh_inode;
@@ -1133,7 +1134,7 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
                nfs4_delete_deviceid(devid->ld, devid->nfs_client,
                                &devid->deviceid);
                rpc_wake_up(&tbl->slot_tbl_waitq);
-               /* fall through */
+               fallthrough;
        default:
                if (ff_layout_avoid_mds_available_ds(lseg))
                        return -NFS4ERR_RESET_TO_PNFS;
@@ -1149,7 +1150,7 @@ reset:
 /* Retry all errors through either pNFS or MDS except for -EJUKEBOX */
 static int ff_layout_async_handle_error_v3(struct rpc_task *task,
                                           struct pnfs_layout_segment *lseg,
-                                          int idx)
+                                          u32 idx)
 {
        struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx);
 
@@ -1184,7 +1185,7 @@ static int ff_layout_async_handle_error(struct rpc_task *task,
                                        struct nfs4_state *state,
                                        struct nfs_client *clp,
                                        struct pnfs_layout_segment *lseg,
-                                       int idx)
+                                       u32 idx)
 {
        int vers = clp->cl_nfs_mod->rpc_vers->number;
 
@@ -1211,7 +1212,7 @@ static int ff_layout_async_handle_error(struct rpc_task *task,
 }
 
 static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
-                                       int idx, u64 offset, u64 length,
+                                       u32 idx, u64 offset, u64 length,
                                        u32 *op_status, int opnum, int error)
 {
        struct nfs4_ff_layout_mirror *mirror;
@@ -1260,7 +1261,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
                 */
                if (opnum == OP_READ)
                        break;
-               /* Fallthrough */
+               fallthrough;
        default:
                pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode,
                                                  lseg);
@@ -1809,7 +1810,7 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
        loff_t offset = hdr->args.offset;
        int vers;
        struct nfs_fh *fh;
-       int idx = hdr->pgio_mirror_idx;
+       u32 idx = hdr->pgio_mirror_idx;
 
        mirror = FF_LAYOUT_COMP(lseg, idx);
        ds = nfs4_ff_layout_prepare_ds(lseg, mirror, true);
index 66949da..222afba 100644 (file)
@@ -651,21 +651,21 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
                switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) {
                case Opt_xprt_udp6:
                        protofamily = AF_INET6;
-                       /* fall through */
+                       fallthrough;
                case Opt_xprt_udp:
                        ctx->flags &= ~NFS_MOUNT_TCP;
                        ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
                        break;
                case Opt_xprt_tcp6:
                        protofamily = AF_INET6;
-                       /* fall through */
+                       fallthrough;
                case Opt_xprt_tcp:
                        ctx->flags |= NFS_MOUNT_TCP;
                        ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
                        break;
                case Opt_xprt_rdma6:
                        protofamily = AF_INET6;
-                       /* fall through */
+                       fallthrough;
                case Opt_xprt_rdma:
                        /* vector side protocols to TCP */
                        ctx->flags |= NFS_MOUNT_TCP;
@@ -684,13 +684,13 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
                switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) {
                case Opt_xprt_udp6:
                        mountfamily = AF_INET6;
-                       /* fall through */
+                       fallthrough;
                case Opt_xprt_udp:
                        ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
                        break;
                case Opt_xprt_tcp6:
                        mountfamily = AF_INET6;
-                       /* fall through */
+                       fallthrough;
                case Opt_xprt_tcp:
                        ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
                        break;
@@ -899,9 +899,11 @@ static int nfs23_parse_monolithic(struct fs_context *fc,
        ctx->version = NFS_DEFAULT_VERSION;
        switch (data->version) {
        case 1:
-               data->namlen = 0; /* fall through */
+               data->namlen = 0;
+               fallthrough;
        case 2:
-               data->bsize = 0; /* fall through */
+               data->bsize = 0;
+               fallthrough;
        case 3:
                if (data->flags & NFS_MOUNT_VER3)
                        goto out_no_v3;
@@ -909,14 +911,14 @@ static int nfs23_parse_monolithic(struct fs_context *fc,
                memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
                /* Turn off security negotiation */
                extra_flags |= NFS_MOUNT_SECFLAVOUR;
-               /* fall through */
+               fallthrough;
        case 4:
                if (data->flags & NFS_MOUNT_SECFLAVOUR)
                        goto out_no_sec;
-               /* fall through */
+               fallthrough;
        case 5:
                memset(data->context, 0, sizeof(data->context));
-               /* fall through */
+               fallthrough;
        case 6:
                if (data->flags & NFS_MOUNT_VER3) {
                        if (data->root.size > NFS3_FHSIZE || data->root.size == 0)
@@ -1037,6 +1039,65 @@ out_invalid_fh:
 }
 
 #if IS_ENABLED(CONFIG_NFS_V4)
+struct compat_nfs_string {
+       compat_uint_t len;
+       compat_uptr_t data;
+};
+
+static inline void compat_nfs_string(struct nfs_string *dst,
+                                    struct compat_nfs_string *src)
+{
+       dst->data = compat_ptr(src->data);
+       dst->len = src->len;
+}
+
+struct compat_nfs4_mount_data_v1 {
+       compat_int_t version;
+       compat_int_t flags;
+       compat_int_t rsize;
+       compat_int_t wsize;
+       compat_int_t timeo;
+       compat_int_t retrans;
+       compat_int_t acregmin;
+       compat_int_t acregmax;
+       compat_int_t acdirmin;
+       compat_int_t acdirmax;
+       struct compat_nfs_string client_addr;
+       struct compat_nfs_string mnt_path;
+       struct compat_nfs_string hostname;
+       compat_uint_t host_addrlen;
+       compat_uptr_t host_addr;
+       compat_int_t proto;
+       compat_int_t auth_flavourlen;
+       compat_uptr_t auth_flavours;
+};
+
+static void nfs4_compat_mount_data_conv(struct nfs4_mount_data *data)
+{
+       struct compat_nfs4_mount_data_v1 *compat =
+                       (struct compat_nfs4_mount_data_v1 *)data;
+
+       /* copy the fields backwards */
+       data->auth_flavours = compat_ptr(compat->auth_flavours);
+       data->auth_flavourlen = compat->auth_flavourlen;
+       data->proto = compat->proto;
+       data->host_addr = compat_ptr(compat->host_addr);
+       data->host_addrlen = compat->host_addrlen;
+       compat_nfs_string(&data->hostname, &compat->hostname);
+       compat_nfs_string(&data->mnt_path, &compat->mnt_path);
+       compat_nfs_string(&data->client_addr, &compat->client_addr);
+       data->acdirmax = compat->acdirmax;
+       data->acdirmin = compat->acdirmin;
+       data->acregmax = compat->acregmax;
+       data->acregmin = compat->acregmin;
+       data->retrans = compat->retrans;
+       data->timeo = compat->timeo;
+       data->wsize = compat->wsize;
+       data->rsize = compat->rsize;
+       data->flags = compat->flags;
+       data->version = compat->version;
+}
+
 /*
  * Validate NFSv4 mount options
  */
@@ -1047,89 +1108,83 @@ static int nfs4_parse_monolithic(struct fs_context *fc,
        struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
        char *c;
 
-       if (data == NULL)
-               goto out_no_data;
+       if (!data) {
+               if (is_remount_fc(fc))
+                       goto done;
+               return nfs_invalf(fc,
+                       "NFS4: mount program didn't pass any mount data");
+       }
 
        ctx->version = 4;
 
-       switch (data->version) {
-       case 1:
-               if (data->host_addrlen > sizeof(ctx->nfs_server.address))
-                       goto out_no_address;
-               if (data->host_addrlen == 0)
-                       goto out_no_address;
-               ctx->nfs_server.addrlen = data->host_addrlen;
-               if (copy_from_user(sap, data->host_addr, data->host_addrlen))
-                       return -EFAULT;
-               if (!nfs_verify_server_address(sap))
-                       goto out_no_address;
-               ctx->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
-
-               if (data->auth_flavourlen) {
-                       rpc_authflavor_t pseudoflavor;
-                       if (data->auth_flavourlen > 1)
-                               goto out_inval_auth;
-                       if (copy_from_user(&pseudoflavor,
-                                          data->auth_flavours,
-                                          sizeof(pseudoflavor)))
-                               return -EFAULT;
-                       ctx->selected_flavor = pseudoflavor;
-               } else
-                       ctx->selected_flavor = RPC_AUTH_UNIX;
-
-               c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
-               if (IS_ERR(c))
-                       return PTR_ERR(c);
-               ctx->nfs_server.hostname = c;
+       if (data->version != 1)
+               return generic_parse_monolithic(fc, data);
 
-               c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
-               if (IS_ERR(c))
-                       return PTR_ERR(c);
-               ctx->nfs_server.export_path = c;
-               dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
+       if (in_compat_syscall())
+               nfs4_compat_mount_data_conv(data);
 
-               c = strndup_user(data->client_addr.data, 16);
-               if (IS_ERR(c))
-                       return PTR_ERR(c);
-               ctx->client_address = c;
-
-               /*
-                * Translate to nfs_fs_context, which nfs_fill_super
-                * can deal with.
-                */
+       if (data->host_addrlen > sizeof(ctx->nfs_server.address))
+               goto out_no_address;
+       if (data->host_addrlen == 0)
+               goto out_no_address;
+       ctx->nfs_server.addrlen = data->host_addrlen;
+       if (copy_from_user(sap, data->host_addr, data->host_addrlen))
+               return -EFAULT;
+       if (!nfs_verify_server_address(sap))
+               goto out_no_address;
+       ctx->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
 
-               ctx->flags      = data->flags & NFS4_MOUNT_FLAGMASK;
-               ctx->rsize      = data->rsize;
-               ctx->wsize      = data->wsize;
-               ctx->timeo      = data->timeo;
-               ctx->retrans    = data->retrans;
-               ctx->acregmin   = data->acregmin;
-               ctx->acregmax   = data->acregmax;
-               ctx->acdirmin   = data->acdirmin;
-               ctx->acdirmax   = data->acdirmax;
-               ctx->nfs_server.protocol = data->proto;
-               nfs_validate_transport_protocol(ctx);
-               if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
-                       goto out_invalid_transport_udp;
+       if (data->auth_flavourlen) {
+               rpc_authflavor_t pseudoflavor;
 
-               break;
-       default:
-               goto generic;
+               if (data->auth_flavourlen > 1)
+                       goto out_inval_auth;
+               if (copy_from_user(&pseudoflavor, data->auth_flavours,
+                                  sizeof(pseudoflavor)))
+                       return -EFAULT;
+               ctx->selected_flavor = pseudoflavor;
+       } else {
+               ctx->selected_flavor = RPC_AUTH_UNIX;
        }
 
+       c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
+       if (IS_ERR(c))
+               return PTR_ERR(c);
+       ctx->nfs_server.hostname = c;
+
+       c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
+       if (IS_ERR(c))
+               return PTR_ERR(c);
+       ctx->nfs_server.export_path = c;
+       dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
+
+       c = strndup_user(data->client_addr.data, 16);
+       if (IS_ERR(c))
+               return PTR_ERR(c);
+       ctx->client_address = c;
+
+       /*
+        * Translate to nfs_fs_context, which nfs_fill_super
+        * can deal with.
+        */
+
+       ctx->flags      = data->flags & NFS4_MOUNT_FLAGMASK;
+       ctx->rsize      = data->rsize;
+       ctx->wsize      = data->wsize;
+       ctx->timeo      = data->timeo;
+       ctx->retrans    = data->retrans;
+       ctx->acregmin   = data->acregmin;
+       ctx->acregmax   = data->acregmax;
+       ctx->acdirmin   = data->acdirmin;
+       ctx->acdirmax   = data->acdirmax;
+       ctx->nfs_server.protocol = data->proto;
+       nfs_validate_transport_protocol(ctx);
+       if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+               goto out_invalid_transport_udp;
+done:
        ctx->skip_reconfig_option_check = true;
        return 0;
 
-generic:
-       return generic_parse_monolithic(fc, data);
-
-out_no_data:
-       if (is_remount_fc(fc)) {
-               ctx->skip_reconfig_option_check = true;
-               return 0;
-       }
-       return nfs_invalf(fc, "NFS4: mount program didn't pass any mount data");
-
 out_inval_auth:
        return nfs_invalf(fc, "NFS4: Invalid number of RPC auth flavours %d",
                      data->auth_flavourlen);
index 26c94b3..c6c8633 100644 (file)
@@ -108,7 +108,7 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
                case -EPROTONOSUPPORT:
                        dprintk("NFS_V3_ACL extension not supported; disabling\n");
                        server->caps &= ~NFS_CAP_ACLS;
-                       /* fall through */
+                       fallthrough;
                case -ENOTSUPP:
                        status = -EOPNOTSUPP;
                default:
@@ -228,7 +228,7 @@ static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
                        dprintk("NFS_V3_ACL SETACL RPC not supported"
                                        "(will not retry)\n");
                        server->caps &= ~NFS_CAP_ACLS;
-                       /* fall through */
+                       fallthrough;
                case -ENOTSUPP:
                        status = -EOPNOTSUPP;
        }
index 142225f..2b2211d 100644 (file)
@@ -356,7 +356,15 @@ static ssize_t _nfs42_proc_copy(struct file *src,
 
        truncate_pagecache_range(dst_inode, pos_dst,
                                 pos_dst + res->write_res.count);
-
+       spin_lock(&dst_inode->i_lock);
+       NFS_I(dst_inode)->cache_validity |= (NFS_INO_REVAL_PAGECACHE |
+                       NFS_INO_REVAL_FORCED | NFS_INO_INVALID_SIZE |
+                       NFS_INO_INVALID_ATTR | NFS_INO_INVALID_DATA);
+       spin_unlock(&dst_inode->i_lock);
+       spin_lock(&src_inode->i_lock);
+       NFS_I(src_inode)->cache_validity |= (NFS_INO_REVAL_PAGECACHE |
+                       NFS_INO_REVAL_FORCED | NFS_INO_INVALID_ATIME);
+       spin_unlock(&src_inode->i_lock);
        status = res->write_res.count;
 out:
        if (args->sync)
index a339707..fdfc774 100644 (file)
@@ -211,7 +211,7 @@ static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
                ret = nfs42_proc_llseek(filep, offset, whence);
                if (ret != -ENOTSUPP)
                        return ret;
-               /* Fall through */
+               fallthrough;
        default:
                return nfs_file_llseek(filep, offset, whence);
        }
index 1e72963..62e6eea 100644 (file)
@@ -520,7 +520,7 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
        switch (token) {
        case Opt_find_uid:
                im->im_type = IDMAP_TYPE_USER;
-               /* Fall through */
+               fallthrough;
        case Opt_find_gid:
                im->im_conv = IDMAP_CONV_NAMETOID;
                ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ);
@@ -528,7 +528,7 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
 
        case Opt_find_user:
                im->im_type = IDMAP_TYPE_USER;
-               /* Fall through */
+               fallthrough;
        case Opt_find_group:
                im->im_conv = IDMAP_CONV_IDTONAME;
                ret = match_int(&substr, &im->im_id);
index dbd0154..6e95c85 100644 (file)
@@ -483,7 +483,7 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
                                                stateid);
                                goto wait_on_recovery;
                        }
-                       /* Fall through */
+                       fallthrough;
                case -NFS4ERR_OPENMODE:
                        if (inode) {
                                int err;
@@ -534,10 +534,10 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
                                ret = -EBUSY;
                                break;
                        }
-                       /* Fall through */
+                       fallthrough;
                case -NFS4ERR_DELAY:
                        nfs_inc_server_stats(server, NFSIOS_DELAY);
-                       /* Fall through */
+                       fallthrough;
                case -NFS4ERR_GRACE:
                case -NFS4ERR_LAYOUTTRYLATER:
                case -NFS4ERR_RECALLCONFLICT:
@@ -1505,7 +1505,7 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode,
        case NFS4_OPEN_CLAIM_PREVIOUS:
                if (!test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
                        break;
-               /* Fall through */
+               fallthrough;
        default:
                return 0;
        }
@@ -2439,7 +2439,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
        case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
        case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
                data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
-               /* Fall through */
+               fallthrough;
        case NFS4_OPEN_CLAIM_FH:
                task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
        }
@@ -3293,8 +3293,10 @@ static int _nfs4_do_setattr(struct inode *inode,
 
        /* Servers should only apply open mode checks for file size changes */
        truncate = (arg->iap->ia_valid & ATTR_SIZE) ? true : false;
-       if (!truncate)
+       if (!truncate) {
+               nfs4_inode_make_writeable(inode);
                goto zero_stateid;
+       }
 
        if (nfs4_copy_delegation_stateid(inode, FMODE_WRITE, &arg->stateid, &delegation_cred)) {
                /* Use that stateid */
@@ -3545,11 +3547,11 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                        nfs4_free_revoked_stateid(server,
                                        &calldata->arg.stateid,
                                        task->tk_msg.rpc_cred);
-                       /* Fallthrough */
+                       fallthrough;
                case -NFS4ERR_BAD_STATEID:
                        if (calldata->arg.fmode == 0)
                                break;
-                       /* Fallthrough */
+                       fallthrough;
                default:
                        task->tk_status = nfs4_async_handle_exception(task,
                                        server, task->tk_status, &exception);
@@ -6294,7 +6296,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
                nfs4_free_revoked_stateid(data->res.server,
                                data->args.stateid,
                                task->tk_msg.rpc_cred);
-               /* Fallthrough */
+               fallthrough;
        case -NFS4ERR_BAD_STATEID:
        case -NFS4ERR_STALE_STATEID:
        case -ETIMEDOUT:
@@ -6314,7 +6316,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
                        data->res.fattr = NULL;
                        goto out_restart;
                }
-               /* Fallthrough */
+               fallthrough;
        default:
                task->tk_status = nfs4_async_handle_exception(task,
                                data->res.server, task->tk_status,
@@ -6622,13 +6624,13 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
                        if (nfs4_update_lock_stateid(calldata->lsp,
                                        &calldata->res.stateid))
                                break;
-                       /* Fall through */
+                       fallthrough;
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_EXPIRED:
                        nfs4_free_revoked_stateid(calldata->server,
                                        &calldata->arg.stateid,
                                        task->tk_msg.rpc_cred);
-                       /* Fall through */
+                       fallthrough;
                case -NFS4ERR_BAD_STATEID:
                case -NFS4ERR_STALE_STATEID:
                        if (nfs4_sync_lock_stateid(&calldata->arg.stateid,
@@ -7298,7 +7300,12 @@ int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state,
        err = nfs4_set_lock_state(state, fl);
        if (err != 0)
                return err;
-       err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
+       do {
+               err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
+               if (err != -NFS4ERR_DELAY)
+                       break;
+               ssleep(1);
+       } while (err == -NFS4ERR_DELAY);
        return nfs4_handle_delegation_recall_error(server, state, stateid, fl, err);
 }
 
@@ -8665,7 +8672,7 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
                dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
                rpc_delay(task, NFS4_POLL_RETRY_MIN);
                task->tk_status = 0;
-               /* fall through */
+               fallthrough;
        case -NFS4ERR_RETRY_UNCACHED_REP:
                rpc_restart_call_prepare(task);
                return;
@@ -9113,13 +9120,13 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf
        switch(task->tk_status) {
        case 0:
                wake_up_all(&clp->cl_lock_waitq);
-               /* Fallthrough */
+               fallthrough;
        case -NFS4ERR_COMPLETE_ALREADY:
        case -NFS4ERR_WRONG_CRED: /* What to do here? */
                break;
        case -NFS4ERR_DELAY:
                rpc_delay(task, NFS4_POLL_RETRY_MAX);
-               /* fall through */
+               fallthrough;
        case -NFS4ERR_RETRY_UNCACHED_REP:
                return -EAGAIN;
        case -NFS4ERR_BADSESSION:
@@ -9434,10 +9441,10 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
                                        &lrp->args.range,
                                        lrp->args.inode))
                        goto out_restart;
-               /* Fallthrough */
+               fallthrough;
        default:
                task->tk_status = 0;
-               /* Fallthrough */
+               fallthrough;
        case 0:
                break;
        case -NFS4ERR_DELAY:
index b1dba24..4bf1079 100644 (file)
@@ -1530,7 +1530,7 @@ restart:
                default:
                        pr_err("NFS: %s: unhandled error %d\n",
                                        __func__, status);
-                       /* Fall through */
+                       fallthrough;
                case -ENOMEM:
                case -NFS4ERR_DENIED:
                case -NFS4ERR_RECLAIM_BAD:
@@ -1667,7 +1667,7 @@ restart:
                                break;
                        }
                        printk(KERN_ERR "NFS: %s: unhandled error %d\n", __func__, status);
-                       /* Fall through */
+                       fallthrough;
                case -ENOENT:
                case -ENOMEM:
                case -EACCES:
@@ -1683,7 +1683,7 @@ restart:
                                set_bit(ops->state_flag_bit, &state->flags);
                                break;
                        }
-                       /* Fall through */
+                       fallthrough;
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_OLD_STATEID:
@@ -1695,7 +1695,7 @@ restart:
                case -NFS4ERR_EXPIRED:
                case -NFS4ERR_NO_GRACE:
                        nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
-                       /* Fall through */
+                       fallthrough;
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_BADSESSION:
                case -NFS4ERR_BADSLOT:
@@ -2273,11 +2273,11 @@ again:
        case -ETIMEDOUT:
                if (clnt->cl_softrtry)
                        break;
-               /* Fall through */
+               fallthrough;
        case -NFS4ERR_DELAY:
        case -EAGAIN:
                ssleep(1);
-               /* Fall through */
+               fallthrough;
        case -NFS4ERR_STALE_CLIENTID:
                dprintk("NFS: %s after status %d, retrying\n",
                        __func__, status);
@@ -2289,7 +2289,7 @@ again:
                }
                if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX)
                        break;
-               /* Fall through */
+               fallthrough;
        case -NFS4ERR_CLID_INUSE:
        case -NFS4ERR_WRONGSEC:
                /* No point in retrying if we already used RPC_AUTH_UNIX */
index 6ea4cac..6985cac 100644 (file)
@@ -711,7 +711,7 @@ static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr,
        case FLUSH_COND_STABLE:
                if (nfs_reqs_to_commit(cinfo))
                        break;
-               /* fall through */
+               fallthrough;
        default:
                hdr->args.stable = NFS_FILE_SYNC;
        }
index 40332c7..71f7741 100644 (file)
@@ -1541,7 +1541,7 @@ void pnfs_roc_release(struct nfs4_layoutreturn_args *args,
        case 0:
                if (res->lrs_present)
                        res_stateid = &res->stateid;
-               /* Fallthrough */
+               fallthrough;
        default:
                arg_stateid = &args->stateid;
        }
index 8ceb642..d056ad2 100644 (file)
@@ -237,7 +237,7 @@ posix_acl_from_nfsacl(struct posix_acl *acl)
                                break;
                        case ACL_MASK:
                                mask = pa;
-                               /* fall through */
+                               fallthrough;
                        case ACL_OTHER:
                                break;
                }
index 9bbaa67..311e5ce 100644 (file)
@@ -83,13 +83,13 @@ nfsd4_block_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
                        bex->soff = iomap.addr;
                        break;
                }
-               /*FALLTHRU*/
+               fallthrough;
        case IOMAP_HOLE:
                if (seg->iomode == IOMODE_READ) {
                        bex->es = PNFS_BLOCK_NONE_DATA;
                        break;
                }
-               /*FALLTHRU*/
+               fallthrough;
        case IOMAP_DELALLOC:
        default:
                WARN(1, "pnfsd: filesystem returned %d extent\n", iomap.type);
index 7fbe984..052be5b 100644 (file)
@@ -1119,7 +1119,7 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
                break;
        case -ESERVERFAULT:
                ++session->se_cb_seq_nr;
-               /* Fall through */
+               fallthrough;
        case 1:
        case -NFS4ERR_BADSESSION:
                nfsd4_mark_cb_fault(cb->cb_clp, cb->cb_seq_status);
index e12409e..a97873f 100644 (file)
@@ -681,7 +681,7 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
                        rpc_delay(task, HZ/100); /* 10 mili-seconds */
                        return 0;
                }
-               /* Fallthrough */
+               fallthrough;
        default:
                /*
                 * Unknown error or non-responding client, we'll need to fence.
index a527da3..eaf50ea 100644 (file)
@@ -428,7 +428,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                                goto out;
                        open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
                        reclaim = true;
-                       /* fall through */
+                       fallthrough;
                case NFS4_OPEN_CLAIM_FH:
                case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
                        status = do_open_fhandle(rqstp, cstate, open);
index 81ed8e8..c09a2a4 100644 (file)
@@ -3117,7 +3117,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                break;
        default:                                /* checked by xdr code */
                WARN_ON_ONCE(1);
-               /* fall through */
+               fallthrough;
        case SP4_SSV:
                status = nfserr_encr_alg_unsupp;
                goto out_nolock;
@@ -4532,7 +4532,7 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
                        rpc_delay(task, 2 * HZ);
                        return 0;
                }
-               /*FALLTHRU*/
+               fallthrough;
        default:
                return 1;
        }
@@ -4597,6 +4597,8 @@ static bool nfsd_breaker_owns_lease(struct file_lock *fl)
        if (!i_am_nfsd())
                return NULL;
        rqst = kthread_data(current);
+       if (!rqst->rq_lease_breaker)
+               return NULL;
        clp = *(rqst->rq_lease_breaker);
        return dl->dl_stid.sc_client == clp;
 }
@@ -5652,7 +5654,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
                break;
        default:
                printk("unknown stateid type %x\n", s->sc_type);
-               /* Fallthrough */
+               fallthrough;
        case NFS4_CLOSED_STID:
        case NFS4_CLOSED_DELEG_STID:
                status = nfserr_bad_stateid;
@@ -6742,7 +6744,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                case NFS4_READW_LT:
                        if (nfsd4_has_session(cstate))
                                fl_flags |= FL_SLEEP;
-                       /* Fallthrough */
+                       fallthrough;
                case NFS4_READ_LT:
                        spin_lock(&fp->fi_lock);
                        nf = find_readable_file_locked(fp);
@@ -6754,7 +6756,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                case NFS4_WRITEW_LT:
                        if (nfsd4_has_session(cstate))
                                fl_flags |= FL_SLEEP;
-                       /* Fallthrough */
+                       fallthrough;
                case NFS4_WRITE_LT:
                        spin_lock(&fp->fi_lock);
                        nf = find_writeable_file_locked(fp);
@@ -6816,7 +6818,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                break;
        case FILE_LOCK_DEFERRED:
                nbl = NULL;
-               /* Fallthrough */
+               fallthrough;
        case -EAGAIN:           /* conflock holds conflicting lock */
                status = nfserr_denied;
                dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
index 37bc8f5..c81dbba 100644 (file)
@@ -459,7 +459,7 @@ static bool fsid_type_ok_for_exp(u8 fsid_type, struct svc_export *exp)
        case FSID_DEV:
                if (!old_valid_dev(exp_sb(exp)->s_dev))
                        return false;
-               /* FALL THROUGH */
+               fallthrough;
        case FSID_MAJOR_MINOR:
        case FSID_ENCODE_DEV:
                return exp_sb(exp)->s_type->fs_flags & FS_REQUIRES_DEV;
@@ -469,7 +469,7 @@ static bool fsid_type_ok_for_exp(u8 fsid_type, struct svc_export *exp)
        case FSID_UUID16:
                if (!is_root_export(exp))
                        return false;
-               /* fall through */
+               fallthrough;
        case FSID_UUID4_INUM:
        case FSID_UUID16_INUM:
                return exp->ex_uuid != NULL;
index 543bbe0..6e0b066 100644 (file)
@@ -314,7 +314,7 @@ nfsd_proc_create(struct svc_rqst *rqstp)
                                        rdev = inode->i_rdev;
                                        attr->ia_valid |= ATTR_SIZE;
 
-                                       /* FALLTHROUGH */
+                                       fallthrough;
                                case S_IFIFO:
                                        /* this is probably a permission check..
                                         * at least IRIX implements perm checking on
index b603dfc..f7f6473 100644 (file)
@@ -221,7 +221,7 @@ int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change)
        case NFSD_TEST:
                if (nn->nfsd_versions)
                        return nn->nfsd_versions[vers];
-               /* Fallthrough */
+               fallthrough;
        case NFSD_AVAIL:
                return nfsd_support_version(vers);
        }
index 7d2933b..aba5af9 100644 (file)
@@ -1456,7 +1456,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                                        *created = true;
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
                case NFS4_CREATE_EXCLUSIVE4_1:
                        if (   d_inode(dchild)->i_mtime.tv_sec == v_mtime
                            && d_inode(dchild)->i_atime.tv_sec == v_atime
@@ -1465,7 +1465,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                                        *created = true;
                                goto set_attr;
                        }
-                       /* fall through */
+                       fallthrough;
                case NFS3_CREATE_GUARDED:
                        err = nfserr_exist;
                }
index fb5a9a8..e516ae3 100644 (file)
@@ -519,7 +519,7 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode)
                break;
        case NILFS_IFILE_INO:
                lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key);
-               /* Fall through */
+               fallthrough;
        default:
                bmap->b_ptr_type = NILFS_BMAP_PTR_VM;
                bmap->b_last_allocated_key = 0;
index 0b453ef..2217f90 100644 (file)
@@ -626,7 +626,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
                            !(flags & NILFS_SS_SYNDT))
                                goto try_next_pseg;
                        state = RF_DSYNC_ST;
-                       /* Fall through */
+                       fallthrough;
                case RF_DSYNC_ST:
                        if (!(flags & NILFS_SS_SYNDT))
                                goto confused;
index a651e82..e3726ac 100644 (file)
@@ -1138,7 +1138,8 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
                        nilfs_sc_cstage_set(sci, NILFS_ST_DAT);
                        goto dat_stage;
                }
-               nilfs_sc_cstage_inc(sci);  /* Fall through */
+               nilfs_sc_cstage_inc(sci);
+               fallthrough;
        case NILFS_ST_GC:
                if (nilfs_doing_gc()) {
                        head = &sci->sc_gc_inodes;
@@ -1159,7 +1160,8 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
                        }
                        sci->sc_stage.gc_inode_ptr = NULL;
                }
-               nilfs_sc_cstage_inc(sci);  /* Fall through */
+               nilfs_sc_cstage_inc(sci);
+               fallthrough;
        case NILFS_ST_FILE:
                head = &sci->sc_dirty_files;
                ii = list_prepare_entry(sci->sc_stage.dirty_file_ptr, head,
@@ -1186,7 +1188,7 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
                }
                nilfs_sc_cstage_inc(sci);
                sci->sc_stage.flags |= NILFS_CF_IFILE_STARTED;
-               /* Fall through */
+               fallthrough;
        case NILFS_ST_IFILE:
                err = nilfs_segctor_scan_file(sci, sci->sc_root->ifile,
                                              &nilfs_sc_file_ops);
@@ -1197,13 +1199,14 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
                err = nilfs_segctor_create_checkpoint(sci);
                if (unlikely(err))
                        break;
-               /* Fall through */
+               fallthrough;
        case NILFS_ST_CPFILE:
                err = nilfs_segctor_scan_file(sci, nilfs->ns_cpfile,
                                              &nilfs_sc_file_ops);
                if (unlikely(err))
                        break;
-               nilfs_sc_cstage_inc(sci);  /* Fall through */
+               nilfs_sc_cstage_inc(sci);
+               fallthrough;
        case NILFS_ST_SUFILE:
                err = nilfs_sufile_freev(nilfs->ns_sufile, sci->sc_freesegs,
                                         sci->sc_nfreesegs, &ndone);
@@ -1219,7 +1222,8 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
                                              &nilfs_sc_file_ops);
                if (unlikely(err))
                        break;
-               nilfs_sc_cstage_inc(sci);  /* Fall through */
+               nilfs_sc_cstage_inc(sci);
+               fallthrough;
        case NILFS_ST_DAT:
  dat_stage:
                err = nilfs_segctor_scan_file(sci, nilfs->ns_dat,
@@ -1230,7 +1234,8 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
                        nilfs_sc_cstage_set(sci, NILFS_ST_DONE);
                        return 0;
                }
-               nilfs_sc_cstage_inc(sci);  /* Fall through */
+               nilfs_sc_cstage_inc(sci);
+               fallthrough;
        case NILFS_ST_SR:
                if (mode == SC_LSEG_SR) {
                        /* Appending a super root */
index 559de31..3e01d8f 100644 (file)
@@ -1147,7 +1147,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
        }
 
        switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
-       case FAN_MARK_ADD:              /* fallthrough */
+       case FAN_MARK_ADD:
        case FAN_MARK_REMOVE:
                if (!mask)
                        return -EINVAL;
index 1ef2457..cea739b 100644 (file)
@@ -67,7 +67,7 @@ static void o2quo_fence_self(void)
        default:
                WARN_ON(o2nm_single_cluster->cl_fence_method >=
                        O2NM_FENCE_METHODS);
-               /* fall through */
+               fallthrough;
        case O2NM_FENCE_RESET:
                printk(KERN_ERR "*** ocfs2 is very sorry to be fencing this "
                       "system by restarting ***\n");
index 60dbee4..0ac1976 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -106,25 +106,6 @@ void pipe_double_lock(struct pipe_inode_info *pipe1,
        }
 }
 
-/* Drop the inode semaphore and wait for a pipe event, atomically */
-void pipe_wait(struct pipe_inode_info *pipe)
-{
-       DEFINE_WAIT(rdwait);
-       DEFINE_WAIT(wrwait);
-
-       /*
-        * Pipes are system-local resources, so sleeping on them
-        * is considered a noninteractive wait:
-        */
-       prepare_to_wait(&pipe->rd_wait, &rdwait, TASK_INTERRUPTIBLE);
-       prepare_to_wait(&pipe->wr_wait, &wrwait, TASK_INTERRUPTIBLE);
-       pipe_unlock(pipe);
-       schedule();
-       finish_wait(&pipe->rd_wait, &rdwait);
-       finish_wait(&pipe->wr_wait, &wrwait);
-       pipe_lock(pipe);
-}
-
 static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
                                  struct pipe_buffer *buf)
 {
@@ -913,19 +894,18 @@ int create_pipe_files(struct file **res, int flags)
 {
        struct inode *inode = get_pipe_inode();
        struct file *f;
+       int error;
 
        if (!inode)
                return -ENFILE;
 
        if (flags & O_NOTIFICATION_PIPE) {
-#ifdef CONFIG_WATCH_QUEUE
-               if (watch_queue_init(inode->i_pipe) < 0) {
+               error = watch_queue_init(inode->i_pipe);
+               if (error) {
+                       free_pipe_info(inode->i_pipe);
                        iput(inode);
-                       return -ENOMEM;
+                       return error;
                }
-#else
-               return -ENOPKG;
-#endif
        }
 
        f = alloc_file_pseudo(inode, pipe_mnt, "",
@@ -1035,12 +1015,52 @@ SYSCALL_DEFINE1(pipe, int __user *, fildes)
        return do_pipe2(fildes, 0);
 }
 
+/*
+ * This is the stupid "wait for pipe to be readable or writable"
+ * model.
+ *
+ * See pipe_read/write() for the proper kind of exclusive wait,
+ * but that requires that we wake up any other readers/writers
+ * if we then do not end up reading everything (ie the whole
+ * "wake_next_reader/writer" logic in pipe_read/write()).
+ */
+void pipe_wait_readable(struct pipe_inode_info *pipe)
+{
+       pipe_unlock(pipe);
+       wait_event_interruptible(pipe->rd_wait, pipe_readable(pipe));
+       pipe_lock(pipe);
+}
+
+void pipe_wait_writable(struct pipe_inode_info *pipe)
+{
+       pipe_unlock(pipe);
+       wait_event_interruptible(pipe->wr_wait, pipe_writable(pipe));
+       pipe_lock(pipe);
+}
+
+/*
+ * This depends on both the wait (here) and the wakeup (wake_up_partner)
+ * holding the pipe lock, so "*cnt" is stable and we know a wakeup cannot
+ * race with the count check and waitqueue prep.
+ *
+ * Normally in order to avoid races, you'd do the prepare_to_wait() first,
+ * then check the condition you're waiting for, and only then sleep. But
+ * because of the pipe lock, we can check the condition before being on
+ * the wait queue.
+ *
+ * We use the 'rd_wait' waitqueue for pipe partner waiting.
+ */
 static int wait_for_partner(struct pipe_inode_info *pipe, unsigned int *cnt)
 {
+       DEFINE_WAIT(rdwait);
        int cur = *cnt;
 
        while (cur == *cnt) {
-               pipe_wait(pipe);
+               prepare_to_wait(&pipe->rd_wait, &rdwait, TASK_INTERRUPTIBLE);
+               pipe_unlock(pipe);
+               schedule();
+               finish_wait(&pipe->rd_wait, &rdwait);
+               pipe_lock(pipe);
                if (signal_pending(current))
                        break;
        }
@@ -1050,7 +1070,6 @@ static int wait_for_partner(struct pipe_inode_info *pipe, unsigned int *cnt)
 static void wake_up_partner(struct pipe_inode_info *pipe)
 {
        wake_up_interruptible_all(&pipe->rd_wait);
-       wake_up_interruptible_all(&pipe->wr_wait);
 }
 
 static int fifo_open(struct inode *inode, struct file *filp)
index f909243..9f1077d 100644 (file)
@@ -217,6 +217,9 @@ u64 stable_page_flags(struct page *page)
        u |= kpf_copy_bit(k, KPF_PRIVATE_2,     PG_private_2);
        u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1);
        u |= kpf_copy_bit(k, KPF_ARCH,          PG_arch_1);
+#ifdef CONFIG_64BIT
+       u |= kpf_copy_bit(k, KPF_ARCH_2,        PG_arch_2);
+#endif
 
        return u;
 };
index 5066b02..35172a9 100644 (file)
@@ -653,6 +653,10 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
                [ilog2(VM_MERGEABLE)]   = "mg",
                [ilog2(VM_UFFD_MISSING)]= "um",
                [ilog2(VM_UFFD_WP)]     = "uw",
+#ifdef CONFIG_ARM64_MTE
+               [ilog2(VM_MTE)]         = "mt",
+               [ilog2(VM_MTE_ALLOWED)] = "",
+#endif
 #ifdef CONFIG_ARCH_HAS_PKEYS
                /* These come out via ProtectionKey: */
                [ilog2(VM_PKEY_BIT0)]   = "",
index 819428d..3ce8921 100644 (file)
@@ -1081,7 +1081,6 @@ next_zone:
                readop = psz_ftrace_read;
                break;
        case PSTORE_TYPE_CONSOLE:
-               fallthrough;
        case PSTORE_TYPE_PMSG:
                readop = psz_record_read;
                break;
index d1ceb76..b59cd17 100644 (file)
@@ -70,8 +70,3 @@ config QFMT_V2
 config QUOTACTL
        bool
        default n
-
-config QUOTACTL_COMPAT
-       bool
-       depends on QUOTACTL && COMPAT_FOR_U64_ALIGNMENT
-       default y
index f2b49d0..9160639 100644 (file)
@@ -4,5 +4,4 @@ obj-$(CONFIG_QFMT_V1)           += quota_v1.o
 obj-$(CONFIG_QFMT_V2)          += quota_v2.o
 obj-$(CONFIG_QUOTA_TREE)       += quota_tree.o
 obj-$(CONFIG_QUOTACTL)         += quota.o kqid.o
-obj-$(CONFIG_QUOTACTL_COMPAT)  += compat.o
 obj-$(CONFIG_QUOTA_NETLINK_INTERFACE)  += netlink.o
diff --git a/fs/quota/compat.c b/fs/quota/compat.c
deleted file mode 100644 (file)
index c305728..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/syscalls.h>
-#include <linux/compat.h>
-#include <linux/quotaops.h>
-
-/*
- * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
- * and is necessary due to alignment problems.
- */
-struct compat_if_dqblk {
-       compat_u64 dqb_bhardlimit;
-       compat_u64 dqb_bsoftlimit;
-       compat_u64 dqb_curspace;
-       compat_u64 dqb_ihardlimit;
-       compat_u64 dqb_isoftlimit;
-       compat_u64 dqb_curinodes;
-       compat_u64 dqb_btime;
-       compat_u64 dqb_itime;
-       compat_uint_t dqb_valid;
-};
-
-/* XFS structures */
-struct compat_fs_qfilestat {
-       compat_u64 dqb_bhardlimit;
-       compat_u64 qfs_nblks;
-       compat_uint_t qfs_nextents;
-};
-
-struct compat_fs_quota_stat {
-       __s8            qs_version;
-       __u16           qs_flags;
-       __s8            qs_pad;
-       struct compat_fs_qfilestat      qs_uquota;
-       struct compat_fs_qfilestat      qs_gquota;
-       compat_uint_t   qs_incoredqs;
-       compat_int_t    qs_btimelimit;
-       compat_int_t    qs_itimelimit;
-       compat_int_t    qs_rtbtimelimit;
-       __u16           qs_bwarnlimit;
-       __u16           qs_iwarnlimit;
-};
-
-COMPAT_SYSCALL_DEFINE4(quotactl32, unsigned int, cmd,
-                      const char __user *, special, qid_t, id,
-                      void __user *, addr)
-{
-       unsigned int cmds;
-       struct if_dqblk __user *dqblk;
-       struct compat_if_dqblk __user *compat_dqblk;
-       struct fs_quota_stat __user *fsqstat;
-       struct compat_fs_quota_stat __user *compat_fsqstat;
-       compat_uint_t data;
-       u16 xdata;
-       long ret;
-
-       cmds = cmd >> SUBCMDSHIFT;
-
-       switch (cmds) {
-       case Q_GETQUOTA:
-               dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
-               compat_dqblk = addr;
-               ret = kernel_quotactl(cmd, special, id, dqblk);
-               if (ret)
-                       break;
-               if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) ||
-                       get_user(data, &dqblk->dqb_valid) ||
-                       put_user(data, &compat_dqblk->dqb_valid))
-                       ret = -EFAULT;
-               break;
-       case Q_SETQUOTA:
-               dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
-               compat_dqblk = addr;
-               ret = -EFAULT;
-               if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) ||
-                       get_user(data, &compat_dqblk->dqb_valid) ||
-                       put_user(data, &dqblk->dqb_valid))
-                       break;
-               ret = kernel_quotactl(cmd, special, id, dqblk);
-               break;
-       case Q_XGETQSTAT:
-               fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat));
-               compat_fsqstat = addr;
-               ret = kernel_quotactl(cmd, special, id, fsqstat);
-               if (ret)
-                       break;
-               ret = -EFAULT;
-               /* Copying qs_version, qs_flags, qs_pad */
-               if (copy_in_user(compat_fsqstat, fsqstat,
-                       offsetof(struct compat_fs_quota_stat, qs_uquota)))
-                       break;
-               /* Copying qs_uquota */
-               if (copy_in_user(&compat_fsqstat->qs_uquota,
-                       &fsqstat->qs_uquota,
-                       sizeof(compat_fsqstat->qs_uquota)) ||
-                       get_user(data, &fsqstat->qs_uquota.qfs_nextents) ||
-                       put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents))
-                       break;
-               /* Copying qs_gquota */
-               if (copy_in_user(&compat_fsqstat->qs_gquota,
-                       &fsqstat->qs_gquota,
-                       sizeof(compat_fsqstat->qs_gquota)) ||
-                       get_user(data, &fsqstat->qs_gquota.qfs_nextents) ||
-                       put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents))
-                       break;
-               /* Copying the rest */
-               if (copy_in_user(&compat_fsqstat->qs_incoredqs,
-                       &fsqstat->qs_incoredqs,
-                       sizeof(struct compat_fs_quota_stat) -
-                       offsetof(struct compat_fs_quota_stat, qs_incoredqs)) ||
-                       get_user(xdata, &fsqstat->qs_iwarnlimit) ||
-                       put_user(xdata, &compat_fsqstat->qs_iwarnlimit))
-                       break;
-               ret = 0;
-               break;
-       default:
-               ret = kernel_quotactl(cmd, special, id, addr);
-       }
-       return ret;
-}
diff --git a/fs/quota/compat.h b/fs/quota/compat.h
new file mode 100644 (file)
index 0000000..ef7d1e1
--- /dev/null
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/compat.h>
+
+struct compat_if_dqblk {
+       compat_u64                      dqb_bhardlimit;
+       compat_u64                      dqb_bsoftlimit;
+       compat_u64                      dqb_curspace;
+       compat_u64                      dqb_ihardlimit;
+       compat_u64                      dqb_isoftlimit;
+       compat_u64                      dqb_curinodes;
+       compat_u64                      dqb_btime;
+       compat_u64                      dqb_itime;
+       compat_uint_t                   dqb_valid;
+};
+
+struct compat_fs_qfilestat {
+       compat_u64                      dqb_bhardlimit;
+       compat_u64                      qfs_nblks;
+       compat_uint_t                   qfs_nextents;
+};
+
+struct compat_fs_quota_stat {
+       __s8                            qs_version;
+       __u16                           qs_flags;
+       __s8                            qs_pad;
+       struct compat_fs_qfilestat      qs_uquota;
+       struct compat_fs_qfilestat      qs_gquota;
+       compat_uint_t                   qs_incoredqs;
+       compat_int_t                    qs_btimelimit;
+       compat_int_t                    qs_itimelimit;
+       compat_int_t                    qs_rtbtimelimit;
+       __u16                           qs_bwarnlimit;
+       __u16                           qs_iwarnlimit;
+};
index 5444d3c..6b37d58 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/types.h>
 #include <linux/writeback.h>
 #include <linux/nospec.h>
+#include "compat.h"
 
 static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
                                     qid_t id)
@@ -38,7 +39,7 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
                if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
                    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
                        break;
-               /*FALLTHROUGH*/
+               fallthrough;
        default:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
@@ -211,8 +212,18 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id,
        if (ret)
                return ret;
        copy_to_if_dqblk(&idq, &fdq);
-       if (copy_to_user(addr, &idq, sizeof(idq)))
-               return -EFAULT;
+
+       if (compat_need_64bit_alignment_fixup()) {
+               struct compat_if_dqblk __user *compat_dqblk = addr;
+
+               if (copy_to_user(compat_dqblk, &idq, sizeof(*compat_dqblk)))
+                       return -EFAULT;
+               if (put_user(idq.dqb_valid, &compat_dqblk->dqb_valid))
+                       return -EFAULT;
+       } else {
+               if (copy_to_user(addr, &idq, sizeof(idq)))
+                       return -EFAULT;
+       }
        return 0;
 }
 
@@ -277,8 +288,16 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id,
        struct if_dqblk idq;
        struct kqid qid;
 
-       if (copy_from_user(&idq, addr, sizeof(idq)))
-               return -EFAULT;
+       if (compat_need_64bit_alignment_fixup()) {
+               struct compat_if_dqblk __user *compat_dqblk = addr;
+
+               if (copy_from_user(&idq, compat_dqblk, sizeof(*compat_dqblk)) ||
+                   get_user(idq.dqb_valid, &compat_dqblk->dqb_valid))
+                       return -EFAULT;
+       } else {
+               if (copy_from_user(&idq, addr, sizeof(idq)))
+                       return -EFAULT;
+       }
        if (!sb->s_qcop->set_dqblk)
                return -ENOSYS;
        qid = make_kqid(current_user_ns(), type, id);
@@ -382,6 +401,33 @@ static int quota_getstate(struct super_block *sb, int type,
        return 0;
 }
 
+static int compat_copy_fs_qfilestat(struct compat_fs_qfilestat __user *to,
+               struct fs_qfilestat *from)
+{
+       if (copy_to_user(to, from, sizeof(*to)) ||
+           put_user(from->qfs_nextents, &to->qfs_nextents))
+               return -EFAULT;
+       return 0;
+}
+
+static int compat_copy_fs_quota_stat(struct compat_fs_quota_stat __user *to,
+               struct fs_quota_stat *from)
+{
+       if (put_user(from->qs_version, &to->qs_version) ||
+           put_user(from->qs_flags, &to->qs_flags) ||
+           put_user(from->qs_pad, &to->qs_pad) ||
+           compat_copy_fs_qfilestat(&to->qs_uquota, &from->qs_uquota) ||
+           compat_copy_fs_qfilestat(&to->qs_gquota, &from->qs_gquota) ||
+           put_user(from->qs_incoredqs, &to->qs_incoredqs) ||
+           put_user(from->qs_btimelimit, &to->qs_btimelimit) ||
+           put_user(from->qs_itimelimit, &to->qs_itimelimit) ||
+           put_user(from->qs_rtbtimelimit, &to->qs_rtbtimelimit) ||
+           put_user(from->qs_bwarnlimit, &to->qs_bwarnlimit) ||
+           put_user(from->qs_iwarnlimit, &to->qs_iwarnlimit))
+               return -EFAULT;
+       return 0;
+}
+
 static int quota_getxstate(struct super_block *sb, int type, void __user *addr)
 {
        struct fs_quota_stat fqs;
@@ -390,9 +436,14 @@ static int quota_getxstate(struct super_block *sb, int type, void __user *addr)
        if (!sb->s_qcop->get_state)
                return -ENOSYS;
        ret = quota_getstate(sb, type, &fqs);
-       if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
+       if (ret)
+               return ret;
+
+       if (compat_need_64bit_alignment_fixup())
+               return compat_copy_fs_quota_stat(addr, &fqs);
+       if (copy_to_user(addr, &fqs, sizeof(fqs)))
                return -EFAULT;
-       return ret;
+       return 0;
 }
 
 static int quota_getstatev(struct super_block *sb, int type,
@@ -816,8 +867,8 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
  * calls. Maybe we need to add the process quotas etc. in the future,
  * but we probably should use rlimits for that.
  */
-int kernel_quotactl(unsigned int cmd, const char __user *special,
-                   qid_t id, void __user *addr)
+SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
+               qid_t, id, void __user *, addr)
 {
        uint cmds, type;
        struct super_block *sb = NULL;
@@ -871,9 +922,3 @@ out:
                path_put(pathp);
        return ret;
 }
-
-SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
-               qid_t, id, void __user *, addr)
-{
-       return kernel_quotactl(cmd, special, id, addr);
-}
index 5db58b8..19f5c4b 100644 (file)
@@ -538,6 +538,14 @@ ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t
        inc_syscw(current);
        return ret;
 }
+/*
+ * This "EXPORT_SYMBOL_GPL()" is more of a "EXPORT_SYMBOL_DONTUSE()",
+ * but autofs is one of the few internal kernel users that actually
+ * wants this _and_ can be built as a module. So we need to export
+ * this symbol for autofs, even though it really isn't appropriate
+ * for any other kernel modules.
+ */
+EXPORT_SYMBOL_GPL(__kernel_write);
 
 ssize_t kernel_write(struct file *file, const void *buf, size_t count,
                            loff_t *pos)
@@ -752,185 +760,6 @@ static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter,
        return ret;
 }
 
-/**
- * rw_copy_check_uvector() - Copy an array of &struct iovec from userspace
- *     into the kernel and check that it is valid.
- *
- * @type: One of %CHECK_IOVEC_ONLY, %READ, or %WRITE.
- * @uvector: Pointer to the userspace array.
- * @nr_segs: Number of elements in userspace array.
- * @fast_segs: Number of elements in @fast_pointer.
- * @fast_pointer: Pointer to (usually small on-stack) kernel array.
- * @ret_pointer: (output parameter) Pointer to a variable that will point to
- *     either @fast_pointer, a newly allocated kernel array, or NULL,
- *     depending on which array was used.
- *
- * This function copies an array of &struct iovec of @nr_segs from
- * userspace into the kernel and checks that each element is valid (e.g.
- * it does not point to a kernel address or cause overflow by being too
- * large, etc.).
- *
- * As an optimization, the caller may provide a pointer to a small
- * on-stack array in @fast_pointer, typically %UIO_FASTIOV elements long
- * (the size of this array, or 0 if unused, should be given in @fast_segs).
- *
- * @ret_pointer will always point to the array that was used, so the
- * caller must take care not to call kfree() on it e.g. in case the
- * @fast_pointer array was used and it was allocated on the stack.
- *
- * Return: The total number of bytes covered by the iovec array on success
- *   or a negative error code on error.
- */
-ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
-                             unsigned long nr_segs, unsigned long fast_segs,
-                             struct iovec *fast_pointer,
-                             struct iovec **ret_pointer)
-{
-       unsigned long seg;
-       ssize_t ret;
-       struct iovec *iov = fast_pointer;
-
-       /*
-        * SuS says "The readv() function *may* fail if the iovcnt argument
-        * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
-        * traditionally returned zero for zero segments, so...
-        */
-       if (nr_segs == 0) {
-               ret = 0;
-               goto out;
-       }
-
-       /*
-        * First get the "struct iovec" from user memory and
-        * verify all the pointers
-        */
-       if (nr_segs > UIO_MAXIOV) {
-               ret = -EINVAL;
-               goto out;
-       }
-       if (nr_segs > fast_segs) {
-               iov = kmalloc_array(nr_segs, sizeof(struct iovec), GFP_KERNEL);
-               if (iov == NULL) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-       }
-       if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
-               ret = -EFAULT;
-               goto out;
-       }
-
-       /*
-        * According to the Single Unix Specification we should return EINVAL
-        * if an element length is < 0 when cast to ssize_t or if the
-        * total length would overflow the ssize_t return value of the
-        * system call.
-        *
-        * Linux caps all read/write calls to MAX_RW_COUNT, and avoids the
-        * overflow case.
-        */
-       ret = 0;
-       for (seg = 0; seg < nr_segs; seg++) {
-               void __user *buf = iov[seg].iov_base;
-               ssize_t len = (ssize_t)iov[seg].iov_len;
-
-               /* see if we we're about to use an invalid len or if
-                * it's about to overflow ssize_t */
-               if (len < 0) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-               if (type >= 0
-                   && unlikely(!access_ok(buf, len))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (len > MAX_RW_COUNT - ret) {
-                       len = MAX_RW_COUNT - ret;
-                       iov[seg].iov_len = len;
-               }
-               ret += len;
-       }
-out:
-       *ret_pointer = iov;
-       return ret;
-}
-
-#ifdef CONFIG_COMPAT
-ssize_t compat_rw_copy_check_uvector(int type,
-               const struct compat_iovec __user *uvector, unsigned long nr_segs,
-               unsigned long fast_segs, struct iovec *fast_pointer,
-               struct iovec **ret_pointer)
-{
-       compat_ssize_t tot_len;
-       struct iovec *iov = *ret_pointer = fast_pointer;
-       ssize_t ret = 0;
-       int seg;
-
-       /*
-        * SuS says "The readv() function *may* fail if the iovcnt argument
-        * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
-        * traditionally returned zero for zero segments, so...
-        */
-       if (nr_segs == 0)
-               goto out;
-
-       ret = -EINVAL;
-       if (nr_segs > UIO_MAXIOV)
-               goto out;
-       if (nr_segs > fast_segs) {
-               ret = -ENOMEM;
-               iov = kmalloc_array(nr_segs, sizeof(struct iovec), GFP_KERNEL);
-               if (iov == NULL)
-                       goto out;
-       }
-       *ret_pointer = iov;
-
-       ret = -EFAULT;
-       if (!access_ok(uvector, nr_segs*sizeof(*uvector)))
-               goto out;
-
-       /*
-        * Single unix specification:
-        * We should -EINVAL if an element length is not >= 0 and fitting an
-        * ssize_t.
-        *
-        * In Linux, the total length is limited to MAX_RW_COUNT, there is
-        * no overflow possibility.
-        */
-       tot_len = 0;
-       ret = -EINVAL;
-       for (seg = 0; seg < nr_segs; seg++) {
-               compat_uptr_t buf;
-               compat_ssize_t len;
-
-               if (__get_user(len, &uvector->iov_len) ||
-                  __get_user(buf, &uvector->iov_base)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (len < 0)    /* size_t not fitting in compat_ssize_t .. */
-                       goto out;
-               if (type >= 0 &&
-                   !access_ok(compat_ptr(buf), len)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (len > MAX_RW_COUNT - tot_len)
-                       len = MAX_RW_COUNT - tot_len;
-               tot_len += len;
-               iov->iov_base = compat_ptr(buf);
-               iov->iov_len = (compat_size_t) len;
-               uvector++;
-               iov++;
-       }
-       ret = tot_len;
-
-out:
-       return ret;
-}
-#endif
-
 static ssize_t do_iter_read(struct file *file, struct iov_iter *iter,
                loff_t *pos, rwf_t flags)
 {
@@ -1247,224 +1076,93 @@ SYSCALL_DEFINE6(pwritev2, unsigned long, fd, const struct iovec __user *, vec,
        return do_pwritev(fd, vec, vlen, pos, flags);
 }
 
+/*
+ * Various compat syscalls.  Note that they all pretend to take a native
+ * iovec - import_iovec will properly treat those as compat_iovecs based on
+ * in_compat_syscall().
+ */
 #ifdef CONFIG_COMPAT
-static size_t compat_readv(struct file *file,
-                          const struct compat_iovec __user *vec,
-                          unsigned long vlen, loff_t *pos, rwf_t flags)
-{
-       struct iovec iovstack[UIO_FASTIOV];
-       struct iovec *iov = iovstack;
-       struct iov_iter iter;
-       ssize_t ret;
-
-       ret = compat_import_iovec(READ, vec, vlen, UIO_FASTIOV, &iov, &iter);
-       if (ret >= 0) {
-               ret = do_iter_read(file, &iter, pos, flags);
-               kfree(iov);
-       }
-       if (ret > 0)
-               add_rchar(current, ret);
-       inc_syscr(current);
-       return ret;
-}
-
-static size_t do_compat_readv(compat_ulong_t fd,
-                                const struct compat_iovec __user *vec,
-                                compat_ulong_t vlen, rwf_t flags)
-{
-       struct fd f = fdget_pos(fd);
-       ssize_t ret;
-       loff_t pos;
-
-       if (!f.file)
-               return -EBADF;
-       pos = f.file->f_pos;
-       ret = compat_readv(f.file, vec, vlen, &pos, flags);
-       if (ret >= 0)
-               f.file->f_pos = pos;
-       fdput_pos(f);
-       return ret;
-
-}
-
-COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
-               const struct compat_iovec __user *,vec,
-               compat_ulong_t, vlen)
-{
-       return do_compat_readv(fd, vec, vlen, 0);
-}
-
-static long do_compat_preadv64(unsigned long fd,
-                                 const struct compat_iovec __user *vec,
-                                 unsigned long vlen, loff_t pos, rwf_t flags)
-{
-       struct fd f;
-       ssize_t ret;
-
-       if (pos < 0)
-               return -EINVAL;
-       f = fdget(fd);
-       if (!f.file)
-               return -EBADF;
-       ret = -ESPIPE;
-       if (f.file->f_mode & FMODE_PREAD)
-               ret = compat_readv(f.file, vec, vlen, &pos, flags);
-       fdput(f);
-       return ret;
-}
-
 #ifdef __ARCH_WANT_COMPAT_SYS_PREADV64
 COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
-               const struct compat_iovec __user *,vec,
+               const struct iovec __user *, vec,
                unsigned long, vlen, loff_t, pos)
 {
-       return do_compat_preadv64(fd, vec, vlen, pos, 0);
+       return do_preadv(fd, vec, vlen, pos, 0);
 }
 #endif
 
 COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd,
-               const struct compat_iovec __user *,vec,
+               const struct iovec __user *, vec,
                compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
 {
        loff_t pos = ((loff_t)pos_high << 32) | pos_low;
 
-       return do_compat_preadv64(fd, vec, vlen, pos, 0);
+       return do_preadv(fd, vec, vlen, pos, 0);
 }
 
 #ifdef __ARCH_WANT_COMPAT_SYS_PREADV64V2
 COMPAT_SYSCALL_DEFINE5(preadv64v2, unsigned long, fd,
-               const struct compat_iovec __user *,vec,
+               const struct iovec __user *, vec,
                unsigned long, vlen, loff_t, pos, rwf_t, flags)
 {
        if (pos == -1)
-               return do_compat_readv(fd, vec, vlen, flags);
-
-       return do_compat_preadv64(fd, vec, vlen, pos, flags);
+               return do_readv(fd, vec, vlen, flags);
+       return do_preadv(fd, vec, vlen, pos, flags);
 }
 #endif
 
 COMPAT_SYSCALL_DEFINE6(preadv2, compat_ulong_t, fd,
-               const struct compat_iovec __user *,vec,
+               const struct iovec __user *, vec,
                compat_ulong_t, vlen, u32, pos_low, u32, pos_high,
                rwf_t, flags)
 {
        loff_t pos = ((loff_t)pos_high << 32) | pos_low;
 
        if (pos == -1)
-               return do_compat_readv(fd, vec, vlen, flags);
-
-       return do_compat_preadv64(fd, vec, vlen, pos, flags);
-}
-
-static size_t compat_writev(struct file *file,
-                           const struct compat_iovec __user *vec,
-                           unsigned long vlen, loff_t *pos, rwf_t flags)
-{
-       struct iovec iovstack[UIO_FASTIOV];
-       struct iovec *iov = iovstack;
-       struct iov_iter iter;
-       ssize_t ret;
-
-       ret = compat_import_iovec(WRITE, vec, vlen, UIO_FASTIOV, &iov, &iter);
-       if (ret >= 0) {
-               file_start_write(file);
-               ret = do_iter_write(file, &iter, pos, flags);
-               file_end_write(file);
-               kfree(iov);
-       }
-       if (ret > 0)
-               add_wchar(current, ret);
-       inc_syscw(current);
-       return ret;
-}
-
-static size_t do_compat_writev(compat_ulong_t fd,
-                                 const struct compat_iovec __user* vec,
-                                 compat_ulong_t vlen, rwf_t flags)
-{
-       struct fd f = fdget_pos(fd);
-       ssize_t ret;
-       loff_t pos;
-
-       if (!f.file)
-               return -EBADF;
-       pos = f.file->f_pos;
-       ret = compat_writev(f.file, vec, vlen, &pos, flags);
-       if (ret >= 0)
-               f.file->f_pos = pos;
-       fdput_pos(f);
-       return ret;
-}
-
-COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
-               const struct compat_iovec __user *, vec,
-               compat_ulong_t, vlen)
-{
-       return do_compat_writev(fd, vec, vlen, 0);
-}
-
-static long do_compat_pwritev64(unsigned long fd,
-                                  const struct compat_iovec __user *vec,
-                                  unsigned long vlen, loff_t pos, rwf_t flags)
-{
-       struct fd f;
-       ssize_t ret;
-
-       if (pos < 0)
-               return -EINVAL;
-       f = fdget(fd);
-       if (!f.file)
-               return -EBADF;
-       ret = -ESPIPE;
-       if (f.file->f_mode & FMODE_PWRITE)
-               ret = compat_writev(f.file, vec, vlen, &pos, flags);
-       fdput(f);
-       return ret;
+               return do_readv(fd, vec, vlen, flags);
+       return do_preadv(fd, vec, vlen, pos, flags);
 }
 
 #ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64
 COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
-               const struct compat_iovec __user *,vec,
+               const struct iovec __user *, vec,
                unsigned long, vlen, loff_t, pos)
 {
-       return do_compat_pwritev64(fd, vec, vlen, pos, 0);
+       return do_pwritev(fd, vec, vlen, pos, 0);
 }
 #endif
 
 COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd,
-               const struct compat_iovec __user *,vec,
+               const struct iovec __user *,vec,
                compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
 {
        loff_t pos = ((loff_t)pos_high << 32) | pos_low;
 
-       return do_compat_pwritev64(fd, vec, vlen, pos, 0);
+       return do_pwritev(fd, vec, vlen, pos, 0);
 }
 
 #ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64V2
 COMPAT_SYSCALL_DEFINE5(pwritev64v2, unsigned long, fd,
-               const struct compat_iovec __user *,vec,
+               const struct iovec __user *, vec,
                unsigned long, vlen, loff_t, pos, rwf_t, flags)
 {
        if (pos == -1)
-               return do_compat_writev(fd, vec, vlen, flags);
-
-       return do_compat_pwritev64(fd, vec, vlen, pos, flags);
+               return do_writev(fd, vec, vlen, flags);
+       return do_pwritev(fd, vec, vlen, pos, flags);
 }
 #endif
 
 COMPAT_SYSCALL_DEFINE6(pwritev2, compat_ulong_t, fd,
-               const struct compat_iovec __user *,vec,
+               const struct iovec __user *,vec,
                compat_ulong_t, vlen, u32, pos_low, u32, pos_high, rwf_t, flags)
 {
        loff_t pos = ((loff_t)pos_high << 32) | pos_low;
 
        if (pos == -1)
-               return do_compat_writev(fd, vec, vlen, flags);
-
-       return do_compat_pwritev64(fd, vec, vlen, pos, flags);
+               return do_writev(fd, vec, vlen, flags);
+       return do_pwritev(fd, vec, vlen, pos, flags);
 }
-
-#endif
+#endif /* CONFIG_COMPAT */
 
 static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
                           size_t count, loff_t max)
index 4e6239f..31219c1 100644 (file)
@@ -295,7 +295,7 @@ loff_t seq_lseek(struct file *file, loff_t offset, int whence)
        switch (whence) {
        case SEEK_CUR:
                offset += file->f_pos;
-               /* fall through */
+               fallthrough;
        case SEEK_SET:
                if (offset < 0)
                        break;
index 5b78719..456046e 100644 (file)
@@ -176,7 +176,7 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info
                if (!nonblock)
                        break;
                ret = -EAGAIN;
-               /* fall through */
+               fallthrough;
        default:
                spin_unlock_irq(&current->sighand->siglock);
                return ret;
index d7c8a7c..70cc52a 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/security.h>
 #include <linux/gfp.h>
 #include <linux/socket.h>
-#include <linux/compat.h>
 #include <linux/sched/signal.h>
 
 #include "internal.h"
@@ -526,6 +525,22 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des
        return 1;
 }
 
+/* We know we have a pipe buffer, but maybe it's empty? */
+static inline bool eat_empty_buffer(struct pipe_inode_info *pipe)
+{
+       unsigned int tail = pipe->tail;
+       unsigned int mask = pipe->ring_size - 1;
+       struct pipe_buffer *buf = &pipe->bufs[tail & mask];
+
+       if (unlikely(!buf->len)) {
+               pipe_buf_release(pipe, buf);
+               pipe->tail = tail+1;
+               return true;
+       }
+
+       return false;
+}
+
 /**
  * splice_from_pipe_next - wait for some data to splice from
  * @pipe:      pipe to splice from
@@ -545,6 +560,7 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des
        if (signal_pending(current))
                return -ERESTARTSYS;
 
+repeat:
        while (pipe_empty(pipe->head, pipe->tail)) {
                if (!pipe->writers)
                        return 0;
@@ -563,9 +579,12 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des
                        sd->need_wakeup = false;
                }
 
-               pipe_wait(pipe);
+               pipe_wait_readable(pipe);
        }
 
+       if (eat_empty_buffer(pipe))
+               goto repeat;
+
        return 1;
 }
 
@@ -1077,7 +1096,7 @@ static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
                        return -EAGAIN;
                if (signal_pending(current))
                        return -ERESTARTSYS;
-               pipe_wait(pipe);
+               pipe_wait_writable(pipe);
        }
 }
 
@@ -1332,20 +1351,6 @@ static int vmsplice_type(struct fd f, int *type)
  * Currently we punt and implement it as a normal copy, see pipe_to_user().
  *
  */
-static long do_vmsplice(struct file *f, struct iov_iter *iter, unsigned int flags)
-{
-       if (unlikely(flags & ~SPLICE_F_ALL))
-               return -EINVAL;
-
-       if (!iov_iter_count(iter))
-               return 0;
-
-       if (iov_iter_rw(iter) == WRITE)
-               return vmsplice_to_pipe(f, iter, flags);
-       else
-               return vmsplice_to_user(f, iter, flags);
-}
-
 SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
                unsigned long, nr_segs, unsigned int, flags)
 {
@@ -1356,6 +1361,9 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
        struct fd f;
        int type;
 
+       if (unlikely(flags & ~SPLICE_F_ALL))
+               return -EINVAL;
+
        f = fdget(fd);
        error = vmsplice_type(f, &type);
        if (error)
@@ -1363,40 +1371,21 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
 
        error = import_iovec(type, uiov, nr_segs,
                             ARRAY_SIZE(iovstack), &iov, &iter);
-       if (error >= 0) {
-               error = do_vmsplice(f.file, &iter, flags);
-               kfree(iov);
-       }
-       fdput(f);
-       return error;
-}
-
-#ifdef CONFIG_COMPAT
-COMPAT_SYSCALL_DEFINE4(vmsplice, int, fd, const struct compat_iovec __user *, iov32,
-                   unsigned int, nr_segs, unsigned int, flags)
-{
-       struct iovec iovstack[UIO_FASTIOV];
-       struct iovec *iov = iovstack;
-       struct iov_iter iter;
-       ssize_t error;
-       struct fd f;
-       int type;
+       if (error < 0)
+               goto out_fdput;
 
-       f = fdget(fd);
-       error = vmsplice_type(f, &type);
-       if (error)
-               return error;
+       if (!iov_iter_count(&iter))
+               error = 0;
+       else if (iov_iter_rw(&iter) == WRITE)
+               error = vmsplice_to_pipe(f.file, &iter, flags);
+       else
+               error = vmsplice_to_user(f.file, &iter, flags);
 
-       error = compat_import_iovec(type, iov32, nr_segs,
-                            ARRAY_SIZE(iovstack), &iov, &iter);
-       if (error >= 0) {
-               error = do_vmsplice(f.file, &iter, flags);
-               kfree(iov);
-       }
+       kfree(iov);
+out_fdput:
        fdput(f);
        return error;
 }
-#endif
 
 SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
                int, fd_out, loff_t __user *, off_out,
@@ -1454,7 +1443,7 @@ static int ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
                        ret = -EAGAIN;
                        break;
                }
-               pipe_wait(pipe);
+               pipe_wait_readable(pipe);
        }
 
        pipe_unlock(pipe);
@@ -1493,7 +1482,7 @@ static int opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
                        ret = -ERESTARTSYS;
                        break;
                }
-               pipe_wait(pipe);
+               pipe_wait_writable(pipe);
        }
 
        pipe_unlock(pipe);
index 9d04294..155521e 100644 (file)
@@ -81,19 +81,6 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
        struct ubifs_inode *ui;
        bool encrypted = false;
 
-       if (IS_ENCRYPTED(dir)) {
-               err = fscrypt_get_encryption_info(dir);
-               if (err) {
-                       ubifs_err(c, "fscrypt_get_encryption_info failed: %i", err);
-                       return ERR_PTR(err);
-               }
-
-               if (!fscrypt_has_encryption_key(dir))
-                       return ERR_PTR(-EPERM);
-
-               encrypted = true;
-       }
-
        inode = new_inode(c->vfs_sb);
        ui = ubifs_inode(inode);
        if (!inode)
@@ -112,6 +99,12 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
                         current_time(inode);
        inode->i_mapping->nrpages = 0;
 
+       err = fscrypt_prepare_new_inode(dir, inode, &encrypted);
+       if (err) {
+               ubifs_err(c, "fscrypt_prepare_new_inode failed: %i", err);
+               goto out_iput;
+       }
+
        switch (mode & S_IFMT) {
        case S_IFREG:
                inode->i_mapping->a_ops = &ubifs_file_address_operations;
@@ -131,7 +124,6 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
        case S_IFBLK:
        case S_IFCHR:
                inode->i_op  = &ubifs_file_inode_operations;
-               encrypted = false;
                break;
        default:
                BUG();
@@ -151,9 +143,8 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
                if (c->highest_inum >= INUM_WATERMARK) {
                        spin_unlock(&c->cnt_lock);
                        ubifs_err(c, "out of inode numbers");
-                       make_bad_inode(inode);
-                       iput(inode);
-                       return ERR_PTR(-EINVAL);
+                       err = -EINVAL;
+                       goto out_iput;
                }
                ubifs_warn(c, "running out of inode numbers (current %lu, max %u)",
                           (unsigned long)c->highest_inum, INUM_WATERMARK);
@@ -171,16 +162,19 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
        spin_unlock(&c->cnt_lock);
 
        if (encrypted) {
-               err = fscrypt_inherit_context(dir, inode, &encrypted, true);
+               err = fscrypt_set_context(inode, NULL);
                if (err) {
-                       ubifs_err(c, "fscrypt_inherit_context failed: %i", err);
-                       make_bad_inode(inode);
-                       iput(inode);
-                       return ERR_PTR(err);
+                       ubifs_err(c, "fscrypt_set_context failed: %i", err);
+                       goto out_iput;
                }
        }
 
        return inode;
+
+out_iput:
+       make_bad_inode(inode);
+       iput(inode);
+       return ERR_PTR(err);
 }
 
 static int dbg_check_name(const struct ubifs_info *c,
@@ -515,7 +509,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
                if (err)
                        return err;
 
-               err = fscrypt_fname_alloc_buffer(dir, UBIFS_MAX_NLEN, &fstr);
+               err = fscrypt_fname_alloc_buffer(UBIFS_MAX_NLEN, &fstr);
                if (err)
                        return err;
 
index 22bfda1..6d6cd85 100644 (file)
@@ -269,7 +269,7 @@ void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
                        break;
                /* No more room on heap so make it un-categorized */
                cat = LPROPS_UNCAT;
-               /* Fall through */
+               fallthrough;
        case LPROPS_UNCAT:
                list_add(&lprops->list, &c->uncat_list);
                break;
@@ -313,7 +313,7 @@ static void ubifs_remove_from_cat(struct ubifs_info *c,
        case LPROPS_FREEABLE:
                c->freeable_cnt -= 1;
                ubifs_assert(c, c->freeable_cnt >= 0);
-               /* Fall through */
+               fallthrough;
        case LPROPS_UNCAT:
        case LPROPS_EMPTY:
        case LPROPS_FRDI_IDX:
index 6023c97..25ff91c 100644 (file)
@@ -52,7 +52,7 @@ static int udf_pc_to_char(struct super_block *sb, unsigned char *from,
                                elen += pc->lengthComponentIdent;
                                break;
                        }
-                       /* Fall through */
+                       fallthrough;
                case 2:
                        if (tolen == 0)
                                return -ENAMETOOLONG;
index e1f1b2e..4931bec 100644 (file)
@@ -42,7 +42,7 @@ ufs_get_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1,
        case UFS_ST_SUNOS:
                if (fs32_to_cpu(sb, usb3->fs_postblformat) == UFS_42POSTBLFMT)
                        return fs32_to_cpu(sb, usb1->fs_u0.fs_sun.fs_state);
-               /* Fall Through - to UFS_ST_SUN */
+               fallthrough;    /* to UFS_ST_SUN */
        case UFS_ST_SUN:
                return fs32_to_cpu(sb, usb3->fs_un2.fs_sun.fs_state);
        case UFS_ST_SUNx86:
@@ -63,7 +63,7 @@ ufs_set_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1,
                        usb1->fs_u0.fs_sun.fs_state = cpu_to_fs32(sb, value);
                        break;
                }
-               /* Fall Through - to UFS_ST_SUN */
+               fallthrough;    /* to UFS_ST_SUN */
        case UFS_ST_SUN:
                usb3->fs_un2.fs_sun.fs_state = cpu_to_fs32(sb, value);
                break;
@@ -197,7 +197,7 @@ ufs_get_inode_uid(struct super_block *sb, struct ufs_inode *inode)
        case UFS_UID_EFT:
                if (inode->ui_u1.oldids.ui_suid == 0xFFFF)
                        return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_uid);
-               /* Fall through */
+               fallthrough;
        default:
                return fs16_to_cpu(sb, inode->ui_u1.oldids.ui_suid);
        }
@@ -215,7 +215,7 @@ ufs_set_inode_uid(struct super_block *sb, struct ufs_inode *inode, u32 value)
                inode->ui_u3.ui_sun.ui_uid = cpu_to_fs32(sb, value);
                if (value > 0xFFFF)
                        value = 0xFFFF;
-               /* Fall through */
+               fallthrough;
        default:
                inode->ui_u1.oldids.ui_suid = cpu_to_fs16(sb, value);
                break;
@@ -231,7 +231,7 @@ ufs_get_inode_gid(struct super_block *sb, struct ufs_inode *inode)
        case UFS_UID_EFT:
                if (inode->ui_u1.oldids.ui_sgid == 0xFFFF)
                        return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_gid);
-               /* Fall through */
+               fallthrough;
        default:
                return fs16_to_cpu(sb, inode->ui_u1.oldids.ui_sgid);
        }
@@ -249,7 +249,7 @@ ufs_set_inode_gid(struct super_block *sb, struct ufs_inode *inode, u32 value)
                inode->ui_u3.ui_sun.ui_gid = cpu_to_fs32(sb, value);
                if (value > 0xFFFF)
                        value = 0xFFFF;
-               /* Fall through */
+               fallthrough;
        default:
                inode->ui_u1.oldids.ui_sgid =  cpu_to_fs16(sb, value);
                break;
index 8fe03b4..25aade3 100644 (file)
@@ -384,7 +384,7 @@ fail_nomem:
 
 static int vboxsf_parse_monolithic(struct fs_context *fc, void *data)
 {
-       char *options = data;
+       unsigned char *options = data;
 
        if (options && options[0] == VBSF_MOUNT_SIGNATURE_BYTE_0 &&
                       options[1] == VBSF_MOUNT_SIGNATURE_BYTE_1 &&
index 96bd160..0180575 100644 (file)
@@ -226,7 +226,7 @@ int vboxsf_getattr(const struct path *path, struct kstat *kstat,
                break;
        case AT_STATX_FORCE_SYNC:
                sf_i->force_restat = 1;
-               /* fall-through */
+               fallthrough;
        default:
                err = vboxsf_inode_revalidate(dentry);
        }
index 8623c81..305d4bc 100644 (file)
@@ -653,8 +653,8 @@ xfs_attr_shortform_create(
                ASSERT(ifp->if_flags & XFS_IFINLINE);
        }
        xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK);
-       hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data;
-       hdr->count = 0;
+       hdr = (struct xfs_attr_sf_hdr *)ifp->if_u1.if_data;
+       memset(hdr, 0, sizeof(*hdr));
        hdr->totsize = cpu_to_be16(sizeof(*hdr));
        xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
 }
@@ -1036,8 +1036,10 @@ xfs_attr_shortform_verify(
                 * struct xfs_attr_sf_entry has a variable length.
                 * Check the fixed-offset parts of the structure are
                 * within the data buffer.
+                * xfs_attr_sf_entry is defined with a 1-byte variable
+                * array at the end, so we must subtract that off.
                 */
-               if (((char *)sfep + sizeof(*sfep)) >= endp)
+               if (((char *)sfep + sizeof(*sfep) - 1) >= endp)
                        return __this_address;
 
                /* Don't allow names with known bad length. */
index 9c40d59..1b0a01b 100644 (file)
@@ -6226,7 +6226,7 @@ xfs_bmap_validate_extent(
 
        isrt = XFS_IS_REALTIME_INODE(ip);
        endfsb = irec->br_startblock + irec->br_blockcount - 1;
-       if (isrt) {
+       if (isrt && whichfork == XFS_DATA_FORK) {
                if (!xfs_verify_rtbno(mp, irec->br_startblock))
                        return __this_address;
                if (!xfs_verify_rtbno(mp, endfsb))
index f742a96..a6b37db 100644 (file)
@@ -688,7 +688,7 @@ xfs_ialloc_ag_alloc(
                args.minalignslop = igeo->cluster_align - 1;
 
                /* Allow space for the inode btree to split. */
-               args.minleft = igeo->inobt_maxlevels - 1;
+               args.minleft = igeo->inobt_maxlevels;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
 
@@ -736,7 +736,7 @@ xfs_ialloc_ag_alloc(
                /*
                 * Allow space for the inode btree to split.
                 */
-               args.minleft = igeo->inobt_maxlevels - 1;
+               args.minleft = igeo->inobt_maxlevels;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
        }
index e151296..b7e222b 100644 (file)
@@ -110,9 +110,9 @@ xfs_trans_log_inode(
         * to log the timestamps, or will clear already cleared fields in the
         * worst case.
         */
-       if (inode->i_state & (I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED)) {
+       if (inode->i_state & I_DIRTY_TIME) {
                spin_lock(&inode->i_lock);
-               inode->i_state &= ~(I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED);
+               inode->i_state &= ~I_DIRTY_TIME;
                spin_unlock(&inode->i_lock);
        }
 
index c6df01a..7ad3659 100644 (file)
@@ -58,7 +58,7 @@
 #define        XFS_IALLOC_SPACE_RES(mp)        \
        (M_IGEO(mp)->ialloc_blks + \
         ((xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1) * \
-         (M_IGEO(mp)->inobt_maxlevels - 1)))
+         M_IGEO(mp)->inobt_maxlevels))
 
 /*
  * Space reservation values for various transactions.
index 73cafc8..5123f82 100644 (file)
@@ -1165,7 +1165,7 @@ xfs_insert_file_space(
                goto out_trans_cancel;
 
        do {
-               error = xfs_trans_roll_inode(&tp, ip);
+               error = xfs_defer_finish(&tp);
                if (error)
                        goto out_trans_cancel;
 
index c31cd3b..a29f78a 100644 (file)
@@ -1223,6 +1223,14 @@ __xfs_filemap_fault(
        return ret;
 }
 
+static inline bool
+xfs_is_write_fault(
+       struct vm_fault         *vmf)
+{
+       return (vmf->flags & FAULT_FLAG_WRITE) &&
+              (vmf->vma->vm_flags & VM_SHARED);
+}
+
 static vm_fault_t
 xfs_filemap_fault(
        struct vm_fault         *vmf)
@@ -1230,7 +1238,7 @@ xfs_filemap_fault(
        /* DAX can shortcut the normal fault path on write faults! */
        return __xfs_filemap_fault(vmf, PE_SIZE_PTE,
                        IS_DAX(file_inode(vmf->vma->vm_file)) &&
-                       (vmf->flags & FAULT_FLAG_WRITE));
+                       xfs_is_write_fault(vmf));
 }
 
 static vm_fault_t
@@ -1243,7 +1251,7 @@ xfs_filemap_huge_fault(
 
        /* DAX can shortcut the normal fault path on write faults! */
        return __xfs_filemap_fault(vmf, pe_size,
-                       (vmf->flags & FAULT_FLAG_WRITE));
+                       xfs_is_write_fault(vmf));
 }
 
 static vm_fault_t
index 379986e..cd223b6 100644 (file)
@@ -60,7 +60,7 @@ atomic_set_release(atomic_t *v, int i)
 static __always_inline void
 atomic_add(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_add(i, v);
 }
 #define atomic_add atomic_add
@@ -69,7 +69,7 @@ atomic_add(int i, atomic_t *v)
 static __always_inline int
 atomic_add_return(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_return(i, v);
 }
 #define atomic_add_return atomic_add_return
@@ -79,7 +79,7 @@ atomic_add_return(int i, atomic_t *v)
 static __always_inline int
 atomic_add_return_acquire(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_return_acquire(i, v);
 }
 #define atomic_add_return_acquire atomic_add_return_acquire
@@ -89,7 +89,7 @@ atomic_add_return_acquire(int i, atomic_t *v)
 static __always_inline int
 atomic_add_return_release(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_return_release(i, v);
 }
 #define atomic_add_return_release atomic_add_return_release
@@ -99,7 +99,7 @@ atomic_add_return_release(int i, atomic_t *v)
 static __always_inline int
 atomic_add_return_relaxed(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_return_relaxed(i, v);
 }
 #define atomic_add_return_relaxed atomic_add_return_relaxed
@@ -109,7 +109,7 @@ atomic_add_return_relaxed(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_add(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_add(i, v);
 }
 #define atomic_fetch_add atomic_fetch_add
@@ -119,7 +119,7 @@ atomic_fetch_add(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_add_acquire(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_add_acquire(i, v);
 }
 #define atomic_fetch_add_acquire atomic_fetch_add_acquire
@@ -129,7 +129,7 @@ atomic_fetch_add_acquire(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_add_release(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_add_release(i, v);
 }
 #define atomic_fetch_add_release atomic_fetch_add_release
@@ -139,7 +139,7 @@ atomic_fetch_add_release(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_add_relaxed(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_add_relaxed(i, v);
 }
 #define atomic_fetch_add_relaxed atomic_fetch_add_relaxed
@@ -148,7 +148,7 @@ atomic_fetch_add_relaxed(int i, atomic_t *v)
 static __always_inline void
 atomic_sub(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_sub(i, v);
 }
 #define atomic_sub atomic_sub
@@ -157,7 +157,7 @@ atomic_sub(int i, atomic_t *v)
 static __always_inline int
 atomic_sub_return(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_sub_return(i, v);
 }
 #define atomic_sub_return atomic_sub_return
@@ -167,7 +167,7 @@ atomic_sub_return(int i, atomic_t *v)
 static __always_inline int
 atomic_sub_return_acquire(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_sub_return_acquire(i, v);
 }
 #define atomic_sub_return_acquire atomic_sub_return_acquire
@@ -177,7 +177,7 @@ atomic_sub_return_acquire(int i, atomic_t *v)
 static __always_inline int
 atomic_sub_return_release(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_sub_return_release(i, v);
 }
 #define atomic_sub_return_release atomic_sub_return_release
@@ -187,7 +187,7 @@ atomic_sub_return_release(int i, atomic_t *v)
 static __always_inline int
 atomic_sub_return_relaxed(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_sub_return_relaxed(i, v);
 }
 #define atomic_sub_return_relaxed atomic_sub_return_relaxed
@@ -197,7 +197,7 @@ atomic_sub_return_relaxed(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_sub(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_sub(i, v);
 }
 #define atomic_fetch_sub atomic_fetch_sub
@@ -207,7 +207,7 @@ atomic_fetch_sub(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_sub_acquire(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_sub_acquire(i, v);
 }
 #define atomic_fetch_sub_acquire atomic_fetch_sub_acquire
@@ -217,7 +217,7 @@ atomic_fetch_sub_acquire(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_sub_release(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_sub_release(i, v);
 }
 #define atomic_fetch_sub_release atomic_fetch_sub_release
@@ -227,7 +227,7 @@ atomic_fetch_sub_release(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_sub_relaxed(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_sub_relaxed(i, v);
 }
 #define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed
@@ -237,7 +237,7 @@ atomic_fetch_sub_relaxed(int i, atomic_t *v)
 static __always_inline void
 atomic_inc(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_inc(v);
 }
 #define atomic_inc atomic_inc
@@ -247,7 +247,7 @@ atomic_inc(atomic_t *v)
 static __always_inline int
 atomic_inc_return(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_return(v);
 }
 #define atomic_inc_return atomic_inc_return
@@ -257,7 +257,7 @@ atomic_inc_return(atomic_t *v)
 static __always_inline int
 atomic_inc_return_acquire(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_return_acquire(v);
 }
 #define atomic_inc_return_acquire atomic_inc_return_acquire
@@ -267,7 +267,7 @@ atomic_inc_return_acquire(atomic_t *v)
 static __always_inline int
 atomic_inc_return_release(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_return_release(v);
 }
 #define atomic_inc_return_release atomic_inc_return_release
@@ -277,7 +277,7 @@ atomic_inc_return_release(atomic_t *v)
 static __always_inline int
 atomic_inc_return_relaxed(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_return_relaxed(v);
 }
 #define atomic_inc_return_relaxed atomic_inc_return_relaxed
@@ -287,7 +287,7 @@ atomic_inc_return_relaxed(atomic_t *v)
 static __always_inline int
 atomic_fetch_inc(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_inc(v);
 }
 #define atomic_fetch_inc atomic_fetch_inc
@@ -297,7 +297,7 @@ atomic_fetch_inc(atomic_t *v)
 static __always_inline int
 atomic_fetch_inc_acquire(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_inc_acquire(v);
 }
 #define atomic_fetch_inc_acquire atomic_fetch_inc_acquire
@@ -307,7 +307,7 @@ atomic_fetch_inc_acquire(atomic_t *v)
 static __always_inline int
 atomic_fetch_inc_release(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_inc_release(v);
 }
 #define atomic_fetch_inc_release atomic_fetch_inc_release
@@ -317,7 +317,7 @@ atomic_fetch_inc_release(atomic_t *v)
 static __always_inline int
 atomic_fetch_inc_relaxed(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_inc_relaxed(v);
 }
 #define atomic_fetch_inc_relaxed atomic_fetch_inc_relaxed
@@ -327,7 +327,7 @@ atomic_fetch_inc_relaxed(atomic_t *v)
 static __always_inline void
 atomic_dec(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_dec(v);
 }
 #define atomic_dec atomic_dec
@@ -337,7 +337,7 @@ atomic_dec(atomic_t *v)
 static __always_inline int
 atomic_dec_return(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_return(v);
 }
 #define atomic_dec_return atomic_dec_return
@@ -347,7 +347,7 @@ atomic_dec_return(atomic_t *v)
 static __always_inline int
 atomic_dec_return_acquire(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_return_acquire(v);
 }
 #define atomic_dec_return_acquire atomic_dec_return_acquire
@@ -357,7 +357,7 @@ atomic_dec_return_acquire(atomic_t *v)
 static __always_inline int
 atomic_dec_return_release(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_return_release(v);
 }
 #define atomic_dec_return_release atomic_dec_return_release
@@ -367,7 +367,7 @@ atomic_dec_return_release(atomic_t *v)
 static __always_inline int
 atomic_dec_return_relaxed(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_return_relaxed(v);
 }
 #define atomic_dec_return_relaxed atomic_dec_return_relaxed
@@ -377,7 +377,7 @@ atomic_dec_return_relaxed(atomic_t *v)
 static __always_inline int
 atomic_fetch_dec(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_dec(v);
 }
 #define atomic_fetch_dec atomic_fetch_dec
@@ -387,7 +387,7 @@ atomic_fetch_dec(atomic_t *v)
 static __always_inline int
 atomic_fetch_dec_acquire(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_dec_acquire(v);
 }
 #define atomic_fetch_dec_acquire atomic_fetch_dec_acquire
@@ -397,7 +397,7 @@ atomic_fetch_dec_acquire(atomic_t *v)
 static __always_inline int
 atomic_fetch_dec_release(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_dec_release(v);
 }
 #define atomic_fetch_dec_release atomic_fetch_dec_release
@@ -407,7 +407,7 @@ atomic_fetch_dec_release(atomic_t *v)
 static __always_inline int
 atomic_fetch_dec_relaxed(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_dec_relaxed(v);
 }
 #define atomic_fetch_dec_relaxed atomic_fetch_dec_relaxed
@@ -416,7 +416,7 @@ atomic_fetch_dec_relaxed(atomic_t *v)
 static __always_inline void
 atomic_and(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_and(i, v);
 }
 #define atomic_and atomic_and
@@ -425,7 +425,7 @@ atomic_and(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_and(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_and(i, v);
 }
 #define atomic_fetch_and atomic_fetch_and
@@ -435,7 +435,7 @@ atomic_fetch_and(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_and_acquire(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_and_acquire(i, v);
 }
 #define atomic_fetch_and_acquire atomic_fetch_and_acquire
@@ -445,7 +445,7 @@ atomic_fetch_and_acquire(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_and_release(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_and_release(i, v);
 }
 #define atomic_fetch_and_release atomic_fetch_and_release
@@ -455,7 +455,7 @@ atomic_fetch_and_release(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_and_relaxed(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_and_relaxed(i, v);
 }
 #define atomic_fetch_and_relaxed atomic_fetch_and_relaxed
@@ -465,7 +465,7 @@ atomic_fetch_and_relaxed(int i, atomic_t *v)
 static __always_inline void
 atomic_andnot(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_andnot(i, v);
 }
 #define atomic_andnot atomic_andnot
@@ -475,7 +475,7 @@ atomic_andnot(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_andnot(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_andnot(i, v);
 }
 #define atomic_fetch_andnot atomic_fetch_andnot
@@ -485,7 +485,7 @@ atomic_fetch_andnot(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_andnot_acquire(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_andnot_acquire(i, v);
 }
 #define atomic_fetch_andnot_acquire atomic_fetch_andnot_acquire
@@ -495,7 +495,7 @@ atomic_fetch_andnot_acquire(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_andnot_release(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_andnot_release(i, v);
 }
 #define atomic_fetch_andnot_release atomic_fetch_andnot_release
@@ -505,7 +505,7 @@ atomic_fetch_andnot_release(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_andnot_relaxed(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_andnot_relaxed(i, v);
 }
 #define atomic_fetch_andnot_relaxed atomic_fetch_andnot_relaxed
@@ -514,7 +514,7 @@ atomic_fetch_andnot_relaxed(int i, atomic_t *v)
 static __always_inline void
 atomic_or(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_or(i, v);
 }
 #define atomic_or atomic_or
@@ -523,7 +523,7 @@ atomic_or(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_or(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_or(i, v);
 }
 #define atomic_fetch_or atomic_fetch_or
@@ -533,7 +533,7 @@ atomic_fetch_or(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_or_acquire(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_or_acquire(i, v);
 }
 #define atomic_fetch_or_acquire atomic_fetch_or_acquire
@@ -543,7 +543,7 @@ atomic_fetch_or_acquire(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_or_release(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_or_release(i, v);
 }
 #define atomic_fetch_or_release atomic_fetch_or_release
@@ -553,7 +553,7 @@ atomic_fetch_or_release(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_or_relaxed(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_or_relaxed(i, v);
 }
 #define atomic_fetch_or_relaxed atomic_fetch_or_relaxed
@@ -562,7 +562,7 @@ atomic_fetch_or_relaxed(int i, atomic_t *v)
 static __always_inline void
 atomic_xor(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_xor(i, v);
 }
 #define atomic_xor atomic_xor
@@ -571,7 +571,7 @@ atomic_xor(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_xor(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_xor(i, v);
 }
 #define atomic_fetch_xor atomic_fetch_xor
@@ -581,7 +581,7 @@ atomic_fetch_xor(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_xor_acquire(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_xor_acquire(i, v);
 }
 #define atomic_fetch_xor_acquire atomic_fetch_xor_acquire
@@ -591,7 +591,7 @@ atomic_fetch_xor_acquire(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_xor_release(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_xor_release(i, v);
 }
 #define atomic_fetch_xor_release atomic_fetch_xor_release
@@ -601,7 +601,7 @@ atomic_fetch_xor_release(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_xor_relaxed(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_xor_relaxed(i, v);
 }
 #define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed
@@ -611,7 +611,7 @@ atomic_fetch_xor_relaxed(int i, atomic_t *v)
 static __always_inline int
 atomic_xchg(atomic_t *v, int i)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_xchg(v, i);
 }
 #define atomic_xchg atomic_xchg
@@ -621,7 +621,7 @@ atomic_xchg(atomic_t *v, int i)
 static __always_inline int
 atomic_xchg_acquire(atomic_t *v, int i)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_xchg_acquire(v, i);
 }
 #define atomic_xchg_acquire atomic_xchg_acquire
@@ -631,7 +631,7 @@ atomic_xchg_acquire(atomic_t *v, int i)
 static __always_inline int
 atomic_xchg_release(atomic_t *v, int i)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_xchg_release(v, i);
 }
 #define atomic_xchg_release atomic_xchg_release
@@ -641,7 +641,7 @@ atomic_xchg_release(atomic_t *v, int i)
 static __always_inline int
 atomic_xchg_relaxed(atomic_t *v, int i)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_xchg_relaxed(v, i);
 }
 #define atomic_xchg_relaxed atomic_xchg_relaxed
@@ -651,7 +651,7 @@ atomic_xchg_relaxed(atomic_t *v, int i)
 static __always_inline int
 atomic_cmpxchg(atomic_t *v, int old, int new)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_cmpxchg(v, old, new);
 }
 #define atomic_cmpxchg atomic_cmpxchg
@@ -661,7 +661,7 @@ atomic_cmpxchg(atomic_t *v, int old, int new)
 static __always_inline int
 atomic_cmpxchg_acquire(atomic_t *v, int old, int new)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_cmpxchg_acquire(v, old, new);
 }
 #define atomic_cmpxchg_acquire atomic_cmpxchg_acquire
@@ -671,7 +671,7 @@ atomic_cmpxchg_acquire(atomic_t *v, int old, int new)
 static __always_inline int
 atomic_cmpxchg_release(atomic_t *v, int old, int new)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_cmpxchg_release(v, old, new);
 }
 #define atomic_cmpxchg_release atomic_cmpxchg_release
@@ -681,7 +681,7 @@ atomic_cmpxchg_release(atomic_t *v, int old, int new)
 static __always_inline int
 atomic_cmpxchg_relaxed(atomic_t *v, int old, int new)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_cmpxchg_relaxed(v, old, new);
 }
 #define atomic_cmpxchg_relaxed atomic_cmpxchg_relaxed
@@ -691,8 +691,8 @@ atomic_cmpxchg_relaxed(atomic_t *v, int old, int new)
 static __always_inline bool
 atomic_try_cmpxchg(atomic_t *v, int *old, int new)
 {
-       instrument_atomic_write(v, sizeof(*v));
-       instrument_atomic_write(old, sizeof(*old));
+       instrument_atomic_read_write(v, sizeof(*v));
+       instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic_try_cmpxchg(v, old, new);
 }
 #define atomic_try_cmpxchg atomic_try_cmpxchg
@@ -702,8 +702,8 @@ atomic_try_cmpxchg(atomic_t *v, int *old, int new)
 static __always_inline bool
 atomic_try_cmpxchg_acquire(atomic_t *v, int *old, int new)
 {
-       instrument_atomic_write(v, sizeof(*v));
-       instrument_atomic_write(old, sizeof(*old));
+       instrument_atomic_read_write(v, sizeof(*v));
+       instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic_try_cmpxchg_acquire(v, old, new);
 }
 #define atomic_try_cmpxchg_acquire atomic_try_cmpxchg_acquire
@@ -713,8 +713,8 @@ atomic_try_cmpxchg_acquire(atomic_t *v, int *old, int new)
 static __always_inline bool
 atomic_try_cmpxchg_release(atomic_t *v, int *old, int new)
 {
-       instrument_atomic_write(v, sizeof(*v));
-       instrument_atomic_write(old, sizeof(*old));
+       instrument_atomic_read_write(v, sizeof(*v));
+       instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic_try_cmpxchg_release(v, old, new);
 }
 #define atomic_try_cmpxchg_release atomic_try_cmpxchg_release
@@ -724,8 +724,8 @@ atomic_try_cmpxchg_release(atomic_t *v, int *old, int new)
 static __always_inline bool
 atomic_try_cmpxchg_relaxed(atomic_t *v, int *old, int new)
 {
-       instrument_atomic_write(v, sizeof(*v));
-       instrument_atomic_write(old, sizeof(*old));
+       instrument_atomic_read_write(v, sizeof(*v));
+       instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic_try_cmpxchg_relaxed(v, old, new);
 }
 #define atomic_try_cmpxchg_relaxed atomic_try_cmpxchg_relaxed
@@ -735,7 +735,7 @@ atomic_try_cmpxchg_relaxed(atomic_t *v, int *old, int new)
 static __always_inline bool
 atomic_sub_and_test(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_sub_and_test(i, v);
 }
 #define atomic_sub_and_test atomic_sub_and_test
@@ -745,7 +745,7 @@ atomic_sub_and_test(int i, atomic_t *v)
 static __always_inline bool
 atomic_dec_and_test(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_and_test(v);
 }
 #define atomic_dec_and_test atomic_dec_and_test
@@ -755,7 +755,7 @@ atomic_dec_and_test(atomic_t *v)
 static __always_inline bool
 atomic_inc_and_test(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_and_test(v);
 }
 #define atomic_inc_and_test atomic_inc_and_test
@@ -765,7 +765,7 @@ atomic_inc_and_test(atomic_t *v)
 static __always_inline bool
 atomic_add_negative(int i, atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_negative(i, v);
 }
 #define atomic_add_negative atomic_add_negative
@@ -775,7 +775,7 @@ atomic_add_negative(int i, atomic_t *v)
 static __always_inline int
 atomic_fetch_add_unless(atomic_t *v, int a, int u)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_add_unless(v, a, u);
 }
 #define atomic_fetch_add_unless atomic_fetch_add_unless
@@ -785,7 +785,7 @@ atomic_fetch_add_unless(atomic_t *v, int a, int u)
 static __always_inline bool
 atomic_add_unless(atomic_t *v, int a, int u)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_unless(v, a, u);
 }
 #define atomic_add_unless atomic_add_unless
@@ -795,7 +795,7 @@ atomic_add_unless(atomic_t *v, int a, int u)
 static __always_inline bool
 atomic_inc_not_zero(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_not_zero(v);
 }
 #define atomic_inc_not_zero atomic_inc_not_zero
@@ -805,7 +805,7 @@ atomic_inc_not_zero(atomic_t *v)
 static __always_inline bool
 atomic_inc_unless_negative(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_unless_negative(v);
 }
 #define atomic_inc_unless_negative atomic_inc_unless_negative
@@ -815,7 +815,7 @@ atomic_inc_unless_negative(atomic_t *v)
 static __always_inline bool
 atomic_dec_unless_positive(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_unless_positive(v);
 }
 #define atomic_dec_unless_positive atomic_dec_unless_positive
@@ -825,7 +825,7 @@ atomic_dec_unless_positive(atomic_t *v)
 static __always_inline int
 atomic_dec_if_positive(atomic_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_if_positive(v);
 }
 #define atomic_dec_if_positive atomic_dec_if_positive
@@ -870,7 +870,7 @@ atomic64_set_release(atomic64_t *v, s64 i)
 static __always_inline void
 atomic64_add(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_add(i, v);
 }
 #define atomic64_add atomic64_add
@@ -879,7 +879,7 @@ atomic64_add(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_add_return(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_return(i, v);
 }
 #define atomic64_add_return atomic64_add_return
@@ -889,7 +889,7 @@ atomic64_add_return(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_add_return_acquire(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_return_acquire(i, v);
 }
 #define atomic64_add_return_acquire atomic64_add_return_acquire
@@ -899,7 +899,7 @@ atomic64_add_return_acquire(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_add_return_release(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_return_release(i, v);
 }
 #define atomic64_add_return_release atomic64_add_return_release
@@ -909,7 +909,7 @@ atomic64_add_return_release(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_add_return_relaxed(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_return_relaxed(i, v);
 }
 #define atomic64_add_return_relaxed atomic64_add_return_relaxed
@@ -919,7 +919,7 @@ atomic64_add_return_relaxed(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_add(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_add(i, v);
 }
 #define atomic64_fetch_add atomic64_fetch_add
@@ -929,7 +929,7 @@ atomic64_fetch_add(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_add_acquire(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_add_acquire(i, v);
 }
 #define atomic64_fetch_add_acquire atomic64_fetch_add_acquire
@@ -939,7 +939,7 @@ atomic64_fetch_add_acquire(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_add_release(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_add_release(i, v);
 }
 #define atomic64_fetch_add_release atomic64_fetch_add_release
@@ -949,7 +949,7 @@ atomic64_fetch_add_release(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_add_relaxed(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_add_relaxed(i, v);
 }
 #define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed
@@ -958,7 +958,7 @@ atomic64_fetch_add_relaxed(s64 i, atomic64_t *v)
 static __always_inline void
 atomic64_sub(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_sub(i, v);
 }
 #define atomic64_sub atomic64_sub
@@ -967,7 +967,7 @@ atomic64_sub(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_sub_return(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_sub_return(i, v);
 }
 #define atomic64_sub_return atomic64_sub_return
@@ -977,7 +977,7 @@ atomic64_sub_return(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_sub_return_acquire(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_sub_return_acquire(i, v);
 }
 #define atomic64_sub_return_acquire atomic64_sub_return_acquire
@@ -987,7 +987,7 @@ atomic64_sub_return_acquire(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_sub_return_release(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_sub_return_release(i, v);
 }
 #define atomic64_sub_return_release atomic64_sub_return_release
@@ -997,7 +997,7 @@ atomic64_sub_return_release(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_sub_return_relaxed(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_sub_return_relaxed(i, v);
 }
 #define atomic64_sub_return_relaxed atomic64_sub_return_relaxed
@@ -1007,7 +1007,7 @@ atomic64_sub_return_relaxed(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_sub(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_sub(i, v);
 }
 #define atomic64_fetch_sub atomic64_fetch_sub
@@ -1017,7 +1017,7 @@ atomic64_fetch_sub(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_sub_acquire(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_sub_acquire(i, v);
 }
 #define atomic64_fetch_sub_acquire atomic64_fetch_sub_acquire
@@ -1027,7 +1027,7 @@ atomic64_fetch_sub_acquire(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_sub_release(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_sub_release(i, v);
 }
 #define atomic64_fetch_sub_release atomic64_fetch_sub_release
@@ -1037,7 +1037,7 @@ atomic64_fetch_sub_release(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_sub_relaxed(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_sub_relaxed(i, v);
 }
 #define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed
@@ -1047,7 +1047,7 @@ atomic64_fetch_sub_relaxed(s64 i, atomic64_t *v)
 static __always_inline void
 atomic64_inc(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_inc(v);
 }
 #define atomic64_inc atomic64_inc
@@ -1057,7 +1057,7 @@ atomic64_inc(atomic64_t *v)
 static __always_inline s64
 atomic64_inc_return(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_return(v);
 }
 #define atomic64_inc_return atomic64_inc_return
@@ -1067,7 +1067,7 @@ atomic64_inc_return(atomic64_t *v)
 static __always_inline s64
 atomic64_inc_return_acquire(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_return_acquire(v);
 }
 #define atomic64_inc_return_acquire atomic64_inc_return_acquire
@@ -1077,7 +1077,7 @@ atomic64_inc_return_acquire(atomic64_t *v)
 static __always_inline s64
 atomic64_inc_return_release(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_return_release(v);
 }
 #define atomic64_inc_return_release atomic64_inc_return_release
@@ -1087,7 +1087,7 @@ atomic64_inc_return_release(atomic64_t *v)
 static __always_inline s64
 atomic64_inc_return_relaxed(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_return_relaxed(v);
 }
 #define atomic64_inc_return_relaxed atomic64_inc_return_relaxed
@@ -1097,7 +1097,7 @@ atomic64_inc_return_relaxed(atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_inc(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_inc(v);
 }
 #define atomic64_fetch_inc atomic64_fetch_inc
@@ -1107,7 +1107,7 @@ atomic64_fetch_inc(atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_inc_acquire(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_inc_acquire(v);
 }
 #define atomic64_fetch_inc_acquire atomic64_fetch_inc_acquire
@@ -1117,7 +1117,7 @@ atomic64_fetch_inc_acquire(atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_inc_release(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_inc_release(v);
 }
 #define atomic64_fetch_inc_release atomic64_fetch_inc_release
@@ -1127,7 +1127,7 @@ atomic64_fetch_inc_release(atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_inc_relaxed(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_inc_relaxed(v);
 }
 #define atomic64_fetch_inc_relaxed atomic64_fetch_inc_relaxed
@@ -1137,7 +1137,7 @@ atomic64_fetch_inc_relaxed(atomic64_t *v)
 static __always_inline void
 atomic64_dec(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_dec(v);
 }
 #define atomic64_dec atomic64_dec
@@ -1147,7 +1147,7 @@ atomic64_dec(atomic64_t *v)
 static __always_inline s64
 atomic64_dec_return(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_return(v);
 }
 #define atomic64_dec_return atomic64_dec_return
@@ -1157,7 +1157,7 @@ atomic64_dec_return(atomic64_t *v)
 static __always_inline s64
 atomic64_dec_return_acquire(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_return_acquire(v);
 }
 #define atomic64_dec_return_acquire atomic64_dec_return_acquire
@@ -1167,7 +1167,7 @@ atomic64_dec_return_acquire(atomic64_t *v)
 static __always_inline s64
 atomic64_dec_return_release(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_return_release(v);
 }
 #define atomic64_dec_return_release atomic64_dec_return_release
@@ -1177,7 +1177,7 @@ atomic64_dec_return_release(atomic64_t *v)
 static __always_inline s64
 atomic64_dec_return_relaxed(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_return_relaxed(v);
 }
 #define atomic64_dec_return_relaxed atomic64_dec_return_relaxed
@@ -1187,7 +1187,7 @@ atomic64_dec_return_relaxed(atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_dec(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_dec(v);
 }
 #define atomic64_fetch_dec atomic64_fetch_dec
@@ -1197,7 +1197,7 @@ atomic64_fetch_dec(atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_dec_acquire(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_dec_acquire(v);
 }
 #define atomic64_fetch_dec_acquire atomic64_fetch_dec_acquire
@@ -1207,7 +1207,7 @@ atomic64_fetch_dec_acquire(atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_dec_release(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_dec_release(v);
 }
 #define atomic64_fetch_dec_release atomic64_fetch_dec_release
@@ -1217,7 +1217,7 @@ atomic64_fetch_dec_release(atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_dec_relaxed(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_dec_relaxed(v);
 }
 #define atomic64_fetch_dec_relaxed atomic64_fetch_dec_relaxed
@@ -1226,7 +1226,7 @@ atomic64_fetch_dec_relaxed(atomic64_t *v)
 static __always_inline void
 atomic64_and(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_and(i, v);
 }
 #define atomic64_and atomic64_and
@@ -1235,7 +1235,7 @@ atomic64_and(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_and(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_and(i, v);
 }
 #define atomic64_fetch_and atomic64_fetch_and
@@ -1245,7 +1245,7 @@ atomic64_fetch_and(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_and_acquire(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_and_acquire(i, v);
 }
 #define atomic64_fetch_and_acquire atomic64_fetch_and_acquire
@@ -1255,7 +1255,7 @@ atomic64_fetch_and_acquire(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_and_release(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_and_release(i, v);
 }
 #define atomic64_fetch_and_release atomic64_fetch_and_release
@@ -1265,7 +1265,7 @@ atomic64_fetch_and_release(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_and_relaxed(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_and_relaxed(i, v);
 }
 #define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed
@@ -1275,7 +1275,7 @@ atomic64_fetch_and_relaxed(s64 i, atomic64_t *v)
 static __always_inline void
 atomic64_andnot(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_andnot(i, v);
 }
 #define atomic64_andnot atomic64_andnot
@@ -1285,7 +1285,7 @@ atomic64_andnot(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_andnot(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_andnot(i, v);
 }
 #define atomic64_fetch_andnot atomic64_fetch_andnot
@@ -1295,7 +1295,7 @@ atomic64_fetch_andnot(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_andnot_acquire(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_andnot_acquire(i, v);
 }
 #define atomic64_fetch_andnot_acquire atomic64_fetch_andnot_acquire
@@ -1305,7 +1305,7 @@ atomic64_fetch_andnot_acquire(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_andnot_release(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_andnot_release(i, v);
 }
 #define atomic64_fetch_andnot_release atomic64_fetch_andnot_release
@@ -1315,7 +1315,7 @@ atomic64_fetch_andnot_release(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_andnot_relaxed(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_andnot_relaxed(i, v);
 }
 #define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot_relaxed
@@ -1324,7 +1324,7 @@ atomic64_fetch_andnot_relaxed(s64 i, atomic64_t *v)
 static __always_inline void
 atomic64_or(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_or(i, v);
 }
 #define atomic64_or atomic64_or
@@ -1333,7 +1333,7 @@ atomic64_or(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_or(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_or(i, v);
 }
 #define atomic64_fetch_or atomic64_fetch_or
@@ -1343,7 +1343,7 @@ atomic64_fetch_or(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_or_acquire(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_or_acquire(i, v);
 }
 #define atomic64_fetch_or_acquire atomic64_fetch_or_acquire
@@ -1353,7 +1353,7 @@ atomic64_fetch_or_acquire(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_or_release(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_or_release(i, v);
 }
 #define atomic64_fetch_or_release atomic64_fetch_or_release
@@ -1363,7 +1363,7 @@ atomic64_fetch_or_release(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_or_relaxed(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_or_relaxed(i, v);
 }
 #define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed
@@ -1372,7 +1372,7 @@ atomic64_fetch_or_relaxed(s64 i, atomic64_t *v)
 static __always_inline void
 atomic64_xor(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_xor(i, v);
 }
 #define atomic64_xor atomic64_xor
@@ -1381,7 +1381,7 @@ atomic64_xor(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_xor(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_xor(i, v);
 }
 #define atomic64_fetch_xor atomic64_fetch_xor
@@ -1391,7 +1391,7 @@ atomic64_fetch_xor(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_xor_acquire(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_xor_acquire(i, v);
 }
 #define atomic64_fetch_xor_acquire atomic64_fetch_xor_acquire
@@ -1401,7 +1401,7 @@ atomic64_fetch_xor_acquire(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_xor_release(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_xor_release(i, v);
 }
 #define atomic64_fetch_xor_release atomic64_fetch_xor_release
@@ -1411,7 +1411,7 @@ atomic64_fetch_xor_release(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_xor_relaxed(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_xor_relaxed(i, v);
 }
 #define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed
@@ -1421,7 +1421,7 @@ atomic64_fetch_xor_relaxed(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_xchg(atomic64_t *v, s64 i)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_xchg(v, i);
 }
 #define atomic64_xchg atomic64_xchg
@@ -1431,7 +1431,7 @@ atomic64_xchg(atomic64_t *v, s64 i)
 static __always_inline s64
 atomic64_xchg_acquire(atomic64_t *v, s64 i)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_xchg_acquire(v, i);
 }
 #define atomic64_xchg_acquire atomic64_xchg_acquire
@@ -1441,7 +1441,7 @@ atomic64_xchg_acquire(atomic64_t *v, s64 i)
 static __always_inline s64
 atomic64_xchg_release(atomic64_t *v, s64 i)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_xchg_release(v, i);
 }
 #define atomic64_xchg_release atomic64_xchg_release
@@ -1451,7 +1451,7 @@ atomic64_xchg_release(atomic64_t *v, s64 i)
 static __always_inline s64
 atomic64_xchg_relaxed(atomic64_t *v, s64 i)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_xchg_relaxed(v, i);
 }
 #define atomic64_xchg_relaxed atomic64_xchg_relaxed
@@ -1461,7 +1461,7 @@ atomic64_xchg_relaxed(atomic64_t *v, s64 i)
 static __always_inline s64
 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_cmpxchg(v, old, new);
 }
 #define atomic64_cmpxchg atomic64_cmpxchg
@@ -1471,7 +1471,7 @@ atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
 static __always_inline s64
 atomic64_cmpxchg_acquire(atomic64_t *v, s64 old, s64 new)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_cmpxchg_acquire(v, old, new);
 }
 #define atomic64_cmpxchg_acquire atomic64_cmpxchg_acquire
@@ -1481,7 +1481,7 @@ atomic64_cmpxchg_acquire(atomic64_t *v, s64 old, s64 new)
 static __always_inline s64
 atomic64_cmpxchg_release(atomic64_t *v, s64 old, s64 new)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_cmpxchg_release(v, old, new);
 }
 #define atomic64_cmpxchg_release atomic64_cmpxchg_release
@@ -1491,7 +1491,7 @@ atomic64_cmpxchg_release(atomic64_t *v, s64 old, s64 new)
 static __always_inline s64
 atomic64_cmpxchg_relaxed(atomic64_t *v, s64 old, s64 new)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_cmpxchg_relaxed(v, old, new);
 }
 #define atomic64_cmpxchg_relaxed atomic64_cmpxchg_relaxed
@@ -1501,8 +1501,8 @@ atomic64_cmpxchg_relaxed(atomic64_t *v, s64 old, s64 new)
 static __always_inline bool
 atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
 {
-       instrument_atomic_write(v, sizeof(*v));
-       instrument_atomic_write(old, sizeof(*old));
+       instrument_atomic_read_write(v, sizeof(*v));
+       instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic64_try_cmpxchg(v, old, new);
 }
 #define atomic64_try_cmpxchg atomic64_try_cmpxchg
@@ -1512,8 +1512,8 @@ atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
 static __always_inline bool
 atomic64_try_cmpxchg_acquire(atomic64_t *v, s64 *old, s64 new)
 {
-       instrument_atomic_write(v, sizeof(*v));
-       instrument_atomic_write(old, sizeof(*old));
+       instrument_atomic_read_write(v, sizeof(*v));
+       instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic64_try_cmpxchg_acquire(v, old, new);
 }
 #define atomic64_try_cmpxchg_acquire atomic64_try_cmpxchg_acquire
@@ -1523,8 +1523,8 @@ atomic64_try_cmpxchg_acquire(atomic64_t *v, s64 *old, s64 new)
 static __always_inline bool
 atomic64_try_cmpxchg_release(atomic64_t *v, s64 *old, s64 new)
 {
-       instrument_atomic_write(v, sizeof(*v));
-       instrument_atomic_write(old, sizeof(*old));
+       instrument_atomic_read_write(v, sizeof(*v));
+       instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic64_try_cmpxchg_release(v, old, new);
 }
 #define atomic64_try_cmpxchg_release atomic64_try_cmpxchg_release
@@ -1534,8 +1534,8 @@ atomic64_try_cmpxchg_release(atomic64_t *v, s64 *old, s64 new)
 static __always_inline bool
 atomic64_try_cmpxchg_relaxed(atomic64_t *v, s64 *old, s64 new)
 {
-       instrument_atomic_write(v, sizeof(*v));
-       instrument_atomic_write(old, sizeof(*old));
+       instrument_atomic_read_write(v, sizeof(*v));
+       instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic64_try_cmpxchg_relaxed(v, old, new);
 }
 #define atomic64_try_cmpxchg_relaxed atomic64_try_cmpxchg_relaxed
@@ -1545,7 +1545,7 @@ atomic64_try_cmpxchg_relaxed(atomic64_t *v, s64 *old, s64 new)
 static __always_inline bool
 atomic64_sub_and_test(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_sub_and_test(i, v);
 }
 #define atomic64_sub_and_test atomic64_sub_and_test
@@ -1555,7 +1555,7 @@ atomic64_sub_and_test(s64 i, atomic64_t *v)
 static __always_inline bool
 atomic64_dec_and_test(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_and_test(v);
 }
 #define atomic64_dec_and_test atomic64_dec_and_test
@@ -1565,7 +1565,7 @@ atomic64_dec_and_test(atomic64_t *v)
 static __always_inline bool
 atomic64_inc_and_test(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_and_test(v);
 }
 #define atomic64_inc_and_test atomic64_inc_and_test
@@ -1575,7 +1575,7 @@ atomic64_inc_and_test(atomic64_t *v)
 static __always_inline bool
 atomic64_add_negative(s64 i, atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_negative(i, v);
 }
 #define atomic64_add_negative atomic64_add_negative
@@ -1585,7 +1585,7 @@ atomic64_add_negative(s64 i, atomic64_t *v)
 static __always_inline s64
 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_add_unless(v, a, u);
 }
 #define atomic64_fetch_add_unless atomic64_fetch_add_unless
@@ -1595,7 +1595,7 @@ atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 static __always_inline bool
 atomic64_add_unless(atomic64_t *v, s64 a, s64 u)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_unless(v, a, u);
 }
 #define atomic64_add_unless atomic64_add_unless
@@ -1605,7 +1605,7 @@ atomic64_add_unless(atomic64_t *v, s64 a, s64 u)
 static __always_inline bool
 atomic64_inc_not_zero(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_not_zero(v);
 }
 #define atomic64_inc_not_zero atomic64_inc_not_zero
@@ -1615,7 +1615,7 @@ atomic64_inc_not_zero(atomic64_t *v)
 static __always_inline bool
 atomic64_inc_unless_negative(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_unless_negative(v);
 }
 #define atomic64_inc_unless_negative atomic64_inc_unless_negative
@@ -1625,7 +1625,7 @@ atomic64_inc_unless_negative(atomic64_t *v)
 static __always_inline bool
 atomic64_dec_unless_positive(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_unless_positive(v);
 }
 #define atomic64_dec_unless_positive atomic64_dec_unless_positive
@@ -1635,7 +1635,7 @@ atomic64_dec_unless_positive(atomic64_t *v)
 static __always_inline s64
 atomic64_dec_if_positive(atomic64_t *v)
 {
-       instrument_atomic_write(v, sizeof(*v));
+       instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_if_positive(v);
 }
 #define atomic64_dec_if_positive atomic64_dec_if_positive
@@ -1786,4 +1786,4 @@ atomic64_dec_if_positive(atomic64_t *v)
 })
 
 #endif /* _ASM_GENERIC_ATOMIC_INSTRUMENTED_H */
-// 89bf97f3a7509b740845e51ddf31055b48a81f40
+// 9d5e6a315fb1335d02f0ccd3655a91c3dafcc63e
index fb2cb33..81915dc 100644 (file)
@@ -67,7 +67,7 @@ static inline void change_bit(long nr, volatile unsigned long *addr)
  */
 static inline bool test_and_set_bit(long nr, volatile unsigned long *addr)
 {
-       instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
+       instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
        return arch_test_and_set_bit(nr, addr);
 }
 
@@ -80,7 +80,7 @@ static inline bool test_and_set_bit(long nr, volatile unsigned long *addr)
  */
 static inline bool test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
-       instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
+       instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
        return arch_test_and_clear_bit(nr, addr);
 }
 
@@ -93,7 +93,7 @@ static inline bool test_and_clear_bit(long nr, volatile unsigned long *addr)
  */
 static inline bool test_and_change_bit(long nr, volatile unsigned long *addr)
 {
-       instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
+       instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
        return arch_test_and_change_bit(nr, addr);
 }
 
index b9bec46..75ef606 100644 (file)
@@ -52,7 +52,7 @@ static inline void __clear_bit_unlock(long nr, volatile unsigned long *addr)
  */
 static inline bool test_and_set_bit_lock(long nr, volatile unsigned long *addr)
 {
-       instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
+       instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
        return arch_test_and_set_bit_lock(nr, addr);
 }
 
index 20f788a..37363d5 100644 (file)
@@ -58,6 +58,30 @@ static inline void __change_bit(long nr, volatile unsigned long *addr)
        arch___change_bit(nr, addr);
 }
 
+static inline void __instrument_read_write_bitop(long nr, volatile unsigned long *addr)
+{
+       if (IS_ENABLED(CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC)) {
+               /*
+                * We treat non-atomic read-write bitops a little more special.
+                * Given the operations here only modify a single bit, assuming
+                * non-atomicity of the writer is sufficient may be reasonable
+                * for certain usage (and follows the permissible nature of the
+                * assume-plain-writes-atomic rule):
+                * 1. report read-modify-write races -> check read;
+                * 2. do not report races with marked readers, but do report
+                *    races with unmarked readers -> check "atomic" write.
+                */
+               kcsan_check_read(addr + BIT_WORD(nr), sizeof(long));
+               /*
+                * Use generic write instrumentation, in case other sanitizers
+                * or tools are enabled alongside KCSAN.
+                */
+               instrument_write(addr + BIT_WORD(nr), sizeof(long));
+       } else {
+               instrument_read_write(addr + BIT_WORD(nr), sizeof(long));
+       }
+}
+
 /**
  * __test_and_set_bit - Set a bit and return its old value
  * @nr: Bit to set
@@ -68,7 +92,7 @@ static inline void __change_bit(long nr, volatile unsigned long *addr)
  */
 static inline bool __test_and_set_bit(long nr, volatile unsigned long *addr)
 {
-       instrument_write(addr + BIT_WORD(nr), sizeof(long));
+       __instrument_read_write_bitop(nr, addr);
        return arch___test_and_set_bit(nr, addr);
 }
 
@@ -82,7 +106,7 @@ static inline bool __test_and_set_bit(long nr, volatile unsigned long *addr)
  */
 static inline bool __test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
-       instrument_write(addr + BIT_WORD(nr), sizeof(long));
+       __instrument_read_write_bitop(nr, addr);
        return arch___test_and_clear_bit(nr, addr);
 }
 
@@ -96,7 +120,7 @@ static inline bool __test_and_clear_bit(long nr, volatile unsigned long *addr)
  */
 static inline bool __test_and_change_bit(long nr, volatile unsigned long *addr)
 {
-       instrument_write(addr + BIT_WORD(nr), sizeof(long));
+       __instrument_read_write_bitop(nr, addr);
        return arch___test_and_change_bit(nr, addr);
 }
 
index cd8b75a..43e18db 100644 (file)
  */
 extern __wsum csum_partial(const void *buff, int len, __wsum sum);
 
-/*
- * the same as csum_partial, but copies from src while it
- * checksums
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-#ifndef csum_partial_copy_nocheck
-__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len,
-               __wsum sum);
-#endif
-
 #ifndef ip_fast_csum
 /*
  * This is a version of ip_compute_csum() optimized for IP headers,
index a86f65b..30f7b18 100644 (file)
@@ -22,4 +22,12 @@ typedef u32 compat_ulong_t;
 typedef u32 compat_uptr_t;
 typedef u32 compat_aio_context_t;
 
+#ifdef CONFIG_COMPAT_FOR_U64_ALIGNMENT
+typedef s64 __attribute__((aligned(4))) compat_s64;
+typedef u64 __attribute__((aligned(4))) compat_u64;
+#else
+typedef s64 compat_s64;
+typedef u64 compat_u64;
+#endif
+
 #endif
index 5430feb..e184397 100644 (file)
@@ -34,6 +34,7 @@
  *
  *     STABS_DEBUG
  *     DWARF_DEBUG
+ *     ELF_DETAILS
  *
  *     DISCARDS                // must be the last
  * }
        KEEP(*(__jump_table))                                           \
        __stop___jump_table = .;
 
+#define STATIC_CALL_DATA                                               \
+       . = ALIGN(8);                                                   \
+       __start_static_call_sites = .;                                  \
+       KEEP(*(.static_call_sites))                                     \
+       __stop_static_call_sites = .;
+
 /*
  * Allow architectures to handle ro_after_init data on their
  * own by defining an empty RO_AFTER_INIT_DATA.
        __start_ro_after_init = .;                                      \
        *(.data..ro_after_init)                                         \
        JUMP_TABLE_DATA                                                 \
+       STATIC_CALL_DATA                                                \
        __end_ro_after_init = .;
 #endif
 
  */
 #define TEXT_TEXT                                                      \
                ALIGN_FUNCTION();                                       \
-               *(.text.hot TEXT_MAIN .text.fixup .text.unlikely)       \
+               *(.text.hot .text.hot.*)                                \
+               *(TEXT_MAIN .text.fixup)                                \
+               *(.text.unlikely .text.unlikely.*)                      \
+               *(.text.unknown .text.unknown.*)                        \
                NOINSTR_TEXT                                            \
                *(.text..refcount)                                      \
                *(.ref.text)                                            \
                *(.softirqentry.text)                                   \
                __softirqentry_text_end = .;
 
+#define STATIC_CALL_TEXT                                               \
+               ALIGN_FUNCTION();                                       \
+               __static_call_text_start = .;                           \
+               *(.static_call.text)                                    \
+               __static_call_text_end = .;
+
 /* Section used for early init (in .S files) */
 #define HEAD_TEXT  KEEP(*(.head.text))
 
 #define BTF                                                            \
        .BTF : AT(ADDR(.BTF) - LOAD_OFFSET) {                           \
                __start_BTF = .;                                        \
-               *(.BTF)                                                 \
+               KEEP(*(.BTF))                                           \
                __stop_BTF = .;                                         \
        }                                                               \
        . = ALIGN(4);                                                   \
                .debug_macro    0 : { *(.debug_macro) }                 \
                .debug_addr     0 : { *(.debug_addr) }
 
-               /* Stabs debugging sections.  */
+/* Stabs debugging sections. */
 #define STABS_DEBUG                                                    \
                .stab 0 : { *(.stab) }                                  \
                .stabstr 0 : { *(.stabstr) }                            \
                .stab.excl 0 : { *(.stab.excl) }                        \
                .stab.exclstr 0 : { *(.stab.exclstr) }                  \
                .stab.index 0 : { *(.stab.index) }                      \
-               .stab.indexstr 0 : { *(.stab.indexstr) }                \
-               .comment 0 : { *(.comment) }
+               .stab.indexstr 0 : { *(.stab.indexstr) }
+
+/* Required sections not related to debugging. */
+#define ELF_DETAILS                                                    \
+               .comment 0 : { *(.comment) }                            \
+               .symtab 0 : { *(.symtab) }                              \
+               .strtab 0 : { *(.strtab) }                              \
+               .shstrtab 0 : { *(.shstrtab) }
 
 #ifdef CONFIG_GENERIC_BUG
 #define BUG_TABLE                                                      \
        EXIT_DATA
 #endif
 
+/*
+ * Clang's -fsanitize=kernel-address and -fsanitize=thread produce
+ * unwanted sections (.eh_frame and .init_array.*), but
+ * CONFIG_CONSTRUCTORS wants to keep any .init_array.* sections.
+ * https://bugs.llvm.org/show_bug.cgi?id=46478
+ */
+#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KCSAN)
+# ifdef CONFIG_CONSTRUCTORS
+#  define SANITIZER_DISCARDS                                           \
+       *(.eh_frame)
+# else
+#  define SANITIZER_DISCARDS                                           \
+       *(.init_array) *(.init_array.*)                                 \
+       *(.eh_frame)
+# endif
+#else
+# define SANITIZER_DISCARDS
+#endif
+
+#define COMMON_DISCARDS                                                        \
+       SANITIZER_DISCARDS                                              \
+       *(.discard)                                                     \
+       *(.discard.*)                                                   \
+       *(.modinfo)                                                     \
+       /* ld.bfd warns about .gnu.version* even when not emitted */    \
+       *(.gnu.version*)                                                \
+
 #define DISCARDS                                                       \
        /DISCARD/ : {                                                   \
        EXIT_DISCARDS                                                   \
        EXIT_CALL                                                       \
-       *(.discard)                                                     \
-       *(.discard.*)                                                   \
-       *(.modinfo)                                                     \
+       COMMON_DISCARDS                                                 \
        }
 
 /**
diff --git a/include/clocksource/timer-sp804.h b/include/clocksource/timer-sp804.h
deleted file mode 100644 (file)
index a5b41f3..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __CLKSOURCE_TIMER_SP804_H
-#define __CLKSOURCE_TIMER_SP804_H
-
-struct clk;
-
-int __sp804_clocksource_and_sched_clock_init(void __iomem *,
-                                            const char *, struct clk *, int);
-int __sp804_clockevents_init(void __iomem *, unsigned int,
-                            struct clk *, const char *);
-void sp804_timer_disable(void __iomem *);
-
-static inline void sp804_clocksource_init(void __iomem *base, const char *name)
-{
-       __sp804_clocksource_and_sched_clock_init(base, name, NULL, 0);
-}
-
-static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base,
-                                                         const char *name)
-{
-       __sp804_clocksource_and_sched_clock_init(base, name, NULL, 1);
-}
-
-static inline void sp804_clockevents_init(void __iomem *base, unsigned int irq, const char *name)
-{
-       __sp804_clockevents_init(base, irq, NULL, name);
-
-}
-#endif
index 143d884..18dd7a4 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/crypto.h>
 #include <linux/list.h>
 #include <linux/kernel.h>
-#include <linux/skbuff.h>
 
 /*
  * Maximum values for blocksize and alignmask, used to allocate
@@ -27,6 +26,7 @@ struct crypto_instance;
 struct module;
 struct rtattr;
 struct seq_file;
+struct sk_buff;
 
 struct crypto_type {
        unsigned int (*ctxsize)(struct crypto_alg *alg, u32 type, u32 mask);
@@ -277,12 +277,6 @@ static inline int crypto_memneq(const void *a, const void *b, size_t size)
        return __crypto_memneq(a, b, size) != 0UL ? 1 : 0;
 }
 
-static inline void crypto_yield(u32 flags)
-{
-       if (flags & CRYPTO_TFM_REQ_MAY_SLEEP)
-               cond_resched();
-}
-
 int crypto_register_notifier(struct notifier_block *nb);
 int crypto_unregister_notifier(struct notifier_block *nb);
 
diff --git a/include/crypto/cbc.h b/include/crypto/cbc.h
deleted file mode 100644 (file)
index 2b6422d..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * CBC: Cipher Block Chaining mode
- *
- * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au>
- */
-
-#ifndef _CRYPTO_CBC_H
-#define _CRYPTO_CBC_H
-
-#include <crypto/internal/skcipher.h>
-#include <linux/string.h>
-#include <linux/types.h>
-
-static inline int crypto_cbc_encrypt_segment(
-       struct skcipher_walk *walk, struct crypto_skcipher *tfm,
-       void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
-{
-       unsigned int bsize = crypto_skcipher_blocksize(tfm);
-       unsigned int nbytes = walk->nbytes;
-       u8 *src = walk->src.virt.addr;
-       u8 *dst = walk->dst.virt.addr;
-       u8 *iv = walk->iv;
-
-       do {
-               crypto_xor(iv, src, bsize);
-               fn(tfm, iv, dst);
-               memcpy(iv, dst, bsize);
-
-               src += bsize;
-               dst += bsize;
-       } while ((nbytes -= bsize) >= bsize);
-
-       return nbytes;
-}
-
-static inline int crypto_cbc_encrypt_inplace(
-       struct skcipher_walk *walk, struct crypto_skcipher *tfm,
-       void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
-{
-       unsigned int bsize = crypto_skcipher_blocksize(tfm);
-       unsigned int nbytes = walk->nbytes;
-       u8 *src = walk->src.virt.addr;
-       u8 *iv = walk->iv;
-
-       do {
-               crypto_xor(src, iv, bsize);
-               fn(tfm, src, src);
-               iv = src;
-
-               src += bsize;
-       } while ((nbytes -= bsize) >= bsize);
-
-       memcpy(walk->iv, iv, bsize);
-
-       return nbytes;
-}
-
-static inline int crypto_cbc_encrypt_walk(struct skcipher_request *req,
-                                         void (*fn)(struct crypto_skcipher *,
-                                                    const u8 *, u8 *))
-{
-       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
-       struct skcipher_walk walk;
-       int err;
-
-       err = skcipher_walk_virt(&walk, req, false);
-
-       while (walk.nbytes) {
-               if (walk.src.virt.addr == walk.dst.virt.addr)
-                       err = crypto_cbc_encrypt_inplace(&walk, tfm, fn);
-               else
-                       err = crypto_cbc_encrypt_segment(&walk, tfm, fn);
-               err = skcipher_walk_done(&walk, err);
-       }
-
-       return err;
-}
-
-static inline int crypto_cbc_decrypt_segment(
-       struct skcipher_walk *walk, struct crypto_skcipher *tfm,
-       void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
-{
-       unsigned int bsize = crypto_skcipher_blocksize(tfm);
-       unsigned int nbytes = walk->nbytes;
-       u8 *src = walk->src.virt.addr;
-       u8 *dst = walk->dst.virt.addr;
-       u8 *iv = walk->iv;
-
-       do {
-               fn(tfm, src, dst);
-               crypto_xor(dst, iv, bsize);
-               iv = src;
-
-               src += bsize;
-               dst += bsize;
-       } while ((nbytes -= bsize) >= bsize);
-
-       memcpy(walk->iv, iv, bsize);
-
-       return nbytes;
-}
-
-static inline int crypto_cbc_decrypt_inplace(
-       struct skcipher_walk *walk, struct crypto_skcipher *tfm,
-       void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
-{
-       unsigned int bsize = crypto_skcipher_blocksize(tfm);
-       unsigned int nbytes = walk->nbytes;
-       u8 *src = walk->src.virt.addr;
-       u8 last_iv[MAX_CIPHER_BLOCKSIZE];
-
-       /* Start of the last block. */
-       src += nbytes - (nbytes & (bsize - 1)) - bsize;
-       memcpy(last_iv, src, bsize);
-
-       for (;;) {
-               fn(tfm, src, src);
-               if ((nbytes -= bsize) < bsize)
-                       break;
-               crypto_xor(src, src - bsize, bsize);
-               src -= bsize;
-       }
-
-       crypto_xor(src, walk->iv, bsize);
-       memcpy(walk->iv, last_iv, bsize);
-
-       return nbytes;
-}
-
-static inline int crypto_cbc_decrypt_blocks(
-       struct skcipher_walk *walk, struct crypto_skcipher *tfm,
-       void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
-{
-       if (walk->src.virt.addr == walk->dst.virt.addr)
-               return crypto_cbc_decrypt_inplace(walk, tfm, fn);
-       else
-               return crypto_cbc_decrypt_segment(walk, tfm, fn);
-}
-
-#endif /* _CRYPTO_CBC_H */
index 0d1b403..af2ff31 100644 (file)
@@ -59,11 +59,6 @@ struct ahash_request {
        void *__ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
-#define AHASH_REQUEST_ON_STACK(name, ahash) \
-       char __##name##_desc[sizeof(struct ahash_request) + \
-               crypto_ahash_reqsize(ahash)] CRYPTO_MINALIGN_ATTR; \
-       struct ahash_request *name = (void *)__##name##_desc
-
 /**
  * struct ahash_alg - asynchronous message digest definition
  * @init: **[mandatory]** Initialize the transformation context. Intended only to initialize the
@@ -123,6 +118,17 @@ struct ahash_request {
  *         data so the transformation can continue from this point onward. No
  *         data processing happens at this point. Driver must not use
  *         req->result.
+ * @init_tfm: Initialize the cryptographic transformation object.
+ *           This function is called only once at the instantiation
+ *           time, right after the transformation context was
+ *           allocated. In case the cryptographic hardware has
+ *           some special requirements which need to be handled
+ *           by software, this function shall check for the precise
+ *           requirement of the transformation and put any software
+ *           fallbacks in place.
+ * @exit_tfm: Deinitialize the cryptographic transformation object.
+ *           This is a counterpart to @init_tfm, used to remove
+ *           various changes set in @init_tfm.
  * @halg: see struct hash_alg_common
  */
 struct ahash_alg {
@@ -135,6 +141,8 @@ struct ahash_alg {
        int (*import)(struct ahash_request *req, const void *in);
        int (*setkey)(struct crypto_ahash *tfm, const u8 *key,
                      unsigned int keylen);
+       int (*init_tfm)(struct crypto_ahash *tfm);
+       void (*exit_tfm)(struct crypto_ahash *tfm);
 
        struct hash_alg_common halg;
 };
index ee64123..a5db866 100644 (file)
@@ -46,6 +46,7 @@ struct af_alg_type {
        void *(*bind)(const char *name, u32 type, u32 mask);
        void (*release)(void *private);
        int (*setkey)(void *private, const u8 *key, unsigned int keylen);
+       int (*setentropy)(void *private, sockptr_t entropy, unsigned int len);
        int (*accept)(void *private, struct sock *sk);
        int (*accept_nokey)(void *private, struct sock *sk);
        int (*setauthsize)(void *private, unsigned int authsize);
index 89f6f46..0a288dd 100644 (file)
@@ -62,25 +62,12 @@ struct crypto_shash_spawn {
 int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err);
 int crypto_hash_walk_first(struct ahash_request *req,
                           struct crypto_hash_walk *walk);
-int crypto_ahash_walk_first(struct ahash_request *req,
-                          struct crypto_hash_walk *walk);
-
-static inline int crypto_ahash_walk_done(struct crypto_hash_walk *walk,
-                                        int err)
-{
-       return crypto_hash_walk_done(walk, err);
-}
 
 static inline int crypto_hash_walk_last(struct crypto_hash_walk *walk)
 {
        return !(walk->entrylen | walk->total);
 }
 
-static inline int crypto_ahash_walk_last(struct crypto_hash_walk *walk)
-{
-       return crypto_hash_walk_last(walk);
-}
-
 int crypto_register_ahash(struct ahash_alg *alg);
 void crypto_unregister_ahash(struct ahash_alg *alg);
 int crypto_register_ahashes(struct ahash_alg *algs, int count);
@@ -177,6 +164,12 @@ static inline struct ahash_instance *ahash_instance(
        return container_of(inst, struct ahash_instance, s.base);
 }
 
+static inline struct ahash_instance *ahash_alg_instance(
+       struct crypto_ahash *ahash)
+{
+       return ahash_instance(crypto_tfm_alg_instance(&ahash->base));
+}
+
 static inline void *ahash_instance_ctx(struct ahash_instance *inst)
 {
        return crypto_instance_ctx(ahash_crypto_instance(inst));
index 11f535c..948c520 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/keyctl.h>
 #include <linux/oid_registry.h>
+#include <crypto/akcipher.h>
 
 /*
  * Cryptographic data for the public-key subtype of the asymmetric key type.
@@ -44,6 +45,8 @@ struct public_key_signature {
        const char *pkey_algo;
        const char *hash_algo;
        const char *encoding;
+       const void *data;
+       unsigned int data_size;
 };
 
 extern void public_key_signature_free(struct public_key_signature *sig);
diff --git a/include/crypto/sm2.h b/include/crypto/sm2.h
new file mode 100644 (file)
index 0000000..af45255
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * sm2.h - SM2 asymmetric public-key algorithm
+ * as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012 SM2 and
+ * described at https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02
+ *
+ * Copyright (c) 2020, Alibaba Group.
+ * Written by Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
+ */
+
+#ifndef _CRYPTO_SM2_H
+#define _CRYPTO_SM2_H
+
+#include <crypto/sm3.h>
+#include <crypto/akcipher.h>
+
+/* The default user id as specified in GM/T 0009-2012 */
+#define SM2_DEFAULT_USERID "1234567812345678"
+#define SM2_DEFAULT_USERID_LEN 16
+
+extern int sm2_compute_z_digest(struct crypto_akcipher *tfm,
+                       const unsigned char *id, size_t id_len,
+                       unsigned char dgst[SM3_DIGEST_SIZE]);
+
+#endif /* _CRYPTO_SM2_H */
index 1438942..42ea212 100644 (file)
@@ -35,6 +35,8 @@ struct shash_desc;
 extern int crypto_sm3_update(struct shash_desc *desc, const u8 *data,
                              unsigned int len);
 
+extern int crypto_sm3_final(struct shash_desc *desc, u8 *out);
+
 extern int crypto_sm3_finup(struct shash_desc *desc, const u8 *data,
                             unsigned int len, u8 *hash);
 #endif
index 887954c..732f327 100644 (file)
@@ -588,7 +588,7 @@ struct drm_dsc_picture_parameter_set {
  * This structure represents the DSC PPS infoframe required to send the Picture
  * Parameter Set metadata required before enabling VESA Display Stream
  * Compression. This is based on the DP Secondary Data Packet structure and
- * comprises of SDP Header as defined &struct struct dp_sdp_header in drm_dp_helper.h
+ * comprises of SDP Header as defined &struct dp_sdp_header in drm_dp_helper.h
  * and PPS payload defined in &struct drm_dsc_picture_parameter_set.
  *
  * @pps_header: Header for PPS as per DP SDP header format of type
index c6bab49..fe58dbb 100644 (file)
@@ -29,6 +29,9 @@
 /* Slave address for the HDCP registers in the receiver */
 #define DRM_HDCP_DDC_ADDR                      0x3A
 
+/* Value to use at the end of the SHA-1 bytestream used for repeaters */
+#define DRM_HDCP_SHA1_TERMINATOR               0x80
+
 /* HDCP register offsets for HDMI/DVI devices */
 #define DRM_HDCP_DDC_BKSV                      0x00
 #define DRM_HDCP_DDC_RI_PRIME                  0x08
index 4fc9a43..aafd073 100644 (file)
@@ -164,6 +164,8 @@ int drm_modeset_lock_all_ctx(struct drm_device *dev,
  * is 0, so no error checking is necessary
  */
 #define DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, flags, ret)               \
+       if (!drm_drv_uses_atomic_modeset(dev))                          \
+               mutex_lock(&dev->mode_config.mutex);                    \
        drm_modeset_acquire_init(&ctx, flags);                          \
 modeset_lock_retry:                                                    \
        ret = drm_modeset_lock_all_ctx(dev, &ctx);                      \
@@ -172,6 +174,7 @@ modeset_lock_retry:                                                 \
 
 /**
  * DRM_MODESET_LOCK_ALL_END - Helper to release and cleanup modeset locks
+ * @dev: drm device
  * @ctx: local modeset acquire context, will be dereferenced
  * @ret: local ret/err/etc variable to track error status
  *
@@ -188,7 +191,7 @@ modeset_lock_retry:                                                 \
  * to that failure. In both of these cases the code between BEGIN/END will not
  * be run, so the failure will reflect the inability to grab the locks.
  */
-#define DRM_MODESET_LOCK_ALL_END(ctx, ret)                             \
+#define DRM_MODESET_LOCK_ALL_END(dev, ctx, ret)                                \
 modeset_lock_fail:                                                     \
        if (ret == -EDEADLK) {                                          \
                ret = drm_modeset_backoff(&ctx);                        \
@@ -196,6 +199,8 @@ modeset_lock_fail:                                                  \
                        goto modeset_lock_retry;                        \
        }                                                               \
        drm_modeset_drop_locks(&ctx);                                   \
-       drm_modeset_acquire_fini(&ctx);
+       drm_modeset_acquire_fini(&ctx);                                 \
+       if (!drm_drv_uses_atomic_modeset(dev))                          \
+               mutex_unlock(&dev->mode_config.mutex);
 
 #endif /* DRM_MODESET_LOCK_H_ */
index 6db0304..dbf4f08 100644 (file)
@@ -27,6 +27,7 @@ struct kvm_pmu {
        bool ready;
        bool created;
        bool irq_level;
+       struct irq_work overflow_work;
 };
 
 #define kvm_arm_pmu_v3_ready(v)                ((v)->arch.pmu.ready)
index 1e4cdc6..64ae25c 100644 (file)
@@ -958,7 +958,7 @@ void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
 acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state,
                                           u32 val_a, u32 val_b);
 
-#ifdef CONFIG_X86
+#ifndef CONFIG_IA64
 void arch_reserve_mem_area(acpi_physical_address addr, size_t size);
 #else
 static inline void arch_reserve_mem_area(acpi_physical_address addr,
diff --git a/include/linux/amba/clcd-regs.h b/include/linux/amba/clcd-regs.h
new file mode 100644 (file)
index 0000000..421b0fa
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * David A Rusling
+ *
+ * Copyright (C) 2001 ARM Limited
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef AMBA_CLCD_REGS_H
+#define AMBA_CLCD_REGS_H
+
+/*
+ * CLCD Controller Internal Register addresses
+ */
+#define CLCD_TIM0              0x00000000
+#define CLCD_TIM1              0x00000004
+#define CLCD_TIM2              0x00000008
+#define CLCD_TIM3              0x0000000c
+#define CLCD_UBAS              0x00000010
+#define CLCD_LBAS              0x00000014
+
+#define CLCD_PL110_IENB                0x00000018
+#define CLCD_PL110_CNTL                0x0000001c
+#define CLCD_PL110_STAT                0x00000020
+#define CLCD_PL110_INTR        0x00000024
+#define CLCD_PL110_UCUR                0x00000028
+#define CLCD_PL110_LCUR                0x0000002C
+
+#define CLCD_PL111_CNTL                0x00000018
+#define CLCD_PL111_IENB                0x0000001c
+#define CLCD_PL111_RIS         0x00000020
+#define CLCD_PL111_MIS         0x00000024
+#define CLCD_PL111_ICR         0x00000028
+#define CLCD_PL111_UCUR                0x0000002c
+#define CLCD_PL111_LCUR                0x00000030
+
+#define CLCD_PALL              0x00000200
+#define CLCD_PALETTE           0x00000200
+
+#define TIM2_PCD_LO_MASK       GENMASK(4, 0)
+#define TIM2_PCD_LO_BITS       5
+#define TIM2_CLKSEL            (1 << 5)
+#define TIM2_ACB_MASK          GENMASK(10, 6)
+#define TIM2_IVS               (1 << 11)
+#define TIM2_IHS               (1 << 12)
+#define TIM2_IPC               (1 << 13)
+#define TIM2_IOE               (1 << 14)
+#define TIM2_BCD               (1 << 26)
+#define TIM2_PCD_HI_MASK       GENMASK(31, 27)
+#define TIM2_PCD_HI_BITS       5
+#define TIM2_PCD_HI_SHIFT      27
+
+#define CNTL_LCDEN             (1 << 0)
+#define CNTL_LCDBPP1           (0 << 1)
+#define CNTL_LCDBPP2           (1 << 1)
+#define CNTL_LCDBPP4           (2 << 1)
+#define CNTL_LCDBPP8           (3 << 1)
+#define CNTL_LCDBPP16          (4 << 1)
+#define CNTL_LCDBPP16_565      (6 << 1)
+#define CNTL_LCDBPP16_444      (7 << 1)
+#define CNTL_LCDBPP24          (5 << 1)
+#define CNTL_LCDBW             (1 << 4)
+#define CNTL_LCDTFT            (1 << 5)
+#define CNTL_LCDMONO8          (1 << 6)
+#define CNTL_LCDDUAL           (1 << 7)
+#define CNTL_BGR               (1 << 8)
+#define CNTL_BEBO              (1 << 9)
+#define CNTL_BEPO              (1 << 10)
+#define CNTL_LCDPWR            (1 << 11)
+#define CNTL_LCDVCOMP(x)       ((x) << 12)
+#define CNTL_LDMAFIFOTIME      (1 << 15)
+#define CNTL_WATERMARK         (1 << 16)
+
+/* ST Microelectronics variant bits */
+#define CNTL_ST_1XBPP_444      0x0
+#define CNTL_ST_1XBPP_5551     (1 << 17)
+#define CNTL_ST_1XBPP_565      (1 << 18)
+#define CNTL_ST_CDWID_12       0x0
+#define CNTL_ST_CDWID_16       (1 << 19)
+#define CNTL_ST_CDWID_18       (1 << 20)
+#define CNTL_ST_CDWID_24       ((1 << 19)|(1 << 20))
+#define CNTL_ST_CEAEN          (1 << 21)
+#define CNTL_ST_LCDBPP24_PACKED        (6 << 1)
+
+#endif /* AMBA_CLCD_REGS_H */
diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h
new file mode 100644 (file)
index 0000000..b6e0cbe
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * linux/include/asm-arm/hardware/amba_clcd.h -- Integrator LCD panel.
+ *
+ * David A Rusling
+ *
+ * Copyright (C) 2001 ARM Limited
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#include <linux/fb.h>
+#include <linux/amba/clcd-regs.h>
+
+enum {
+       /* individual formats */
+       CLCD_CAP_RGB444         = (1 << 0),
+       CLCD_CAP_RGB5551        = (1 << 1),
+       CLCD_CAP_RGB565         = (1 << 2),
+       CLCD_CAP_RGB888         = (1 << 3),
+       CLCD_CAP_BGR444         = (1 << 4),
+       CLCD_CAP_BGR5551        = (1 << 5),
+       CLCD_CAP_BGR565         = (1 << 6),
+       CLCD_CAP_BGR888         = (1 << 7),
+
+       /* connection layouts */
+       CLCD_CAP_444            = CLCD_CAP_RGB444 | CLCD_CAP_BGR444,
+       CLCD_CAP_5551           = CLCD_CAP_RGB5551 | CLCD_CAP_BGR5551,
+       CLCD_CAP_565            = CLCD_CAP_RGB565 | CLCD_CAP_BGR565,
+       CLCD_CAP_888            = CLCD_CAP_RGB888 | CLCD_CAP_BGR888,
+
+       /* red/blue ordering */
+       CLCD_CAP_RGB            = CLCD_CAP_RGB444 | CLCD_CAP_RGB5551 |
+                                 CLCD_CAP_RGB565 | CLCD_CAP_RGB888,
+       CLCD_CAP_BGR            = CLCD_CAP_BGR444 | CLCD_CAP_BGR5551 |
+                                 CLCD_CAP_BGR565 | CLCD_CAP_BGR888,
+
+       CLCD_CAP_ALL            = CLCD_CAP_BGR | CLCD_CAP_RGB,
+};
+
+struct backlight_device;
+
+struct clcd_panel {
+       struct fb_videomode     mode;
+       signed short            width;  /* width in mm */
+       signed short            height; /* height in mm */
+       u32                     tim2;
+       u32                     tim3;
+       u32                     cntl;
+       u32                     caps;
+       unsigned int            bpp:8,
+                               fixedtimings:1,
+                               grayscale:1;
+       unsigned int            connector;
+       struct backlight_device *backlight;
+       /*
+        * If the B/R lines are switched between the CLCD
+        * and the panel we need to know this and not try to
+        * compensate with the BGR bit in the control register.
+        */
+       bool                    bgr_connection;
+};
+
+struct clcd_regs {
+       u32                     tim0;
+       u32                     tim1;
+       u32                     tim2;
+       u32                     tim3;
+       u32                     cntl;
+       unsigned long           pixclock;
+};
+
+struct clcd_fb;
+
+/*
+ * the board-type specific routines
+ */
+struct clcd_board {
+       const char *name;
+
+       /*
+        * Optional.  Hardware capability flags.
+        */
+       u32     caps;
+
+       /*
+        * Optional.  Check whether the var structure is acceptable
+        * for this display.
+        */
+       int     (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var);
+
+       /*
+        * Compulsory.  Decode fb->fb.var into regs->*.  In the case of
+        * fixed timing, set regs->* to the register values required.
+        */
+       void    (*decode)(struct clcd_fb *fb, struct clcd_regs *regs);
+
+       /*
+        * Optional.  Disable any extra display hardware.
+        */
+       void    (*disable)(struct clcd_fb *);
+
+       /*
+        * Optional.  Enable any extra display hardware.
+        */
+       void    (*enable)(struct clcd_fb *);
+
+       /*
+        * Setup platform specific parts of CLCD driver
+        */
+       int     (*setup)(struct clcd_fb *);
+
+       /*
+        * mmap the framebuffer memory
+        */
+       int     (*mmap)(struct clcd_fb *, struct vm_area_struct *);
+
+       /*
+        * Remove platform specific parts of CLCD driver
+        */
+       void    (*remove)(struct clcd_fb *);
+};
+
+struct amba_device;
+struct clk;
+
+/* this data structure describes each frame buffer device we find */
+struct clcd_fb {
+       struct fb_info          fb;
+       struct amba_device      *dev;
+       struct clk              *clk;
+       struct clcd_panel       *panel;
+       struct clcd_board       *board;
+       void                    *board_data;
+       void __iomem            *regs;
+       u16                     off_ienb;
+       u16                     off_cntl;
+       u32                     clcd_cntl;
+       u32                     cmap[16];
+       bool                    clk_enabled;
+};
+
+static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
+{
+       struct fb_var_screeninfo *var = &fb->fb.var;
+       u32 val, cpl;
+
+       /*
+        * Program the CLCD controller registers and start the CLCD
+        */
+       val = ((var->xres / 16) - 1) << 2;
+       val |= (var->hsync_len - 1) << 8;
+       val |= (var->right_margin - 1) << 16;
+       val |= (var->left_margin - 1) << 24;
+       regs->tim0 = val;
+
+       val = var->yres;
+       if (fb->panel->cntl & CNTL_LCDDUAL)
+               val /= 2;
+       val -= 1;
+       val |= (var->vsync_len - 1) << 10;
+       val |= var->lower_margin << 16;
+       val |= var->upper_margin << 24;
+       regs->tim1 = val;
+
+       val = fb->panel->tim2;
+       val |= var->sync & FB_SYNC_HOR_HIGH_ACT  ? 0 : TIM2_IHS;
+       val |= var->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS;
+
+       cpl = var->xres_virtual;
+       if (fb->panel->cntl & CNTL_LCDTFT)        /* TFT */
+               /* / 1 */;
+       else if (!var->grayscale)                 /* STN color */
+               cpl = cpl * 8 / 3;
+       else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */
+               cpl /= 8;
+       else                                      /* STN monochrome, 4bit */
+               cpl /= 4;
+
+       regs->tim2 = val | ((cpl - 1) << 16);
+
+       regs->tim3 = fb->panel->tim3;
+
+       val = fb->panel->cntl;
+       if (var->grayscale)
+               val |= CNTL_LCDBW;
+
+       if (fb->panel->caps && fb->board->caps && var->bits_per_pixel >= 16) {
+               /*
+                * if board and panel supply capabilities, we can support
+                * changing BGR/RGB depending on supplied parameters. Here
+                * we switch to what the framebuffer is providing if need
+                * be, so if the framebuffer is BGR but the display connection
+                * is RGB (first case) we switch it around. Vice versa mutatis
+                * mutandis if the framebuffer is RGB but the display connection
+                * is BGR, we flip it around.
+                */
+               if (var->red.offset == 0)
+                       val &= ~CNTL_BGR;
+               else
+                       val |= CNTL_BGR;
+               if (fb->panel->bgr_connection)
+                       val ^= CNTL_BGR;
+       }
+
+       switch (var->bits_per_pixel) {
+       case 1:
+               val |= CNTL_LCDBPP1;
+               break;
+       case 2:
+               val |= CNTL_LCDBPP2;
+               break;
+       case 4:
+               val |= CNTL_LCDBPP4;
+               break;
+       case 8:
+               val |= CNTL_LCDBPP8;
+               break;
+       case 16:
+               /*
+                * PL110 cannot choose between 5551 and 565 modes in its
+                * control register.  It is possible to use 565 with
+                * custom external wiring.
+                */
+               if (amba_part(fb->dev) == 0x110 ||
+                   var->green.length == 5)
+                       val |= CNTL_LCDBPP16;
+               else if (var->green.length == 6)
+                       val |= CNTL_LCDBPP16_565;
+               else
+                       val |= CNTL_LCDBPP16_444;
+               break;
+       case 32:
+               val |= CNTL_LCDBPP24;
+               break;
+       }
+
+       regs->cntl = val;
+       regs->pixclock = var->pixclock;
+}
+
+static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var)
+{
+       var->xres_virtual = var->xres = (var->xres + 15) & ~15;
+       var->yres_virtual = var->yres = (var->yres + 1) & ~1;
+
+#define CHECK(e,l,h) (var->e < l || var->e > h)
+       if (CHECK(right_margin, (5+1), 256) ||  /* back porch */
+           CHECK(left_margin, (5+1), 256) ||   /* front porch */
+           CHECK(hsync_len, (5+1), 256) ||
+           var->xres > 4096 ||
+           var->lower_margin > 255 ||          /* back porch */
+           var->upper_margin > 255 ||          /* front porch */
+           var->vsync_len > 32 ||
+           var->yres > 1024)
+               return -EINVAL;
+#undef CHECK
+
+       /* single panel mode: PCD = max(PCD, 1) */
+       /* dual panel mode: PCD = max(PCD, 5) */
+
+       /*
+        * You can't change the grayscale setting, and
+        * we can only do non-interlaced video.
+        */
+       if (var->grayscale != fb->fb.var.grayscale ||
+           (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+               return -EINVAL;
+
+#define CHECK(e) (var->e != fb->fb.var.e)
+       if (fb->panel->fixedtimings &&
+           (CHECK(xres)                ||
+            CHECK(yres)                ||
+            CHECK(bits_per_pixel)      ||
+            CHECK(pixclock)            ||
+            CHECK(left_margin)         ||
+            CHECK(right_margin)        ||
+            CHECK(upper_margin)        ||
+            CHECK(lower_margin)        ||
+            CHECK(hsync_len)           ||
+            CHECK(vsync_len)           ||
+            CHECK(sync)))
+               return -EINVAL;
+#undef CHECK
+
+       var->nonstd = 0;
+       var->accel_flags = 0;
+
+       return 0;
+}
index 21e950e..4507172 100644 (file)
@@ -76,7 +76,7 @@ extern void amd_iommu_free_device(struct pci_dev *pdev);
  *
  * The function returns 0 on success or a negative value on error.
  */
-extern int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid,
+extern int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
                                struct task_struct *task);
 
 /**
@@ -88,7 +88,7 @@ extern int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid,
  * When this function returns the device is no longer using the PASID
  * and the PASID is no longer bound to its task.
  */
-extern void amd_iommu_unbind_pasid(struct pci_dev *pdev, int pasid);
+extern void amd_iommu_unbind_pasid(struct pci_dev *pdev, u32 pasid);
 
 /**
  * amd_iommu_set_invalid_ppr_cb() - Register a call-back for failed
@@ -114,7 +114,7 @@ extern void amd_iommu_unbind_pasid(struct pci_dev *pdev, int pasid);
 #define AMD_IOMMU_INV_PRI_RSP_FAIL     2
 
 typedef int (*amd_iommu_invalid_ppr_cb)(struct pci_dev *pdev,
-                                       int pasid,
+                                       u32 pasid,
                                        unsigned long address,
                                        u16);
 
@@ -166,7 +166,7 @@ extern int amd_iommu_device_info(struct pci_dev *pdev,
  * @cb: The call-back function
  */
 
-typedef void (*amd_iommu_invalidate_ctx)(struct pci_dev *pdev, int pasid);
+typedef void (*amd_iommu_invalidate_ctx)(struct pci_dev *pdev, u32 pasid);
 
 extern int amd_iommu_set_invalidate_ctx_cb(struct pci_dev *pdev,
                                           amd_iommu_invalidate_ctx cb);
index 4ecf4fe..b3fc5d3 100644 (file)
@@ -497,13 +497,12 @@ static inline int op_stat_group(unsigned int op)
 
 typedef unsigned int blk_qc_t;
 #define BLK_QC_T_NONE          -1U
-#define BLK_QC_T_EAGAIN                -2U
 #define BLK_QC_T_SHIFT         16
 #define BLK_QC_T_INTERNAL      (1U << 31)
 
 static inline bool blk_qc_t_valid(blk_qc_t cookie)
 {
-       return cookie != BLK_QC_T_NONE && cookie != BLK_QC_T_EAGAIN;
+       return cookie != BLK_QC_T_NONE;
 }
 
 static inline unsigned int blk_qc_t_to_queue_num(blk_qc_t cookie)
index bb5636c..868e11f 100644 (file)
@@ -352,6 +352,8 @@ struct queue_limits {
 typedef int (*report_zones_cb)(struct blk_zone *zone, unsigned int idx,
                               void *data);
 
+void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model);
+
 #ifdef CONFIG_BLK_DEV_ZONED
 
 #define BLK_ALL_ZONES  ((unsigned int)-1)
index ac0c729..dd74503 100644 (file)
@@ -117,11 +117,18 @@ static inline bool bvec_iter_advance(const struct bio_vec *bv,
        return true;
 }
 
+static inline void bvec_iter_skip_zero_bvec(struct bvec_iter *iter)
+{
+       iter->bi_bvec_done = 0;
+       iter->bi_idx++;
+}
+
 #define for_each_bvec(bvl, bio_vec, iter, start)                       \
        for (iter = (start);                                            \
             (iter).bi_size &&                                          \
                ((bvl = bvec_iter_bvec((bio_vec), (iter))), 1); \
-            bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len))
+            (bvl).bv_len ? (void)bvec_iter_advance((bio_vec), &(iter), \
+                    (bvl).bv_len) : bvec_iter_skip_zero_bvec(&(iter)))
 
 /* for iterating one bio from start to end */
 #define BVEC_ITER_ALL_INIT (struct bvec_iter)                          \
index 46b92cd..4f72b47 100644 (file)
@@ -3,6 +3,7 @@
 #define _LINUX_CACHEINFO_H
 
 #include <linux/bitops.h>
+#include <linux/cpu.h>
 #include <linux/cpumask.h>
 #include <linux/smp.h>
 
@@ -119,4 +120,24 @@ int acpi_find_last_cache_level(unsigned int cpu);
 
 const struct attribute_group *cache_get_priv_group(struct cacheinfo *this_leaf);
 
+/*
+ * Get the id of the cache associated with @cpu at level @level.
+ * cpuhp lock must be held.
+ */
+static inline int get_cpu_cacheinfo_id(int cpu, int level)
+{
+       struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu);
+       int i;
+
+       for (i = 0; i < ci->num_leaves; i++) {
+               if (ci->info_list[i].level == level) {
+                       if (ci->info_list[i].attributes & CACHE_ID)
+                               return ci->info_list[i].id;
+                       return -1;
+               }
+       }
+
+       return -1;
+}
+
 #endif /* _LINUX_CACHEINFO_H */
index fcd84e8..999636d 100644 (file)
 #define CEPH_FEATURE_INCARNATION_2 (1ull<<57) // CEPH_FEATURE_SERVER_JEWEL
 
 #define DEFINE_CEPH_FEATURE(bit, incarnation, name)                    \
-       static const uint64_t CEPH_FEATURE_##name = (1ULL<<bit);                \
-       static const uint64_t CEPH_FEATUREMASK_##name =                 \
+       static const uint64_t __maybe_unused CEPH_FEATURE_##name = (1ULL<<bit);         \
+       static const uint64_t __maybe_unused CEPH_FEATUREMASK_##name =                  \
                (1ULL<<bit | CEPH_FEATURE_INCARNATION_##incarnation);
 
 /* this bit is ignored but still advertised by release *when* */
 #define DEFINE_CEPH_FEATURE_DEPRECATED(bit, incarnation, name, when) \
-       static const uint64_t DEPRECATED_CEPH_FEATURE_##name = (1ULL<<bit); \
-       static const uint64_t DEPRECATED_CEPH_FEATUREMASK_##name =              \
+       static const uint64_t __maybe_unused DEPRECATED_CEPH_FEATURE_##name = (1ULL<<bit);      \
+       static const uint64_t __maybe_unused DEPRECATED_CEPH_FEATUREMASK_##name =               \
                (1ULL<<bit | CEPH_FEATURE_INCARNATION_##incarnation);
 
 /*
index d38c4d7..14d5142 100644 (file)
        static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
 #endif /* COMPAT_SYSCALL_DEFINEx */
 
+struct compat_iovec {
+       compat_uptr_t   iov_base;
+       compat_size_t   iov_len;
+};
+
 #ifdef CONFIG_COMPAT
 
 #ifndef compat_user_stack_pointer
@@ -248,11 +253,6 @@ typedef struct compat_siginfo {
        } _sifields;
 } compat_siginfo_t;
 
-struct compat_iovec {
-       compat_uptr_t   iov_base;
-       compat_size_t   iov_len;
-};
-
 struct compat_rlimit {
        compat_ulong_t  rlim_cur;
        compat_ulong_t  rlim_max;
@@ -429,11 +429,11 @@ put_compat_sigset(compat_sigset_t __user *compat, const sigset_t *set,
        compat_sigset_t v;
        switch (_NSIG_WORDS) {
        case 4: v.sig[7] = (set->sig[3] >> 32); v.sig[6] = set->sig[3];
-               /* fall through */
+               fallthrough;
        case 3: v.sig[5] = (set->sig[2] >> 32); v.sig[4] = set->sig[2];
-               /* fall through */
+               fallthrough;
        case 2: v.sig[3] = (set->sig[1] >> 32); v.sig[2] = set->sig[1];
-               /* fall through */
+               fallthrough;
        case 1: v.sig[1] = (set->sig[0] >> 32); v.sig[0] = set->sig[0];
        }
        return copy_to_user(compat, &v, size) ? -EFAULT : 0;
@@ -451,12 +451,6 @@ extern long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 
 struct epoll_event;    /* fortunately, this one is fixed-layout */
 
-extern ssize_t compat_rw_copy_check_uvector(int type,
-               const struct compat_iovec __user *uvector,
-               unsigned long nr_segs,
-               unsigned long fast_segs, struct iovec *fast_pointer,
-               struct iovec **ret_pointer);
-
 extern void __user *compat_alloc_user_space(unsigned long len);
 
 int compat_restore_altstack(const compat_stack_t __user *uss);
@@ -522,12 +516,6 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
 asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
                                 compat_ulong_t arg);
 
-/* fs/namespace.c */
-asmlinkage long compat_sys_mount(const char __user *dev_name,
-                                const char __user *dir_name,
-                                const char __user *type, compat_ulong_t flags,
-                                const void __user *data);
-
 /* fs/open.c */
 asmlinkage long compat_sys_statfs(const char __user *pathname,
                                  struct compat_statfs __user *buf);
@@ -551,26 +539,22 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
 
 /* fs/read_write.c */
 asmlinkage long compat_sys_lseek(unsigned int, compat_off_t, unsigned int);
-asmlinkage ssize_t compat_sys_readv(compat_ulong_t fd,
-               const struct compat_iovec __user *vec, compat_ulong_t vlen);
-asmlinkage ssize_t compat_sys_writev(compat_ulong_t fd,
-               const struct compat_iovec __user *vec, compat_ulong_t vlen);
 /* No generic prototype for pread64 and pwrite64 */
 asmlinkage ssize_t compat_sys_preadv(compat_ulong_t fd,
-               const struct compat_iovec __user *vec,
+               const struct iovec __user *vec,
                compat_ulong_t vlen, u32 pos_low, u32 pos_high);
 asmlinkage ssize_t compat_sys_pwritev(compat_ulong_t fd,
-               const struct compat_iovec __user *vec,
+               const struct iovec __user *vec,
                compat_ulong_t vlen, u32 pos_low, u32 pos_high);
 #ifdef __ARCH_WANT_COMPAT_SYS_PREADV64
 asmlinkage long compat_sys_preadv64(unsigned long fd,
-               const struct compat_iovec __user *vec,
+               const struct iovec __user *vec,
                unsigned long vlen, loff_t pos);
 #endif
 
 #ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64
 asmlinkage long compat_sys_pwritev64(unsigned long fd,
-               const struct compat_iovec __user *vec,
+               const struct iovec __user *vec,
                unsigned long vlen, loff_t pos);
 #endif
 
@@ -607,10 +591,6 @@ asmlinkage long compat_sys_signalfd4(int ufd,
                                     const compat_sigset_t __user *sigmask,
                                     compat_size_t sigsetsize, int flags);
 
-/* fs/splice.c */
-asmlinkage long compat_sys_vmsplice(int fd, const struct compat_iovec __user *,
-                                   unsigned int nr_segs, unsigned int flags);
-
 /* fs/stat.c */
 asmlinkage long compat_sys_newfstatat(unsigned int dfd,
                                      const char __user *filename,
@@ -794,32 +774,24 @@ asmlinkage long compat_sys_open_by_handle_at(int mountdirfd,
                                             int flags);
 asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
                                    unsigned vlen, unsigned int flags);
-asmlinkage ssize_t compat_sys_process_vm_readv(compat_pid_t pid,
-               const struct compat_iovec __user *lvec,
-               compat_ulong_t liovcnt, const struct compat_iovec __user *rvec,
-               compat_ulong_t riovcnt, compat_ulong_t flags);
-asmlinkage ssize_t compat_sys_process_vm_writev(compat_pid_t pid,
-               const struct compat_iovec __user *lvec,
-               compat_ulong_t liovcnt, const struct compat_iovec __user *rvec,
-               compat_ulong_t riovcnt, compat_ulong_t flags);
 asmlinkage long compat_sys_execveat(int dfd, const char __user *filename,
                     const compat_uptr_t __user *argv,
                     const compat_uptr_t __user *envp, int flags);
 asmlinkage ssize_t compat_sys_preadv2(compat_ulong_t fd,
-               const struct compat_iovec __user *vec,
+               const struct iovec __user *vec,
                compat_ulong_t vlen, u32 pos_low, u32 pos_high, rwf_t flags);
 asmlinkage ssize_t compat_sys_pwritev2(compat_ulong_t fd,
-               const struct compat_iovec __user *vec,
+               const struct iovec __user *vec,
                compat_ulong_t vlen, u32 pos_low, u32 pos_high, rwf_t flags);
 #ifdef __ARCH_WANT_COMPAT_SYS_PREADV64V2
-asmlinkage long  compat_sys_readv64v2(unsigned long fd,
-               const struct compat_iovec __user *vec,
+asmlinkage long  compat_sys_preadv64v2(unsigned long fd,
+               const struct iovec __user *vec,
                unsigned long vlen, loff_t pos, rwf_t flags);
 #endif
 
 #ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64V2
 asmlinkage long compat_sys_pwritev64v2(unsigned long fd,
-               const struct compat_iovec __user *vec,
+               const struct iovec __user *vec,
                unsigned long vlen, loff_t pos, rwf_t flags);
 #endif
 
@@ -933,6 +905,15 @@ static inline bool in_compat_syscall(void) { return false; }
 #endif /* CONFIG_COMPAT */
 
 /*
+ * Some legacy ABIs like the i386 one use less than natural alignment for 64-bit
+ * types, and will need special compat treatment for that.  Most architectures
+ * don't need that special handling even for compat syscalls.
+ */
+#ifndef compat_need_64bit_alignment_fixup
+#define compat_need_64bit_alignment_fixup()            false
+#endif
+
+/*
  * A pointer passed in from user mode. This should not
  * be used for syscall parameters, just declare them
  * as pointers because the syscall entry code will have
index 6810d80..92ef163 100644 (file)
@@ -207,7 +207,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
  */
 #define __ADDRESSABLE(sym) \
        static void * __section(.discard.addressable) __used \
-               __PASTE(__addressable_##sym, __LINE__) = (void *)&sym;
+               __UNIQUE_ID(__PASTE(__addressable_,sym)) = (void *)&sym;
 
 /**
  * offset_to_ptr - convert a relative memory offset to an absolute pointer
index 6122efd..ea7b756 100644 (file)
 
 /*
  * __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17.
- * In the meantime, to support 4.6 <= gcc < 5, we implement __has_attribute
+ * In the meantime, to support gcc < 5, we implement __has_attribute
  * by hand.
- *
- * sparse does not support __has_attribute (yet) and defines __GNUC_MINOR__
- * depending on the compiler used to build it; however, these attributes have
- * no semantic effects for sparse, so it does not matter. Also note that,
- * in order to avoid sparse's warnings, even the unsupported ones must be
- * defined to 0.
  */
 #ifndef __has_attribute
 # define __has_attribute(x) __GCC4_has_attribute_##x
index 4b33cb3..6e390d5 100644 (file)
@@ -11,8 +11,8 @@
 # define __iomem       __attribute__((noderef, address_space(__iomem)))
 # define __percpu      __attribute__((noderef, address_space(__percpu)))
 # define __rcu         __attribute__((noderef, address_space(__rcu)))
-extern void __chk_user_ptr(const volatile void __user *);
-extern void __chk_io_ptr(const volatile void __iomem *);
+static inline void __chk_user_ptr(const volatile void __user *ptr) { }
+static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
 /* context/locking */
 # define __must_hold(x)        __attribute__((context(x,1,1)))
 # define __acquires(x) __attribute__((context(x,0,1)))
index 8537e92..6a511a1 100644 (file)
@@ -230,6 +230,18 @@ enum {
 #define CPER_MEM_VALID_RANK_NUMBER             0x8000
 #define CPER_MEM_VALID_CARD_HANDLE             0x10000
 #define CPER_MEM_VALID_MODULE_HANDLE           0x20000
+#define CPER_MEM_VALID_ROW_EXT                 0x40000
+#define CPER_MEM_VALID_BANK_GROUP              0x80000
+#define CPER_MEM_VALID_BANK_ADDRESS            0x100000
+#define CPER_MEM_VALID_CHIP_ID                 0x200000
+
+#define CPER_MEM_EXT_ROW_MASK                  0x3
+#define CPER_MEM_EXT_ROW_SHIFT                 16
+
+#define CPER_MEM_BANK_ADDRESS_MASK             0xff
+#define CPER_MEM_BANK_GROUP_SHIFT              8
+
+#define CPER_MEM_CHIP_ID_SHIFT                 5
 
 #define CPER_PCIE_VALID_PORT_TYPE              0x0001
 #define CPER_PCIE_VALID_VERSION                        0x0002
@@ -443,7 +455,7 @@ struct cper_sec_mem_err_old {
        u8      error_type;
 };
 
-/* Memory Error Section (UEFI >= v2.3), UEFI v2.7 sec N.2.5 */
+/* Memory Error Section (UEFI >= v2.3), UEFI v2.8 sec N.2.5 */
 struct cper_sec_mem_err {
        u64     validation_bits;
        u64     error_status;
@@ -461,7 +473,7 @@ struct cper_sec_mem_err {
        u64     responder_id;
        u64     target_id;
        u8      error_type;
-       u8      reserved;
+       u8      extended;
        u16     rank;
        u16     mem_array_handle;       /* "card handle" in UEFI 2.4 */
        u16     mem_dev_handle;         /* "module handle" in UEFI 2.4 */
@@ -483,8 +495,16 @@ struct cper_mem_err_compact {
        u16     rank;
        u16     mem_array_handle;
        u16     mem_dev_handle;
+       u8      extended;
 };
 
+static inline u32 cper_get_mem_extension(u64 mem_valid, u8 mem_extended)
+{
+       if (!(mem_valid & CPER_MEM_VALID_ROW_EXT))
+               return 0;
+       return (mem_extended & CPER_MEM_EXT_ROW_MASK) << CPER_MEM_EXT_ROW_SHIFT;
+}
+
 /* PCI Express Error Section, UEFI v2.7 sec N.2.7 */
 struct cper_sec_pcie {
        u64             validation_bits;
index 8f141d4..a911e5d 100644 (file)
@@ -956,8 +956,8 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
        case CPUFREQ_RELATION_C:
                return cpufreq_table_find_index_c(policy, target_freq);
        default:
-               pr_err("%s: Invalid relation: %d\n", __func__, relation);
-               return -EINVAL;
+               WARN_ON_ONCE(1);
+               return 0;
        }
 }
 
index 3215023..6f524bb 100644 (file)
@@ -36,6 +36,7 @@ enum cpuhp_state {
        CPUHP_X86_MCE_DEAD,
        CPUHP_VIRT_NET_DEAD,
        CPUHP_SLUB_DEAD,
+       CPUHP_DEBUG_OBJ_DEAD,
        CPUHP_MM_WRITEBACK_DEAD,
        CPUHP_MM_VMSTAT_DEAD,
        CPUHP_SOFTIRQ_DEAD,
@@ -142,7 +143,6 @@ enum cpuhp_state {
        /* Must be the last timer callback */
        CPUHP_AP_DUMMY_TIMER_STARTING,
        CPUHP_AP_ARM_XEN_STARTING,
-       CPUHP_AP_ARM_KVMPV_STARTING,
        CPUHP_AP_ARM_CORESIGHT_STARTING,
        CPUHP_AP_ARM_CORESIGHT_CTI_STARTING,
        CPUHP_AP_ARM64_ISNDEP_STARTING,
index b65909a..6175c77 100644 (file)
@@ -75,12 +75,14 @@ struct cpuidle_state {
 };
 
 /* Idle State Flags */
-#define CPUIDLE_FLAG_NONE       (0x00)
-#define CPUIDLE_FLAG_POLLING   BIT(0) /* polling state */
-#define CPUIDLE_FLAG_COUPLED   BIT(1) /* state applies to multiple cpus */
-#define CPUIDLE_FLAG_TIMER_STOP BIT(2) /* timer is stopped on this state */
-#define CPUIDLE_FLAG_UNUSABLE  BIT(3) /* avoid using this state */
-#define CPUIDLE_FLAG_OFF       BIT(4) /* disable this state by default */
+#define CPUIDLE_FLAG_NONE              (0x00)
+#define CPUIDLE_FLAG_POLLING           BIT(0) /* polling state */
+#define CPUIDLE_FLAG_COUPLED           BIT(1) /* state applies to multiple cpus */
+#define CPUIDLE_FLAG_TIMER_STOP        BIT(2) /* timer is stopped on this state */
+#define CPUIDLE_FLAG_UNUSABLE          BIT(3) /* avoid using this state */
+#define CPUIDLE_FLAG_OFF               BIT(4) /* disable this state by default */
+#define CPUIDLE_FLAG_TLB_FLUSHED       BIT(5) /* idle-state flushes TLBs */
+#define CPUIDLE_FLAG_RCU_IDLE          BIT(6) /* idle-state takes care of RCU */
 
 struct cpuidle_device_kobj;
 struct cpuidle_state_kobj;
index 6904d4e..43b39ab 100644 (file)
@@ -58,6 +58,8 @@ static inline void set_dax_synchronous(struct dax_device *dax_dev)
 {
        __set_dax_synchronous(dax_dev);
 }
+bool dax_supported(struct dax_device *dax_dev, struct block_device *bdev,
+               int blocksize, sector_t start, sector_t len);
 /*
  * Check if given mapping is supported by the file / underlying device.
  */
@@ -104,6 +106,12 @@ static inline bool dax_synchronous(struct dax_device *dax_dev)
 static inline void set_dax_synchronous(struct dax_device *dax_dev)
 {
 }
+static inline bool dax_supported(struct dax_device *dax_dev,
+               struct block_device *bdev, int blocksize, sector_t start,
+               sector_t len)
+{
+       return false;
+}
 static inline bool daxdev_mapping_supported(struct vm_area_struct *vma,
                                struct dax_device *dax_dev)
 {
@@ -189,14 +197,23 @@ static inline void dax_unlock_page(struct page *page, dax_entry_t cookie)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_DAX)
 int dax_read_lock(void);
 void dax_read_unlock(int id);
+#else
+static inline int dax_read_lock(void)
+{
+       return 0;
+}
+
+static inline void dax_read_unlock(int id)
+{
+}
+#endif /* CONFIG_DAX */
 bool dax_alive(struct dax_device *dax_dev);
 void *dax_get_private(struct dax_device *dax_dev);
 long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages,
                void **kaddr, pfn_t *pfn);
-bool dax_supported(struct dax_device *dax_dev, struct block_device *bdev,
-               int blocksize, sector_t start, sector_t len);
 size_t dax_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,
                size_t bytes, struct iov_iter *i);
 size_t dax_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,
index 65d975b..6f95c33 100644 (file)
@@ -213,7 +213,7 @@ struct dentry_operations {
 
 #define DCACHE_MAY_FREE                        0x00800000
 #define DCACHE_FALLTHRU                        0x01000000 /* Fall through to lower layer */
-#define DCACHE_ENCRYPTED_NAME          0x02000000 /* Encrypted name (dir key was unavailable) */
+#define DCACHE_NOKEY_NAME              0x02000000 /* Encrypted name encoded without key */
 #define DCACHE_OP_REAL                 0x04000000
 
 #define DCACHE_PAR_LOOKUP              0x10000000 /* being looked up (with parent locked shared) */
index afc416e..8d2dde2 100644 (file)
@@ -30,7 +30,7 @@ struct debug_obj {
        enum debug_obj_state    state;
        unsigned int            astate;
        void                    *object;
-       struct debug_obj_descr  *descr;
+       const struct debug_obj_descr *descr;
 };
 
 /**
@@ -64,14 +64,14 @@ struct debug_obj_descr {
 };
 
 #ifdef CONFIG_DEBUG_OBJECTS
-extern void debug_object_init      (void *addr, struct debug_obj_descr *descr);
+extern void debug_object_init      (void *addr, const struct debug_obj_descr *descr);
 extern void
-debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr);
-extern int debug_object_activate  (void *addr, struct debug_obj_descr *descr);
-extern void debug_object_deactivate(void *addr, struct debug_obj_descr *descr);
-extern void debug_object_destroy   (void *addr, struct debug_obj_descr *descr);
-extern void debug_object_free      (void *addr, struct debug_obj_descr *descr);
-extern void debug_object_assert_init(void *addr, struct debug_obj_descr *descr);
+debug_object_init_on_stack(void *addr, const struct debug_obj_descr *descr);
+extern int debug_object_activate  (void *addr, const struct debug_obj_descr *descr);
+extern void debug_object_deactivate(void *addr, const struct debug_obj_descr *descr);
+extern void debug_object_destroy   (void *addr, const struct debug_obj_descr *descr);
+extern void debug_object_free      (void *addr, const struct debug_obj_descr *descr);
+extern void debug_object_assert_init(void *addr, const struct debug_obj_descr *descr);
 
 /*
  * Active state:
@@ -79,26 +79,26 @@ extern void debug_object_assert_init(void *addr, struct debug_obj_descr *descr);
  * - Must return to 0 before deactivation.
  */
 extern void
-debug_object_active_state(void *addr, struct debug_obj_descr *descr,
+debug_object_active_state(void *addr, const struct debug_obj_descr *descr,
                          unsigned int expect, unsigned int next);
 
 extern void debug_objects_early_init(void);
 extern void debug_objects_mem_init(void);
 #else
 static inline void
-debug_object_init      (void *addr, struct debug_obj_descr *descr) { }
+debug_object_init      (void *addr, const struct debug_obj_descr *descr) { }
 static inline void
-debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr) { }
+debug_object_init_on_stack(void *addr, const struct debug_obj_descr *descr) { }
 static inline int
-debug_object_activate  (void *addr, struct debug_obj_descr *descr) { return 0; }
+debug_object_activate  (void *addr, const struct debug_obj_descr *descr) { return 0; }
 static inline void
-debug_object_deactivate(void *addr, struct debug_obj_descr *descr) { }
+debug_object_deactivate(void *addr, const struct debug_obj_descr *descr) { }
 static inline void
-debug_object_destroy   (void *addr, struct debug_obj_descr *descr) { }
+debug_object_destroy   (void *addr, const struct debug_obj_descr *descr) { }
 static inline void
-debug_object_free      (void *addr, struct debug_obj_descr *descr) { }
+debug_object_free      (void *addr, const struct debug_obj_descr *descr) { }
 static inline void
-debug_object_assert_init(void *addr, struct debug_obj_descr *descr) { }
+debug_object_assert_init(void *addr, const struct debug_obj_descr *descr) { }
 
 static inline void debug_objects_early_init(void) { }
 static inline void debug_objects_mem_init(void) { }
index ca18da4..9e6ea89 100644 (file)
@@ -454,6 +454,7 @@ struct dev_links_info {
  * @pm_domain: Provide callbacks that are executed during system suspend,
  *             hibernation, system resume and during runtime PM transitions
  *             along with subsystem-level and driver-level callbacks.
+ * @em_pd:     device's energy model performance domain
  * @pins:      For device pin management.
  *             See Documentation/driver-api/pinctl.rst for details.
  * @msi_list:  Hosts MSI descriptors
index aa9ff9e..8aa0c7c 100644 (file)
@@ -49,6 +49,10 @@ struct _ddebug {
 
 
 #if defined(CONFIG_DYNAMIC_DEBUG_CORE)
+
+/* exported for module authors to exercise >control */
+int dynamic_debug_exec_queries(const char *query, const char *modname);
+
 int ddebug_add_module(struct _ddebug *tab, unsigned int n,
                                const char *modname);
 extern int ddebug_remove_module(const char *mod_name);
@@ -105,7 +109,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
        static_branch_unlikely(&descriptor.key.dd_key_false)
 #endif
 
-#else /* !HAVE_JUMP_LABEL */
+#else /* !CONFIG_JUMP_LABEL */
 
 #define _DPRINTK_KEY_INIT
 
@@ -117,7 +121,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
        unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
 #endif
 
-#endif
+#endif /* CONFIG_JUMP_LABEL */
 
 #define __dynamic_func_call(id, fmt, func, ...) do {   \
        DEFINE_DYNAMIC_DEBUG_METADATA(id, fmt);         \
@@ -172,10 +176,11 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
                                   KERN_DEBUG, prefix_str, prefix_type, \
                                   rowsize, groupsize, buf, len, ascii)
 
-#else
+#else /* !CONFIG_DYNAMIC_DEBUG_CORE */
 
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/printk.h>
 
 static inline int ddebug_add_module(struct _ddebug *tab, unsigned int n,
                                    const char *modname)
@@ -210,6 +215,13 @@ static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
                print_hex_dump(KERN_DEBUG, prefix_str, prefix_type,     \
                                rowsize, groupsize, buf, len, ascii);   \
        } while (0)
-#endif
+
+static inline int dynamic_debug_exec_queries(const char *query, const char *modname)
+{
+       pr_warn("kernel not built with CONFIG_DYNAMIC_DEBUG_CORE\n");
+       return 0;
+}
+
+#endif /* !CONFIG_DYNAMIC_DEBUG_CORE */
 
 #endif
index 73db1ae..d7c0e73 100644 (file)
@@ -122,6 +122,7 @@ typedef     struct {
                                ((u64)0x0000000000010000ULL)    /* higher reliability */
 #define EFI_MEMORY_RO          ((u64)0x0000000000020000ULL)    /* read-only */
 #define EFI_MEMORY_SP          ((u64)0x0000000000040000ULL)    /* soft reserved */
+#define EFI_MEMORY_CPU_CRYPTO  ((u64)0x0000000000080000ULL)    /* supports encryption */
 #define EFI_MEMORY_RUNTIME     ((u64)0x8000000000000000ULL)    /* range requires runtime mapping */
 #define EFI_MEMORY_DESCRIPTOR_VERSION  1
 
@@ -357,6 +358,7 @@ void efi_native_runtime_setup(void);
 #define LINUX_EFI_TPM_FINAL_LOG_GUID           EFI_GUID(0x1e2ed096, 0x30e2, 0x4254,  0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
 #define LINUX_EFI_MEMRESERVE_TABLE_GUID                EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5,  0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
 #define LINUX_EFI_INITRD_MEDIA_GUID            EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
+#define LINUX_EFI_MOK_VARIABLE_TABLE_GUID      EFI_GUID(0xc451ed2b, 0x9694, 0x45d3,  0xba, 0xba, 0xed, 0x9f, 0x89, 0x88, 0xa3, 0x89)
 
 /* OEM GUIDs */
 #define DELLEMC_EFI_RCI2_TABLE_GUID            EFI_GUID(0x2d9f28a2, 0xa886, 0x456a,  0x97, 0xa8, 0xf1, 0x1e, 0xf2, 0x4f, 0xf4, 0x55)
@@ -546,6 +548,7 @@ extern struct efi {
        unsigned long                   esrt;                   /* ESRT table */
        unsigned long                   tpm_log;                /* TPM2 Event Log table */
        unsigned long                   tpm_final_log;          /* TPM2 Final Events Log table */
+       unsigned long                   mokvar_table;           /* MOK variable config table */
 
        efi_get_time_t                  *get_time;
        efi_set_time_t                  *set_time;
@@ -984,8 +987,6 @@ struct efivar_entry {
        bool deleting;
 };
 
-extern struct list_head efivar_sysfs_list;
-
 static inline void
 efivar_unregister(struct efivar_entry *var)
 {
@@ -1037,15 +1038,6 @@ bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
 bool efivar_variable_is_removable(efi_guid_t vendor, const char *name,
                                  size_t len);
 
-extern struct work_struct efivar_work;
-void efivar_run_worker(void);
-
-#if defined(CONFIG_EFI_VARS) || defined(CONFIG_EFI_VARS_MODULE)
-int efivars_sysfs_init(void);
-
-#define EFIVARS_DATA_SIZE_MAX 1024
-
-#endif /* CONFIG_EFI_VARS */
 extern bool efi_capsule_pending(int *reset_type);
 
 extern int efi_capsule_supported(efi_guid_t guid, u32 flags,
@@ -1252,4 +1244,36 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size);
 
 char *efi_systab_show_arch(char *str);
 
+/*
+ * The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table can be provided
+ * to the kernel by an EFI boot loader. The table contains a packed
+ * sequence of these entries, one for each named MOK variable.
+ * The sequence is terminated by an entry with a completely NULL
+ * name and 0 data size.
+ */
+struct efi_mokvar_table_entry {
+       char name[256];
+       u64 data_size;
+       u8 data[];
+} __attribute((packed));
+
+#ifdef CONFIG_LOAD_UEFI_KEYS
+extern void __init efi_mokvar_table_init(void);
+extern struct efi_mokvar_table_entry *efi_mokvar_entry_next(
+                       struct efi_mokvar_table_entry **mokvar_entry);
+extern struct efi_mokvar_table_entry *efi_mokvar_entry_find(const char *name);
+#else
+static inline void efi_mokvar_table_init(void) { }
+static inline struct efi_mokvar_table_entry *efi_mokvar_entry_next(
+                       struct efi_mokvar_table_entry **mokvar_entry)
+{
+       return NULL;
+}
+static inline struct efi_mokvar_table_entry *efi_mokvar_entry_find(
+                       const char *name)
+{
+       return NULL;
+}
+#endif
+
 #endif /* _LINUX_EFI_H */
index 57eac52..a97a12b 100644 (file)
@@ -8,8 +8,8 @@
 #define EFI_EMBEDDED_FW_PREFIX_LEN             8
 
 /*
- * This struct and efi_embedded_fw_list are private to the efi-embedded fw
- * implementation they are in this header for use by lib/test_firmware.c only!
+ * This struct is private to the efi-embedded fw implementation.
+ * They are in this header for use by lib/test_firmware.c only!
  */
 struct efi_embedded_fw {
        struct list_head list;
@@ -18,8 +18,6 @@ struct efi_embedded_fw {
        size_t length;
 };
 
-extern struct list_head efi_embedded_fw_list;
-
 /**
  * struct efi_embedded_fw_desc - This struct is used by the EFI embedded-fw
  *                               code to search for embedded firmwares.
index efebbff..474f296 100644 (file)
@@ -38,7 +38,7 @@
 #endif
 
 /*
- * TIF flags handled in syscall_enter_from_usermode()
+ * TIF flags handled in syscall_enter_from_user_mode()
  */
 #ifndef ARCH_SYSCALL_ENTER_WORK
 # define ARCH_SYSCALL_ENTER_WORK       (0)
@@ -110,15 +110,30 @@ static inline __must_check int arch_syscall_enter_tracehook(struct pt_regs *regs
 #endif
 
 /**
- * syscall_enter_from_user_mode - Check and handle work before invoking
- *                              a syscall
+ * syscall_enter_from_user_mode_prepare - Establish state and enable interrupts
  * @regs:      Pointer to currents pt_regs
- * @syscall:   The syscall number
  *
  * Invoked from architecture specific syscall entry code with interrupts
  * disabled. The calling code has to be non-instrumentable. When the
- * function returns all state is correct and the subsequent functions can be
- * instrumented.
+ * function returns all state is correct, interrupts are enabled and the
+ * subsequent functions can be instrumented.
+ *
+ * This handles lockdep, RCU (context tracking) and tracing state.
+ *
+ * This is invoked when there is extra architecture specific functionality
+ * to be done between establishing state and handling user mode entry work.
+ */
+void syscall_enter_from_user_mode_prepare(struct pt_regs *regs);
+
+/**
+ * syscall_enter_from_user_mode_work - Check and handle work before invoking
+ *                                    a syscall
+ * @regs:      Pointer to currents pt_regs
+ * @syscall:   The syscall number
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * enabled after invoking syscall_enter_from_user_mode_prepare() and extra
+ * architecture specific work.
  *
  * Returns: The original or a modified syscall number
  *
@@ -127,12 +142,30 @@ static inline __must_check int arch_syscall_enter_tracehook(struct pt_regs *regs
  * syscall_set_return_value() first.  If neither of those are called and -1
  * is returned, then the syscall will fail with ENOSYS.
  *
- * The following functionality is handled here:
+ * It handles the following work items:
  *
- *  1) Establish state (lockdep, RCU (context tracking), tracing)
- *  2) TIF flag dependent invocations of arch_syscall_enter_tracehook(),
+ *  1) TIF flag dependent invocations of arch_syscall_enter_tracehook(),
  *     __secure_computing(), trace_sys_enter()
- *  3) Invocation of audit_syscall_entry()
+ *  2) Invocation of audit_syscall_entry()
+ */
+long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall);
+
+/**
+ * syscall_enter_from_user_mode - Establish state and check and handle work
+ *                               before invoking a syscall
+ * @regs:      Pointer to currents pt_regs
+ * @syscall:   The syscall number
+ *
+ * Invoked from architecture specific syscall entry code with interrupts
+ * disabled. The calling code has to be non-instrumentable. When the
+ * function returns all state is correct, interrupts are enabled and the
+ * subsequent functions can be instrumented.
+ *
+ * This is combination of syscall_enter_from_user_mode_prepare() and
+ * syscall_enter_from_user_mode_work().
+ *
+ * Returns: The original or a modified syscall number. See
+ * syscall_enter_from_user_mode_work() for further explanation.
  */
 long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall);
 
index 0a355b0..ebfb7cf 100644 (file)
@@ -1200,7 +1200,7 @@ static inline u16 bpf_anc_helper(const struct sock_filter *ftest)
                BPF_ANCILLARY(RANDOM);
                BPF_ANCILLARY(VLAN_TPID);
                }
-               /* Fallthrough. */
+               fallthrough;
        default:
                return ftest->code;
        }
index 51b91c8..59faa80 100644 (file)
@@ -59,4 +59,17 @@ extern const struct font_desc *get_default_font(int xres, int yres,
 /* Max. length for the name of a predefined font */
 #define MAX_FONT_NAME  32
 
+/* Extra word getters */
+#define REFCOUNT(fd)   (((int *)(fd))[-1])
+#define FNTSIZE(fd)    (((int *)(fd))[-2])
+#define FNTCHARCNT(fd) (((int *)(fd))[-3])
+#define FNTSUM(fd)     (((int *)(fd))[-4])
+
+#define FONT_EXTRA_WORDS 4
+
+struct font_data {
+       unsigned int extra[FONT_EXTRA_WORDS];
+       const unsigned char data[];
+} __packed;
+
 #endif /* _VIDEO_FONT_H */
index e019ea2..e69b45b 100644 (file)
@@ -179,14 +179,6 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 #define FMODE_BUF_RASYNC       ((__force fmode_t)0x40000000)
 
 /*
- * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector
- * that indicates that they should check the contents of the iovec are
- * valid, but not check the memory that the iovec elements
- * points too.
- */
-#define CHECK_IOVEC_ONLY -1
-
-/*
  * Attribute flags.  These should be or-ed together to figure out what
  * has been changed!
  */
@@ -1887,11 +1879,6 @@ static inline int call_mmap(struct file *file, struct vm_area_struct *vma)
        return file->f_op->mmap(file, vma);
 }
 
-ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
-                             unsigned long nr_segs, unsigned long fast_segs,
-                             struct iovec *fast_pointer,
-                             struct iovec **ret_pointer);
-
 extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
 extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
 extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
@@ -2132,6 +2119,10 @@ static inline void kiocb_clone(struct kiocb *kiocb, struct kiocb *kiocb_src,
  *
  * I_DONTCACHE         Evict inode as soon as it is not used anymore.
  *
+ * I_SYNC_QUEUED       Inode is queued in b_io or b_more_io writeback lists.
+ *                     Used to detect that mark_inode_dirty() should not move
+ *                     inode between dirty lists.
+ *
  * Q: What is the difference between I_WILL_FREE and I_FREEING?
  */
 #define I_DIRTY_SYNC           (1 << 0)
@@ -2149,12 +2140,11 @@ static inline void kiocb_clone(struct kiocb *kiocb, struct kiocb *kiocb_src,
 #define I_DIO_WAKEUP           (1 << __I_DIO_WAKEUP)
 #define I_LINKABLE             (1 << 10)
 #define I_DIRTY_TIME           (1 << 11)
-#define __I_DIRTY_TIME_EXPIRED 12
-#define I_DIRTY_TIME_EXPIRED   (1 << __I_DIRTY_TIME_EXPIRED)
 #define I_WB_SWITCH            (1 << 13)
 #define I_OVL_INUSE            (1 << 14)
 #define I_CREATING             (1 << 15)
 #define I_DONTCACHE            (1 << 16)
+#define I_SYNC_QUEUED          (1 << 17)
 
 #define I_DIRTY_INODE (I_DIRTY_SYNC | I_DIRTY_DATASYNC)
 #define I_DIRTY (I_DIRTY_INODE | I_DIRTY_PAGES)
index 2eab6d5..aab0ffc 100644 (file)
@@ -120,7 +120,7 @@ static inline bool fs_validate_description(const char *name,
 #define fsparam_u32oct(NAME, OPT) \
                        __fsparam(fs_param_is_u32, NAME, OPT, 0, (void *)8)
 #define fsparam_u32hex(NAME, OPT) \
-                       __fsparam(fs_param_is_u32_hex, NAME, OPT, 0, (void *16))
+                       __fsparam(fs_param_is_u32_hex, NAME, OPT, 0, (void *)16)
 #define fsparam_s32(NAME, OPT) __fsparam(fs_param_is_s32, NAME, OPT, 0, NULL)
 #define fsparam_u64(NAME, OPT) __fsparam(fs_param_is_u64, NAME, OPT, 0, NULL)
 #define fsparam_enum(NAME, OPT, array) __fsparam(fs_param_is_enum, NAME, OPT, 0, array)
index 991ff85..a8f7a43 100644 (file)
 
 #include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/parser.h>
 #include <linux/slab.h>
 #include <uapi/linux/fscrypt.h>
 
 #define FS_CRYPTO_BLOCK_SIZE           16
 
-union fscrypt_context;
+union fscrypt_policy;
 struct fscrypt_info;
 struct seq_file;
 
@@ -36,7 +35,7 @@ struct fscrypt_name {
        u32 hash;
        u32 minor_hash;
        struct fscrypt_str crypto_buf;
-       bool is_ciphertext_name;
+       bool is_nokey_name;
 };
 
 #define FSTR_INIT(n, l)                { .name = n, .len = l }
@@ -62,8 +61,7 @@ struct fscrypt_operations {
        int (*get_context)(struct inode *inode, void *ctx, size_t len);
        int (*set_context)(struct inode *inode, const void *ctx, size_t len,
                           void *fs_data);
-       const union fscrypt_context *(*get_dummy_context)(
-               struct super_block *sb);
+       const union fscrypt_policy *(*get_dummy_policy)(struct super_block *sb);
        bool (*empty_dir)(struct inode *inode);
        unsigned int max_namelen;
        bool (*has_stable_inodes)(struct super_block *sb);
@@ -101,24 +99,16 @@ static inline bool fscrypt_needs_contents_encryption(const struct inode *inode)
        return IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode);
 }
 
-static inline const union fscrypt_context *
-fscrypt_get_dummy_context(struct super_block *sb)
-{
-       if (!sb->s_cop->get_dummy_context)
-               return NULL;
-       return sb->s_cop->get_dummy_context(sb);
-}
-
 /*
- * When d_splice_alias() moves a directory's encrypted alias to its decrypted
- * alias as a result of the encryption key being added, DCACHE_ENCRYPTED_NAME
- * must be cleared.  Note that we don't have to support arbitrary moves of this
- * flag because fscrypt doesn't allow encrypted aliases to be the source or
- * target of a rename().
+ * When d_splice_alias() moves a directory's no-key alias to its plaintext alias
+ * as a result of the encryption key being added, DCACHE_NOKEY_NAME must be
+ * cleared.  Note that we don't have to support arbitrary moves of this flag
+ * because fscrypt doesn't allow no-key names to be the source or target of a
+ * rename().
  */
 static inline void fscrypt_handle_d_move(struct dentry *dentry)
 {
-       dentry->d_flags &= ~DCACHE_ENCRYPTED_NAME;
+       dentry->d_flags &= ~DCACHE_NOKEY_NAME;
 }
 
 /* crypto.c */
@@ -156,23 +146,21 @@ int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg);
 int fscrypt_ioctl_get_policy_ex(struct file *filp, void __user *arg);
 int fscrypt_ioctl_get_nonce(struct file *filp, void __user *arg);
 int fscrypt_has_permitted_context(struct inode *parent, struct inode *child);
-int fscrypt_inherit_context(struct inode *parent, struct inode *child,
-                           void *fs_data, bool preload);
+int fscrypt_set_context(struct inode *inode, void *fs_data);
 
-struct fscrypt_dummy_context {
-       const union fscrypt_context *ctx;
+struct fscrypt_dummy_policy {
+       const union fscrypt_policy *policy;
 };
 
-int fscrypt_set_test_dummy_encryption(struct super_block *sb,
-                                     const substring_t *arg,
-                                     struct fscrypt_dummy_context *dummy_ctx);
+int fscrypt_set_test_dummy_encryption(struct super_block *sb, const char *arg,
+                               struct fscrypt_dummy_policy *dummy_policy);
 void fscrypt_show_test_dummy_encryption(struct seq_file *seq, char sep,
                                        struct super_block *sb);
 static inline void
-fscrypt_free_dummy_context(struct fscrypt_dummy_context *dummy_ctx)
+fscrypt_free_dummy_policy(struct fscrypt_dummy_policy *dummy_policy)
 {
-       kfree(dummy_ctx->ctx);
-       dummy_ctx->ctx = NULL;
+       kfree(dummy_policy->policy);
+       dummy_policy->policy = NULL;
 }
 
 /* keyring.c */
@@ -184,6 +172,8 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *arg);
 
 /* keysetup.c */
 int fscrypt_get_encryption_info(struct inode *inode);
+int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
+                             bool *encrypt_ret);
 void fscrypt_put_encryption_info(struct inode *inode);
 void fscrypt_free_inode(struct inode *inode);
 int fscrypt_drop_inode(struct inode *inode);
@@ -197,7 +187,7 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname)
        kfree(fname->crypto_buf.name);
 }
 
-int fscrypt_fname_alloc_buffer(const struct inode *inode, u32 max_encrypted_len,
+int fscrypt_fname_alloc_buffer(u32 max_encrypted_len,
                               struct fscrypt_str *crypto_str);
 void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str);
 int fscrypt_fname_disk_to_usr(const struct inode *inode,
@@ -207,6 +197,7 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
 bool fscrypt_match_name(const struct fscrypt_name *fname,
                        const u8 *de_name, u32 de_name_len);
 u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name);
+int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags);
 
 /* bio.c */
 void fscrypt_decrypt_bio(struct bio *bio);
@@ -224,9 +215,9 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
                             struct fscrypt_name *fname);
 int fscrypt_prepare_setflags(struct inode *inode,
                             unsigned int oldflags, unsigned int flags);
-int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
-                             unsigned int max_len,
-                             struct fscrypt_str *disk_link);
+int fscrypt_prepare_symlink(struct inode *dir, const char *target,
+                           unsigned int len, unsigned int max_len,
+                           struct fscrypt_str *disk_link);
 int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
                              unsigned int len, struct fscrypt_str *disk_link);
 const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
@@ -249,12 +240,6 @@ static inline bool fscrypt_needs_contents_encryption(const struct inode *inode)
        return false;
 }
 
-static inline const union fscrypt_context *
-fscrypt_get_dummy_context(struct super_block *sb)
-{
-       return NULL;
-}
-
 static inline void fscrypt_handle_d_move(struct dentry *dentry)
 {
 }
@@ -340,14 +325,12 @@ static inline int fscrypt_has_permitted_context(struct inode *parent,
        return 0;
 }
 
-static inline int fscrypt_inherit_context(struct inode *parent,
-                                         struct inode *child,
-                                         void *fs_data, bool preload)
+static inline int fscrypt_set_context(struct inode *inode, void *fs_data)
 {
        return -EOPNOTSUPP;
 }
 
-struct fscrypt_dummy_context {
+struct fscrypt_dummy_policy {
 };
 
 static inline void fscrypt_show_test_dummy_encryption(struct seq_file *seq,
@@ -357,7 +340,7 @@ static inline void fscrypt_show_test_dummy_encryption(struct seq_file *seq,
 }
 
 static inline void
-fscrypt_free_dummy_context(struct fscrypt_dummy_context *dummy_ctx)
+fscrypt_free_dummy_policy(struct fscrypt_dummy_policy *dummy_policy)
 {
 }
 
@@ -394,6 +377,15 @@ static inline int fscrypt_get_encryption_info(struct inode *inode)
        return -EOPNOTSUPP;
 }
 
+static inline int fscrypt_prepare_new_inode(struct inode *dir,
+                                           struct inode *inode,
+                                           bool *encrypt_ret)
+{
+       if (IS_ENCRYPTED(dir))
+               return -EOPNOTSUPP;
+       return 0;
+}
+
 static inline void fscrypt_put_encryption_info(struct inode *inode)
 {
        return;
@@ -428,8 +420,7 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname)
        return;
 }
 
-static inline int fscrypt_fname_alloc_buffer(const struct inode *inode,
-                                            u32 max_encrypted_len,
+static inline int fscrypt_fname_alloc_buffer(u32 max_encrypted_len,
                                             struct fscrypt_str *crypto_str)
 {
        return -EOPNOTSUPP;
@@ -464,6 +455,12 @@ static inline u64 fscrypt_fname_siphash(const struct inode *dir,
        return 0;
 }
 
+static inline int fscrypt_d_revalidate(struct dentry *dentry,
+                                      unsigned int flags)
+{
+       return 1;
+}
+
 /* bio.c */
 static inline void fscrypt_decrypt_bio(struct bio *bio)
 {
@@ -513,15 +510,21 @@ static inline int fscrypt_prepare_setflags(struct inode *inode,
        return 0;
 }
 
-static inline int __fscrypt_prepare_symlink(struct inode *dir,
-                                           unsigned int len,
-                                           unsigned int max_len,
-                                           struct fscrypt_str *disk_link)
+static inline int fscrypt_prepare_symlink(struct inode *dir,
+                                         const char *target,
+                                         unsigned int len,
+                                         unsigned int max_len,
+                                         struct fscrypt_str *disk_link)
 {
-       return -EOPNOTSUPP;
+       if (IS_ENCRYPTED(dir))
+               return -EOPNOTSUPP;
+       disk_link->name = (unsigned char *)target;
+       disk_link->len = len + 1;
+       if (disk_link->len > max_len)
+               return -ENAMETOOLONG;
+       return 0;
 }
 
-
 static inline int __fscrypt_encrypt_symlink(struct inode *inode,
                                            const char *target,
                                            unsigned int len,
@@ -734,17 +737,16 @@ static inline int fscrypt_prepare_rename(struct inode *old_dir,
  * @fname: (output) the name to use to search the on-disk directory
  *
  * Prepare for ->lookup() in a directory which may be encrypted by determining
- * the name that will actually be used to search the directory on-disk.  Lookups
- * can be done with or without the directory's encryption key; without the key,
- * filenames are presented in encrypted form.  Therefore, we'll try to set up
- * the directory's encryption key, but even without it the lookup can continue.
+ * the name that will actually be used to search the directory on-disk.  If the
+ * directory's encryption key is available, then the lookup is assumed to be by
+ * plaintext name; otherwise, it is assumed to be by no-key name.
  *
  * This also installs a custom ->d_revalidate() method which will invalidate the
  * dentry if it was created without the key and the key is later added.
  *
- * Return: 0 on success; -ENOENT if key is unavailable but the filename isn't a
- * correctly formed encoded ciphertext name, so a negative dentry should be
- * created; or another -errno code.
+ * Return: 0 on success; -ENOENT if the directory's key is unavailable but the
+ * filename isn't a valid no-key name, so a negative dentry should be created;
+ * or another -errno code.
  */
 static inline int fscrypt_prepare_lookup(struct inode *dir,
                                         struct dentry *dentry,
@@ -787,45 +789,6 @@ static inline int fscrypt_prepare_setattr(struct dentry *dentry,
 }
 
 /**
- * fscrypt_prepare_symlink() - prepare to create a possibly-encrypted symlink
- * @dir: directory in which the symlink is being created
- * @target: plaintext symlink target
- * @len: length of @target excluding null terminator
- * @max_len: space the filesystem has available to store the symlink target
- * @disk_link: (out) the on-disk symlink target being prepared
- *
- * This function computes the size the symlink target will require on-disk,
- * stores it in @disk_link->len, and validates it against @max_len.  An
- * encrypted symlink may be longer than the original.
- *
- * Additionally, @disk_link->name is set to @target if the symlink will be
- * unencrypted, but left NULL if the symlink will be encrypted.  For encrypted
- * symlinks, the filesystem must call fscrypt_encrypt_symlink() to create the
- * on-disk target later.  (The reason for the two-step process is that some
- * filesystems need to know the size of the symlink target before creating the
- * inode, e.g. to determine whether it will be a "fast" or "slow" symlink.)
- *
- * Return: 0 on success, -ENAMETOOLONG if the symlink target is too long,
- * -ENOKEY if the encryption key is missing, or another -errno code if a problem
- * occurred while setting up the encryption key.
- */
-static inline int fscrypt_prepare_symlink(struct inode *dir,
-                                         const char *target,
-                                         unsigned int len,
-                                         unsigned int max_len,
-                                         struct fscrypt_str *disk_link)
-{
-       if (IS_ENCRYPTED(dir) || fscrypt_get_dummy_context(dir->i_sb) != NULL)
-               return __fscrypt_prepare_symlink(dir, len, max_len, disk_link);
-
-       disk_link->name = (unsigned char *)target;
-       disk_link->len = len + 1;
-       if (disk_link->len > max_len)
-               return -ENAMETOOLONG;
-       return 0;
-}
-
-/**
  * fscrypt_encrypt_symlink() - encrypt the symlink target if needed
  * @inode: symlink inode
  * @target: plaintext symlink target
index ce2c06f..e5c2d5c 100644 (file)
@@ -85,8 +85,7 @@ static inline int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *val
 extern int ftrace_enabled;
 extern int
 ftrace_enable_sysctl(struct ctl_table *table, int write,
-                    void __user *buffer, size_t *lenp,
-                    loff_t *ppos);
+                    void *buffer, size_t *lenp, loff_t *ppos);
 
 struct ftrace_ops;
 
index 875f711..c7044a1 100644 (file)
@@ -959,34 +959,49 @@ static inline void hid_device_io_stop(struct hid_device *hid) {
  * @max: maximal valid usage->code to consider later (out parameter)
  * @type: input event type (EV_KEY, EV_REL, ...)
  * @c: code which corresponds to this usage and type
+ *
+ * The value pointed to by @bit will be set to NULL if either @type is
+ * an unhandled event type, or if @c is out of range for @type. This
+ * can be used as an error condition.
  */
 static inline void hid_map_usage(struct hid_input *hidinput,
                struct hid_usage *usage, unsigned long **bit, int *max,
-               __u8 type, __u16 c)
+               __u8 type, unsigned int c)
 {
        struct input_dev *input = hidinput->input;
-
-       usage->type = type;
-       usage->code = c;
+       unsigned long *bmap = NULL;
+       unsigned int limit = 0;
 
        switch (type) {
        case EV_ABS:
-               *bit = input->absbit;
-               *max = ABS_MAX;
+               bmap = input->absbit;
+               limit = ABS_MAX;
                break;
        case EV_REL:
-               *bit = input->relbit;
-               *max = REL_MAX;
+               bmap = input->relbit;
+               limit = REL_MAX;
                break;
        case EV_KEY:
-               *bit = input->keybit;
-               *max = KEY_MAX;
+               bmap = input->keybit;
+               limit = KEY_MAX;
                break;
        case EV_LED:
-               *bit = input->ledbit;
-               *max = LED_MAX;
+               bmap = input->ledbit;
+               limit = LED_MAX;
                break;
        }
+
+       if (unlikely(c > limit || !bmap)) {
+               pr_warn_ratelimited("%s: Invalid code %d type %d\n",
+                                   input->name, c, type);
+               *bit = NULL;
+               return;
+       }
+
+       usage->type = type;
+       usage->code = c;
+       *max = limit;
+       *bit = bmap;
 }
 
 /**
@@ -1000,7 +1015,8 @@ static inline void hid_map_usage_clear(struct hid_input *hidinput,
                __u8 type, __u16 c)
 {
        hid_map_usage(hidinput, usage, bit, max, type, c);
-       clear_bit(c, *bit);
+       if (*bit)
+               clear_bit(usage->code, *bit);
 }
 
 /**
diff --git a/include/linux/hidden.h b/include/linux/hidden.h
new file mode 100644 (file)
index 0000000..49a17b6
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * When building position independent code with GCC using the -fPIC option,
+ * (or even the -fPIE one on older versions), it will assume that we are
+ * building a dynamic object (either a shared library or an executable) that
+ * may have symbol references that can only be resolved at load time. For a
+ * variety of reasons (ELF symbol preemption, the CoW footprint of the section
+ * that is modified by the loader), this results in all references to symbols
+ * with external linkage to go via entries in the Global Offset Table (GOT),
+ * which carries absolute addresses which need to be fixed up when the
+ * executable image is loaded at an offset which is different from its link
+ * time offset.
+ *
+ * Fortunately, there is a way to inform the compiler that such symbol
+ * references will be satisfied at link time rather than at load time, by
+ * giving them 'hidden' visibility.
+ */
+
+#pragma GCC visibility push(hidden)
index d030717..7c522fd 100644 (file)
 #define I2C_PCA_CON_SI         0x08 /* Serial Interrupt */
 #define I2C_PCA_CON_CR         0x07 /* Clock Rate (MASK) */
 
+/**
+ * struct pca_i2c_bus_settings - The configured PCA i2c bus settings
+ * @mode: Configured i2c bus mode
+ * @tlow: Configured SCL LOW period
+ * @thi: Configured SCL HIGH period
+ * @clock_freq: The configured clock frequency
+ */
+struct pca_i2c_bus_settings {
+       int mode;
+       int tlow;
+       int thi;
+       int clock_freq;
+};
+
 struct i2c_algo_pca_data {
        void                            *data;  /* private low level data */
        void (*write_byte)              (void *data, int reg, int val);
@@ -64,6 +78,7 @@ struct i2c_algo_pca_data {
         * For PCA9665, use the frequency you want here. */
        unsigned int                    i2c_clock;
        unsigned int                    chip;
+       struct pca_i2c_bus_settings             bus_settings;
 };
 
 int i2c_pca_add_bus(struct i2c_adapter *);
index e2df67a..f1daaba 100644 (file)
@@ -641,7 +641,7 @@ static inline struct iio_dev *iio_device_get(struct iio_dev *indio_dev)
  *
  * This utility must be called between IIO device allocation
  * (via devm_iio_device_alloc()) & IIO device registration
- * (via {devm_}iio_device_register()).
+ * (via iio_device_register() and devm_iio_device_register())).
  * By default, the device allocation will also assign a parent device to
  * the IIO device object. In cases where devm_iio_device_alloc() is used,
  * sometimes the parent device must be different than the device used to
index 43e6ea5..42faebb 100644 (file)
@@ -43,6 +43,21 @@ static __always_inline void instrument_write(const volatile void *v, size_t size
 }
 
 /**
+ * instrument_read_write - instrument regular read-write access
+ *
+ * Instrument a regular write access. The instrumentation should be inserted
+ * before the actual write happens.
+ *
+ * @ptr address of access
+ * @size size of access
+ */
+static __always_inline void instrument_read_write(const volatile void *v, size_t size)
+{
+       kasan_check_write(v, size);
+       kcsan_check_read_write(v, size);
+}
+
+/**
  * instrument_atomic_read - instrument atomic read access
  *
  * Instrument an atomic read access. The instrumentation should be inserted
@@ -73,6 +88,21 @@ static __always_inline void instrument_atomic_write(const volatile void *v, size
 }
 
 /**
+ * instrument_atomic_read_write - instrument atomic read-write access
+ *
+ * Instrument an atomic read-write access. The instrumentation should be
+ * inserted before the actual write happens.
+ *
+ * @ptr address of access
+ * @size size of access
+ */
+static __always_inline void instrument_atomic_read_write(const volatile void *v, size_t size)
+{
+       kasan_check_write(v, size);
+       kcsan_check_atomic_read_write(v, size);
+}
+
+/**
  * instrument_copy_to_user - instrument reads of copy_to_user
  *
  * Instrument reads from kernel memory, that are due to copy_to_user (and
index b1ed2f2..473b24e 100644 (file)
@@ -425,6 +425,8 @@ struct q_inval {
        int             free_cnt;
 };
 
+struct dmar_pci_notify_info;
+
 #ifdef CONFIG_IRQ_REMAP
 /* 1MB - maximum possible interrupt remapping table size */
 #define INTR_REMAP_PAGE_ORDER  8
@@ -439,6 +441,11 @@ struct ir_table {
        struct irte *base;
        unsigned long *bitmap;
 };
+
+void intel_irq_remap_add_device(struct dmar_pci_notify_info *info);
+#else
+static inline void
+intel_irq_remap_add_device(struct dmar_pci_notify_info *info) { }
 #endif
 
 struct iommu_flush {
@@ -549,7 +556,7 @@ struct dmar_domain {
                                           2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
        u64             max_addr;       /* maximum mapped address */
 
-       int             default_pasid;  /*
+       u32             default_pasid;  /*
                                         * The default pasid used for non-SVM
                                         * traffic on mediated devices.
                                         */
@@ -708,7 +715,7 @@ void qi_flush_dev_iotlb_pasid(struct intel_iommu *iommu, u16 sid, u16 pfsid,
                              u32 pasid, u16 qdep, u64 addr,
                              unsigned int size_order);
 void qi_flush_pasid_cache(struct intel_iommu *iommu, u16 did, u64 granu,
-                         int pasid);
+                         u32 pasid);
 
 int qi_submit_sync(struct intel_iommu *iommu, struct qi_desc *desc,
                   unsigned int count, unsigned long options);
@@ -737,11 +744,11 @@ extern int intel_svm_enable_prq(struct intel_iommu *iommu);
 extern int intel_svm_finish_prq(struct intel_iommu *iommu);
 int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
                          struct iommu_gpasid_bind_data *data);
-int intel_svm_unbind_gpasid(struct device *dev, int pasid);
+int intel_svm_unbind_gpasid(struct device *dev, u32 pasid);
 struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm,
                                 void *drvdata);
 void intel_svm_unbind(struct iommu_sva *handle);
-int intel_svm_get_pasid(struct iommu_sva *handle);
+u32 intel_svm_get_pasid(struct iommu_sva *handle);
 int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
                            struct iommu_page_response *msg);
 
@@ -753,7 +760,7 @@ struct intel_svm_dev {
        struct device *dev;
        struct svm_dev_ops *ops;
        struct iommu_sva sva;
-       int pasid;
+       u32 pasid;
        int users;
        u16 did;
        u16 dev_iotlb:1;
@@ -765,8 +772,8 @@ struct intel_svm {
        struct mm_struct *mm;
 
        struct intel_iommu *iommu;
-       int flags;
-       int pasid;
+       unsigned int flags;
+       u32 pasid;
        int gpasid; /* In case that guest PASID is different from host PASID */
        struct list_head devs;
        struct list_head list;
index c9e7e60..39d368a 100644 (file)
@@ -11,7 +11,7 @@
 struct device;
 
 struct svm_dev_ops {
-       void (*fault_cb)(struct device *dev, int pasid, u64 address,
+       void (*fault_cb)(struct device *dev, u32 pasid, u64 address,
                         void *private, int rwxp, int response);
 };
 
index fee209e..e57e819 100644 (file)
@@ -286,7 +286,7 @@ struct iommu_ops {
        struct iommu_sva *(*sva_bind)(struct device *dev, struct mm_struct *mm,
                                      void *drvdata);
        void (*sva_unbind)(struct iommu_sva *handle);
-       int (*sva_get_pasid)(struct iommu_sva *handle);
+       u32 (*sva_get_pasid)(struct iommu_sva *handle);
 
        int (*page_response)(struct device *dev,
                             struct iommu_fault_event *evt,
@@ -296,7 +296,7 @@ struct iommu_ops {
        int (*sva_bind_gpasid)(struct iommu_domain *domain,
                        struct device *dev, struct iommu_gpasid_bind_data *data);
 
-       int (*sva_unbind_gpasid)(struct device *dev, int pasid);
+       int (*sva_unbind_gpasid)(struct device *dev, u32 pasid);
 
        int (*def_domain_type)(struct device *dev);
 
@@ -634,7 +634,7 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev,
                                        struct mm_struct *mm,
                                        void *drvdata);
 void iommu_sva_unbind_device(struct iommu_sva *handle);
-int iommu_sva_get_pasid(struct iommu_sva *handle);
+u32 iommu_sva_get_pasid(struct iommu_sva *handle);
 
 #else /* CONFIG_IOMMU_API */
 
@@ -1027,7 +1027,7 @@ static inline void iommu_sva_unbind_device(struct iommu_sva *handle)
 {
 }
 
-static inline int iommu_sva_get_pasid(struct iommu_sva *handle)
+static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle)
 {
        return IOMMU_PASID_INVALID;
 }
@@ -1046,7 +1046,7 @@ static inline int iommu_sva_bind_gpasid(struct iommu_domain *domain,
 }
 
 static inline int iommu_sva_unbind_gpasid(struct iommu_domain *domain,
-                                          struct device *dev, int pasid)
+                                          struct device *dev, u32 pasid)
 {
        return -ENODEV;
 }
index 1b7f4df..c543653 100644 (file)
@@ -71,6 +71,7 @@ enum irqchip_irq_state;
  *                               it from the spurious interrupt detection
  *                               mechanism and from core side polling.
  * IRQ_DISABLE_UNLAZY          - Disable lazy irq disable
+ * IRQ_HIDDEN                  - Don't show up in /proc/interrupts
  */
 enum {
        IRQ_TYPE_NONE           = 0x00000000,
@@ -97,13 +98,14 @@ enum {
        IRQ_PER_CPU_DEVID       = (1 << 17),
        IRQ_IS_POLLED           = (1 << 18),
        IRQ_DISABLE_UNLAZY      = (1 << 19),
+       IRQ_HIDDEN              = (1 << 20),
 };
 
 #define IRQF_MODIFY_MASK       \
        (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
         IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
         IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID | \
-        IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY)
+        IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY | IRQ_HIDDEN)
 
 #define IRQ_NO_BALANCING_MASK  (IRQ_PER_CPU | IRQ_NO_BALANCING)
 
@@ -215,6 +217,8 @@ struct irq_data {
  *                               from actual interrupt context.
  * IRQD_AFFINITY_ON_ACTIVATE   - Affinity is set on activation. Don't call
  *                               irq_chip::irq_set_affinity() when deactivated.
+ * IRQD_IRQ_ENABLED_ON_SUSPEND - Interrupt is enabled on suspend by irq pm if
+ *                               irqchip have flag IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND set.
  */
 enum {
        IRQD_TRIGGER_MASK               = 0xf,
@@ -240,6 +244,7 @@ enum {
        IRQD_MSI_NOMASK_QUIRK           = (1 << 27),
        IRQD_HANDLE_ENFORCE_IRQCTX      = (1 << 28),
        IRQD_AFFINITY_ON_ACTIVATE       = (1 << 29),
+       IRQD_IRQ_ENABLED_ON_SUSPEND     = (1 << 30),
 };
 
 #define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors)
@@ -319,6 +324,11 @@ static inline bool irqd_is_handle_enforce_irqctx(struct irq_data *d)
        return __irqd_to_state(d) & IRQD_HANDLE_ENFORCE_IRQCTX;
 }
 
+static inline bool irqd_is_enabled_on_suspend(struct irq_data *d)
+{
+       return __irqd_to_state(d) & IRQD_IRQ_ENABLED_ON_SUSPEND;
+}
+
 static inline bool irqd_is_wakeup_set(struct irq_data *d)
 {
        return __irqd_to_state(d) & IRQD_WAKEUP_STATE;
@@ -545,27 +555,30 @@ struct irq_chip {
 /*
  * irq_chip specific flags
  *
- * IRQCHIP_SET_TYPE_MASKED:    Mask before calling chip.irq_set_type()
- * IRQCHIP_EOI_IF_HANDLED:     Only issue irq_eoi() when irq was handled
- * IRQCHIP_MASK_ON_SUSPEND:    Mask non wake irqs in the suspend path
- * IRQCHIP_ONOFFLINE_ENABLED:  Only call irq_on/off_line callbacks
- *                             when irq enabled
- * IRQCHIP_SKIP_SET_WAKE:      Skip chip.irq_set_wake(), for this irq chip
- * IRQCHIP_ONESHOT_SAFE:       One shot does not require mask/unmask
- * IRQCHIP_EOI_THREADED:       Chip requires eoi() on unmask in threaded mode
- * IRQCHIP_SUPPORTS_LEVEL_MSI  Chip can provide two doorbells for Level MSIs
- * IRQCHIP_SUPPORTS_NMI:       Chip can deliver NMIs, only for root irqchips
+ * IRQCHIP_SET_TYPE_MASKED:           Mask before calling chip.irq_set_type()
+ * IRQCHIP_EOI_IF_HANDLED:            Only issue irq_eoi() when irq was handled
+ * IRQCHIP_MASK_ON_SUSPEND:           Mask non wake irqs in the suspend path
+ * IRQCHIP_ONOFFLINE_ENABLED:         Only call irq_on/off_line callbacks
+ *                                    when irq enabled
+ * IRQCHIP_SKIP_SET_WAKE:             Skip chip.irq_set_wake(), for this irq chip
+ * IRQCHIP_ONESHOT_SAFE:              One shot does not require mask/unmask
+ * IRQCHIP_EOI_THREADED:              Chip requires eoi() on unmask in threaded mode
+ * IRQCHIP_SUPPORTS_LEVEL_MSI:        Chip can provide two doorbells for Level MSIs
+ * IRQCHIP_SUPPORTS_NMI:              Chip can deliver NMIs, only for root irqchips
+ * IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND:  Invokes __enable_irq()/__disable_irq() for wake irqs
+ *                                    in the suspend path if they are in disabled state
  */
 enum {
-       IRQCHIP_SET_TYPE_MASKED         = (1 <<  0),
-       IRQCHIP_EOI_IF_HANDLED          = (1 <<  1),
-       IRQCHIP_MASK_ON_SUSPEND         = (1 <<  2),
-       IRQCHIP_ONOFFLINE_ENABLED       = (1 <<  3),
-       IRQCHIP_SKIP_SET_WAKE           = (1 <<  4),
-       IRQCHIP_ONESHOT_SAFE            = (1 <<  5),
-       IRQCHIP_EOI_THREADED            = (1 <<  6),
-       IRQCHIP_SUPPORTS_LEVEL_MSI      = (1 <<  7),
-       IRQCHIP_SUPPORTS_NMI            = (1 <<  8),
+       IRQCHIP_SET_TYPE_MASKED                 = (1 <<  0),
+       IRQCHIP_EOI_IF_HANDLED                  = (1 <<  1),
+       IRQCHIP_MASK_ON_SUSPEND                 = (1 <<  2),
+       IRQCHIP_ONOFFLINE_ENABLED               = (1 <<  3),
+       IRQCHIP_SKIP_SET_WAKE                   = (1 <<  4),
+       IRQCHIP_ONESHOT_SAFE                    = (1 <<  5),
+       IRQCHIP_EOI_THREADED                    = (1 <<  6),
+       IRQCHIP_SUPPORTS_LEVEL_MSI              = (1 <<  7),
+       IRQCHIP_SUPPORTS_NMI                    = (1 <<  8),
+       IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND        = (1 <<  9),
 };
 
 #include <linux/irqdesc.h>
@@ -634,6 +647,7 @@ static inline int irq_set_parent(int irq, int parent_irq)
  */
 extern void handle_level_irq(struct irq_desc *desc);
 extern void handle_fasteoi_irq(struct irq_desc *desc);
+extern void handle_percpu_devid_fasteoi_ipi(struct irq_desc *desc);
 extern void handle_edge_irq(struct irq_desc *desc);
 extern void handle_edge_eoi_irq(struct irq_desc *desc);
 extern void handle_simple_irq(struct irq_desc *desc);
@@ -1252,6 +1266,12 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *));
  * top-level IRQ handler.
  */
 extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init;
+#else
+#define set_handle_irq(handle_irq)             \
+       do {                                    \
+               (void)handle_irq;               \
+               WARN_ON(1);                     \
+       } while (0)
 #endif
 
 #endif /* _LINUX_IRQ_H */
index b37350c..71535e8 100644 (file)
@@ -84,6 +84,7 @@ enum irq_domain_bus_token {
        DOMAIN_BUS_FSL_MC_MSI,
        DOMAIN_BUS_TI_SCI_INTA_MSI,
        DOMAIN_BUS_WAKEUP,
+       DOMAIN_BUS_VMD_MSI,
 };
 
 /**
@@ -509,6 +510,9 @@ extern void irq_domain_free_irqs_parent(struct irq_domain *domain,
                                        unsigned int irq_base,
                                        unsigned int nr_irqs);
 
+extern int irq_domain_disconnect_hierarchy(struct irq_domain *domain,
+                                          unsigned int virq);
+
 static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
 {
        return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY;
index bd5c557..3ed4e87 100644 (file)
@@ -49,17 +49,18 @@ struct irqtrace_events {
 DECLARE_PER_CPU(int, hardirqs_enabled);
 DECLARE_PER_CPU(int, hardirq_context);
 
-  extern void trace_hardirqs_on_prepare(void);
-  extern void trace_hardirqs_off_finish(void);
-  extern void trace_hardirqs_on(void);
-  extern void trace_hardirqs_off(void);
-# define lockdep_hardirq_context()     (this_cpu_read(hardirq_context))
+extern void trace_hardirqs_on_prepare(void);
+extern void trace_hardirqs_off_finish(void);
+extern void trace_hardirqs_on(void);
+extern void trace_hardirqs_off(void);
+
+# define lockdep_hardirq_context()     (raw_cpu_read(hardirq_context))
 # define lockdep_softirq_context(p)    ((p)->softirq_context)
 # define lockdep_hardirqs_enabled()    (this_cpu_read(hardirqs_enabled))
 # define lockdep_softirqs_enabled(p)   ((p)->softirqs_enabled)
 # define lockdep_hardirq_enter()                       \
 do {                                                   \
-       if (this_cpu_inc_return(hardirq_context) == 1)  \
+       if (__this_cpu_inc_return(hardirq_context) == 1)\
                current->hardirq_threaded = 0;          \
 } while (0)
 # define lockdep_hardirq_threaded()            \
@@ -68,7 +69,7 @@ do {                                          \
 } while (0)
 # define lockdep_hardirq_exit()                        \
 do {                                           \
-       this_cpu_dec(hardirq_context);          \
+       __this_cpu_dec(hardirq_context);        \
 } while (0)
 # define lockdep_softirq_enter()               \
 do {                                           \
@@ -120,17 +121,17 @@ do {                                              \
 #else
 # define trace_hardirqs_on_prepare()           do { } while (0)
 # define trace_hardirqs_off_finish()           do { } while (0)
-# define trace_hardirqs_on()           do { } while (0)
-# define trace_hardirqs_off()          do { } while (0)
-# define lockdep_hardirq_context()     0
-# define lockdep_softirq_context(p)    0
-# define lockdep_hardirqs_enabled()    0
-# define lockdep_softirqs_enabled(p)   0
-# define lockdep_hardirq_enter()       do { } while (0)
-# define lockdep_hardirq_threaded()    do { } while (0)
-# define lockdep_hardirq_exit()                do { } while (0)
-# define lockdep_softirq_enter()       do { } while (0)
-# define lockdep_softirq_exit()                do { } while (0)
+# define trace_hardirqs_on()                   do { } while (0)
+# define trace_hardirqs_off()                  do { } while (0)
+# define lockdep_hardirq_context()             0
+# define lockdep_softirq_context(p)            0
+# define lockdep_hardirqs_enabled()            0
+# define lockdep_softirqs_enabled(p)           0
+# define lockdep_hardirq_enter()               do { } while (0)
+# define lockdep_hardirq_threaded()            do { } while (0)
+# define lockdep_hardirq_exit()                        do { } while (0)
+# define lockdep_softirq_enter()               do { } while (0)
+# define lockdep_softirq_exit()                        do { } while (0)
 # define lockdep_hrtimer_enter(__hrtimer)      false
 # define lockdep_hrtimer_exit(__context)       do { } while (0)
 # define lockdep_posixtimer_enter()            do { } while (0)
@@ -181,26 +182,33 @@ do {                                              \
  * if !TRACE_IRQFLAGS.
  */
 #ifdef CONFIG_TRACE_IRQFLAGS
-#define local_irq_enable() \
-       do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0)
-#define local_irq_disable() \
-       do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0)
+
+#define local_irq_enable()                             \
+       do {                                            \
+               trace_hardirqs_on();                    \
+               raw_local_irq_enable();                 \
+       } while (0)
+
+#define local_irq_disable()                            \
+       do {                                            \
+               bool was_disabled = raw_irqs_disabled();\
+               raw_local_irq_disable();                \
+               if (!was_disabled)                      \
+                       trace_hardirqs_off();           \
+       } while (0)
+
 #define local_irq_save(flags)                          \
        do {                                            \
                raw_local_irq_save(flags);              \
-               trace_hardirqs_off();                   \
+               if (!raw_irqs_disabled_flags(flags))    \
+                       trace_hardirqs_off();           \
        } while (0)
 
-
 #define local_irq_restore(flags)                       \
        do {                                            \
-               if (raw_irqs_disabled_flags(flags)) {   \
-                       raw_local_irq_restore(flags);   \
-                       trace_hardirqs_off();           \
-               } else {                                \
+               if (!raw_irqs_disabled_flags(flags))    \
                        trace_hardirqs_on();            \
-                       raw_local_irq_restore(flags);   \
-               }                                       \
+               raw_local_irq_restore(flags);           \
        } while (0)
 
 #define safe_halt()                            \
@@ -214,10 +222,7 @@ do {                                               \
 
 #define local_irq_enable()     do { raw_local_irq_enable(); } while (0)
 #define local_irq_disable()    do { raw_local_irq_disable(); } while (0)
-#define local_irq_save(flags)                                  \
-       do {                                                    \
-               raw_local_irq_save(flags);                      \
-       } while (0)
+#define local_irq_save(flags)  do { raw_local_irq_save(flags); } while (0)
 #define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0)
 #define safe_halt()            do { raw_safe_halt(); } while (0)
 
index 19ddd43..cfb62e9 100644 (file)
@@ -86,17 +86,17 @@ static inline u32 jhash(const void *key, u32 length, u32 initval)
        }
        /* Last block: affect all 32 bits of (c) */
        switch (length) {
-       case 12: c += (u32)k[11]<<24;   /* fall through */
-       case 11: c += (u32)k[10]<<16;   /* fall through */
-       case 10: c += (u32)k[9]<<8;     /* fall through */
-       case 9:  c += k[8];             /* fall through */
-       case 8:  b += (u32)k[7]<<24;    /* fall through */
-       case 7:  b += (u32)k[6]<<16;    /* fall through */
-       case 6:  b += (u32)k[5]<<8;     /* fall through */
-       case 5:  b += k[4];             /* fall through */
-       case 4:  a += (u32)k[3]<<24;    /* fall through */
-       case 3:  a += (u32)k[2]<<16;    /* fall through */
-       case 2:  a += (u32)k[1]<<8;     /* fall through */
+       case 12: c += (u32)k[11]<<24;   fallthrough;
+       case 11: c += (u32)k[10]<<16;   fallthrough;
+       case 10: c += (u32)k[9]<<8;     fallthrough;
+       case 9:  c += k[8];             fallthrough;
+       case 8:  b += (u32)k[7]<<24;    fallthrough;
+       case 7:  b += (u32)k[6]<<16;    fallthrough;
+       case 6:  b += (u32)k[5]<<8;     fallthrough;
+       case 5:  b += k[4];             fallthrough;
+       case 4:  a += (u32)k[3]<<24;    fallthrough;
+       case 3:  a += (u32)k[2]<<16;    fallthrough;
+       case 2:  a += (u32)k[1]<<8;     fallthrough;
        case 1:  a += k[0];
                 __jhash_final(a, b, c);
        case 0: /* Nothing left to add */
@@ -132,8 +132,8 @@ static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
 
        /* Handle the last 3 u32's */
        switch (length) {
-       case 3: c += k[2];      /* fall through */
-       case 2: b += k[1];      /* fall through */
+       case 3: c += k[2];      fallthrough;
+       case 2: b += k[1];      fallthrough;
        case 1: a += k[0];
                __jhash_final(a, b, c);
        case 0: /* Nothing left to add */
index c5f6c1d..cf14840 100644 (file)
@@ -7,19 +7,13 @@
 #include <linux/compiler_attributes.h>
 #include <linux/types.h>
 
-/*
- * ACCESS TYPE MODIFIERS
- *
- *   <none>: normal read access;
- *   WRITE : write access;
- *   ATOMIC: access is atomic;
- *   ASSERT: access is not a regular access, but an assertion;
- *   SCOPED: access is a scoped access;
- */
-#define KCSAN_ACCESS_WRITE  0x1
-#define KCSAN_ACCESS_ATOMIC 0x2
-#define KCSAN_ACCESS_ASSERT 0x4
-#define KCSAN_ACCESS_SCOPED 0x8
+/* Access types -- if KCSAN_ACCESS_WRITE is not set, the access is a read. */
+#define KCSAN_ACCESS_WRITE     (1 << 0) /* Access is a write. */
+#define KCSAN_ACCESS_COMPOUND  (1 << 1) /* Compounded read-write instrumentation. */
+#define KCSAN_ACCESS_ATOMIC    (1 << 2) /* Access is atomic. */
+/* The following are special, and never due to compiler instrumentation. */
+#define KCSAN_ACCESS_ASSERT    (1 << 3) /* Access is an assertion. */
+#define KCSAN_ACCESS_SCOPED    (1 << 4) /* Access is a scoped access. */
 
 /*
  * __kcsan_*: Always calls into the runtime when KCSAN is enabled. This may be used
@@ -205,6 +199,15 @@ static inline void __kcsan_disable_current(void) { }
        __kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE)
 
 /**
+ * __kcsan_check_read_write - check regular read-write access for races
+ *
+ * @ptr: address of access
+ * @size: size of access
+ */
+#define __kcsan_check_read_write(ptr, size)                                    \
+       __kcsan_check_access(ptr, size, KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE)
+
+/**
  * kcsan_check_read - check regular read access for races
  *
  * @ptr: address of access
@@ -221,18 +224,30 @@ static inline void __kcsan_disable_current(void) { }
 #define kcsan_check_write(ptr, size)                                           \
        kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE)
 
+/**
+ * kcsan_check_read_write - check regular read-write access for races
+ *
+ * @ptr: address of access
+ * @size: size of access
+ */
+#define kcsan_check_read_write(ptr, size)                                      \
+       kcsan_check_access(ptr, size, KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE)
+
 /*
  * Check for atomic accesses: if atomic accesses are not ignored, this simply
  * aliases to kcsan_check_access(), otherwise becomes a no-op.
  */
 #ifdef CONFIG_KCSAN_IGNORE_ATOMICS
-#define kcsan_check_atomic_read(...)   do { } while (0)
-#define kcsan_check_atomic_write(...)  do { } while (0)
+#define kcsan_check_atomic_read(...)           do { } while (0)
+#define kcsan_check_atomic_write(...)          do { } while (0)
+#define kcsan_check_atomic_read_write(...)     do { } while (0)
 #else
 #define kcsan_check_atomic_read(ptr, size)                                     \
        kcsan_check_access(ptr, size, KCSAN_ACCESS_ATOMIC)
 #define kcsan_check_atomic_write(ptr, size)                                    \
        kcsan_check_access(ptr, size, KCSAN_ACCESS_ATOMIC | KCSAN_ACCESS_WRITE)
+#define kcsan_check_atomic_read_write(ptr, size)                               \
+       kcsan_check_access(ptr, size, KCSAN_ACCESS_ATOMIC | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_COMPOUND)
 #endif
 
 /**
index abd20ef..eee1877 100644 (file)
@@ -17,5 +17,6 @@
 #define KPF_ARCH               38
 #define KPF_UNCACHED           39
 #define KPF_SOFTDIRTY          40
+#define KPF_ARCH_2             41
 
 #endif /* LINUX_KERNEL_PAGE_FLAGS_H */
index 500def6..c25b8e4 100644 (file)
  * lower_32_bits - return bits 0-31 of a number
  * @n: the number we're accessing
  */
-#define lower_32_bits(n) ((u32)(n))
+#define lower_32_bits(n) ((u32)((n) & 0xffffffff))
 
 struct completion;
 struct pt_regs;
index bc45ea1..c941b73 100644 (file)
@@ -15,6 +15,7 @@ extern int __khugepaged_enter(struct mm_struct *mm);
 extern void __khugepaged_exit(struct mm_struct *mm);
 extern int khugepaged_enter_vma_merge(struct vm_area_struct *vma,
                                      unsigned long vm_flags);
+extern void khugepaged_min_free_kbytes_update(void);
 #ifdef CONFIG_SHMEM
 extern void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr);
 #else
@@ -85,6 +86,10 @@ static inline void collapse_pte_mapped_thp(struct mm_struct *mm,
                                           unsigned long addr)
 {
 }
+
+static inline void khugepaged_min_free_kbytes_update(void)
+{
+}
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 #endif /* _LINUX_KHUGEPAGED_H */
index 9be1bff..629abaf 100644 (file)
@@ -156,7 +156,10 @@ struct kretprobe {
 };
 
 struct kretprobe_instance {
-       struct hlist_node hlist;
+       union {
+               struct hlist_node hlist;
+               struct rcu_head rcu;
+       };
        struct kretprobe *rp;
        kprobe_opcode_t *ret_addr;
        struct task_struct *task;
@@ -187,10 +190,37 @@ static inline int kprobes_built_in(void)
        return 1;
 }
 
+extern void kprobe_busy_begin(void);
+extern void kprobe_busy_end(void);
+
 #ifdef CONFIG_KRETPROBES
 extern void arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                   struct pt_regs *regs);
 extern int arch_trampoline_kprobe(struct kprobe *p);
+
+/* If the trampoline handler called from a kprobe, use this version */
+unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,
+                               void *trampoline_address,
+                               void *frame_pointer);
+
+static nokprobe_inline
+unsigned long kretprobe_trampoline_handler(struct pt_regs *regs,
+                               void *trampoline_address,
+                               void *frame_pointer)
+{
+       unsigned long ret;
+       /*
+        * Set a dummy kprobe for avoiding kretprobe recursion.
+        * Since kretprobe never runs in kprobe handler, no kprobe must
+        * be running at this point.
+        */
+       kprobe_busy_begin();
+       ret = __kretprobe_trampoline_handler(regs, trampoline_address, frame_pointer);
+       kprobe_busy_end();
+
+       return ret;
+}
+
 #else /* CONFIG_KRETPROBES */
 static inline void arch_prepare_kretprobe(struct kretprobe *rp,
                                        struct pt_regs *regs)
@@ -204,16 +234,6 @@ static inline int arch_trampoline_kprobe(struct kprobe *p)
 
 extern struct kretprobe_blackpoint kretprobe_blacklist[];
 
-static inline void kretprobe_assert(struct kretprobe_instance *ri,
-       unsigned long orig_ret_address, unsigned long trampoline_address)
-{
-       if (!orig_ret_address || (orig_ret_address == trampoline_address)) {
-               printk("kretprobe BUG!: Processing kretprobe %p @ %p\n",
-                               ri->rp, ri->rp->kp.addr);
-               BUG();
-       }
-}
-
 #ifdef CONFIG_KPROBES_SANITY_TEST
 extern int init_test_probes(void);
 #else
@@ -333,10 +353,6 @@ int arch_check_ftrace_location(struct kprobe *p);
 
 /* Get the kprobe at this addr (if any) - called with preemption disabled */
 struct kprobe *get_kprobe(void *addr);
-void kretprobe_hash_lock(struct task_struct *tsk,
-                        struct hlist_head **head, unsigned long *flags);
-void kretprobe_hash_unlock(struct task_struct *tsk, unsigned long *flags);
-struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk);
 
 /* kprobe_running() will just return the current_kprobe on this CPU */
 static inline struct kprobe *kprobe_running(void)
@@ -354,10 +370,6 @@ static inline struct kprobe_ctlblk *get_kprobe_ctlblk(void)
        return this_cpu_ptr(&kprobe_ctlblk);
 }
 
-extern struct kprobe kprobe_busy;
-void kprobe_busy_begin(void);
-void kprobe_busy_end(void);
-
 kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset);
 int register_kprobe(struct kprobe *p);
 void unregister_kprobe(struct kprobe *p);
@@ -371,7 +383,8 @@ int register_kretprobes(struct kretprobe **rps, int num);
 void unregister_kretprobes(struct kretprobe **rps, int num);
 
 void kprobe_flush_task(struct task_struct *tk);
-void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head);
+
+void kprobe_free_init_mem(void);
 
 int disable_kprobe(struct kprobe *kp);
 int enable_kprobe(struct kprobe *kp);
@@ -435,6 +448,9 @@ static inline void unregister_kretprobes(struct kretprobe **rps, int num)
 static inline void kprobe_flush_task(struct task_struct *tk)
 {
 }
+static inline void kprobe_free_init_mem(void)
+{
+}
 static inline int disable_kprobe(struct kprobe *kp)
 {
        return -ENOSYS;
index e48b1e4..161e816 100644 (file)
@@ -53,8 +53,6 @@ struct page *ksm_might_need_to_copy(struct page *page,
 
 void rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc);
 void ksm_migrate_page(struct page *newpage, struct page *oldpage);
-bool reuse_ksm_page(struct page *page,
-                       struct vm_area_struct *vma, unsigned long address);
 
 #else  /* !CONFIG_KSM */
 
@@ -88,11 +86,6 @@ static inline void rmap_walk_ksm(struct page *page,
 static inline void ksm_migrate_page(struct page *newpage, struct page *oldpage)
 {
 }
-static inline bool reuse_ksm_page(struct page *page,
-                       struct vm_area_struct *vma, unsigned long address)
-{
-       return false;
-}
 #endif /* CONFIG_MMU */
 #endif /* !CONFIG_KSM */
 
index a230767..05e3c2f 100644 (file)
@@ -749,25 +749,46 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
                              gpa_t gpa, unsigned long len);
 
-#define __kvm_put_guest(kvm, gfn, offset, value, type)                 \
+#define __kvm_get_guest(kvm, gfn, offset, v)                           \
 ({                                                                     \
        unsigned long __addr = gfn_to_hva(kvm, gfn);                    \
-       type __user *__uaddr = (type __user *)(__addr + offset);        \
+       typeof(v) __user *__uaddr = (typeof(__uaddr))(__addr + offset); \
        int __ret = -EFAULT;                                            \
                                                                        \
        if (!kvm_is_error_hva(__addr))                                  \
-               __ret = put_user(value, __uaddr);                       \
+               __ret = get_user(v, __uaddr);                           \
+       __ret;                                                          \
+})
+
+#define kvm_get_guest(kvm, gpa, v)                                     \
+({                                                                     \
+       gpa_t __gpa = gpa;                                              \
+       struct kvm *__kvm = kvm;                                        \
+                                                                       \
+       __kvm_get_guest(__kvm, __gpa >> PAGE_SHIFT,                     \
+                       offset_in_page(__gpa), v);                      \
+})
+
+#define __kvm_put_guest(kvm, gfn, offset, v)                           \
+({                                                                     \
+       unsigned long __addr = gfn_to_hva(kvm, gfn);                    \
+       typeof(v) __user *__uaddr = (typeof(__uaddr))(__addr + offset); \
+       int __ret = -EFAULT;                                            \
+                                                                       \
+       if (!kvm_is_error_hva(__addr))                                  \
+               __ret = put_user(v, __uaddr);                           \
        if (!__ret)                                                     \
                mark_page_dirty(kvm, gfn);                              \
        __ret;                                                          \
 })
 
-#define kvm_put_guest(kvm, gpa, value, type)                           \
+#define kvm_put_guest(kvm, gpa, v)                                     \
 ({                                                                     \
        gpa_t __gpa = gpa;                                              \
        struct kvm *__kvm = kvm;                                        \
+                                                                       \
        __kvm_put_guest(__kvm, __gpa >> PAGE_SHIFT,                     \
-                       offset_in_page(__gpa), (value), type);          \
+                       offset_in_page(__gpa), v);                      \
 })
 
 int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len);
index 77ccf04..5f550eb 100644 (file)
@@ -421,6 +421,7 @@ enum {
        ATA_HORKAGE_NO_DMA_LOG  = (1 << 23),    /* don't use DMA for log read */
        ATA_HORKAGE_NOTRIM      = (1 << 24),    /* don't use TRIM */
        ATA_HORKAGE_MAX_SEC_1024 = (1 << 25),   /* Limit max sects to 1024 */
+       ATA_HORKAGE_MAX_TRIM_128M = (1 << 26),  /* Limit max trim size to 128M */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
index 62a382d..f559487 100644 (file)
@@ -54,7 +54,11 @@ struct lock_list {
        struct lock_class               *class;
        struct lock_class               *links_to;
        const struct lock_trace         *trace;
-       int                             distance;
+       u16                             distance;
+       /* bitmap of different dependencies from head to this */
+       u8                              dep;
+       /* used by BFS to record whether "prev -> this" only has -(*R)-> */
+       u8                              only_xr;
 
        /*
         * The parent field is used to implement breadth-first search, and the
@@ -469,6 +473,20 @@ static inline void print_irqtrace_events(struct task_struct *curr)
 }
 #endif
 
+/* Variable used to make lockdep treat read_lock() as recursive in selftests */
+#ifdef CONFIG_DEBUG_LOCKING_API_SELFTESTS
+extern unsigned int force_read_lock_recursive;
+#else /* CONFIG_DEBUG_LOCKING_API_SELFTESTS */
+#define force_read_lock_recursive 0
+#endif /* CONFIG_DEBUG_LOCKING_API_SELFTESTS */
+
+#ifdef CONFIG_LOCKDEP
+extern bool read_lock_is_recursive(void);
+#else /* CONFIG_LOCKDEP */
+/* If !LOCKDEP, the value is meaningless */
+#define read_lock_is_recursive() 0
+#endif
+
 /*
  * For trivial one-depth nesting of a lock-class, the following
  * global define can be used. (Subsystems with multiple levels
@@ -490,7 +508,14 @@ static inline void print_irqtrace_events(struct task_struct *curr)
 #define spin_release(l, i)                     lock_release(l, i)
 
 #define rwlock_acquire(l, s, t, i)             lock_acquire_exclusive(l, s, t, NULL, i)
-#define rwlock_acquire_read(l, s, t, i)                lock_acquire_shared_recursive(l, s, t, NULL, i)
+#define rwlock_acquire_read(l, s, t, i)                                        \
+do {                                                                   \
+       if (read_lock_is_recursive())                                   \
+               lock_acquire_shared_recursive(l, s, t, NULL, i);        \
+       else                                                            \
+               lock_acquire_shared(l, s, t, NULL, i);                  \
+} while (0)
+
 #define rwlock_release(l, i)                   lock_release(l, i)
 
 #define seqcount_acquire(l, s, t, i)           lock_acquire_exclusive(l, s, t, NULL, i)
@@ -512,19 +537,19 @@ static inline void print_irqtrace_events(struct task_struct *curr)
 #define lock_map_release(l)                    lock_release(l, _THIS_IP_)
 
 #ifdef CONFIG_PROVE_LOCKING
-# define might_lock(lock)                                              \
+# define might_lock(lock)                                              \
 do {                                                                   \
        typecheck(struct lockdep_map *, &(lock)->dep_map);              \
        lock_acquire(&(lock)->dep_map, 0, 0, 0, 1, NULL, _THIS_IP_);    \
        lock_release(&(lock)->dep_map, _THIS_IP_);                      \
 } while (0)
-# define might_lock_read(lock)                                                 \
+# define might_lock_read(lock)                                         \
 do {                                                                   \
        typecheck(struct lockdep_map *, &(lock)->dep_map);              \
        lock_acquire(&(lock)->dep_map, 0, 0, 1, 1, NULL, _THIS_IP_);    \
        lock_release(&(lock)->dep_map, _THIS_IP_);                      \
 } while (0)
-# define might_lock_nested(lock, subclass)                             \
+# define might_lock_nested(lock, subclass)                             \
 do {                                                                   \
        typecheck(struct lockdep_map *, &(lock)->dep_map);              \
        lock_acquire(&(lock)->dep_map, subclass, 0, 1, 1, NULL,         \
@@ -534,26 +559,29 @@ do {                                                                      \
 
 DECLARE_PER_CPU(int, hardirqs_enabled);
 DECLARE_PER_CPU(int, hardirq_context);
+DECLARE_PER_CPU(unsigned int, lockdep_recursion);
+
+#define __lockdep_enabled      (debug_locks && !this_cpu_read(lockdep_recursion))
 
 #define lockdep_assert_irqs_enabled()                                  \
 do {                                                                   \
-       WARN_ON_ONCE(debug_locks && !this_cpu_read(hardirqs_enabled));  \
+       WARN_ON_ONCE(__lockdep_enabled && !this_cpu_read(hardirqs_enabled)); \
 } while (0)
 
 #define lockdep_assert_irqs_disabled()                                 \
 do {                                                                   \
-       WARN_ON_ONCE(debug_locks && this_cpu_read(hardirqs_enabled));   \
+       WARN_ON_ONCE(__lockdep_enabled && this_cpu_read(hardirqs_enabled)); \
 } while (0)
 
 #define lockdep_assert_in_irq()                                                \
 do {                                                                   \
-       WARN_ON_ONCE(debug_locks && !this_cpu_read(hardirq_context));   \
+       WARN_ON_ONCE(__lockdep_enabled && !this_cpu_read(hardirq_context)); \
 } while (0)
 
 #define lockdep_assert_preemption_enabled()                            \
 do {                                                                   \
        WARN_ON_ONCE(IS_ENABLED(CONFIG_PREEMPT_COUNT)   &&              \
-                    debug_locks                        &&              \
+                    __lockdep_enabled                  &&              \
                     (preempt_count() != 0              ||              \
                      !this_cpu_read(hardirqs_enabled)));               \
 } while (0)
@@ -561,7 +589,7 @@ do {                                                                        \
 #define lockdep_assert_preemption_disabled()                           \
 do {                                                                   \
        WARN_ON_ONCE(IS_ENABLED(CONFIG_PREEMPT_COUNT)   &&              \
-                    debug_locks                        &&              \
+                    __lockdep_enabled                  &&              \
                     (preempt_count() == 0              &&              \
                      this_cpu_read(hardirqs_enabled)));                \
 } while (0)
index bb35b44..9a1fd49 100644 (file)
@@ -35,8 +35,12 @@ enum lockdep_wait_type {
 /*
  * We'd rather not expose kernel/lockdep_states.h this wide, but we do need
  * the total number of states... :-(
+ *
+ * XXX_LOCK_USAGE_STATES is the number of lines in lockdep_states.h, for each
+ * of those we generates 4 states, Additionally we report on USED and USED_READ.
  */
-#define XXX_LOCK_USAGE_STATES          (1+2*4)
+#define XXX_LOCK_USAGE_STATES          2
+#define LOCK_TRACE_STATES              (XXX_LOCK_USAGE_STATES*4 + 2)
 
 /*
  * NR_LOCKDEP_CACHING_CLASSES ... Number of classes
@@ -106,7 +110,7 @@ struct lock_class {
         * IRQ/softirq usage tracking bits:
         */
        unsigned long                   usage_mask;
-       const struct lock_trace         *usage_traces[XXX_LOCK_USAGE_STATES];
+       const struct lock_trace         *usage_traces[LOCK_TRACE_STATES];
 
        /*
         * Generation counter, when doing certain classes of graph walking,
index 83a4a3c..c619ec6 100644 (file)
@@ -173,7 +173,7 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
 #define roundup_pow_of_two(n)                  \
 (                                              \
        __builtin_constant_p(n) ? (             \
-               (n == 1) ? 1 :                  \
+               ((n) == 1) ? 1 :                \
                (1UL << (ilog2((n) - 1) + 1))   \
                                   ) :          \
        __roundup_pow_of_two(n)                 \
index 5f5b2df..e586274 100644 (file)
@@ -46,11 +46,10 @@ struct vmem_altmap {
  * wakeup is used to coordinate physical address space management (ex:
  * fs truncate/hole punch) vs pinned pages (ex: device dma).
  *
- * MEMORY_DEVICE_DEVDAX:
+ * MEMORY_DEVICE_GENERIC:
  * Host memory that has similar access semantics as System RAM i.e. DMA
- * coherent and supports page pinning. In contrast to
- * MEMORY_DEVICE_FS_DAX, this memory is access via a device-dax
- * character device.
+ * coherent and supports page pinning. This is for example used by DAX devices
+ * that expose memory using a character device.
  *
  * MEMORY_DEVICE_PCI_P2PDMA:
  * Device memory residing in a PCI BAR intended for use with Peer-to-Peer
@@ -60,7 +59,7 @@ enum memory_type {
        /* 0 is reserved to catch uninitialized type fields */
        MEMORY_DEVICE_PRIVATE = 1,
        MEMORY_DEVICE_FS_DAX,
-       MEMORY_DEVICE_DEVDAX,
+       MEMORY_DEVICE_GENERIC,
        MEMORY_DEVICE_PCI_P2PDMA,
 };
 
index da4c65f..ebf73d4 100644 (file)
@@ -281,6 +281,7 @@ struct memstick_host {
 
        struct memstick_dev *card;
        unsigned int        retries;
+       bool removing;
 
        /* Notify the host that some requests are pending. */
        void                (*request)(struct memstick_host *host);
index c145de0..372100c 100644 (file)
@@ -767,6 +767,8 @@ struct mlx5_cmd_work_ent {
        u64                     ts2;
        u16                     op;
        bool                    polling;
+       /* Track the max comp handlers */
+       refcount_t              refcnt;
 };
 
 struct mlx5_pas {
@@ -933,6 +935,7 @@ int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
 int mlx5_cmd_exec_polling(struct mlx5_core_dev *dev, void *in, int in_size,
                          void *out, int out_size);
 void mlx5_cmd_mbox_status(void *out, u8 *status, u32 *syndrome);
+bool mlx5_cmd_is_down(struct mlx5_core_dev *dev);
 
 int mlx5_core_get_caps(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type);
 int mlx5_cmd_alloc_uar(struct mlx5_core_dev *dev, u32 *uarn);
index 1983e08..13dc9b9 100644 (file)
@@ -41,6 +41,8 @@ struct writeback_control;
 struct bdi_writeback;
 struct pt_regs;
 
+extern int sysctl_page_lock_unfairness;
+
 void init_mm_internals(void);
 
 #ifndef CONFIG_NEED_MULTIPLE_NODES     /* Don't use mapnrs, do it properly */
@@ -157,11 +159,14 @@ static inline void __mm_zero_struct_page(struct page *page)
 
        switch (sizeof(struct page)) {
        case 80:
-               _pp[9] = 0;     /* fallthrough */
+               _pp[9] = 0;
+               fallthrough;
        case 72:
-               _pp[8] = 0;     /* fallthrough */
+               _pp[8] = 0;
+               fallthrough;
        case 64:
-               _pp[7] = 0;     /* fallthrough */
+               _pp[7] = 0;
+               fallthrough;
        case 56:
                _pp[6] = 0;
                _pp[5] = 0;
@@ -321,6 +326,8 @@ extern unsigned int kobjsize(const void *objp);
 
 #if defined(CONFIG_X86)
 # define VM_PAT                VM_ARCH_1       /* PAT reserves whole VMA at once (x86) */
+#elif defined(CONFIG_PPC)
+# define VM_SAO                VM_ARCH_1       /* Strong Access Ordering (powerpc) */
 #elif defined(CONFIG_PARISC)
 # define VM_GROWSUP    VM_ARCH_1
 #elif defined(CONFIG_IA64)
@@ -335,6 +342,14 @@ extern unsigned int kobjsize(const void *objp);
 # define VM_MAPPED_COPY        VM_ARCH_1       /* T if mapped copy of data (nommu mmap) */
 #endif
 
+#if defined(CONFIG_ARM64_MTE)
+# define VM_MTE                VM_HIGH_ARCH_0  /* Use Tagged memory for access control */
+# define VM_MTE_ALLOWED        VM_HIGH_ARCH_1  /* Tagged memory permitted */
+#else
+# define VM_MTE                VM_NONE
+# define VM_MTE_ALLOWED        VM_NONE
+#endif
+
 #ifndef VM_GROWSUP
 # define VM_GROWSUP    VM_NONE
 #endif
@@ -1639,7 +1654,7 @@ struct mmu_notifier_range;
 void free_pgd_range(struct mmu_gather *tlb, unsigned long addr,
                unsigned long end, unsigned long floor, unsigned long ceiling);
 int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
-                       struct vm_area_struct *vma);
+                   struct vm_area_struct *vma, struct vm_area_struct *new);
 int follow_pte_pmd(struct mm_struct *mm, unsigned long address,
                   struct mmu_notifier_range *range,
                   pte_t **ptepp, pmd_t **pmdpp, spinlock_t **ptlp);
@@ -2409,7 +2424,7 @@ extern int __meminit __early_pfn_to_nid(unsigned long pfn,
 
 extern void set_dma_reserve(unsigned long new_dma_reserve);
 extern void memmap_init_zone(unsigned long, int, unsigned long, unsigned long,
-               enum memmap_context, struct vmem_altmap *);
+               enum meminit_context, struct vmem_altmap *);
 extern void setup_per_zone_wmarks(void);
 extern int __meminit init_per_zone_wmark_min(void);
 extern void mem_init(void);
index 496c3ff..5a9238f 100644 (file)
@@ -436,6 +436,16 @@ struct mm_struct {
                 */
                atomic_t mm_count;
 
+               /**
+                * @has_pinned: Whether this mm has pinned any pages.  This can
+                * be either replaced in the future by @pinned_vm when it
+                * becomes stable, or grow into a counter on its own. We're
+                * aggresive on this bit now - even if the pinned pages were
+                * unpinned later on, we'll still keep this bit set for the
+                * lifecycle of this mm just for simplicity.
+                */
+               atomic_t has_pinned;
+
 #ifdef CONFIG_MMU
                atomic_long_t pgtables_bytes;   /* PTE page table pages */
 #endif
@@ -542,6 +552,10 @@ struct mm_struct {
                atomic_long_t hugetlb_usage;
 #endif
                struct work_struct async_put_work;
+
+#ifdef CONFIG_IOMMU_SUPPORT
+               u32 pasid;
+#endif
        } __randomize_layout;
 
        /*
index 6f34c33..629cefc 100644 (file)
@@ -78,13 +78,18 @@ static inline void vm_unacct_memory(long pages)
 }
 
 /*
- * Allow architectures to handle additional protection bits
+ * Allow architectures to handle additional protection and flag bits. The
+ * overriding macros must be defined in the arch-specific asm/mman.h file.
  */
 
 #ifndef arch_calc_vm_prot_bits
 #define arch_calc_vm_prot_bits(prot, pkey) 0
 #endif
 
+#ifndef arch_calc_vm_flag_bits
+#define arch_calc_vm_flag_bits(flags) 0
+#endif
+
 #ifndef arch_vm_get_page_prot
 #define arch_vm_get_page_prot(vm_flags) __pgprot(0)
 #endif
@@ -103,6 +108,19 @@ static inline bool arch_validate_prot(unsigned long prot, unsigned long addr)
 #define arch_validate_prot arch_validate_prot
 #endif
 
+#ifndef arch_validate_flags
+/*
+ * This is called from mmap() and mprotect() with the updated vma->vm_flags.
+ *
+ * Returns true if the VM_* flags are valid.
+ */
+static inline bool arch_validate_flags(unsigned long flags)
+{
+       return true;
+}
+#define arch_validate_flags arch_validate_flags
+#endif
+
 /*
  * Optimisation macro.  It is equivalent to:
  *      (x & bit1) ? bit2 : 0
@@ -135,7 +153,8 @@ calc_vm_flag_bits(unsigned long flags)
        return _calc_vm_trans(flags, MAP_GROWSDOWN,  VM_GROWSDOWN ) |
               _calc_vm_trans(flags, MAP_DENYWRITE,  VM_DENYWRITE ) |
               _calc_vm_trans(flags, MAP_LOCKED,     VM_LOCKED    ) |
-              _calc_vm_trans(flags, MAP_SYNC,       VM_SYNC      );
+              _calc_vm_trans(flags, MAP_SYNC,       VM_SYNC      ) |
+              arch_calc_vm_flag_bits(flags);
 }
 
 unsigned long vm_commit_limit(void);
index c51a841..03dee12 100644 (file)
@@ -3,10 +3,15 @@
 #define _LINUX_MMU_CONTEXT_H
 
 #include <asm/mmu_context.h>
+#include <asm/mmu.h>
 
 /* Architectures that care about IRQ state in switch_mm can override this. */
 #ifndef switch_mm_irqs_off
 # define switch_mm_irqs_off switch_mm
 #endif
 
+#ifndef leave_mm
+static inline void leave_mm(int cpu) { }
+#endif
+
 #endif
index 8379432..0f7a4ff 100644 (file)
@@ -824,10 +824,15 @@ bool zone_watermark_ok(struct zone *z, unsigned int order,
                unsigned int alloc_flags);
 bool zone_watermark_ok_safe(struct zone *z, unsigned int order,
                unsigned long mark, int highest_zoneidx);
-enum memmap_context {
-       MEMMAP_EARLY,
-       MEMMAP_HOTPLUG,
+/*
+ * Memory initialization context, use to differentiate memory added by
+ * the platform statically or via memory hotplug interface.
+ */
+enum meminit_context {
+       MEMINIT_EARLY,
+       MEMINIT_HOTPLUG,
 };
+
 extern void init_currently_empty_zone(struct zone *zone, unsigned long start_pfn,
                                     unsigned long size);
 
index e30ed5f..a29187f 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/error-injection.h>
 #include <linux/tracepoint-defs.h>
 #include <linux/srcu.h>
+#include <linux/static_call_types.h>
 
 #include <linux/percpu.h>
 #include <asm/module.h>
@@ -498,6 +499,10 @@ struct module {
        unsigned long *kprobe_blacklist;
        unsigned int num_kprobe_blacklist;
 #endif
+#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
+       int num_static_call_sites;
+       struct static_call_site *static_call_sites;
+#endif
 
 #ifdef CONFIG_LIVEPATCH
        bool klp; /* Is this a livepatch module? */
index 5d906df..3e5358f 100644 (file)
@@ -40,21 +40,79 @@ struct gcry_mpi {
 typedef struct gcry_mpi *MPI;
 
 #define mpi_get_nlimbs(a)     ((a)->nlimbs)
+#define mpi_has_sign(a)       ((a)->sign)
 
 /*-- mpiutil.c --*/
 MPI mpi_alloc(unsigned nlimbs);
+void mpi_clear(MPI a);
 void mpi_free(MPI a);
 int mpi_resize(MPI a, unsigned nlimbs);
 
+static inline MPI mpi_new(unsigned int nbits)
+{
+       return mpi_alloc((nbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB);
+}
+
+MPI mpi_copy(MPI a);
+MPI mpi_alloc_like(MPI a);
+void mpi_snatch(MPI w, MPI u);
+MPI mpi_set(MPI w, MPI u);
+MPI mpi_set_ui(MPI w, unsigned long u);
+MPI mpi_alloc_set_ui(unsigned long u);
+void mpi_swap_cond(MPI a, MPI b, unsigned long swap);
+
+/* Constants used to return constant MPIs.  See mpi_init if you
+ * want to add more constants.
+ */
+#define MPI_NUMBER_OF_CONSTANTS 6
+enum gcry_mpi_constants {
+       MPI_C_ZERO,
+       MPI_C_ONE,
+       MPI_C_TWO,
+       MPI_C_THREE,
+       MPI_C_FOUR,
+       MPI_C_EIGHT
+};
+
+MPI mpi_const(enum gcry_mpi_constants no);
+
 /*-- mpicoder.c --*/
+
+/* Different formats of external big integer representation. */
+enum gcry_mpi_format {
+       GCRYMPI_FMT_NONE = 0,
+       GCRYMPI_FMT_STD = 1,    /* Twos complement stored without length. */
+       GCRYMPI_FMT_PGP = 2,    /* As used by OpenPGP (unsigned only). */
+       GCRYMPI_FMT_SSH = 3,    /* As used by SSH (like STD but with length). */
+       GCRYMPI_FMT_HEX = 4,    /* Hex format. */
+       GCRYMPI_FMT_USG = 5,    /* Like STD but unsigned. */
+       GCRYMPI_FMT_OPAQUE = 8  /* Opaque format (some functions only). */
+};
+
 MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes);
 MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread);
+int mpi_fromstr(MPI val, const char *str);
+MPI mpi_scanval(const char *string);
 MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len);
 void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign);
 int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
                    int *sign);
 int mpi_write_to_sgl(MPI a, struct scatterlist *sg, unsigned nbytes,
                     int *sign);
+int mpi_print(enum gcry_mpi_format format, unsigned char *buffer,
+                       size_t buflen, size_t *nwritten, MPI a);
+
+/*-- mpi-mod.c --*/
+void mpi_mod(MPI rem, MPI dividend, MPI divisor);
+
+/* Context used with Barrett reduction.  */
+struct barrett_ctx_s;
+typedef struct barrett_ctx_s *mpi_barrett_t;
+
+mpi_barrett_t mpi_barrett_init(MPI m, int copy);
+void mpi_barrett_free(mpi_barrett_t ctx);
+void mpi_mod_barrett(MPI r, MPI x, mpi_barrett_t ctx);
+void mpi_mul_barrett(MPI w, MPI u, MPI v, mpi_barrett_t ctx);
 
 /*-- mpi-pow.c --*/
 int mpi_powm(MPI res, MPI base, MPI exp, MPI mod);
@@ -62,6 +120,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod);
 /*-- mpi-cmp.c --*/
 int mpi_cmp_ui(MPI u, ulong v);
 int mpi_cmp(MPI u, MPI v);
+int mpi_cmpabs(MPI u, MPI v);
 
 /*-- mpi-sub-ui.c --*/
 int mpi_sub_ui(MPI w, MPI u, unsigned long vval);
@@ -69,6 +128,139 @@ int mpi_sub_ui(MPI w, MPI u, unsigned long vval);
 /*-- mpi-bit.c --*/
 void mpi_normalize(MPI a);
 unsigned mpi_get_nbits(MPI a);
+int mpi_test_bit(MPI a, unsigned int n);
+void mpi_set_bit(MPI a, unsigned int n);
+void mpi_set_highbit(MPI a, unsigned int n);
+void mpi_clear_highbit(MPI a, unsigned int n);
+void mpi_clear_bit(MPI a, unsigned int n);
+void mpi_rshift_limbs(MPI a, unsigned int count);
+void mpi_rshift(MPI x, MPI a, unsigned int n);
+void mpi_lshift_limbs(MPI a, unsigned int count);
+void mpi_lshift(MPI x, MPI a, unsigned int n);
+
+/*-- mpi-add.c --*/
+void mpi_add_ui(MPI w, MPI u, unsigned long v);
+void mpi_add(MPI w, MPI u, MPI v);
+void mpi_sub(MPI w, MPI u, MPI v);
+void mpi_addm(MPI w, MPI u, MPI v, MPI m);
+void mpi_subm(MPI w, MPI u, MPI v, MPI m);
+
+/*-- mpi-mul.c --*/
+void mpi_mul(MPI w, MPI u, MPI v);
+void mpi_mulm(MPI w, MPI u, MPI v, MPI m);
+
+/*-- mpi-div.c --*/
+void mpi_tdiv_r(MPI rem, MPI num, MPI den);
+void mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor);
+void mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor);
+
+/*-- mpi-inv.c --*/
+int mpi_invm(MPI x, MPI a, MPI n);
+
+/*-- ec.c --*/
+
+/* Object to represent a point in projective coordinates */
+struct gcry_mpi_point {
+       MPI x;
+       MPI y;
+       MPI z;
+};
+
+typedef struct gcry_mpi_point *MPI_POINT;
+
+/* Models describing an elliptic curve */
+enum gcry_mpi_ec_models {
+       /* The Short Weierstrass equation is
+        *      y^2 = x^3 + ax + b
+        */
+       MPI_EC_WEIERSTRASS = 0,
+       /* The Montgomery equation is
+        *      by^2 = x^3 + ax^2 + x
+        */
+       MPI_EC_MONTGOMERY,
+       /* The Twisted Edwards equation is
+        *      ax^2 + y^2 = 1 + bx^2y^2
+        * Note that we use 'b' instead of the commonly used 'd'.
+        */
+       MPI_EC_EDWARDS
+};
+
+/* Dialects used with elliptic curves */
+enum ecc_dialects {
+       ECC_DIALECT_STANDARD = 0,
+       ECC_DIALECT_ED25519,
+       ECC_DIALECT_SAFECURVE
+};
+
+/* This context is used with all our EC functions. */
+struct mpi_ec_ctx {
+       enum gcry_mpi_ec_models model; /* The model describing this curve. */
+       enum ecc_dialects dialect;     /* The ECC dialect used with the curve. */
+       int flags;                     /* Public key flags (not always used). */
+       unsigned int nbits;            /* Number of bits.  */
+
+       /* Domain parameters.  Note that they may not all be set and if set
+        * the MPIs may be flaged as constant.
+        */
+       MPI p;         /* Prime specifying the field GF(p).  */
+       MPI a;         /* First coefficient of the Weierstrass equation.  */
+       MPI b;         /* Second coefficient of the Weierstrass equation.  */
+       MPI_POINT G;   /* Base point (generator).  */
+       MPI n;         /* Order of G.  */
+       unsigned int h;       /* Cofactor.  */
+
+       /* The actual key.  May not be set.  */
+       MPI_POINT Q;   /* Public key.   */
+       MPI d;         /* Private key.  */
+
+       const char *name;      /* Name of the curve.  */
+
+       /* This structure is private to mpi/ec.c! */
+       struct {
+               struct {
+                       unsigned int a_is_pminus3:1;
+                       unsigned int two_inv_p:1;
+               } valid; /* Flags to help setting the helper vars below.  */
+
+               int a_is_pminus3;  /* True if A = P - 3. */
+
+               MPI two_inv_p;
+
+               mpi_barrett_t p_barrett;
+
+               /* Scratch variables.  */
+               MPI scratch[11];
+
+               /* Helper for fast reduction.  */
+               /*   int nist_nbits; /\* If this is a NIST curve, the # of bits. *\/ */
+               /*   MPI s[10]; */
+               /*   MPI c; */
+       } t;
+
+       /* Curve specific computation routines for the field.  */
+       void (*addm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx);
+       void (*subm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ec);
+       void (*mulm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx);
+       void (*pow2)(MPI w, const MPI b, struct mpi_ec_ctx *ctx);
+       void (*mul2)(MPI w, MPI u, struct mpi_ec_ctx *ctx);
+};
+
+void mpi_ec_init(struct mpi_ec_ctx *ctx, enum gcry_mpi_ec_models model,
+                       enum ecc_dialects dialect,
+                       int flags, MPI p, MPI a, MPI b);
+void mpi_ec_deinit(struct mpi_ec_ctx *ctx);
+MPI_POINT mpi_point_new(unsigned int nbits);
+void mpi_point_release(MPI_POINT p);
+void mpi_point_init(MPI_POINT p);
+void mpi_point_free_parts(MPI_POINT p);
+int mpi_ec_get_affine(MPI x, MPI y, MPI_POINT point, struct mpi_ec_ctx *ctx);
+void mpi_ec_add_points(MPI_POINT result,
+                       MPI_POINT p1, MPI_POINT p2,
+                       struct mpi_ec_ctx *ctx);
+void mpi_ec_mul_point(MPI_POINT result,
+                       MPI scalar, MPI_POINT point,
+                       struct mpi_ec_ctx *ctx);
+int mpi_ec_curve_point(MPI_POINT point, struct mpi_ec_ctx *ctx);
 
 /* inline functions */
 
index 8ad679e..6b584cc 100644 (file)
@@ -193,17 +193,38 @@ void pci_msi_mask_irq(struct irq_data *data);
 void pci_msi_unmask_irq(struct irq_data *data);
 
 /*
- * The arch hooks to setup up msi irqs. Those functions are
- * implemented as weak symbols so that they /can/ be overriden by
- * architecture specific code if needed.
+ * The arch hooks to setup up msi irqs. Default functions are implemented
+ * as weak symbols so that they /can/ be overriden by architecture specific
+ * code if needed. These hooks must be enabled by the architecture or by
+ * drivers which depend on them via msi_controller based MSI handling.
+ *
+ * If CONFIG_PCI_MSI_ARCH_FALLBACKS is not selected they are replaced by
+ * stubs with warnings.
  */
+#ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS
 int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
 void arch_teardown_msi_irq(unsigned int irq);
 int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
 void arch_teardown_msi_irqs(struct pci_dev *dev);
-void arch_restore_msi_irqs(struct pci_dev *dev);
-
 void default_teardown_msi_irqs(struct pci_dev *dev);
+#else
+static inline int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+       WARN_ON_ONCE(1);
+       return -ENODEV;
+}
+
+static inline void arch_teardown_msi_irqs(struct pci_dev *dev)
+{
+       WARN_ON_ONCE(1);
+}
+#endif
+
+/*
+ * The restore hooks are still available as they are useful even
+ * for fully irq domain based setups. Courtesy to XEN/X86.
+ */
+void arch_restore_msi_irqs(struct pci_dev *dev);
 void default_restore_msi_irqs(struct pci_dev *dev);
 
 struct msi_controller {
@@ -241,6 +262,10 @@ struct msi_domain_info;
  * @msi_finish:                Optional callback to finalize the allocation
  * @set_desc:          Set the msi descriptor for an interrupt
  * @handle_error:      Optional error handler if the allocation fails
+ * @domain_alloc_irqs: Optional function to override the default allocation
+ *                     function.
+ * @domain_free_irqs:  Optional function to override the default free
+ *                     function.
  *
  * @get_hwirq, @msi_init and @msi_free are callbacks used by
  * msi_create_irq_domain() and related interfaces
@@ -248,6 +273,22 @@ struct msi_domain_info;
  * @msi_check, @msi_prepare, @msi_finish, @set_desc and @handle_error
  * are callbacks used by msi_domain_alloc_irqs() and related
  * interfaces which are based on msi_desc.
+ *
+ * @domain_alloc_irqs, @domain_free_irqs can be used to override the
+ * default allocation/free functions (__msi_domain_alloc/free_irqs). This
+ * is initially for a wrapper around XENs seperate MSI universe which can't
+ * be wrapped into the regular irq domains concepts by mere mortals.  This
+ * allows to universally use msi_domain_alloc/free_irqs without having to
+ * special case XEN all over the place.
+ *
+ * Contrary to other operations @domain_alloc_irqs and @domain_free_irqs
+ * are set to the default implementation if NULL and even when
+ * MSI_FLAG_USE_DEF_DOM_OPS is not set to avoid breaking existing users and
+ * because these callbacks are obviously mandatory.
+ *
+ * This is NOT meant to be abused, but it can be useful to build wrappers
+ * for specialized MSI irq domains which need extra work before and after
+ * calling __msi_domain_alloc_irqs()/__msi_domain_free_irqs().
  */
 struct msi_domain_ops {
        irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info,
@@ -270,6 +311,10 @@ struct msi_domain_ops {
                                    struct msi_desc *desc);
        int             (*handle_error)(struct irq_domain *domain,
                                        struct msi_desc *desc, int error);
+       int             (*domain_alloc_irqs)(struct irq_domain *domain,
+                                            struct device *dev, int nvec);
+       void            (*domain_free_irqs)(struct irq_domain *domain,
+                                           struct device *dev);
 };
 
 /**
@@ -327,8 +372,11 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
 struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
                                         struct msi_domain_info *info,
                                         struct irq_domain *parent);
+int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
+                           int nvec);
 int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
                          int nvec);
+void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
 void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
 struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
 
@@ -369,12 +417,11 @@ void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg);
 struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
                                             struct msi_domain_info *info,
                                             struct irq_domain *parent);
-irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
-                                         struct msi_desc *desc);
 int pci_msi_domain_check_cap(struct irq_domain *domain,
                             struct msi_domain_info *info, struct device *dev);
 u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev);
 struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev);
+bool pci_dev_has_special_msi_domain(struct pci_dev *pdev);
 #else
 static inline struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
 {
index d48ff11..ae713c8 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/rcupdate.h>
 #include <linux/once.h>
 #include <linux/fs.h>
+#include <linux/mm.h>
 #include <linux/sockptr.h>
 
 #include <uapi/linux/net.h>
@@ -286,6 +287,21 @@ do {                                                                       \
 #define net_get_random_once_wait(buf, nbytes)                  \
        get_random_once_wait((buf), (nbytes))
 
+/*
+ * E.g. XFS meta- & log-data is in slab pages, or bcache meta
+ * data pages, or other high order pages allocated by
+ * __get_free_pages() without __GFP_COMP, which have a page_count
+ * of 0 and/or have PageSlab() set. We cannot use send_page for
+ * those, as that does get_page(); put_page(); and would cause
+ * either a VM_BUG directly, or __page_cache_release a page that
+ * would actually still be referenced by someone, leading to some
+ * obscure delayed Oops somewhere else.
+ */
+static inline bool sendpage_ok(struct page *page)
+{
+       return !PageSlab(page) && page_count(page) >= 1;
+}
+
 int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
                   size_t num, size_t len);
 int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
index 2cc3cf8..0b17c43 100644 (file)
@@ -193,7 +193,7 @@ static inline int find_next_netdev_feature(u64 feature, unsigned long start)
 #define NETIF_F_GSO_MASK       (__NETIF_F_BIT(NETIF_F_GSO_LAST + 1) - \
                __NETIF_F_BIT(NETIF_F_GSO_SHIFT))
 
-/* List of IP checksum features. Note that NETIF_F_ HW_CSUM should not be
+/* List of IP checksum features. Note that NETIF_F_HW_CSUM should not be
  * set in features when NETIF_F_IP_CSUM or NETIF_F_IPV6_CSUM are set--
  * this would be contradictory
  */
index b0e303f..18dec08 100644 (file)
@@ -1784,6 +1784,7 @@ enum netdev_priv_flags {
  *                             the watchdog (see dev_watchdog())
  *     @watchdog_timer:        List of timers
  *
+ *     @proto_down_reason:     reason a netdev interface is held down
  *     @pcpu_refcnt:           Number of references to this device
  *     @todo_list:             Delayed register/unregister
  *     @link_watch_list:       XXX: need comments on this one
@@ -1848,6 +1849,12 @@ enum netdev_priv_flags {
  *     @udp_tunnel_nic_info:   static structure describing the UDP tunnel
  *                             offload capabilities of the device
  *     @udp_tunnel_nic:        UDP tunnel offload state
+ *     @xdp_state:             stores info on attached XDP BPF programs
+ *
+ *     @nested_level:  Used as as a parameter of spin_lock_nested() of
+ *                     dev->addr_list_lock.
+ *     @unlink_list:   As netif_addr_lock() can be called recursively,
+ *                     keep a list of interfaces to be deleted.
  *
  *     FIXME: cleanup struct net_device such that network protocol info
  *     moves out.
@@ -1953,6 +1960,7 @@ struct net_device {
        unsigned short          type;
        unsigned short          hard_header_len;
        unsigned char           min_header_len;
+       unsigned char           name_assign_type;
 
        unsigned short          needed_headroom;
        unsigned short          needed_tailroom;
@@ -1963,12 +1971,12 @@ struct net_device {
        unsigned char           addr_len;
        unsigned char           upper_level;
        unsigned char           lower_level;
+
        unsigned short          neigh_priv_len;
        unsigned short          dev_id;
        unsigned short          dev_port;
        spinlock_t              addr_list_lock;
-       unsigned char           name_assign_type;
-       bool                    uc_promisc;
+
        struct netdev_hw_addr_list      uc;
        struct netdev_hw_addr_list      mc;
        struct netdev_hw_addr_list      dev_addrs;
@@ -1976,8 +1984,15 @@ struct net_device {
 #ifdef CONFIG_SYSFS
        struct kset             *queues_kset;
 #endif
+#ifdef CONFIG_LOCKDEP
+       struct list_head        unlink_list;
+#endif
        unsigned int            promiscuity;
        unsigned int            allmulti;
+       bool                    uc_promisc;
+#ifdef CONFIG_LOCKDEP
+       unsigned char           nested_level;
+#endif
 
 
        /* Protocol-specific pointers */
@@ -4258,17 +4273,23 @@ static inline void netif_tx_disable(struct net_device *dev)
 
 static inline void netif_addr_lock(struct net_device *dev)
 {
-       spin_lock(&dev->addr_list_lock);
-}
+       unsigned char nest_level = 0;
 
-static inline void netif_addr_lock_nested(struct net_device *dev)
-{
-       spin_lock_nested(&dev->addr_list_lock, dev->lower_level);
+#ifdef CONFIG_LOCKDEP
+       nest_level = dev->nested_level;
+#endif
+       spin_lock_nested(&dev->addr_list_lock, nest_level);
 }
 
 static inline void netif_addr_lock_bh(struct net_device *dev)
 {
-       spin_lock_bh(&dev->addr_list_lock);
+       unsigned char nest_level = 0;
+
+#ifdef CONFIG_LOCKDEP
+       nest_level = dev->nested_level;
+#endif
+       local_bh_disable();
+       spin_lock_nested(&dev->addr_list_lock, nest_level);
 }
 
 static inline void netif_addr_unlock(struct net_device *dev)
@@ -4453,12 +4474,38 @@ extern int              dev_rx_weight;
 extern int             dev_tx_weight;
 extern int             gro_normal_batch;
 
+enum {
+       NESTED_SYNC_IMM_BIT,
+       NESTED_SYNC_TODO_BIT,
+};
+
+#define __NESTED_SYNC_BIT(bit) ((u32)1 << (bit))
+#define __NESTED_SYNC(name)    __NESTED_SYNC_BIT(NESTED_SYNC_ ## name ## _BIT)
+
+#define NESTED_SYNC_IMM                __NESTED_SYNC(IMM)
+#define NESTED_SYNC_TODO       __NESTED_SYNC(TODO)
+
+struct netdev_nested_priv {
+       unsigned char flags;
+       void *data;
+};
+
 bool netdev_has_upper_dev(struct net_device *dev, struct net_device *upper_dev);
 struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
                                                     struct list_head **iter);
 struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev,
                                                     struct list_head **iter);
 
+#ifdef CONFIG_LOCKDEP
+static LIST_HEAD(net_unlink_list);
+
+static inline void net_unlink_todo(struct net_device *dev)
+{
+       if (list_empty(&dev->unlink_list))
+               list_add_tail(&dev->unlink_list, &net_unlink_list);
+}
+#endif
+
 /* iterate through upper list, must be called under RCU read lock */
 #define netdev_for_each_upper_dev_rcu(dev, updev, iter) \
        for (iter = &(dev)->adj_list.upper, \
@@ -4468,8 +4515,8 @@ struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev,
 
 int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
                                  int (*fn)(struct net_device *upper_dev,
-                                           void *data),
-                                 void *data);
+                                           struct netdev_nested_priv *priv),
+                                 struct netdev_nested_priv *priv);
 
 bool netdev_has_upper_dev_all_rcu(struct net_device *dev,
                                  struct net_device *upper_dev);
@@ -4506,12 +4553,12 @@ struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
                                             struct list_head **iter);
 int netdev_walk_all_lower_dev(struct net_device *dev,
                              int (*fn)(struct net_device *lower_dev,
-                                       void *data),
-                             void *data);
+                                       struct netdev_nested_priv *priv),
+                             struct netdev_nested_priv *priv);
 int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
                                  int (*fn)(struct net_device *lower_dev,
-                                           void *data),
-                                 void *data);
+                                           struct netdev_nested_priv *priv),
+                                 struct netdev_nested_priv *priv);
 
 void *netdev_adjacent_get_private(struct list_head *adj_list);
 void *netdev_lower_get_first_private_rcu(struct net_device *dev);
index 9a33f17..625f491 100644 (file)
@@ -9,6 +9,8 @@ struct ip_ct_sctp {
        enum sctp_conntrack state;
 
        __be32 vtag[IP_CT_DIR_MAX];
+       u8 last_dir;
+       u8 flags;
 };
 
 #endif /* _NF_CONNTRACK_SCTP_H */
index 851425c..89016d0 100644 (file)
@@ -43,8 +43,7 @@ int nfnetlink_has_listeners(struct net *net, unsigned int group);
 int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid,
                   unsigned int group, int echo, gfp_t flags);
 int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error);
-int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
-                     int flags);
+int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid);
 
 static inline u16 nfnl_msg_type(u8 subsys, u8 msg_type)
 {
index 9408f32..69cb46f 100644 (file)
@@ -1611,8 +1611,8 @@ struct nfs_pgio_header {
        __u64                   mds_offset;     /* Filelayout dense stripe */
        struct nfs_page_array   page_array;
        struct nfs_client       *ds_clp;        /* pNFS data server */
-       int                     ds_commit_idx;  /* ds index if ds_clp is set */
-       int                     pgio_mirror_idx;/* mirror index in pgio layer */
+       u32                     ds_commit_idx;  /* ds index if ds_clp is set */
+       u32                     pgio_mirror_idx;/* mirror index in pgio layer */
 };
 
 struct nfs_mds_commit_info {
index 4866f32..014ba3a 100644 (file)
@@ -99,11 +99,13 @@ extern struct node *node_devices[];
 typedef  void (*node_registration_func_t)(struct node *);
 
 #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_NUMA)
-extern int link_mem_sections(int nid, unsigned long start_pfn,
-                            unsigned long end_pfn);
+int link_mem_sections(int nid, unsigned long start_pfn,
+                     unsigned long end_pfn,
+                     enum meminit_context context);
 #else
 static inline int link_mem_sections(int nid, unsigned long start_pfn,
-                                   unsigned long end_pfn)
+                                   unsigned long end_pfn,
+                                   enum meminit_context context)
 {
        return 0;
 }
@@ -128,7 +130,8 @@ static inline int register_one_node(int nid)
                if (error)
                        return error;
                /* link memory sections under this node */
-               error = link_mem_sections(nid, start_pfn, end_pfn);
+               error = link_mem_sections(nid, start_pfn, end_pfn,
+                                         MEMINIT_EARLY);
        }
 
        return error;
index 0189476..2fb373a 100644 (file)
@@ -161,20 +161,19 @@ extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
 
 extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
                unsigned long val, void *v);
-extern int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
-       unsigned long val, void *v, int nr_to_call, int *nr_calls);
 extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
                unsigned long val, void *v);
-extern int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
-       unsigned long val, void *v, int nr_to_call, int *nr_calls);
 extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
                unsigned long val, void *v);
-extern int __raw_notifier_call_chain(struct raw_notifier_head *nh,
-       unsigned long val, void *v, int nr_to_call, int *nr_calls);
 extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
                unsigned long val, void *v);
-extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
-       unsigned long val, void *v, int nr_to_call, int *nr_calls);
+
+extern int atomic_notifier_call_chain_robust(struct atomic_notifier_head *nh,
+               unsigned long val_up, unsigned long val_down, void *v);
+extern int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
+               unsigned long val_up, unsigned long val_down, void *v);
+extern int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
+               unsigned long val_up, unsigned long val_down, void *v);
 
 #define NOTIFY_DONE            0x0000          /* Don't care */
 #define NOTIFY_OK              0x0001          /* Suits me */
index 657d6bf..4462ed2 100644 (file)
@@ -107,6 +107,12 @@ enum OID {
        OID_gostTC26Sign512B,           /* 1.2.643.7.1.2.1.2.2 */
        OID_gostTC26Sign512C,           /* 1.2.643.7.1.2.1.2.3 */
 
+       /* OSCCA */
+       OID_sm2,                        /* 1.2.156.10197.1.301 */
+       OID_sm3,                        /* 1.2.156.10197.1.401 */
+       OID_SM2_with_SM3,               /* 1.2.156.10197.1.501 */
+       OID_sm3WithRSAEncryption,       /* 1.2.156.10197.1.504 */
+
        OID__NR
 };
 
index 6be1aa5..276140c 100644 (file)
@@ -136,6 +136,9 @@ enum pageflags {
        PG_young,
        PG_idle,
 #endif
+#ifdef CONFIG_64BIT
+       PG_arch_2,
+#endif
        __NR_PAGEFLAGS,
 
        /* Filesystems */
index 7de11dc..434c9c3 100644 (file)
@@ -54,7 +54,8 @@ static inline void mapping_set_error(struct address_space *mapping, int error)
        __filemap_set_wb_err(mapping, error);
 
        /* Record it in superblock */
-       errseq_set(&mapping->host->i_sb->s_wb_err, error);
+       if (mapping->host)
+               errseq_set(&mapping->host->i_sb->s_wb_err, error);
 
        /* Record it in flags for now, for legacy callers */
        if (error == -ENOSPC)
index 8ad71d7..daf09ff 100644 (file)
@@ -55,6 +55,9 @@
 #define        IMAGE_FILE_MACHINE_POWERPC      0x01f0
 #define        IMAGE_FILE_MACHINE_POWERPCFP    0x01f1
 #define        IMAGE_FILE_MACHINE_R4000        0x0166
+#define        IMAGE_FILE_MACHINE_RISCV32      0x5032
+#define        IMAGE_FILE_MACHINE_RISCV64      0x5064
+#define        IMAGE_FILE_MACHINE_RISCV128     0x5128
 #define        IMAGE_FILE_MACHINE_SH3          0x01a2
 #define        IMAGE_FILE_MACHINE_SH3DSP       0x01a3
 #define        IMAGE_FILE_MACHINE_SH3E         0x01a4
index 5e033fe..5fda40f 100644 (file)
@@ -60,7 +60,7 @@ static inline void percpu_down_read(struct percpu_rw_semaphore *sem)
         * anything we did within this RCU-sched read-size critical section.
         */
        if (likely(rcu_sync_is_idle(&sem->rss)))
-               __this_cpu_inc(*sem->read_count);
+               this_cpu_inc(*sem->read_count);
        else
                __percpu_down_read(sem, false); /* Unconditional memory barrier */
        /*
@@ -79,7 +79,7 @@ static inline bool percpu_down_read_trylock(struct percpu_rw_semaphore *sem)
         * Same as in percpu_down_read().
         */
        if (likely(rcu_sync_is_idle(&sem->rss)))
-               __this_cpu_inc(*sem->read_count);
+               this_cpu_inc(*sem->read_count);
        else
                ret = __percpu_down_read(sem, true); /* Unconditional memory barrier */
        preempt_enable();
@@ -103,7 +103,7 @@ static inline void percpu_up_read(struct percpu_rw_semaphore *sem)
         * Same as in percpu_down_read().
         */
        if (likely(rcu_sync_is_idle(&sem->rss))) {
-               __this_cpu_dec(*sem->read_count);
+               this_cpu_dec(*sem->read_count);
        } else {
                /*
                 * slowpath; reader will only ever wake a single blocked
@@ -115,7 +115,7 @@ static inline void percpu_up_read(struct percpu_rw_semaphore *sem)
                 * aggregate zero, as that is the only time it matters) they
                 * will also see our critical section.
                 */
-               __this_cpu_dec(*sem->read_count);
+               this_cpu_dec(*sem->read_count);
                rcuwait_wake_up(&sem->writer);
        }
        preempt_enable();
index 5b616dd..5054802 100644 (file)
@@ -73,6 +73,7 @@ enum armpmu_attr_groups {
        ARMPMU_ATTR_GROUP_COMMON,
        ARMPMU_ATTR_GROUP_EVENTS,
        ARMPMU_ATTR_GROUP_FORMATS,
+       ARMPMU_ATTR_GROUP_CAPS,
        ARMPMU_NR_ATTR_GROUPS
 };
 
@@ -109,6 +110,8 @@ struct arm_pmu {
        struct notifier_block   cpu_pm_nb;
        /* the attr_groups array must be NULL-terminated */
        const struct attribute_group *attr_groups[ARMPMU_NR_ATTR_GROUPS + 1];
+       /* store the PMMIR_EL1 to expose slots */
+       u64             reg_pmmir;
 
        /* Only to be used by ACPI probing code */
        unsigned long acpi_cpuid;
index 04a49cc..0c19d27 100644 (file)
@@ -212,17 +212,26 @@ struct hw_perf_event {
         */
        u64                             sample_period;
 
-       /*
-        * The period we started this sample with.
-        */
-       u64                             last_period;
+       union {
+               struct { /* Sampling */
+                       /*
+                        * The period we started this sample with.
+                        */
+                       u64                             last_period;
 
-       /*
-        * However much is left of the current period; note that this is
-        * a full 64bit value and allows for generation of periods longer
-        * than hardware might allow.
-        */
-       local64_t                       period_left;
+                       /*
+                        * However much is left of the current period;
+                        * note that this is a full 64bit value and
+                        * allows for generation of periods longer
+                        * than hardware might allow.
+                        */
+                       local64_t                       period_left;
+               };
+               struct { /* Topdown events counting for context switch */
+                       u64                             saved_metric;
+                       u64                             saved_slots;
+               };
+       };
 
        /*
         * State for throttling the event, see __perf_event_overflow() and
@@ -576,9 +585,13 @@ typedef void (*perf_overflow_handler_t)(struct perf_event *,
  * PERF_EV_CAP_SOFTWARE: Is a software event.
  * PERF_EV_CAP_READ_ACTIVE_PKG: A CPU event (or cgroup event) that can be read
  * from any CPU in the package where it is active.
+ * PERF_EV_CAP_SIBLING: An event with this flag must be a group sibling and
+ * cannot be a group leader. If an event with this flag is detached from the
+ * group it is scheduled out and moved into an unrecoverable ERROR state.
  */
 #define PERF_EV_CAP_SOFTWARE           BIT(0)
 #define PERF_EV_CAP_READ_ACTIVE_PKG    BIT(1)
+#define PERF_EV_CAP_SIBLING            BIT(2)
 
 #define SWEVENT_HLIST_BITS             8
 #define SWEVENT_HLIST_SIZE             (1 << SWEVENT_HLIST_BITS)
@@ -859,7 +872,6 @@ struct perf_cpu_context {
        struct list_head                cgrp_cpuctx_entry;
 #endif
 
-       struct list_head                sched_cb_entry;
        int                             sched_cb_usage;
 
        int                             online;
index e8cbc2e..38c33ea 100644 (file)
@@ -633,6 +633,34 @@ static inline int arch_unmap_one(struct mm_struct *mm,
 }
 #endif
 
+/*
+ * Allow architectures to preserve additional metadata associated with
+ * swapped-out pages. The corresponding __HAVE_ARCH_SWAP_* macros and function
+ * prototypes must be defined in the arch-specific asm/pgtable.h file.
+ */
+#ifndef __HAVE_ARCH_PREPARE_TO_SWAP
+static inline int arch_prepare_to_swap(struct page *page)
+{
+       return 0;
+}
+#endif
+
+#ifndef __HAVE_ARCH_SWAP_INVALIDATE
+static inline void arch_swap_invalidate_page(int type, pgoff_t offset)
+{
+}
+
+static inline void arch_swap_invalidate_area(int type)
+{
+}
+#endif
+
+#ifndef __HAVE_ARCH_SWAP_RESTORE
+static inline void arch_swap_restore(swp_entry_t entry, struct page *page)
+{
+}
+#endif
+
 #ifndef __HAVE_ARCH_PGD_OFFSET_GATE
 #define pgd_offset_gate(mm, addr)      pgd_offset(mm, addr)
 #endif
@@ -1427,6 +1455,16 @@ typedef unsigned int pgtbl_mod_mask;
 #define mm_pmd_folded(mm)      __is_defined(__PAGETABLE_PMD_FOLDED)
 #endif
 
+#ifndef p4d_offset_lockless
+#define p4d_offset_lockless(pgdp, pgd, address) p4d_offset(&(pgd), address)
+#endif
+#ifndef pud_offset_lockless
+#define pud_offset_lockless(p4dp, p4d, address) pud_offset(&(p4d), address)
+#endif
+#ifndef pmd_offset_lockless
+#define pmd_offset_lockless(pudp, pud, address) pmd_offset(&(pud), address)
+#endif
+
 /*
  * p?d_leaf() - true if this entry is a final mapping to a physical address.
  * This differs from p?d_huge() by the fact that they are always available (if
index 50afd0d..5d2705f 100644 (file)
@@ -240,8 +240,9 @@ extern unsigned int pipe_max_size;
 extern unsigned long pipe_user_pages_hard;
 extern unsigned long pipe_user_pages_soft;
 
-/* Drop the inode semaphore and wait for a pipe event, atomically */
-void pipe_wait(struct pipe_inode_info *pipe);
+/* Wait for a pipe to be readable/writable while dropping the pipe lock */
+void pipe_wait_readable(struct pipe_inode_info *);
+void pipe_wait_writable(struct pipe_inode_info *);
 
 struct pipe_inode_info *alloc_pipe_info(void);
 void free_pipe_info(struct pipe_inode_info *);
index 9e46678..255d51c 100644 (file)
@@ -19,7 +19,7 @@
 #define AMD_FCH_GPIO_REG_GPIO49                0x40
 #define AMD_FCH_GPIO_REG_GPIO50                0x41
 #define AMD_FCH_GPIO_REG_GPIO51                0x42
-#define AMD_FCH_GPIO_REG_GPIO59_DEVSLP0        0x43
+#define AMD_FCH_GPIO_REG_GPIO55_DEVSLP0        0x43
 #define AMD_FCH_GPIO_REG_GPIO57                0x44
 #define AMD_FCH_GPIO_REG_GPIO58                0x45
 #define AMD_FCH_GPIO_REG_GPIO59_DEVSLP1        0x46
index 4537f57..3d557bb 100644 (file)
@@ -44,19 +44,18 @@ struct powercap_control_type_ops {
 };
 
 /**
- * struct powercap_control_type- Defines a powercap control_type
- * @name:              name of control_type
+ * struct powercap_control_type - Defines a powercap control_type
  * @dev:               device for this control_type
  * @idr:               idr to have unique id for its child
- * @root_node:         Root holding power zones for this control_type
+ * @nr_zones:          counter for number of zones of this type
  * @ops:               Pointer to callback struct
- * @node_lock:         mutex for control type
+ * @lock:              mutex for control type
  * @allocated:         This is possible that client owns the memory
  *                     used by this structure. In this case
  *                     this flag is set to false by framework to
  *                     prevent deallocation during release process.
  *                     Otherwise this flag is set to true.
- * @ctrl_inst:         link to the control_type list
+ * @node:              linked-list node
  *
  * Defines powercap control_type. This acts as a container for power
  * zones, which use same method to control power. E.g. RAPL, RAPL-PCI etc.
@@ -129,7 +128,7 @@ struct powercap_zone_ops {
  *                     this flag is set to false by framework to
  *                     prevent deallocation during release process.
  *                     Otherwise this flag is set to true.
- * @constraint_ptr:    List of constraints for this zone.
+ * @constraints:       List of constraints for this zone.
  *
  * This defines a power zone instance. The fields of this structure are
  * private, and should not be used by client drivers.
index cd6a5c7..cdd73af 100644 (file)
@@ -623,6 +623,7 @@ struct qed_dev_info {
 #define QED_MFW_VERSION_3_OFFSET       24
 
        u32             flash_size;
+       bool            b_arfs_capable;
        bool            b_inter_pf_switch;
        bool            tx_switching;
        bool            rdma_supported;
index 9cf0cd3..a0f6668 100644 (file)
@@ -27,9 +27,6 @@ static inline bool is_quota_modification(struct inode *inode, struct iattr *ia)
                (ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid));
 }
 
-int kernel_quotactl(unsigned int cmd, const char __user *special,
-                   qid_t id, void __user *addr);
-
 #if defined(CONFIG_QUOTA)
 
 #define quota_error(sb, fmt, args...) \
index 7d012fa..3d1a9e7 100644 (file)
@@ -42,8 +42,8 @@ struct latch_tree_node {
 };
 
 struct latch_tree_root {
-       seqcount_t      seq;
-       struct rb_root  tree[2];
+       seqcount_latch_t        seq;
+       struct rb_root          tree[2];
 };
 
 /**
@@ -206,7 +206,7 @@ latch_tree_find(void *key, struct latch_tree_root *root,
        do {
                seq = raw_read_seqcount_latch(&root->seq);
                node = __lt_find(key, root, seq & 1, ops->comp);
-       } while (read_seqcount_retry(&root->seq, seq));
+       } while (read_seqcount_latch_retry(&root->seq, seq));
 
        return node;
 }
index 0e3ee25..7fabb1a 100644 (file)
@@ -165,7 +165,7 @@ static inline unsigned int refcount_read(const refcount_t *r)
  *
  * Return: false if the passed refcount is 0, true otherwise
  */
-static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)
+static inline __must_check bool __refcount_add_not_zero(int i, refcount_t *r, int *oldp)
 {
        int old = refcount_read(r);
 
@@ -174,12 +174,20 @@ static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)
                        break;
        } while (!atomic_try_cmpxchg_relaxed(&r->refs, &old, old + i));
 
+       if (oldp)
+               *oldp = old;
+
        if (unlikely(old < 0 || old + i < 0))
                refcount_warn_saturate(r, REFCOUNT_ADD_NOT_ZERO_OVF);
 
        return old;
 }
 
+static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)
+{
+       return __refcount_add_not_zero(i, r, NULL);
+}
+
 /**
  * refcount_add - add a value to a refcount
  * @i: the value to add to the refcount
@@ -196,16 +204,24 @@ static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)
  * cases, refcount_inc(), or one of its variants, should instead be used to
  * increment a reference count.
  */
-static inline void refcount_add(int i, refcount_t *r)
+static inline void __refcount_add(int i, refcount_t *r, int *oldp)
 {
        int old = atomic_fetch_add_relaxed(i, &r->refs);
 
+       if (oldp)
+               *oldp = old;
+
        if (unlikely(!old))
                refcount_warn_saturate(r, REFCOUNT_ADD_UAF);
        else if (unlikely(old < 0 || old + i < 0))
                refcount_warn_saturate(r, REFCOUNT_ADD_OVF);
 }
 
+static inline void refcount_add(int i, refcount_t *r)
+{
+       __refcount_add(i, r, NULL);
+}
+
 /**
  * refcount_inc_not_zero - increment a refcount unless it is 0
  * @r: the refcount to increment
@@ -219,9 +235,14 @@ static inline void refcount_add(int i, refcount_t *r)
  *
  * Return: true if the increment was successful, false otherwise
  */
+static inline __must_check bool __refcount_inc_not_zero(refcount_t *r, int *oldp)
+{
+       return __refcount_add_not_zero(1, r, oldp);
+}
+
 static inline __must_check bool refcount_inc_not_zero(refcount_t *r)
 {
-       return refcount_add_not_zero(1, r);
+       return __refcount_inc_not_zero(r, NULL);
 }
 
 /**
@@ -236,9 +257,14 @@ static inline __must_check bool refcount_inc_not_zero(refcount_t *r)
  * Will WARN if the refcount is 0, as this represents a possible use-after-free
  * condition.
  */
+static inline void __refcount_inc(refcount_t *r, int *oldp)
+{
+       __refcount_add(1, r, oldp);
+}
+
 static inline void refcount_inc(refcount_t *r)
 {
-       refcount_add(1, r);
+       __refcount_inc(r, NULL);
 }
 
 /**
@@ -261,10 +287,13 @@ static inline void refcount_inc(refcount_t *r)
  *
  * Return: true if the resulting refcount is 0, false otherwise
  */
-static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r)
+static inline __must_check bool __refcount_sub_and_test(int i, refcount_t *r, int *oldp)
 {
        int old = atomic_fetch_sub_release(i, &r->refs);
 
+       if (oldp)
+               *oldp = old;
+
        if (old == i) {
                smp_acquire__after_ctrl_dep();
                return true;
@@ -276,6 +305,11 @@ static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r)
        return false;
 }
 
+static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r)
+{
+       return __refcount_sub_and_test(i, r, NULL);
+}
+
 /**
  * refcount_dec_and_test - decrement a refcount and test if it is 0
  * @r: the refcount
@@ -289,9 +323,14 @@ static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r)
  *
  * Return: true if the resulting refcount is 0, false otherwise
  */
+static inline __must_check bool __refcount_dec_and_test(refcount_t *r, int *oldp)
+{
+       return __refcount_sub_and_test(1, r, oldp);
+}
+
 static inline __must_check bool refcount_dec_and_test(refcount_t *r)
 {
-       return refcount_sub_and_test(1, r);
+       return __refcount_dec_and_test(r, NULL);
 }
 
 /**
@@ -304,12 +343,22 @@ static inline __must_check bool refcount_dec_and_test(refcount_t *r)
  * Provides release memory ordering, such that prior loads and stores are done
  * before.
  */
-static inline void refcount_dec(refcount_t *r)
+static inline void __refcount_dec(refcount_t *r, int *oldp)
 {
-       if (unlikely(atomic_fetch_sub_release(1, &r->refs) <= 1))
+       int old = atomic_fetch_sub_release(1, &r->refs);
+
+       if (oldp)
+               *oldp = old;
+
+       if (unlikely(old <= 1))
                refcount_warn_saturate(r, REFCOUNT_DEC_LEAK);
 }
 
+static inline void refcount_dec(refcount_t *r)
+{
+       __refcount_dec(r, NULL);
+}
+
 extern __must_check bool refcount_dec_if_one(refcount_t *r);
 extern __must_check bool refcount_dec_not_one(refcount_t *r);
 extern __must_check bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock);
index daf5cf6..9b05af9 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _RESCTRL_H
 #define _RESCTRL_H
 
+#include <linux/pid.h>
+
 #ifdef CONFIG_PROC_CPU_RESCTRL
 
 int proc_resctrl_show(struct seq_file *m,
index 93ecd93..d383cf0 100644 (file)
@@ -1308,6 +1308,8 @@ struct task_struct {
 #endif
 
 #ifdef CONFIG_X86_MCE
+       void __user                     *mce_vaddr;
+       __u64                           mce_kflags;
        u64                             mce_addr;
        __u64                           mce_ripv : 1,
                                        mce_whole_page : 1,
@@ -1489,9 +1491,10 @@ extern struct pid *cad_pid;
 /*
  * Per process flags
  */
+#define PF_VCPU                        0x00000001      /* I'm a virtual CPU */
 #define PF_IDLE                        0x00000002      /* I am an IDLE thread */
 #define PF_EXITING             0x00000004      /* Getting shut down */
-#define PF_VCPU                        0x00000010      /* I'm a virtual CPU */
+#define PF_IO_WORKER           0x00000010      /* Task is an IO worker */
 #define PF_WQ_WORKER           0x00000020      /* I'm a workqueue worker */
 #define PF_FORKNOEXEC          0x00000040      /* Forked but didn't exec */
 #define PF_MCE_PROCESS         0x00000080      /* Process policy on mce errors */
@@ -1515,7 +1518,6 @@ extern struct pid *cad_pid;
 #define PF_NO_SETAFFINITY      0x04000000      /* Userland is not allowed to meddle with cpus_mask */
 #define PF_MCE_EARLY           0x08000000      /* Early kill for mce process policy */
 #define PF_MEMALLOC_NOCMA      0x10000000      /* All allocation request will have _GFP_MOVABLE cleared */
-#define PF_IO_WORKER           0x20000000      /* Task is an IO worker */
 #define PF_FREEZER_SKIP                0x40000000      /* Freezer should not count it as freezable */
 #define PF_SUSPEND_TASK                0x80000000      /* This thread called freeze_processes() and should not be frozen */
 
@@ -1666,7 +1668,7 @@ extern struct task_struct *idle_task(int cpu);
  *
  * Return: 1 if @p is an idle task. 0 otherwise.
  */
-static inline bool is_idle_task(const struct task_struct *p)
+static __always_inline bool is_idle_task(const struct task_struct *p)
 {
        return !!(p->flags & PF_IDLE);
 }
@@ -2044,6 +2046,7 @@ const struct sched_avg *sched_trace_rq_avg_dl(struct rq *rq);
 const struct sched_avg *sched_trace_rq_avg_irq(struct rq *rq);
 
 int sched_trace_rq_cpu(struct rq *rq);
+int sched_trace_rq_cpu_capacity(struct rq *rq);
 int sched_trace_rq_nr_running(struct rq *rq);
 
 const struct cpumask *sched_trace_rd_span(struct root_domain *rd);
index f889e33..15bfb06 100644 (file)
@@ -348,10 +348,13 @@ enum {
        MEMBARRIER_STATE_GLOBAL_EXPEDITED                       = (1U << 3),
        MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY      = (1U << 4),
        MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE            = (1U << 5),
+       MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ_READY           = (1U << 6),
+       MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ                 = (1U << 7),
 };
 
 enum {
        MEMBARRIER_FLAG_SYNC_CORE       = (1U << 0),
+       MEMBARRIER_FLAG_RSEQ            = (1U << 1),
 };
 
 #ifdef CONFIG_ARCH_HAS_MEMBARRIER_CALLBACKS
diff --git a/include/linux/sched/sd_flags.h b/include/linux/sched/sd_flags.h
new file mode 100644 (file)
index 0000000..34b21e9
--- /dev/null
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * sched-domains (multiprocessor balancing) flag declarations.
+ */
+
+#ifndef SD_FLAG
+# error "Incorrect import of SD flags definitions"
+#endif
+
+/*
+ * Hierarchical metaflags
+ *
+ * SHARED_CHILD: These flags are meant to be set from the base domain upwards.
+ * If a domain has this flag set, all of its children should have it set. This
+ * is usually because the flag describes some shared resource (all CPUs in that
+ * domain share the same resource), or because they are tied to a scheduling
+ * behaviour that we want to disable at some point in the hierarchy for
+ * scalability reasons.
+ *
+ * In those cases it doesn't make sense to have the flag set for a domain but
+ * not have it in (some of) its children: sched domains ALWAYS span their child
+ * domains, so operations done with parent domains will cover CPUs in the lower
+ * child domains.
+ *
+ *
+ * SHARED_PARENT: These flags are meant to be set from the highest domain
+ * downwards. If a domain has this flag set, all of its parents should have it
+ * set. This is usually for topology properties that start to appear above a
+ * certain level (e.g. domain starts spanning CPUs outside of the base CPU's
+ * socket).
+ */
+#define SDF_SHARED_CHILD       0x1
+#define SDF_SHARED_PARENT      0x2
+
+/*
+ * Behavioural metaflags
+ *
+ * NEEDS_GROUPS: These flags are only relevant if the domain they are set on has
+ * more than one group. This is usually for balancing flags (load balancing
+ * involves equalizing a metric between groups), or for flags describing some
+ * shared resource (which would be shared between groups).
+ */
+#define SDF_NEEDS_GROUPS       0x4
+
+/*
+ * Balance when about to become idle
+ *
+ * SHARED_CHILD: Set from the base domain up to cpuset.sched_relax_domain_level.
+ * NEEDS_GROUPS: Load balancing flag.
+ */
+SD_FLAG(SD_BALANCE_NEWIDLE, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
+
+/*
+ * Balance on exec
+ *
+ * SHARED_CHILD: Set from the base domain up to the NUMA reclaim level.
+ * NEEDS_GROUPS: Load balancing flag.
+ */
+SD_FLAG(SD_BALANCE_EXEC, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
+
+/*
+ * Balance on fork, clone
+ *
+ * SHARED_CHILD: Set from the base domain up to the NUMA reclaim level.
+ * NEEDS_GROUPS: Load balancing flag.
+ */
+SD_FLAG(SD_BALANCE_FORK, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
+
+/*
+ * Balance on wakeup
+ *
+ * SHARED_CHILD: Set from the base domain up to cpuset.sched_relax_domain_level.
+ * NEEDS_GROUPS: Load balancing flag.
+ */
+SD_FLAG(SD_BALANCE_WAKE, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
+
+/*
+ * Consider waking task on waking CPU.
+ *
+ * SHARED_CHILD: Set from the base domain up to the NUMA reclaim level.
+ */
+SD_FLAG(SD_WAKE_AFFINE, SDF_SHARED_CHILD)
+
+/*
+ * Domain members have different CPU capacities
+ *
+ * SHARED_PARENT: Set from the topmost domain down to the first domain where
+ *                asymmetry is detected.
+ * NEEDS_GROUPS: Per-CPU capacity is asymmetric between groups.
+ */
+SD_FLAG(SD_ASYM_CPUCAPACITY, SDF_SHARED_PARENT | SDF_NEEDS_GROUPS)
+
+/*
+ * Domain members share CPU capacity (i.e. SMT)
+ *
+ * SHARED_CHILD: Set from the base domain up until spanned CPUs no longer share
+ *               CPU capacity.
+ * NEEDS_GROUPS: Capacity is shared between groups.
+ */
+SD_FLAG(SD_SHARE_CPUCAPACITY, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
+
+/*
+ * Domain members share CPU package resources (i.e. caches)
+ *
+ * SHARED_CHILD: Set from the base domain up until spanned CPUs no longer share
+ *               the same cache(s).
+ * NEEDS_GROUPS: Caches are shared between groups.
+ */
+SD_FLAG(SD_SHARE_PKG_RESOURCES, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
+
+/*
+ * Only a single load balancing instance
+ *
+ * SHARED_PARENT: Set for all NUMA levels above NODE. Could be set from a
+ *                different level upwards, but it doesn't change that if a
+ *                domain has this flag set, then all of its parents need to have
+ *                it too (otherwise the serialization doesn't make sense).
+ * NEEDS_GROUPS: No point in preserving domain if it has a single group.
+ */
+SD_FLAG(SD_SERIALIZE, SDF_SHARED_PARENT | SDF_NEEDS_GROUPS)
+
+/*
+ * Place busy tasks earlier in the domain
+ *
+ * SHARED_CHILD: Usually set on the SMT level. Technically could be set further
+ *               up, but currently assumed to be set from the base domain
+ *               upwards (see update_top_cache_domain()).
+ * NEEDS_GROUPS: Load balancing flag.
+ */
+SD_FLAG(SD_ASYM_PACKING, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
+
+/*
+ * Prefer to place tasks in a sibling domain
+ *
+ * Set up until domains start spanning NUMA nodes. Close to being a SHARED_CHILD
+ * flag, but cleared below domains with SD_ASYM_CPUCAPACITY.
+ *
+ * NEEDS_GROUPS: Load balancing flag.
+ */
+SD_FLAG(SD_PREFER_SIBLING, SDF_NEEDS_GROUPS)
+
+/*
+ * sched_groups of this level overlap
+ *
+ * SHARED_PARENT: Set for all NUMA levels above NODE.
+ * NEEDS_GROUPS: Overlaps can only exist with more than one group.
+ */
+SD_FLAG(SD_OVERLAP, SDF_SHARED_PARENT | SDF_NEEDS_GROUPS)
+
+/*
+ * Cross-node balancing
+ *
+ * SHARED_PARENT: Set for all NUMA levels above NODE.
+ * NEEDS_GROUPS: No point in preserving domain if it has a single group.
+ */
+SD_FLAG(SD_NUMA, SDF_SHARED_PARENT | SDF_NEEDS_GROUPS)
index 8205112..9ef7bf6 100644 (file)
  */
 #ifdef CONFIG_SMP
 
-#define SD_BALANCE_NEWIDLE     0x0001  /* Balance when about to become idle */
-#define SD_BALANCE_EXEC                0x0002  /* Balance on exec */
-#define SD_BALANCE_FORK                0x0004  /* Balance on fork, clone */
-#define SD_BALANCE_WAKE                0x0008  /* Balance on wakeup */
-#define SD_WAKE_AFFINE         0x0010  /* Wake task to waking CPU */
-#define SD_ASYM_CPUCAPACITY    0x0020  /* Domain members have different CPU capacities */
-#define SD_SHARE_CPUCAPACITY   0x0040  /* Domain members share CPU capacity */
-#define SD_SHARE_POWERDOMAIN   0x0080  /* Domain members share power domain */
-#define SD_SHARE_PKG_RESOURCES 0x0100  /* Domain members share CPU pkg resources */
-#define SD_SERIALIZE           0x0200  /* Only a single load balancing instance */
-#define SD_ASYM_PACKING                0x0400  /* Place busy groups earlier in the domain */
-#define SD_PREFER_SIBLING      0x0800  /* Prefer to place tasks in a sibling domain */
-#define SD_OVERLAP             0x1000  /* sched_domains of this level overlap */
-#define SD_NUMA                        0x2000  /* cross-node balancing */
+/* Generate SD flag indexes */
+#define SD_FLAG(name, mflags) __##name,
+enum {
+       #include <linux/sched/sd_flags.h>
+       __SD_FLAG_CNT,
+};
+#undef SD_FLAG
+/* Generate SD flag bits */
+#define SD_FLAG(name, mflags) name = 1 << __##name,
+enum {
+       #include <linux/sched/sd_flags.h>
+};
+#undef SD_FLAG
+
+#ifdef CONFIG_SCHED_DEBUG
+
+struct sd_flag_debug {
+       unsigned int meta_flags;
+       char *name;
+};
+extern const struct sd_flag_debug sd_flag_debug[];
+
+#endif
 
 #ifdef CONFIG_SCHED_SMT
 static inline int cpu_smt_flags(void)
index 962d976..ac5b07f 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kcsan-checks.h>
 #include <linux/lockdep.h>
 #include <linux/mutex.h>
+#include <linux/ww_mutex.h>
 #include <linux/preempt.h>
 #include <linux/spinlock.h>
 
@@ -53,7 +54,7 @@
  *
  * If the write serialization mechanism is one of the common kernel
  * locking primitives, use a sequence counter with associated lock
- * (seqcount_LOCKTYPE_t) instead.
+ * (seqcount_LOCKNAME_t) instead.
  *
  * If it's desired to automatically handle the sequence counter writer
  * serialization and non-preemptibility requirements, use a sequential
@@ -117,7 +118,7 @@ static inline void seqcount_lockdep_reader_access(const seqcount_t *s)
 #define SEQCNT_ZERO(name) { .sequence = 0, SEQCOUNT_DEP_MAP_INIT(name) }
 
 /*
- * Sequence counters with associated locks (seqcount_LOCKTYPE_t)
+ * Sequence counters with associated locks (seqcount_LOCKNAME_t)
  *
  * A sequence counter which associates the lock used for writer
  * serialization at initialization time. This enables lockdep to validate
@@ -131,63 +132,117 @@ static inline void seqcount_lockdep_reader_access(const seqcount_t *s)
  * See Documentation/locking/seqlock.rst
  */
 
-#ifdef CONFIG_LOCKDEP
+/*
+ * For PREEMPT_RT, seqcount_LOCKNAME_t write side critical sections cannot
+ * disable preemption. It can lead to higher latencies, and the write side
+ * sections will not be able to acquire locks which become sleeping locks
+ * (e.g. spinlock_t).
+ *
+ * To remain preemptible while avoiding a possible livelock caused by the
+ * reader preempting the writer, use a different technique: let the reader
+ * detect if a seqcount_LOCKNAME_t writer is in progress. If that is the
+ * case, acquire then release the associated LOCKNAME writer serialization
+ * lock. This will allow any possibly-preempted writer to make progress
+ * until the end of its writer serialization lock critical section.
+ *
+ * This lock-unlock technique must be implemented for all of PREEMPT_RT
+ * sleeping locks.  See Documentation/locking/locktypes.rst
+ */
+#if defined(CONFIG_LOCKDEP) || defined(CONFIG_PREEMPT_RT)
 #define __SEQ_LOCK(expr)       expr
 #else
 #define __SEQ_LOCK(expr)
 #endif
 
 /**
- * typedef seqcount_LOCKNAME_t - sequence counter with LOCKTYPR associated
+ * typedef seqcount_LOCKNAME_t - sequence counter with LOCKNAME associated
  * @seqcount:  The real sequence counter
- * @lock:      Pointer to the associated spinlock
+ * @lock:      Pointer to the associated lock
  *
- * A plain sequence counter with external writer synchronization by a
- * spinlock. The spinlock is associated to the sequence count in the
+ * A plain sequence counter with external writer synchronization by
+ * LOCKNAME @lock. The lock is associated to the sequence counter in the
  * static initializer or init function. This enables lockdep to validate
  * that the write side critical section is properly serialized.
+ *
+ * LOCKNAME:   raw_spinlock, spinlock, rwlock, mutex, or ww_mutex.
  */
 
-/**
+/*
  * seqcount_LOCKNAME_init() - runtime initializer for seqcount_LOCKNAME_t
  * @s:         Pointer to the seqcount_LOCKNAME_t instance
- * @lock:      Pointer to the associated LOCKTYPE
+ * @lock:      Pointer to the associated lock
  */
 
+#define seqcount_LOCKNAME_init(s, _lock, lockname)                     \
+       do {                                                            \
+               seqcount_##lockname##_t *____s = (s);                   \
+               seqcount_init(&____s->seqcount);                        \
+               __SEQ_LOCK(____s->lock = (_lock));                      \
+       } while (0)
+
+#define seqcount_raw_spinlock_init(s, lock)    seqcount_LOCKNAME_init(s, lock, raw_spinlock)
+#define seqcount_spinlock_init(s, lock)                seqcount_LOCKNAME_init(s, lock, spinlock)
+#define seqcount_rwlock_init(s, lock)          seqcount_LOCKNAME_init(s, lock, rwlock);
+#define seqcount_mutex_init(s, lock)           seqcount_LOCKNAME_init(s, lock, mutex);
+#define seqcount_ww_mutex_init(s, lock)                seqcount_LOCKNAME_init(s, lock, ww_mutex);
+
 /*
- * SEQCOUNT_LOCKTYPE() - Instantiate seqcount_LOCKNAME_t and helpers
- * @locktype:          actual typename
- * @lockname:          name
+ * SEQCOUNT_LOCKNAME() - Instantiate seqcount_LOCKNAME_t and helpers
+ * seqprop_LOCKNAME_*()        - Property accessors for seqcount_LOCKNAME_t
+ *
+ * @lockname:          "LOCKNAME" part of seqcount_LOCKNAME_t
+ * @locktype:          LOCKNAME canonical C data type
  * @preemptible:       preemptibility of above locktype
  * @lockmember:                argument for lockdep_assert_held()
+ * @lockbase:          associated lock release function (prefix only)
+ * @lock_acquire:      associated lock acquisition function (full call)
  */
-#define SEQCOUNT_LOCKTYPE(locktype, lockname, preemptible, lockmember) \
+#define SEQCOUNT_LOCKNAME(lockname, locktype, preemptible, lockmember, lockbase, lock_acquire) \
 typedef struct seqcount_##lockname {                                   \
        seqcount_t              seqcount;                               \
        __SEQ_LOCK(locktype     *lock);                                 \
 } seqcount_##lockname##_t;                                             \
                                                                        \
-static __always_inline void                                            \
-seqcount_##lockname##_init(seqcount_##lockname##_t *s, locktype *lock) \
+static __always_inline seqcount_t *                                    \
+__seqprop_##lockname##_ptr(seqcount_##lockname##_t *s)                 \
 {                                                                      \
-       seqcount_init(&s->seqcount);                                    \
-       __SEQ_LOCK(s->lock = lock);                                     \
+       return &s->seqcount;                                            \
 }                                                                      \
                                                                        \
-static __always_inline seqcount_t *                                    \
-__seqcount_##lockname##_ptr(seqcount_##lockname##_t *s)                        \
+static __always_inline unsigned                                                \
+__seqprop_##lockname##_sequence(const seqcount_##lockname##_t *s)      \
 {                                                                      \
-       return &s->seqcount;                                            \
+       unsigned seq = READ_ONCE(s->seqcount.sequence);                 \
+                                                                       \
+       if (!IS_ENABLED(CONFIG_PREEMPT_RT))                             \
+               return seq;                                             \
+                                                                       \
+       if (preemptible && unlikely(seq & 1)) {                         \
+               __SEQ_LOCK(lock_acquire);                               \
+               __SEQ_LOCK(lockbase##_unlock(s->lock));                 \
+                                                                       \
+               /*                                                      \
+                * Re-read the sequence counter since the (possibly     \
+                * preempted) writer made progress.                     \
+                */                                                     \
+               seq = READ_ONCE(s->seqcount.sequence);                  \
+       }                                                               \
+                                                                       \
+       return seq;                                                     \
 }                                                                      \
                                                                        \
 static __always_inline bool                                            \
-__seqcount_##lockname##_preemptible(seqcount_##lockname##_t *s)                \
+__seqprop_##lockname##_preemptible(const seqcount_##lockname##_t *s)   \
 {                                                                      \
-       return preemptible;                                             \
+       if (!IS_ENABLED(CONFIG_PREEMPT_RT))                             \
+               return preemptible;                                     \
+                                                                       \
+       /* PREEMPT_RT relies on the above LOCK+UNLOCK */                \
+       return false;                                                   \
 }                                                                      \
                                                                        \
 static __always_inline void                                            \
-__seqcount_##lockname##_assert(seqcount_##lockname##_t *s)             \
+__seqprop_##lockname##_assert(const seqcount_##lockname##_t *s)                \
 {                                                                      \
        __SEQ_LOCK(lockdep_assert_held(lockmember));                    \
 }
@@ -196,50 +251,56 @@ __seqcount_##lockname##_assert(seqcount_##lockname##_t *s)                \
  * __seqprop() for seqcount_t
  */
 
-static inline seqcount_t *__seqcount_ptr(seqcount_t *s)
+static inline seqcount_t *__seqprop_ptr(seqcount_t *s)
 {
        return s;
 }
 
-static inline bool __seqcount_preemptible(seqcount_t *s)
+static inline unsigned __seqprop_sequence(const seqcount_t *s)
+{
+       return READ_ONCE(s->sequence);
+}
+
+static inline bool __seqprop_preemptible(const seqcount_t *s)
 {
        return false;
 }
 
-static inline void __seqcount_assert(seqcount_t *s)
+static inline void __seqprop_assert(const seqcount_t *s)
 {
        lockdep_assert_preemption_disabled();
 }
 
-SEQCOUNT_LOCKTYPE(raw_spinlock_t,      raw_spinlock,   false,  s->lock)
-SEQCOUNT_LOCKTYPE(spinlock_t,          spinlock,       false,  s->lock)
-SEQCOUNT_LOCKTYPE(rwlock_t,            rwlock,         false,  s->lock)
-SEQCOUNT_LOCKTYPE(struct mutex,                mutex,          true,   s->lock)
-SEQCOUNT_LOCKTYPE(struct ww_mutex,     ww_mutex,       true,   &s->lock->base)
+#define __SEQ_RT       IS_ENABLED(CONFIG_PREEMPT_RT)
 
-/**
+SEQCOUNT_LOCKNAME(raw_spinlock, raw_spinlock_t,  false,    s->lock,        raw_spin, raw_spin_lock(s->lock))
+SEQCOUNT_LOCKNAME(spinlock,     spinlock_t,      __SEQ_RT, s->lock,        spin,     spin_lock(s->lock))
+SEQCOUNT_LOCKNAME(rwlock,       rwlock_t,        __SEQ_RT, s->lock,        read,     read_lock(s->lock))
+SEQCOUNT_LOCKNAME(mutex,        struct mutex,    true,     s->lock,        mutex,    mutex_lock(s->lock))
+SEQCOUNT_LOCKNAME(ww_mutex,     struct ww_mutex, true,     &s->lock->base, ww_mutex, ww_mutex_lock(s->lock, NULL))
+
+/*
  * SEQCNT_LOCKNAME_ZERO - static initializer for seqcount_LOCKNAME_t
  * @name:      Name of the seqcount_LOCKNAME_t instance
- * @lock:      Pointer to the associated LOCKTYPE
+ * @lock:      Pointer to the associated LOCKNAME
  */
 
-#define SEQCOUNT_LOCKTYPE_ZERO(seq_name, assoc_lock) {                 \
+#define SEQCOUNT_LOCKNAME_ZERO(seq_name, assoc_lock) {                 \
        .seqcount               = SEQCNT_ZERO(seq_name.seqcount),       \
        __SEQ_LOCK(.lock        = (assoc_lock))                         \
 }
 
-#define SEQCNT_SPINLOCK_ZERO(name, lock)       SEQCOUNT_LOCKTYPE_ZERO(name, lock)
-#define SEQCNT_RAW_SPINLOCK_ZERO(name, lock)   SEQCOUNT_LOCKTYPE_ZERO(name, lock)
-#define SEQCNT_RWLOCK_ZERO(name, lock)         SEQCOUNT_LOCKTYPE_ZERO(name, lock)
-#define SEQCNT_MUTEX_ZERO(name, lock)          SEQCOUNT_LOCKTYPE_ZERO(name, lock)
-#define SEQCNT_WW_MUTEX_ZERO(name, lock)       SEQCOUNT_LOCKTYPE_ZERO(name, lock)
-
+#define SEQCNT_RAW_SPINLOCK_ZERO(name, lock)   SEQCOUNT_LOCKNAME_ZERO(name, lock)
+#define SEQCNT_SPINLOCK_ZERO(name, lock)       SEQCOUNT_LOCKNAME_ZERO(name, lock)
+#define SEQCNT_RWLOCK_ZERO(name, lock)         SEQCOUNT_LOCKNAME_ZERO(name, lock)
+#define SEQCNT_MUTEX_ZERO(name, lock)          SEQCOUNT_LOCKNAME_ZERO(name, lock)
+#define SEQCNT_WW_MUTEX_ZERO(name, lock)       SEQCOUNT_LOCKNAME_ZERO(name, lock)
 
 #define __seqprop_case(s, lockname, prop)                              \
-       seqcount_##lockname##_t: __seqcount_##lockname##_##prop((void *)(s))
+       seqcount_##lockname##_t: __seqprop_##lockname##_##prop((void *)(s))
 
 #define __seqprop(s, prop) _Generic(*(s),                              \
-       seqcount_t:             __seqcount_##prop((void *)(s)),         \
+       seqcount_t:             __seqprop_##prop((void *)(s)),          \
        __seqprop_case((s),     raw_spinlock,   prop),                  \
        __seqprop_case((s),     spinlock,       prop),                  \
        __seqprop_case((s),     rwlock,         prop),                  \
@@ -247,12 +308,13 @@ SEQCOUNT_LOCKTYPE(struct ww_mutex,        ww_mutex,       true,   &s->lock->base)
        __seqprop_case((s),     ww_mutex,       prop))
 
 #define __seqcount_ptr(s)              __seqprop(s, ptr)
+#define __seqcount_sequence(s)         __seqprop(s, sequence)
 #define __seqcount_lock_preemptible(s) __seqprop(s, preemptible)
 #define __seqcount_assert_lock_held(s) __seqprop(s, assert)
 
 /**
  * __read_seqcount_begin() - begin a seqcount_t read section w/o barrier
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  *
  * __read_seqcount_begin is like read_seqcount_begin, but has no smp_rmb()
  * barrier. Callers should ensure that smp_rmb() or equivalent ordering is
@@ -265,56 +327,45 @@ SEQCOUNT_LOCKTYPE(struct ww_mutex,        ww_mutex,       true,   &s->lock->base)
  * Return: count to be passed to read_seqcount_retry()
  */
 #define __read_seqcount_begin(s)                                       \
-       __read_seqcount_t_begin(__seqcount_ptr(s))
-
-static inline unsigned __read_seqcount_t_begin(const seqcount_t *s)
-{
-       unsigned ret;
-
-repeat:
-       ret = READ_ONCE(s->sequence);
-       if (unlikely(ret & 1)) {
-               cpu_relax();
-               goto repeat;
-       }
-       kcsan_atomic_next(KCSAN_SEQLOCK_REGION_MAX);
-       return ret;
-}
+({                                                                     \
+       unsigned seq;                                                   \
+                                                                       \
+       while ((seq = __seqcount_sequence(s)) & 1)                      \
+               cpu_relax();                                            \
+                                                                       \
+       kcsan_atomic_next(KCSAN_SEQLOCK_REGION_MAX);                    \
+       seq;                                                            \
+})
 
 /**
  * raw_read_seqcount_begin() - begin a seqcount_t read section w/o lockdep
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  *
  * Return: count to be passed to read_seqcount_retry()
  */
 #define raw_read_seqcount_begin(s)                                     \
-       raw_read_seqcount_t_begin(__seqcount_ptr(s))
-
-static inline unsigned raw_read_seqcount_t_begin(const seqcount_t *s)
-{
-       unsigned ret = __read_seqcount_t_begin(s);
-       smp_rmb();
-       return ret;
-}
+({                                                                     \
+       unsigned seq = __read_seqcount_begin(s);                        \
+                                                                       \
+       smp_rmb();                                                      \
+       seq;                                                            \
+})
 
 /**
  * read_seqcount_begin() - begin a seqcount_t read critical section
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  *
  * Return: count to be passed to read_seqcount_retry()
  */
 #define read_seqcount_begin(s)                                         \
-       read_seqcount_t_begin(__seqcount_ptr(s))
-
-static inline unsigned read_seqcount_t_begin(const seqcount_t *s)
-{
-       seqcount_lockdep_reader_access(s);
-       return raw_read_seqcount_t_begin(s);
-}
+({                                                                     \
+       seqcount_lockdep_reader_access(__seqcount_ptr(s));              \
+       raw_read_seqcount_begin(s);                                     \
+})
 
 /**
  * raw_read_seqcount() - read the raw seqcount_t counter value
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  *
  * raw_read_seqcount opens a read critical section of the given
  * seqcount_t, without any lockdep checking, and without checking or
@@ -324,20 +375,18 @@ static inline unsigned read_seqcount_t_begin(const seqcount_t *s)
  * Return: count to be passed to read_seqcount_retry()
  */
 #define raw_read_seqcount(s)                                           \
-       raw_read_seqcount_t(__seqcount_ptr(s))
-
-static inline unsigned raw_read_seqcount_t(const seqcount_t *s)
-{
-       unsigned ret = READ_ONCE(s->sequence);
-       smp_rmb();
-       kcsan_atomic_next(KCSAN_SEQLOCK_REGION_MAX);
-       return ret;
-}
+({                                                                     \
+       unsigned seq = __seqcount_sequence(s);                          \
+                                                                       \
+       smp_rmb();                                                      \
+       kcsan_atomic_next(KCSAN_SEQLOCK_REGION_MAX);                    \
+       seq;                                                            \
+})
 
 /**
  * raw_seqcount_begin() - begin a seqcount_t read critical section w/o
  *                        lockdep and w/o counter stabilization
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  *
  * raw_seqcount_begin opens a read critical section of the given
  * seqcount_t. Unlike read_seqcount_begin(), this function will not wait
@@ -352,20 +401,17 @@ static inline unsigned raw_read_seqcount_t(const seqcount_t *s)
  * Return: count to be passed to read_seqcount_retry()
  */
 #define raw_seqcount_begin(s)                                          \
-       raw_seqcount_t_begin(__seqcount_ptr(s))
-
-static inline unsigned raw_seqcount_t_begin(const seqcount_t *s)
-{
-       /*
-        * If the counter is odd, let read_seqcount_retry() fail
-        * by decrementing the counter.
-        */
-       return raw_read_seqcount_t(s) & ~1;
-}
+({                                                                     \
+       /*                                                              \
+        * If the counter is odd, let read_seqcount_retry() fail        \
+        * by decrementing the counter.                                 \
+        */                                                             \
+       raw_read_seqcount(s) & ~1;                                      \
+})
 
 /**
  * __read_seqcount_retry() - end a seqcount_t read section w/o barrier
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  * @start: count, from read_seqcount_begin()
  *
  * __read_seqcount_retry is like read_seqcount_retry, but has no smp_rmb()
@@ -389,7 +435,7 @@ static inline int __read_seqcount_t_retry(const seqcount_t *s, unsigned start)
 
 /**
  * read_seqcount_retry() - end a seqcount_t read critical section
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  * @start: count, from read_seqcount_begin()
  *
  * read_seqcount_retry closes the read critical section of given
@@ -409,7 +455,7 @@ static inline int read_seqcount_t_retry(const seqcount_t *s, unsigned start)
 
 /**
  * raw_write_seqcount_begin() - start a seqcount_t write section w/o lockdep
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  */
 #define raw_write_seqcount_begin(s)                                    \
 do {                                                                   \
@@ -428,7 +474,7 @@ static inline void raw_write_seqcount_t_begin(seqcount_t *s)
 
 /**
  * raw_write_seqcount_end() - end a seqcount_t write section w/o lockdep
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  */
 #define raw_write_seqcount_end(s)                                      \
 do {                                                                   \
@@ -448,7 +494,7 @@ static inline void raw_write_seqcount_t_end(seqcount_t *s)
 /**
  * write_seqcount_begin_nested() - start a seqcount_t write section with
  *                                 custom lockdep nesting level
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  * @subclass: lockdep nesting level
  *
  * See Documentation/locking/lockdep-design.rst
@@ -471,7 +517,7 @@ static inline void write_seqcount_t_begin_nested(seqcount_t *s, int subclass)
 
 /**
  * write_seqcount_begin() - start a seqcount_t write side critical section
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  *
  * write_seqcount_begin opens a write side critical section of the given
  * seqcount_t.
@@ -497,7 +543,7 @@ static inline void write_seqcount_t_begin(seqcount_t *s)
 
 /**
  * write_seqcount_end() - end a seqcount_t write side critical section
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  *
  * The write section must've been opened with write_seqcount_begin().
  */
@@ -517,7 +563,7 @@ static inline void write_seqcount_t_end(seqcount_t *s)
 
 /**
  * raw_write_seqcount_barrier() - do a seqcount_t write barrier
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  *
  * This can be used to provide an ordering guarantee instead of the usual
  * consistency guarantee. It is one wmb cheaper, because it can collapse
@@ -571,7 +617,7 @@ static inline void raw_write_seqcount_t_barrier(seqcount_t *s)
 /**
  * write_seqcount_invalidate() - invalidate in-progress seqcount_t read
  *                               side operations
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * @s: Pointer to seqcount_t or any of the seqcount_LOCKNAME_t variants
  *
  * After write_seqcount_invalidate, no seqcount_t read side operations
  * will complete successfully and see data older than this.
@@ -587,34 +633,73 @@ static inline void write_seqcount_t_invalidate(seqcount_t *s)
        kcsan_nestable_atomic_end();
 }
 
-/**
- * raw_read_seqcount_latch() - pick even/odd seqcount_t latch data copy
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+/*
+ * Latch sequence counters (seqcount_latch_t)
  *
- * Use seqcount_t latching to switch between two storage places protected
- * by a sequence counter. Doing so allows having interruptible, preemptible,
- * seqcount_t write side critical sections.
+ * A sequence counter variant where the counter even/odd value is used to
+ * switch between two copies of protected data. This allows the read path,
+ * typically NMIs, to safely interrupt the write side critical section.
  *
- * Check raw_write_seqcount_latch() for more details and a full reader and
- * writer usage example.
+ * As the write sections are fully preemptible, no special handling for
+ * PREEMPT_RT is needed.
+ */
+typedef struct {
+       seqcount_t seqcount;
+} seqcount_latch_t;
+
+/**
+ * SEQCNT_LATCH_ZERO() - static initializer for seqcount_latch_t
+ * @seq_name: Name of the seqcount_latch_t instance
+ */
+#define SEQCNT_LATCH_ZERO(seq_name) {                                  \
+       .seqcount               = SEQCNT_ZERO(seq_name.seqcount),       \
+}
+
+/**
+ * seqcount_latch_init() - runtime initializer for seqcount_latch_t
+ * @s: Pointer to the seqcount_latch_t instance
+ */
+static inline void seqcount_latch_init(seqcount_latch_t *s)
+{
+       seqcount_init(&s->seqcount);
+}
+
+/**
+ * raw_read_seqcount_latch() - pick even/odd latch data copy
+ * @s: Pointer to seqcount_latch_t
+ *
+ * See raw_write_seqcount_latch() for details and a full reader/writer
+ * usage example.
  *
  * Return: sequence counter raw value. Use the lowest bit as an index for
- * picking which data copy to read. The full counter value must then be
- * checked with read_seqcount_retry().
+ * picking which data copy to read. The full counter must then be checked
+ * with read_seqcount_latch_retry().
  */
-#define raw_read_seqcount_latch(s)                                     \
-       raw_read_seqcount_t_latch(__seqcount_ptr(s))
+static inline unsigned raw_read_seqcount_latch(const seqcount_latch_t *s)
+{
+       /*
+        * Pairs with the first smp_wmb() in raw_write_seqcount_latch().
+        * Due to the dependent load, a full smp_rmb() is not needed.
+        */
+       return READ_ONCE(s->seqcount.sequence);
+}
 
-static inline int raw_read_seqcount_t_latch(seqcount_t *s)
+/**
+ * read_seqcount_latch_retry() - end a seqcount_latch_t read section
+ * @s:         Pointer to seqcount_latch_t
+ * @start:     count, from raw_read_seqcount_latch()
+ *
+ * Return: true if a read section retry is required, else false
+ */
+static inline int
+read_seqcount_latch_retry(const seqcount_latch_t *s, unsigned start)
 {
-       /* Pairs with the first smp_wmb() in raw_write_seqcount_latch() */
-       int seq = READ_ONCE(s->sequence); /* ^^^ */
-       return seq;
+       return read_seqcount_retry(&s->seqcount, start);
 }
 
 /**
- * raw_write_seqcount_latch() - redirect readers to even/odd copy
- * @s: Pointer to seqcount_t or any of the seqcount_locktype_t variants
+ * raw_write_seqcount_latch() - redirect latch readers to even/odd copy
+ * @s: Pointer to seqcount_latch_t
  *
  * The latch technique is a multiversion concurrency control method that allows
  * queries during non-atomic modifications. If you can guarantee queries never
@@ -633,7 +718,7 @@ static inline int raw_read_seqcount_t_latch(seqcount_t *s)
  * The basic form is a data structure like::
  *
  *     struct latch_struct {
- *             seqcount_t              seq;
+ *             seqcount_latch_t        seq;
  *             struct data_struct      data[2];
  *     };
  *
@@ -643,13 +728,13 @@ static inline int raw_read_seqcount_t_latch(seqcount_t *s)
  *     void latch_modify(struct latch_struct *latch, ...)
  *     {
  *             smp_wmb();      // Ensure that the last data[1] update is visible
- *             latch->seq++;
+ *             latch->seq.sequence++;
  *             smp_wmb();      // Ensure that the seqcount update is visible
  *
  *             modify(latch->data[0], ...);
  *
  *             smp_wmb();      // Ensure that the data[0] update is visible
- *             latch->seq++;
+ *             latch->seq.sequence++;
  *             smp_wmb();      // Ensure that the seqcount update is visible
  *
  *             modify(latch->data[1], ...);
@@ -668,8 +753,8 @@ static inline int raw_read_seqcount_t_latch(seqcount_t *s)
  *                     idx = seq & 0x01;
  *                     entry = data_query(latch->data[idx], ...);
  *
- *             // read_seqcount_retry() includes needed smp_rmb()
- *             } while (read_seqcount_retry(&latch->seq, seq));
+ *             // This includes needed smp_rmb()
+ *             } while (read_seqcount_latch_retry(&latch->seq, seq));
  *
  *             return entry;
  *     }
@@ -688,19 +773,16 @@ static inline int raw_read_seqcount_t_latch(seqcount_t *s)
  *     to miss an entire modification sequence, once it resumes it might
  *     observe the new entry.
  *
- * NOTE:
+ * NOTE2:
  *
  *     When data is a dynamic data structure; one should use regular RCU
  *     patterns to manage the lifetimes of the objects within.
  */
-#define raw_write_seqcount_latch(s)                                    \
-       raw_write_seqcount_t_latch(__seqcount_ptr(s))
-
-static inline void raw_write_seqcount_t_latch(seqcount_t *s)
+static inline void raw_write_seqcount_latch(seqcount_latch_t *s)
 {
-       smp_wmb();      /* prior stores before incrementing "sequence" */
-       s->sequence++;
-       smp_wmb();      /* increment "sequence" before following stores */
+       smp_wmb();      /* prior stores before incrementing "sequence" */
+       s->seqcount.sequence++;
+       smp_wmb();      /* increment "sequence" before following stores */
 }
 
 /*
@@ -714,13 +796,17 @@ static inline void raw_write_seqcount_t_latch(seqcount_t *s)
  *    - Documentation/locking/seqlock.rst
  */
 typedef struct {
-       struct seqcount seqcount;
+       /*
+        * Make sure that readers don't starve writers on PREEMPT_RT: use
+        * seqcount_spinlock_t instead of seqcount_t. Check __SEQ_LOCK().
+        */
+       seqcount_spinlock_t seqcount;
        spinlock_t lock;
 } seqlock_t;
 
 #define __SEQLOCK_UNLOCKED(lockname)                                   \
        {                                                               \
-               .seqcount = SEQCNT_ZERO(lockname),                      \
+               .seqcount = SEQCNT_SPINLOCK_ZERO(lockname, &(lockname).lock), \
                .lock = __SPIN_LOCK_UNLOCKED(lockname)                  \
        }
 
@@ -730,12 +816,12 @@ typedef struct {
  */
 #define seqlock_init(sl)                                               \
        do {                                                            \
-               seqcount_init(&(sl)->seqcount);                         \
                spin_lock_init(&(sl)->lock);                            \
+               seqcount_spinlock_init(&(sl)->seqcount, &(sl)->lock);   \
        } while (0)
 
 /**
- * DEFINE_SEQLOCK() - Define a statically allocated seqlock_t
+ * DEFINE_SEQLOCK(sl) - Define a statically allocated seqlock_t
  * @sl: Name of the seqlock_t instance
  */
 #define DEFINE_SEQLOCK(sl) \
@@ -778,6 +864,12 @@ static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start)
        return read_seqcount_retry(&sl->seqcount, start);
 }
 
+/*
+ * For all seqlock_t write side functions, use write_seqcount_*t*_begin()
+ * instead of the generic write_seqcount_begin(). This way, no redundant
+ * lockdep_assert_held() checks are added.
+ */
+
 /**
  * write_seqlock() - start a seqlock_t write side critical section
  * @sl: Pointer to seqlock_t
@@ -794,7 +886,7 @@ static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start)
 static inline void write_seqlock(seqlock_t *sl)
 {
        spin_lock(&sl->lock);
-       write_seqcount_t_begin(&sl->seqcount);
+       write_seqcount_t_begin(&sl->seqcount.seqcount);
 }
 
 /**
@@ -806,7 +898,7 @@ static inline void write_seqlock(seqlock_t *sl)
  */
 static inline void write_sequnlock(seqlock_t *sl)
 {
-       write_seqcount_t_end(&sl->seqcount);
+       write_seqcount_t_end(&sl->seqcount.seqcount);
        spin_unlock(&sl->lock);
 }
 
@@ -820,7 +912,7 @@ static inline void write_sequnlock(seqlock_t *sl)
 static inline void write_seqlock_bh(seqlock_t *sl)
 {
        spin_lock_bh(&sl->lock);
-       write_seqcount_t_begin(&sl->seqcount);
+       write_seqcount_t_begin(&sl->seqcount.seqcount);
 }
 
 /**
@@ -833,7 +925,7 @@ static inline void write_seqlock_bh(seqlock_t *sl)
  */
 static inline void write_sequnlock_bh(seqlock_t *sl)
 {
-       write_seqcount_t_end(&sl->seqcount);
+       write_seqcount_t_end(&sl->seqcount.seqcount);
        spin_unlock_bh(&sl->lock);
 }
 
@@ -847,7 +939,7 @@ static inline void write_sequnlock_bh(seqlock_t *sl)
 static inline void write_seqlock_irq(seqlock_t *sl)
 {
        spin_lock_irq(&sl->lock);
-       write_seqcount_t_begin(&sl->seqcount);
+       write_seqcount_t_begin(&sl->seqcount.seqcount);
 }
 
 /**
@@ -859,7 +951,7 @@ static inline void write_seqlock_irq(seqlock_t *sl)
  */
 static inline void write_sequnlock_irq(seqlock_t *sl)
 {
-       write_seqcount_t_end(&sl->seqcount);
+       write_seqcount_t_end(&sl->seqcount.seqcount);
        spin_unlock_irq(&sl->lock);
 }
 
@@ -868,7 +960,7 @@ static inline unsigned long __write_seqlock_irqsave(seqlock_t *sl)
        unsigned long flags;
 
        spin_lock_irqsave(&sl->lock, flags);
-       write_seqcount_t_begin(&sl->seqcount);
+       write_seqcount_t_begin(&sl->seqcount.seqcount);
        return flags;
 }
 
@@ -897,7 +989,7 @@ static inline unsigned long __write_seqlock_irqsave(seqlock_t *sl)
 static inline void
 write_sequnlock_irqrestore(seqlock_t *sl, unsigned long flags)
 {
-       write_seqcount_t_end(&sl->seqcount);
+       write_seqcount_t_end(&sl->seqcount.seqcount);
        spin_unlock_irqrestore(&sl->lock, flags);
 }
 
index 01fc4d9..8a99279 100644 (file)
@@ -248,6 +248,7 @@ struct uart_port {
 
        unsigned char           hub6;                   /* this should be in the 8250 driver */
        unsigned char           suspended;
+       unsigned char           console_reinit;
        const char              *name;                  /* port name */
        struct attribute_group  *attr_group;            /* port specific attributes */
        const struct attribute_group **tty_groups;      /* all attributes (serial core use only) */
index 6bb1a3f..7bbc0e9 100644 (file)
@@ -137,11 +137,11 @@ static inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \
                b3 = b->sig[3]; b2 = b->sig[2];                         \
                r->sig[3] = op(a3, b3);                                 \
                r->sig[2] = op(a2, b2);                                 \
-               /* fall through */                                      \
+               fallthrough;                                            \
        case 2:                                                         \
                a1 = a->sig[1]; b1 = b->sig[1];                         \
                r->sig[1] = op(a1, b1);                                 \
-               /* fall through */                                      \
+               fallthrough;                                            \
        case 1:                                                         \
                a0 = a->sig[0]; b0 = b->sig[0];                         \
                r->sig[0] = op(a0, b0);                                 \
@@ -171,9 +171,9 @@ static inline void name(sigset_t *set)                                      \
        switch (_NSIG_WORDS) {                                          \
        case 4: set->sig[3] = op(set->sig[3]);                          \
                set->sig[2] = op(set->sig[2]);                          \
-               /* fall through */                                      \
+               fallthrough;                                            \
        case 2: set->sig[1] = op(set->sig[1]);                          \
-               /* fall through */                                      \
+               fallthrough;                                            \
        case 1: set->sig[0] = op(set->sig[0]);                          \
                    break;                                              \
        default:                                                        \
@@ -194,7 +194,7 @@ static inline void sigemptyset(sigset_t *set)
                memset(set, 0, sizeof(sigset_t));
                break;
        case 2: set->sig[1] = 0;
-               /* fall through */
+               fallthrough;
        case 1: set->sig[0] = 0;
                break;
        }
@@ -207,7 +207,7 @@ static inline void sigfillset(sigset_t *set)
                memset(set, -1, sizeof(sigset_t));
                break;
        case 2: set->sig[1] = -1;
-               /* fall through */
+               fallthrough;
        case 1: set->sig[0] = -1;
                break;
        }
index 46881d9..416bf95 100644 (file)
@@ -71,7 +71,7 @@
  *     NETIF_F_IPV6_CSUM - Driver (device) is only able to checksum plain
  *                       TCP or UDP packets over IPv6. These are specifically
  *                       unencapsulated packets of the form IPv6|TCP or
- *                       IPv4|UDP where the Next Header field in the IPv6
+ *                       IPv6|UDP where the Next Header field in the IPv6
  *                       header is either TCP or UDP. IPv6 extension headers
  *                       are not supported with this feature. This feature
  *                       cannot be set in features for a device with
@@ -1056,7 +1056,16 @@ void kfree_skb(struct sk_buff *skb);
 void kfree_skb_list(struct sk_buff *segs);
 void skb_dump(const char *level, const struct sk_buff *skb, bool full_pkt);
 void skb_tx_error(struct sk_buff *skb);
+
+#ifdef CONFIG_TRACEPOINTS
 void consume_skb(struct sk_buff *skb);
+#else
+static inline void consume_skb(struct sk_buff *skb)
+{
+       return kfree_skb(skb);
+}
+#endif
+
 void __consume_stateless_skb(struct sk_buff *skb);
 void  __kfree_skb(struct sk_buff *skb);
 extern struct kmem_cache *skbuff_head_cache;
@@ -2658,7 +2667,7 @@ static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len)
  *
  * Using max(32, L1_CACHE_BYTES) makes sense (especially with RPS)
  * to reduce average number of cache lines per packet.
- * get_rps_cpus() for example only access one 64 bytes aligned block :
+ * get_rps_cpu() for example only access one 64 bytes aligned block :
  * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
  */
 #ifndef NET_SKB_PAD
@@ -3214,8 +3223,9 @@ static inline int skb_padto(struct sk_buff *skb, unsigned int len)
  *     is untouched. Otherwise it is extended. Returns zero on
  *     success. The skb is freed on error if @free_on_error is true.
  */
-static inline int __skb_put_padto(struct sk_buff *skb, unsigned int len,
-                                 bool free_on_error)
+static inline int __must_check __skb_put_padto(struct sk_buff *skb,
+                                              unsigned int len,
+                                              bool free_on_error)
 {
        unsigned int size = skb->len;
 
@@ -3238,7 +3248,7 @@ static inline int __skb_put_padto(struct sk_buff *skb, unsigned int len,
  *     is untouched. Otherwise it is extended. Returns zero on
  *     success. The skb is freed on error.
  */
-static inline int skb_put_padto(struct sk_buff *skb, unsigned int len)
+static inline int __must_check skb_put_padto(struct sk_buff *skb, unsigned int len)
 {
        return __skb_put_padto(skb, len, true);
 }
@@ -3535,7 +3545,7 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
 int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
 int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
 __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
-                             int len, __wsum csum);
+                             int len);
 int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
                    struct pipe_inode_info *pipe, unsigned int len,
                    unsigned int flags);
@@ -3745,19 +3755,19 @@ static inline bool __skb_metadata_differs(const struct sk_buff *skb_a,
 #define __it(x, op) (x -= sizeof(u##op))
 #define __it_diff(a, b, op) (*(u##op *)__it(a, op)) ^ (*(u##op *)__it(b, op))
        case 32: diffs |= __it_diff(a, b, 64);
-                /* fall through */
+               fallthrough;
        case 24: diffs |= __it_diff(a, b, 64);
-                /* fall through */
+               fallthrough;
        case 16: diffs |= __it_diff(a, b, 64);
-                /* fall through */
+               fallthrough;
        case  8: diffs |= __it_diff(a, b, 64);
                break;
        case 28: diffs |= __it_diff(a, b, 64);
-                /* fall through */
+               fallthrough;
        case 20: diffs |= __it_diff(a, b, 64);
-                /* fall through */
+               fallthrough;
        case 12: diffs |= __it_diff(a, b, 64);
-                /* fall through */
+               fallthrough;
        case  4: diffs |= __it_diff(a, b, 32);
                break;
        }
index 49c5d29..cf27b08 100644 (file)
@@ -220,6 +220,9 @@ struct ti_sci_rm_core_ops {
                                    u16 *range_start, u16 *range_num);
 };
 
+#define TI_SCI_RESASG_SUBTYPE_IR_OUTPUT                0
+#define TI_SCI_RESASG_SUBTYPE_IA_VINT          0xa
+#define TI_SCI_RESASG_SUBTYPE_GLOBAL_EVENT_SEVT        0xd
 /**
  * struct ti_sci_rm_irq_ops: IRQ management operations
  * @set_irq:           Set an IRQ route between the requested source
@@ -556,6 +559,9 @@ u32 ti_sci_get_num_resources(struct ti_sci_resource *res);
 struct ti_sci_resource *
 devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
                            struct device *dev, u32 dev_id, char *of_prop);
+struct ti_sci_resource *
+devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev,
+                        u32 dev_id, u32 sub_type);
 
 #else  /* CONFIG_TI_SCI_PROTOCOL */
 
@@ -609,6 +615,13 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
 {
        return ERR_PTR(-EINVAL);
 }
+
+static inline struct ti_sci_resource *
+devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev,
+                        u32 dev_id, u32 sub_type);
+{
+       return ERR_PTR(-EINVAL);
+}
 #endif /* CONFIG_TI_SCI_PROTOCOL */
 
 #endif /* __TISCI_PROTOCOL_H */
index 3d5c327..a59db2f 100644 (file)
@@ -25,7 +25,7 @@ static inline void stackleak_task_init(struct task_struct *t)
 
 #ifdef CONFIG_STACKLEAK_RUNTIME_DISABLE
 int stack_erasing_sysctl(struct ctl_table *table, int write,
-                       void __user *buffer, size_t *lenp, loff_t *ppos);
+                       void *buffer, size_t *lenp, loff_t *ppos);
 #endif
 
 #else /* !CONFIG_GCC_PLUGIN_STACKLEAK */
index b7af8cc..50e2df3 100644 (file)
@@ -29,14 +29,11 @@ unsigned int stack_trace_save_user(unsigned long *store, unsigned int size);
  * stack_trace_consume_fn - Callback for arch_stack_walk()
  * @cookie:    Caller supplied pointer handed back by arch_stack_walk()
  * @addr:      The stack entry address to consume
- * @reliable:  True when the stack entry is reliable. Required by
- *             some printk based consumers.
  *
  * Return:     True, if the entry was consumed or skipped
  *             False, if there is no space left to store
  */
-typedef bool (*stack_trace_consume_fn)(void *cookie, unsigned long addr,
-                                      bool reliable);
+typedef bool (*stack_trace_consume_fn)(void *cookie, unsigned long addr);
 /**
  * arch_stack_walk - Architecture specific function to walk the stack
  * @consume_entry:     Callback which is invoked by the architecture code for
diff --git a/include/linux/static_call.h b/include/linux/static_call.h
new file mode 100644 (file)
index 0000000..695da4c
--- /dev/null
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_STATIC_CALL_H
+#define _LINUX_STATIC_CALL_H
+
+/*
+ * Static call support
+ *
+ * Static calls use code patching to hard-code function pointers into direct
+ * branch instructions. They give the flexibility of function pointers, but
+ * with improved performance. This is especially important for cases where
+ * retpolines would otherwise be used, as retpolines can significantly impact
+ * performance.
+ *
+ *
+ * API overview:
+ *
+ *   DECLARE_STATIC_CALL(name, func);
+ *   DEFINE_STATIC_CALL(name, func);
+ *   DEFINE_STATIC_CALL_NULL(name, typename);
+ *   static_call(name)(args...);
+ *   static_call_cond(name)(args...);
+ *   static_call_update(name, func);
+ *
+ * Usage example:
+ *
+ *   # Start with the following functions (with identical prototypes):
+ *   int func_a(int arg1, int arg2);
+ *   int func_b(int arg1, int arg2);
+ *
+ *   # Define a 'my_name' reference, associated with func_a() by default
+ *   DEFINE_STATIC_CALL(my_name, func_a);
+ *
+ *   # Call func_a()
+ *   static_call(my_name)(arg1, arg2);
+ *
+ *   # Update 'my_name' to point to func_b()
+ *   static_call_update(my_name, &func_b);
+ *
+ *   # Call func_b()
+ *   static_call(my_name)(arg1, arg2);
+ *
+ *
+ * Implementation details:
+ *
+ *   This requires some arch-specific code (CONFIG_HAVE_STATIC_CALL).
+ *   Otherwise basic indirect calls are used (with function pointers).
+ *
+ *   Each static_call() site calls into a trampoline associated with the name.
+ *   The trampoline has a direct branch to the default function.  Updates to a
+ *   name will modify the trampoline's branch destination.
+ *
+ *   If the arch has CONFIG_HAVE_STATIC_CALL_INLINE, then the call sites
+ *   themselves will be patched at runtime to call the functions directly,
+ *   rather than calling through the trampoline.  This requires objtool or a
+ *   compiler plugin to detect all the static_call() sites and annotate them
+ *   in the .static_call_sites section.
+ *
+ *
+ * Notes on NULL function pointers:
+ *
+ *   Static_call()s support NULL functions, with many of the caveats that
+ *   regular function pointers have.
+ *
+ *   Clearly calling a NULL function pointer is 'BAD', so too for
+ *   static_call()s (although when HAVE_STATIC_CALL it might not be immediately
+ *   fatal). A NULL static_call can be the result of:
+ *
+ *     DECLARE_STATIC_CALL_NULL(my_static_call, void (*)(int));
+ *
+ *   which is equivalent to declaring a NULL function pointer with just a
+ *   typename:
+ *
+ *     void (*my_func_ptr)(int arg1) = NULL;
+ *
+ *   or using static_call_update() with a NULL function. In both cases the
+ *   HAVE_STATIC_CALL implementation will patch the trampoline with a RET
+ *   instruction, instead of an immediate tail-call JMP. HAVE_STATIC_CALL_INLINE
+ *   architectures can patch the trampoline call to a NOP.
+ *
+ *   In all cases, any argument evaluation is unconditional. Unlike a regular
+ *   conditional function pointer call:
+ *
+ *     if (my_func_ptr)
+ *         my_func_ptr(arg1)
+ *
+ *   where the argument evaludation also depends on the pointer value.
+ *
+ *   When calling a static_call that can be NULL, use:
+ *
+ *     static_call_cond(name)(arg1);
+ *
+ *   which will include the required value tests to avoid NULL-pointer
+ *   dereferences.
+ */
+
+#include <linux/types.h>
+#include <linux/cpu.h>
+#include <linux/static_call_types.h>
+
+#ifdef CONFIG_HAVE_STATIC_CALL
+#include <asm/static_call.h>
+
+/*
+ * Either @site or @tramp can be NULL.
+ */
+extern void arch_static_call_transform(void *site, void *tramp, void *func, bool tail);
+
+#define STATIC_CALL_TRAMP_ADDR(name) &STATIC_CALL_TRAMP(name)
+
+/*
+ * __ADDRESSABLE() is used to ensure the key symbol doesn't get stripped from
+ * the symbol table so that objtool can reference it when it generates the
+ * .static_call_sites section.
+ */
+#define __static_call(name)                                            \
+({                                                                     \
+       __ADDRESSABLE(STATIC_CALL_KEY(name));                           \
+       &STATIC_CALL_TRAMP(name);                                       \
+})
+
+#else
+#define STATIC_CALL_TRAMP_ADDR(name) NULL
+#endif
+
+
+#define DECLARE_STATIC_CALL(name, func)                                        \
+       extern struct static_call_key STATIC_CALL_KEY(name);            \
+       extern typeof(func) STATIC_CALL_TRAMP(name);
+
+#define static_call_update(name, func)                                 \
+({                                                                     \
+       BUILD_BUG_ON(!__same_type(*(func), STATIC_CALL_TRAMP(name)));   \
+       __static_call_update(&STATIC_CALL_KEY(name),                    \
+                            STATIC_CALL_TRAMP_ADDR(name), func);       \
+})
+
+#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
+
+extern int __init static_call_init(void);
+
+struct static_call_mod {
+       struct static_call_mod *next;
+       struct module *mod; /* for vmlinux, mod == NULL */
+       struct static_call_site *sites;
+};
+
+struct static_call_key {
+       void *func;
+       union {
+               /* bit 0: 0 = mods, 1 = sites */
+               unsigned long type;
+               struct static_call_mod *mods;
+               struct static_call_site *sites;
+       };
+};
+
+extern void __static_call_update(struct static_call_key *key, void *tramp, void *func);
+extern int static_call_mod_init(struct module *mod);
+extern int static_call_text_reserved(void *start, void *end);
+
+#define DEFINE_STATIC_CALL(name, _func)                                        \
+       DECLARE_STATIC_CALL(name, _func);                               \
+       struct static_call_key STATIC_CALL_KEY(name) = {                \
+               .func = _func,                                          \
+               .type = 1,                                              \
+       };                                                              \
+       ARCH_DEFINE_STATIC_CALL_TRAMP(name, _func)
+
+#define DEFINE_STATIC_CALL_NULL(name, _func)                           \
+       DECLARE_STATIC_CALL(name, _func);                               \
+       struct static_call_key STATIC_CALL_KEY(name) = {                \
+               .func = NULL,                                           \
+               .type = 1,                                              \
+       };                                                              \
+       ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)
+
+#define static_call(name)      __static_call(name)
+#define static_call_cond(name) (void)__static_call(name)
+
+#define EXPORT_STATIC_CALL(name)                                       \
+       EXPORT_SYMBOL(STATIC_CALL_KEY(name));                           \
+       EXPORT_SYMBOL(STATIC_CALL_TRAMP(name))
+
+#define EXPORT_STATIC_CALL_GPL(name)                                   \
+       EXPORT_SYMBOL_GPL(STATIC_CALL_KEY(name));                       \
+       EXPORT_SYMBOL_GPL(STATIC_CALL_TRAMP(name))
+
+#elif defined(CONFIG_HAVE_STATIC_CALL)
+
+static inline int static_call_init(void) { return 0; }
+
+struct static_call_key {
+       void *func;
+};
+
+#define DEFINE_STATIC_CALL(name, _func)                                        \
+       DECLARE_STATIC_CALL(name, _func);                               \
+       struct static_call_key STATIC_CALL_KEY(name) = {                \
+               .func = _func,                                          \
+       };                                                              \
+       ARCH_DEFINE_STATIC_CALL_TRAMP(name, _func)
+
+#define DEFINE_STATIC_CALL_NULL(name, _func)                           \
+       DECLARE_STATIC_CALL(name, _func);                               \
+       struct static_call_key STATIC_CALL_KEY(name) = {                \
+               .func = NULL,                                           \
+       };                                                              \
+       ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)
+
+#define static_call(name)      __static_call(name)
+#define static_call_cond(name) (void)__static_call(name)
+
+static inline
+void __static_call_update(struct static_call_key *key, void *tramp, void *func)
+{
+       cpus_read_lock();
+       WRITE_ONCE(key->func, func);
+       arch_static_call_transform(NULL, tramp, func, false);
+       cpus_read_unlock();
+}
+
+static inline int static_call_text_reserved(void *start, void *end)
+{
+       return 0;
+}
+
+#define EXPORT_STATIC_CALL(name)                                       \
+       EXPORT_SYMBOL(STATIC_CALL_KEY(name));                           \
+       EXPORT_SYMBOL(STATIC_CALL_TRAMP(name))
+
+#define EXPORT_STATIC_CALL_GPL(name)                                   \
+       EXPORT_SYMBOL_GPL(STATIC_CALL_KEY(name));                       \
+       EXPORT_SYMBOL_GPL(STATIC_CALL_TRAMP(name))
+
+#else /* Generic implementation */
+
+static inline int static_call_init(void) { return 0; }
+
+struct static_call_key {
+       void *func;
+};
+
+#define DEFINE_STATIC_CALL(name, _func)                                        \
+       DECLARE_STATIC_CALL(name, _func);                               \
+       struct static_call_key STATIC_CALL_KEY(name) = {                \
+               .func = _func,                                          \
+       }
+
+#define DEFINE_STATIC_CALL_NULL(name, _func)                           \
+       DECLARE_STATIC_CALL(name, _func);                               \
+       struct static_call_key STATIC_CALL_KEY(name) = {                \
+               .func = NULL,                                           \
+       }
+
+#define static_call(name)                                              \
+       ((typeof(STATIC_CALL_TRAMP(name))*)(STATIC_CALL_KEY(name).func))
+
+static inline void __static_call_nop(void) { }
+
+/*
+ * This horrific hack takes care of two things:
+ *
+ *  - it ensures the compiler will only load the function pointer ONCE,
+ *    which avoids a reload race.
+ *
+ *  - it ensures the argument evaluation is unconditional, similar
+ *    to the HAVE_STATIC_CALL variant.
+ *
+ * Sadly current GCC/Clang (10 for both) do not optimize this properly
+ * and will emit an indirect call for the NULL case :-(
+ */
+#define __static_call_cond(name)                                       \
+({                                                                     \
+       void *func = READ_ONCE(STATIC_CALL_KEY(name).func);             \
+       if (!func)                                                      \
+               func = &__static_call_nop;                              \
+       (typeof(STATIC_CALL_TRAMP(name))*)func;                         \
+})
+
+#define static_call_cond(name) (void)__static_call_cond(name)
+
+static inline
+void __static_call_update(struct static_call_key *key, void *tramp, void *func)
+{
+       WRITE_ONCE(key->func, func);
+}
+
+static inline int static_call_text_reserved(void *start, void *end)
+{
+       return 0;
+}
+
+#define EXPORT_STATIC_CALL(name)       EXPORT_SYMBOL(STATIC_CALL_KEY(name))
+#define EXPORT_STATIC_CALL_GPL(name)   EXPORT_SYMBOL_GPL(STATIC_CALL_KEY(name))
+
+#endif /* CONFIG_HAVE_STATIC_CALL */
+
+#endif /* _LINUX_STATIC_CALL_H */
diff --git a/include/linux/static_call_types.h b/include/linux/static_call_types.h
new file mode 100644 (file)
index 0000000..89135bb
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _STATIC_CALL_TYPES_H
+#define _STATIC_CALL_TYPES_H
+
+#include <linux/types.h>
+#include <linux/stringify.h>
+
+#define STATIC_CALL_KEY_PREFIX         __SCK__
+#define STATIC_CALL_KEY_PREFIX_STR     __stringify(STATIC_CALL_KEY_PREFIX)
+#define STATIC_CALL_KEY_PREFIX_LEN     (sizeof(STATIC_CALL_KEY_PREFIX_STR) - 1)
+#define STATIC_CALL_KEY(name)          __PASTE(STATIC_CALL_KEY_PREFIX, name)
+
+#define STATIC_CALL_TRAMP_PREFIX       __SCT__
+#define STATIC_CALL_TRAMP_PREFIX_STR   __stringify(STATIC_CALL_TRAMP_PREFIX)
+#define STATIC_CALL_TRAMP_PREFIX_LEN   (sizeof(STATIC_CALL_TRAMP_PREFIX_STR) - 1)
+#define STATIC_CALL_TRAMP(name)                __PASTE(STATIC_CALL_TRAMP_PREFIX, name)
+#define STATIC_CALL_TRAMP_STR(name)    __stringify(STATIC_CALL_TRAMP(name))
+
+/*
+ * Flags in the low bits of static_call_site::key.
+ */
+#define STATIC_CALL_SITE_TAIL 1UL      /* tail call */
+#define STATIC_CALL_SITE_INIT 2UL      /* init section */
+#define STATIC_CALL_SITE_FLAGS 3UL
+
+/*
+ * The static call site table needs to be created by external tooling (objtool
+ * or a compiler plugin).
+ */
+struct static_call_site {
+       s32 addr;
+       s32 key;
+};
+
+#endif /* _STATIC_CALL_TYPES_H */
index 9b7a063..b1f3894 100644 (file)
@@ -161,20 +161,13 @@ extern int bcmp(const void *,const void *,__kernel_size_t);
 #ifndef __HAVE_ARCH_MEMCHR
 extern void * memchr(const void *,int,__kernel_size_t);
 #endif
-#ifndef __HAVE_ARCH_MEMCPY_MCSAFE
-static inline __must_check unsigned long memcpy_mcsafe(void *dst,
-               const void *src, size_t cnt)
-{
-       memcpy(dst, src, cnt);
-       return 0;
-}
-#endif
 #ifndef __HAVE_ARCH_MEMCPY_FLUSHCACHE
 static inline void memcpy_flushcache(void *dst, const void *src, size_t cnt)
 {
        memcpy(dst, src, cnt);
 }
 #endif
+
 void *memchr_inv(const void *s, int c, size_t n);
 char *strreplace(char *s, char old, char new);
 
index e8f8ffe..91f43d8 100644 (file)
@@ -141,14 +141,12 @@ enum sgn_alg {
        SGN_ALG_MD2_5 = 0x0001,
        SGN_ALG_DES_MAC = 0x0002,
        SGN_ALG_3 = 0x0003,             /* not published */
-       SGN_ALG_HMAC_MD5 = 0x0011,      /* microsoft w2k; no support */
        SGN_ALG_HMAC_SHA1_DES3_KD = 0x0004
 };
 enum seal_alg {
        SEAL_ALG_NONE = 0xffff,
        SEAL_ALG_DES = 0x0000,
        SEAL_ALG_1 = 0x0001,            /* not published */
-       SEAL_ALG_MICROSOFT_RC4 = 0x0010,/* microsoft w2k; no support */
        SEAL_ALG_DES3KD = 0x0002
 };
 
@@ -316,14 +314,5 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
                     struct xdr_buf *buf, u32 *plainoffset,
                     u32 *plainlen);
 
-int
-krb5_rc4_setup_seq_key(struct krb5_ctx *kctx,
-                      struct crypto_sync_skcipher *cipher,
-                      unsigned char *cksum);
-
-int
-krb5_rc4_setup_enc_key(struct krb5_ctx *kctx,
-                      struct crypto_sync_skcipher *cipher,
-                      s32 seqnum);
 void
 gss_krb5_make_confounder(char *p, u32 conflen);
index 981c89c..87eea67 100644 (file)
 #ifdef CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES
 
 /*
- * NB: This list includes encryption types that were deprecated
- * by RFC 8429 (DES3_CBC_SHA1 and ARCFOUR_HMAC).
+ * NB: This list includes DES3_CBC_SHA1, which was deprecated by RFC 8429.
  *
  * ENCTYPE_AES256_CTS_HMAC_SHA1_96
  * ENCTYPE_AES128_CTS_HMAC_SHA1_96
  * ENCTYPE_DES3_CBC_SHA1
- * ENCTYPE_ARCFOUR_HMAC
  */
-#define KRB5_SUPPORTED_ENCTYPES "18,17,16,23"
+#define KRB5_SUPPORTED_ENCTYPES "18,17,16"
 
 #else  /* CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES */
 
  * ENCTYPE_AES256_CTS_HMAC_SHA1_96
  * ENCTYPE_AES128_CTS_HMAC_SHA1_96
  * ENCTYPE_DES3_CBC_SHA1
- * ENCTYPE_ARCFOUR_HMAC
  * ENCTYPE_DES_CBC_MD5
  * ENCTYPE_DES_CBC_CRC
  * ENCTYPE_DES_CBC_MD4
  */
-#define KRB5_SUPPORTED_ENCTYPES "18,17,16,23,3,1,2"
+#define KRB5_SUPPORTED_ENCTYPES "18,17,16,3,1,2"
 
 #endif /* CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES */
 
index 75ac7f8..06db098 100644 (file)
@@ -974,7 +974,7 @@ asmlinkage long sys_execveat(int dfd, const char __user *filename,
                        const char __user *const __user *argv,
                        const char __user *const __user *envp, int flags);
 asmlinkage long sys_userfaultfd(int flags);
-asmlinkage long sys_membarrier(int cmd, int flags);
+asmlinkage long sys_membarrier(int cmd, unsigned int flags, int cpu_id);
 asmlinkage long sys_mlock2(unsigned long start, size_t len, int flags);
 asmlinkage long sys_copy_file_range(int fd_in, loff_t __user *off_in,
                                    int fd_out, loff_t __user *off_out,
index d5471d6..7f7e4a3 100644 (file)
@@ -222,6 +222,18 @@ extern bool timekeeping_rtc_skipresume(void);
 
 extern void timekeeping_inject_sleeptime64(const struct timespec64 *delta);
 
+/*
+ * struct ktime_timestanps - Simultaneous mono/boot/real timestamps
+ * @mono:      Monotonic timestamp
+ * @boot:      Boottime timestamp
+ * @real:      Realtime timestamp
+ */
+struct ktime_timestamps {
+       u64             mono;
+       u64             boot;
+       u64             real;
+};
+
 /**
  * struct system_time_snapshot - simultaneous raw/real time capture with
  *                              counter value
@@ -280,6 +292,9 @@ extern int get_device_system_crosststamp(
  */
 extern void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot);
 
+/* NMI safe mono/boot/realtime timestamps */
+extern void ktime_get_fast_timestamps(struct ktime_timestamps *snap);
+
 /*
  * Persistent clock related interfaces
  */
index 07910ae..d10bc7e 100644 (file)
@@ -67,6 +67,7 @@ struct timer_list {
 #define TIMER_DEFERRABLE       0x00080000
 #define TIMER_PINNED           0x00100000
 #define TIMER_IRQSAFE          0x00200000
+#define TIMER_INIT_FLAGS       (TIMER_DEFERRABLE | TIMER_PINNED | TIMER_IRQSAFE)
 #define TIMER_ARRAYSHIFT       22
 #define TIMER_ARRAYMASK                0xFFC00000
 
index b29950a..de97450 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/atomic.h>
 #include <linux/static_key.h>
 
+struct static_call_key;
+
 struct trace_print_flags {
        unsigned long           mask;
        const char              *name;
@@ -30,6 +32,9 @@ struct tracepoint_func {
 struct tracepoint {
        const char *name;               /* Tracepoint name */
        struct static_key key;
+       struct static_call_key *static_call_key;
+       void *static_call_tramp;
+       void *iterator;
        int (*regfunc)(void);
        void (*unregfunc)(void);
        struct tracepoint_func __rcu *funcs;
index 598fec9..81fa0b2 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/cpumask.h>
 #include <linux/rcupdate.h>
 #include <linux/tracepoint-defs.h>
+#include <linux/static_call.h>
 
 struct module;
 struct tracepoint;
@@ -92,7 +93,9 @@ extern int syscall_regfunc(void);
 extern void syscall_unregfunc(void);
 #endif /* CONFIG_HAVE_SYSCALL_TRACEPOINTS */
 
+#ifndef PARAMS
 #define PARAMS(args...) args
+#endif
 
 #define TRACE_DEFINE_ENUM(x)
 #define TRACE_DEFINE_SIZEOF(x)
@@ -148,6 +151,12 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
 
 #ifdef TRACEPOINTS_ENABLED
 
+#ifdef CONFIG_HAVE_STATIC_CALL
+#define __DO_TRACE_CALL(name)  static_call(tp_func_##name)
+#else
+#define __DO_TRACE_CALL(name)  __traceiter_##name
+#endif /* CONFIG_HAVE_STATIC_CALL */
+
 /*
  * it_func[0] is never NULL because there is at least one element in the array
  * when the array itself is non NULL.
@@ -157,12 +166,11 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
  * has a "void" prototype, then it is invalid to declare a function
  * as "(void *, void)".
  */
-#define __DO_TRACE(tp, proto, args, cond, rcuidle)                     \
+#define __DO_TRACE(name, proto, args, cond, rcuidle)                   \
        do {                                                            \
                struct tracepoint_func *it_func_ptr;                    \
-               void *it_func;                                          \
-               void *__data;                                           \
                int __maybe_unused __idx = 0;                           \
+               void *__data;                                           \
                                                                        \
                if (!(cond))                                            \
                        return;                                         \
@@ -182,14 +190,11 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
                        rcu_irq_enter_irqson();                         \
                }                                                       \
                                                                        \
-               it_func_ptr = rcu_dereference_raw((tp)->funcs);         \
-                                                                       \
+               it_func_ptr =                                           \
+                       rcu_dereference_raw((&__tracepoint_##name)->funcs); \
                if (it_func_ptr) {                                      \
-                       do {                                            \
-                               it_func = (it_func_ptr)->func;          \
-                               __data = (it_func_ptr)->data;           \
-                               ((void(*)(proto))(it_func))(args);      \
-                       } while ((++it_func_ptr)->func);                \
+                       __data = (it_func_ptr)->data;                   \
+                       __DO_TRACE_CALL(name)(args);                    \
                }                                                       \
                                                                        \
                if (rcuidle) {                                          \
@@ -205,7 +210,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
        static inline void trace_##name##_rcuidle(proto)                \
        {                                                               \
                if (static_key_false(&__tracepoint_##name.key))         \
-                       __DO_TRACE(&__tracepoint_##name,                \
+                       __DO_TRACE(name,                                \
                                TP_PROTO(data_proto),                   \
                                TP_ARGS(data_args),                     \
                                TP_CONDITION(cond), 1);                 \
@@ -227,11 +232,13 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
  * poking RCU a bit.
  */
 #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
+       extern int __traceiter_##name(data_proto);                      \
+       DECLARE_STATIC_CALL(tp_func_##name, __traceiter_##name);        \
        extern struct tracepoint __tracepoint_##name;                   \
        static inline void trace_##name(proto)                          \
        {                                                               \
                if (static_key_false(&__tracepoint_##name.key))         \
-                       __DO_TRACE(&__tracepoint_##name,                \
+                       __DO_TRACE(name,                                \
                                TP_PROTO(data_proto),                   \
                                TP_ARGS(data_args),                     \
                                TP_CONDITION(cond), 0);                 \
@@ -277,21 +284,50 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
  * structures, so we create an array of pointers that will be used for iteration
  * on the tracepoints.
  */
-#define DEFINE_TRACE_FN(name, reg, unreg)                               \
-       static const char __tpstrtab_##name[]                            \
-       __section(__tracepoints_strings) = #name;                        \
-       struct tracepoint __tracepoint_##name __used                     \
-       __section(__tracepoints) =                                       \
-               { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\
-       __TRACEPOINT_ENTRY(name);
+#define DEFINE_TRACE_FN(_name, _reg, _unreg, proto, args)              \
+       static const char __tpstrtab_##_name[]                          \
+       __section(__tracepoints_strings) = #_name;                      \
+       extern struct static_call_key STATIC_CALL_KEY(tp_func_##_name); \
+       int __traceiter_##_name(void *__data, proto);                   \
+       struct tracepoint __tracepoint_##_name  __used                  \
+       __section(__tracepoints) = {                                    \
+               .name = __tpstrtab_##_name,                             \
+               .key = STATIC_KEY_INIT_FALSE,                           \
+               .static_call_key = &STATIC_CALL_KEY(tp_func_##_name),   \
+               .static_call_tramp = STATIC_CALL_TRAMP_ADDR(tp_func_##_name), \
+               .iterator = &__traceiter_##_name,                       \
+               .regfunc = _reg,                                        \
+               .unregfunc = _unreg,                                    \
+               .funcs = NULL };                                        \
+       __TRACEPOINT_ENTRY(_name);                                      \
+       int __traceiter_##_name(void *__data, proto)                    \
+       {                                                               \
+               struct tracepoint_func *it_func_ptr;                    \
+               void *it_func;                                          \
+                                                                       \
+               it_func_ptr =                                           \
+                       rcu_dereference_raw((&__tracepoint_##_name)->funcs); \
+               do {                                                    \
+                       it_func = (it_func_ptr)->func;                  \
+                       __data = (it_func_ptr)->data;                   \
+                       ((void(*)(void *, proto))(it_func))(__data, args); \
+               } while ((++it_func_ptr)->func);                        \
+               return 0;                                               \
+       }                                                               \
+       DEFINE_STATIC_CALL(tp_func_##_name, __traceiter_##_name);
 
-#define DEFINE_TRACE(name)                                             \
-       DEFINE_TRACE_FN(name, NULL, NULL);
+#define DEFINE_TRACE(name, proto, args)                \
+       DEFINE_TRACE_FN(name, NULL, NULL, PARAMS(proto), PARAMS(args));
 
 #define EXPORT_TRACEPOINT_SYMBOL_GPL(name)                             \
-       EXPORT_SYMBOL_GPL(__tracepoint_##name)
+       EXPORT_SYMBOL_GPL(__tracepoint_##name);                         \
+       EXPORT_SYMBOL_GPL(__traceiter_##name);                          \
+       EXPORT_STATIC_CALL_GPL(tp_func_##name)
 #define EXPORT_TRACEPOINT_SYMBOL(name)                                 \
-       EXPORT_SYMBOL(__tracepoint_##name)
+       EXPORT_SYMBOL(__tracepoint_##name);                             \
+       EXPORT_SYMBOL(__traceiter_##name);                              \
+       EXPORT_STATIC_CALL(tp_func_##name)
+
 
 #else /* !TRACEPOINTS_ENABLED */
 #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
@@ -320,8 +356,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
                return false;                                           \
        }
 
-#define DEFINE_TRACE_FN(name, reg, unreg)
-#define DEFINE_TRACE(name)
+#define DEFINE_TRACE_FN(name, reg, unreg, proto, args)
+#define DEFINE_TRACE(name, proto, args)
 #define EXPORT_TRACEPOINT_SYMBOL_GPL(name)
 #define EXPORT_TRACEPOINT_SYMBOL(name)
 
index 454c2f6..48e319f 100644 (file)
@@ -81,7 +81,7 @@ struct uacce_queue {
        struct list_head list;
        struct uacce_qfile_region *qfrs[UACCE_MAX_REGION];
        enum uacce_q_state state;
-       int pasid;
+       u32 pasid;
        struct iommu_sva *handle;
 };
 
index 94b2854..1ae36bc 100644 (file)
@@ -179,6 +179,19 @@ copy_in_user(void __user *to, const void __user *from, unsigned long n)
 }
 #endif
 
+#ifndef copy_mc_to_kernel
+/*
+ * Without arch opt-in this generic copy_mc_to_kernel() will not handle
+ * #MC (or arch equivalent) during source read.
+ */
+static inline unsigned long __must_check
+copy_mc_to_kernel(void *dst, const void *src, size_t cnt)
+{
+       memcpy(dst, src, cnt);
+       return 0;
+}
+#endif
+
 static __always_inline void pagefault_disabled_inc(void)
 {
        current->pagefault_disabled++;
index 3835a8a..72d8856 100644 (file)
@@ -185,10 +185,10 @@ size_t _copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i);
 #define _copy_from_iter_flushcache _copy_from_iter_nocache
 #endif
 
-#ifdef CONFIG_ARCH_HAS_UACCESS_MCSAFE
-size_t _copy_to_iter_mcsafe(const void *addr, size_t bytes, struct iov_iter *i);
+#ifdef CONFIG_ARCH_HAS_COPY_MC
+size_t _copy_mc_to_iter(const void *addr, size_t bytes, struct iov_iter *i);
 #else
-#define _copy_to_iter_mcsafe _copy_to_iter
+#define _copy_mc_to_iter _copy_to_iter
 #endif
 
 static __always_inline __must_check
@@ -201,12 +201,12 @@ size_t copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i)
 }
 
 static __always_inline __must_check
-size_t copy_to_iter_mcsafe(void *addr, size_t bytes, struct iov_iter *i)
+size_t copy_mc_to_iter(void *addr, size_t bytes, struct iov_iter *i)
 {
        if (unlikely(!check_copy_size(addr, bytes, true)))
                return 0;
        else
-               return _copy_to_iter_mcsafe(addr, bytes, i);
+               return _copy_mc_to_iter(addr, bytes, i);
 }
 
 size_t iov_iter_zero(size_t bytes, struct iov_iter *);
@@ -266,17 +266,15 @@ bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum, struct
 size_t hash_and_copy_to_iter(const void *addr, size_t bytes, void *hashp,
                struct iov_iter *i);
 
-ssize_t import_iovec(int type, const struct iovec __user * uvector,
-                unsigned nr_segs, unsigned fast_segs,
-                struct iovec **iov, struct iov_iter *i);
-
-#ifdef CONFIG_COMPAT
-struct compat_iovec;
-ssize_t compat_import_iovec(int type, const struct compat_iovec __user * uvector,
-                unsigned nr_segs, unsigned fast_segs,
-                struct iovec **iov, struct iov_iter *i);
-#endif
-
+struct iovec *iovec_from_user(const struct iovec __user *uvector,
+               unsigned long nr_segs, unsigned long fast_segs,
+               struct iovec *fast_iov, bool compat);
+ssize_t import_iovec(int type, const struct iovec __user *uvec,
+                unsigned nr_segs, unsigned fast_segs, struct iovec **iovp,
+                struct iov_iter *i);
+ssize_t __import_iovec(int type, const struct iovec __user *uvec,
+                unsigned nr_segs, unsigned fast_segs, struct iovec **iovp,
+                struct iov_iter *i, bool compat);
 int import_single_range(int type, void __user *buf, size_t len,
                 struct iovec *iov, struct iov_iter *i);
 
index 2e6ca53..18e7597 100644 (file)
@@ -30,6 +30,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
                PGFAULT, PGMAJFAULT,
                PGLAZYFREED,
                PGREFILL,
+               PGREUSE,
                PGSTEAL_KSWAPD,
                PGSTEAL_DIRECT,
                PGSCAN_KSWAPD,
index 91220ac..7557c10 100644 (file)
@@ -312,6 +312,11 @@ static inline void __mod_zone_page_state(struct zone *zone,
 static inline void __mod_node_page_state(struct pglist_data *pgdat,
                        enum node_stat_item item, int delta)
 {
+       if (vmstat_item_in_bytes(item)) {
+               VM_WARN_ON_ONCE(delta & (PAGE_SIZE - 1));
+               delta >>= PAGE_SHIFT;
+       }
+
        node_page_state_add(delta, pgdat, item);
 }
 
index 898c890..27fb99c 100644 (file)
@@ -21,6 +21,7 @@ int default_wake_function(struct wait_queue_entry *wq_entry, unsigned mode, int
 #define WQ_FLAG_WOKEN          0x02
 #define WQ_FLAG_BOOKMARK       0x04
 #define WQ_FLAG_CUSTOM         0x08
+#define WQ_FLAG_DONE           0x10
 
 /*
  * A single wait-queue entry structure:
index 5e08db2..c994d1b 100644 (file)
@@ -122,6 +122,12 @@ static inline void remove_watch_list(struct watch_list *wlist, u64 id)
  */
 #define watch_sizeof(STRUCT) (sizeof(STRUCT) << WATCH_INFO_LENGTH__SHIFT)
 
+#else
+static inline int watch_queue_init(struct pipe_inode_info *pipe)
+{
+       return -ENOPKG;
+}
+
 #endif
 
 #endif /* _LINUX_WATCH_QUEUE_H */
index adcc6a9..143568d 100644 (file)
@@ -308,7 +308,7 @@ do {                                                                             \
                                                                             \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):                          \
     R##_e = X##_e;                                                          \
-         /* Fall through */                                                 \
+       fallthrough;                                                         \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):                           \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):                              \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                                     \
@@ -319,7 +319,7 @@ do {                                                                             \
                                                                             \
   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):                          \
     R##_e = Y##_e;                                                          \
-         /* Fall through */                                                 \
+       fallthrough;                                                         \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):                           \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):                              \
   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                                     \
@@ -417,7 +417,7 @@ do {                                                        \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):         \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                \
     R##_s = X##_s;                                     \
-       /* Fall through */                              \
+         fallthrough;                                  \
                                                        \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):         \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):      \
@@ -431,7 +431,7 @@ do {                                                        \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):         \
   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                \
     R##_s = Y##_s;                                     \
-       /* Fall through */                              \
+         fallthrough;                                  \
                                                        \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):      \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):     \
@@ -497,7 +497,7 @@ do {                                                        \
                                                        \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):     \
     FP_SET_EXCEPTION(FP_EX_DIVZERO);                   \
-         /* Fall through */                            \
+       fallthrough;                                    \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):      \
     R##_c = FP_CLS_INF;                                        \
index 52ef920..bbb3f26 100644 (file)
@@ -744,8 +744,6 @@ void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb);
  * vb2_core_reqbufs() - Initiate streaming.
  * @q:         pointer to &struct vb2_queue with videobuf2 queue.
  * @memory:    memory type, as defined by &enum vb2_memory.
- * @flags:     auxiliary queue/buffer management flags. Currently, the only
- *             used flag is %V4L2_FLAG_MEMORY_NON_CONSISTENT.
  * @count:     requested buffer count.
  *
  * Videobuf2 core helper to implement VIDIOC_REQBUF() operation. It is called
@@ -770,13 +768,12 @@ void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb);
  * Return: returns zero on success; an error code otherwise.
  */
 int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
-                   unsigned int flags, unsigned int *count);
+                   unsigned int *count);
 
 /**
  * vb2_core_create_bufs() - Allocate buffers and any required auxiliary structs
  * @q: pointer to &struct vb2_queue with videobuf2 queue.
  * @memory: memory type, as defined by &enum vb2_memory.
- * @flags: auxiliary queue/buffer management flags.
  * @count: requested buffer count.
  * @requested_planes: number of planes requested.
  * @requested_sizes: array with the size of the planes.
@@ -794,7 +791,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
  * Return: returns zero on success; an error code otherwise.
  */
 int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
-                        unsigned int flags, unsigned int *count,
+                        unsigned int *count,
                         unsigned int requested_planes,
                         const unsigned int requested_sizes[]);
 
index cb382a8..8721492 100644 (file)
@@ -166,8 +166,6 @@ int tcf_idr_create_from_flags(struct tc_action_net *tn, u32 index,
                              struct nlattr *est, struct tc_action **a,
                              const struct tc_action_ops *ops, int bind,
                              u32 flags);
-void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a);
-
 void tcf_idr_cleanup(struct tc_action_net *tn, u32 index);
 int tcf_idr_check_alloc(struct tc_action_net *tn, u32 *index,
                        struct tc_action **a, int bind);
index 91eacbd..f6abcc0 100644 (file)
@@ -59,7 +59,7 @@ bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
 void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *);
 void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *,
                           struct sockaddr_rxrpc *);
-u32 rxrpc_kernel_get_srtt(struct socket *, struct rxrpc_call *);
+bool rxrpc_kernel_get_srtt(struct socket *, struct rxrpc_call *, u32 *);
 int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t,
                               rxrpc_user_attach_call_t, unsigned long, gfp_t,
                               unsigned int);
index 46754ba..0d05b9e 100644 (file)
 #ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
 static inline
 __wsum csum_and_copy_from_user (const void __user *src, void *dst,
-                                     int len, __wsum sum, int *err_ptr)
+                                     int len)
 {
        if (copy_from_user(dst, src, len))
-               *err_ptr = -EFAULT;
-       return csum_partial(dst, len, sum);
+               return 0;
+       return csum_partial(dst, len, ~0U);
 }
 #endif
 
 #ifndef HAVE_CSUM_COPY_USER
 static __inline__ __wsum csum_and_copy_to_user
-(const void *src, void __user *dst, int len, __wsum sum, int *err_ptr)
+(const void *src, void __user *dst, int len)
 {
-       sum = csum_partial(src, len, sum);
+       __wsum sum = csum_partial(src, len, ~0U);
 
        if (copy_to_user(dst, src, len) == 0)
                return sum;
-       if (len)
-               *err_ptr = -EFAULT;
+       return 0;
+}
+#endif
 
-       return (__force __wsum)-1; /* invalid checksum */
+#ifndef _HAVE_ARCH_CSUM_AND_COPY
+static inline __wsum
+csum_partial_copy_nocheck(const void *src, void *dst, int len)
+{
+       memcpy(dst, src, len);
+       return csum_partial(dst, len, 0);
 }
 #endif
 
index 929d3ca..b2531df 100644 (file)
@@ -116,6 +116,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
        fl4->saddr = saddr;
        fl4->fl4_dport = dport;
        fl4->fl4_sport = sport;
+       fl4->flowi4_multipath_hash = 0;
 }
 
 /* Reset some input parameters after previous lookup */
index 6e5f1e1..8899d74 100644 (file)
@@ -138,6 +138,7 @@ genl_dumpit_info(struct netlink_callback *cb)
  * @cmd: command identifier
  * @internal_flags: flags used by the family
  * @flags: flags
+ * @validate: validation flags from enum genl_validate_flags
  * @doit: standard command callback
  * @start: start callback for dumps
  * @dumpit: callback for dumpers
index b09c48d..2a52787 100644 (file)
@@ -436,12 +436,18 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
                                                    bool forwarding)
 {
        struct net *net = dev_net(dst->dev);
+       unsigned int mtu;
 
        if (net->ipv4.sysctl_ip_fwd_use_pmtu ||
            ip_mtu_locked(dst) ||
            !forwarding)
                return dst_mtu(dst);
 
+       /* 'forwarding = true' case should always honour route mtu */
+       mtu = dst_metric_raw(dst, RTAX_MTU);
+       if (mtu)
+               return mtu;
+
        return min(READ_ONCE(dst->dev->mtu), IP_MAX_MTU);
 }
 
index 9205a76..38e4094 100644 (file)
@@ -494,7 +494,7 @@ int igmp6_event_report(struct sk_buff *skb);
 
 #ifdef CONFIG_SYSCTL
 int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write,
-                              void __user *buffer, size_t *lenp, loff_t *ppos);
+                              void *buffer, size_t *lenp, loff_t *ppos);
 int ndisc_ifinfo_sysctl_strategy(struct ctl_table *ctl,
                                 void __user *oldval, size_t __user *oldlenp,
                                 void __user *newval, size_t newlen);
index bf9491b..224d194 100644 (file)
@@ -143,6 +143,8 @@ static inline u64 nft_reg_load64(const u32 *sreg)
 static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
                                 unsigned int len)
 {
+       if (len % NFT_REG32_SIZE)
+               dst[len / NFT_REG32_SIZE] = 0;
        memcpy(dst, src, len);
 }
 
index c0411f1..271620f 100644 (file)
@@ -726,7 +726,6 @@ static inline int __nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen,
  * @hdrlen: length of family specific header
  * @tb: destination array with maxtype+1 elements
  * @maxtype: maximum attribute type to be expected
- * @validate: validation strictness
  * @extack: extended ACK report struct
  *
  * See nla_parse()
@@ -824,7 +823,6 @@ static inline int nla_validate_deprecated(const struct nlattr *head, int len,
  * @len: length of attribute stream
  * @maxtype: maximum attribute type to be expected
  * @policy: validation policy
- * @validate: validation strictness
  * @extack: extended ACK report struct
  *
  * Validates all attributes in the specified attribute stream against the
@@ -1936,7 +1934,8 @@ void nla_get_range_signed(const struct nla_policy *pt,
 int netlink_policy_dump_start(const struct nla_policy *policy,
                              unsigned int maxtype,
                              unsigned long *state);
-bool netlink_policy_dump_loop(unsigned long *state);
+bool netlink_policy_dump_loop(unsigned long state);
 int netlink_policy_dump_write(struct sk_buff *skb, unsigned long state);
+void netlink_policy_dump_free(unsigned long state);
 
 #endif
index a1a8d45..6c0806b 100644 (file)
@@ -8,6 +8,7 @@ struct netns_nftables {
        struct list_head        tables;
        struct list_head        commit_list;
        struct list_head        module_list;
+       struct list_head        notify_list;
        struct mutex            commit_mutex;
        unsigned int            base_seq;
        u8                      gencursor;
index b33f1ae..0bdff38 100644 (file)
@@ -226,12 +226,14 @@ struct sctp_sock {
                data_ready_signalled:1;
 
        atomic_t pd_mode;
+
+       /* Fields after this point will be skipped on copies, like on accept
+        * and peeloff operations
+        */
+
        /* Receive to here while partial delivery is in effect. */
        struct sk_buff_head pd_lobby;
 
-       /* These must be the last fields, as they will skipped on copies,
-        * like on accept and peeloff operations
-        */
        struct list_head auto_asconf_list;
        int do_auto_asconf;
 };
index 3a41627..08537aa 100644 (file)
@@ -121,6 +121,9 @@ struct vxlanhdr_gbp {
 #define VXLAN_GBP_POLICY_APPLIED       (BIT(3) << 16)
 #define VXLAN_GBP_ID_MASK              (0xFFFF)
 
+#define VXLAN_GBP_MASK (VXLAN_GBP_DONT_LEARN | VXLAN_GBP_POLICY_APPLIED | \
+                       VXLAN_GBP_ID_MASK)
+
 /*
  * VXLAN Generic Protocol Extension (VXLAN_F_GPE):
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
index 2737d24..9e806c7 100644 (file)
@@ -1773,21 +1773,17 @@ static inline unsigned int xfrm_replay_state_esn_len(struct xfrm_replay_state_es
 static inline int xfrm_replay_clone(struct xfrm_state *x,
                                     struct xfrm_state *orig)
 {
-       x->replay_esn = kzalloc(xfrm_replay_state_esn_len(orig->replay_esn),
+
+       x->replay_esn = kmemdup(orig->replay_esn,
+                               xfrm_replay_state_esn_len(orig->replay_esn),
                                GFP_KERNEL);
        if (!x->replay_esn)
                return -ENOMEM;
-
-       x->replay_esn->bmp_len = orig->replay_esn->bmp_len;
-       x->replay_esn->replay_window = orig->replay_esn->replay_window;
-
-       x->preplay_esn = kmemdup(x->replay_esn,
-                                xfrm_replay_state_esn_len(x->replay_esn),
+       x->preplay_esn = kmemdup(orig->preplay_esn,
+                                xfrm_replay_state_esn_len(orig->preplay_esn),
                                 GFP_KERNEL);
-       if (!x->preplay_esn) {
-               kfree(x->replay_esn);
+       if (!x->preplay_esn)
                return -ENOMEM;
-       }
 
        return 0;
 }
index da369b1..0ac4e7f 100644 (file)
@@ -566,6 +566,7 @@ struct ocelot_port {
        u8                              ptp_cmd;
        struct sk_buff_head             tx_skbs;
        u8                              ts_id;
+       spinlock_t                      ts_id_lock;
 
        phy_interface_t                 phy_mode;
 
@@ -677,6 +678,7 @@ void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
 int ocelot_init(struct ocelot *ocelot);
 void ocelot_deinit(struct ocelot *ocelot);
 void ocelot_init_port(struct ocelot *ocelot, int port);
+void ocelot_deinit_port(struct ocelot *ocelot, int port);
 
 /* DSA callbacks */
 void ocelot_port_enable(struct ocelot *ocelot, int port,
index 841c6ec..1669481 100644 (file)
 #define ANA_SG_CONFIG_REG_3_LIST_LENGTH_M                 GENMASK(18, 16)
 #define ANA_SG_CONFIG_REG_3_LIST_LENGTH_X(x)              (((x) & GENMASK(18, 16)) >> 16)
 #define ANA_SG_CONFIG_REG_3_GATE_ENABLE                   BIT(20)
-#define ANA_SG_CONFIG_REG_3_INIT_IPS(x)                   (((x) << 24) & GENMASK(27, 24))
-#define ANA_SG_CONFIG_REG_3_INIT_IPS_M                    GENMASK(27, 24)
-#define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x)                 (((x) & GENMASK(27, 24)) >> 24)
-#define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE               BIT(28)
+#define ANA_SG_CONFIG_REG_3_INIT_IPS(x)                   (((x) << 21) & GENMASK(24, 21))
+#define ANA_SG_CONFIG_REG_3_INIT_IPS_M                    GENMASK(24, 21)
+#define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x)                 (((x) & GENMASK(24, 21)) >> 21)
+#define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE               BIT(25)
 
 #define ANA_SG_GCL_GS_CONFIG_RSZ                          0x4
 
index 9b1d43d..8c18dc6 100644 (file)
 #define CTOP_INST_MOV2B_FLIP_R3_B1_B2_INST     0x5B60
 #define CTOP_INST_MOV2B_FLIP_R3_B1_B2_LIMM     0x00010422
 
+#ifndef AUX_IENABLE
+#define AUX_IENABLE                            0x40c
+#endif
+
+#define CTOP_AUX_IACK                          (0xFFFFF800 + 0x088)
+
 #ifndef __ASSEMBLY__
 
 /* In order to increase compilation test coverage */
index 5e3919f..fc4fcac 100644 (file)
@@ -1193,6 +1193,8 @@ struct snd_soc_pcm_runtime {
             ((i) < (rtd)->num_cpus + (rtd)->num_codecs) &&             \
                     ((dai) = (rtd)->dais[i]);                          \
             (i)++)
+#define for_each_rtd_dais_rollback(rtd, i, dai)                \
+       for (; (--(i) >= 0) && ((dai) = (rtd)->dais[i]);)
 
 void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd);
 
@@ -1361,6 +1363,8 @@ void snd_soc_unregister_dai(struct snd_soc_dai *dai);
 
 struct snd_soc_dai *snd_soc_find_dai(
        const struct snd_soc_dai_link_component *dlc);
+struct snd_soc_dai *snd_soc_find_dai_with_mutex(
+       const struct snd_soc_dai_link_component *dlc);
 
 #include <sound/soc-dai.h>
 
index bd75f97..0072393 100644 (file)
@@ -25,7 +25,7 @@
 
 #undef TRACE_EVENT
 #define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
-       DEFINE_TRACE(name)
+       DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
 
 #undef TRACE_EVENT_CONDITION
 #define TRACE_EVENT_CONDITION(name, proto, args, cond, tstruct, assign, print) \
 #undef TRACE_EVENT_FN
 #define TRACE_EVENT_FN(name, proto, args, tstruct,             \
                assign, print, reg, unreg)                      \
-       DEFINE_TRACE_FN(name, reg, unreg)
+       DEFINE_TRACE_FN(name, reg, unreg, PARAMS(proto), PARAMS(args))
 
 #undef TRACE_EVENT_FN_COND
 #define TRACE_EVENT_FN_COND(name, proto, args, cond, tstruct,          \
                assign, print, reg, unreg)                      \
-       DEFINE_TRACE_FN(name, reg, unreg)
+       DEFINE_TRACE_FN(name, reg, unreg, PARAMS(proto), PARAMS(args))
 
 #undef TRACE_EVENT_NOP
 #define TRACE_EVENT_NOP(name, proto, args, struct, assign, print)
 
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args) \
-       DEFINE_TRACE(name)
+       DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
 
 #undef DEFINE_EVENT_FN
 #define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg) \
-       DEFINE_TRACE_FN(name, reg, unreg)
+       DEFINE_TRACE_FN(name, reg, unreg, PARAMS(proto), PARAMS(args))
 
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
-       DEFINE_TRACE(name)
+       DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
 
 #undef DEFINE_EVENT_CONDITION
 #define DEFINE_EVENT_CONDITION(template, name, proto, args, cond) \
@@ -70,7 +70,7 @@
 
 #undef DECLARE_TRACE
 #define DECLARE_TRACE(name, proto, args)       \
-       DEFINE_TRACE(name)
+       DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
 
 #undef TRACE_INCLUDE
 #undef __TRACE_INCLUDE
index c705e49..1646dad 100644 (file)
@@ -92,7 +92,7 @@ DECLARE_EVENT_CLASS(filelock_lock,
                __entry->ret = ret;
        ),
 
-       TP_printk("fl=0x%p dev=0x%x:0x%x ino=0x%lx fl_blocker=0x%p fl_owner=0x%p fl_pid=%u fl_flags=%s fl_type=%s fl_start=%lld fl_end=%lld ret=%d",
+       TP_printk("fl=%p dev=0x%x:0x%x ino=0x%lx fl_blocker=%p fl_owner=%p fl_pid=%u fl_flags=%s fl_type=%s fl_start=%lld fl_end=%lld ret=%d",
                __entry->fl, MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
                __entry->i_ino, __entry->fl_blocker, __entry->fl_owner,
                __entry->fl_pid, show_fl_flags(__entry->fl_flags),
@@ -145,7 +145,7 @@ DECLARE_EVENT_CLASS(filelock_lease,
                __entry->fl_downgrade_time = fl ? fl->fl_downgrade_time : 0;
        ),
 
-       TP_printk("fl=0x%p dev=0x%x:0x%x ino=0x%lx fl_blocker=0x%p fl_owner=0x%p fl_flags=%s fl_type=%s fl_break_time=%lu fl_downgrade_time=%lu",
+       TP_printk("fl=%p dev=0x%x:0x%x ino=0x%lx fl_blocker=%p fl_owner=%p fl_flags=%s fl_type=%s fl_break_time=%lu fl_downgrade_time=%lu",
                __entry->fl, MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
                __entry->i_ino, __entry->fl_blocker, __entry->fl_owner,
                show_fl_flags(__entry->fl_flags),
@@ -195,7 +195,7 @@ TRACE_EVENT(generic_add_lease,
                __entry->fl_type = fl->fl_type;
        ),
 
-       TP_printk("dev=0x%x:0x%x ino=0x%lx wcount=%d rcount=%d icount=%d fl_owner=0x%p fl_flags=%s fl_type=%s",
+       TP_printk("dev=0x%x:0x%x ino=0x%lx wcount=%d rcount=%d icount=%d fl_owner=%p fl_flags=%s fl_type=%s",
                MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
                __entry->i_ino, __entry->wcount, __entry->rcount,
                __entry->icount, __entry->fl_owner,
@@ -228,7 +228,7 @@ TRACE_EVENT(leases_conflict,
                __entry->conflict = conflict;
        ),
 
-       TP_printk("conflict %d: lease=0x%p fl_flags=%s fl_type=%s; breaker=0x%p fl_flags=%s fl_type=%s",
+       TP_printk("conflict %d: lease=%p fl_flags=%s fl_type=%s; breaker=%p fl_flags=%s fl_type=%s",
                __entry->conflict,
                __entry->lease,
                show_fl_flags(__entry->l_fl_flags),
index 939092d..67018d3 100644 (file)
 #define IF_HAVE_PG_IDLE(flag,string)
 #endif
 
+#ifdef CONFIG_64BIT
+#define IF_HAVE_PG_ARCH_2(flag,string) ,{1UL << flag, string}
+#else
+#define IF_HAVE_PG_ARCH_2(flag,string)
+#endif
+
 #define __def_pageflag_names                                           \
        {1UL << PG_locked,              "locked"        },              \
        {1UL << PG_waiters,             "waiters"       },              \
@@ -105,7 +111,8 @@ IF_HAVE_PG_MLOCK(PG_mlocked,                "mlocked"       )               \
 IF_HAVE_PG_UNCACHED(PG_uncached,       "uncached"      )               \
 IF_HAVE_PG_HWPOISON(PG_hwpoison,       "hwpoison"      )               \
 IF_HAVE_PG_IDLE(PG_young,              "young"         )               \
-IF_HAVE_PG_IDLE(PG_idle,               "idle"          )
+IF_HAVE_PG_IDLE(PG_idle,               "idle"          )               \
+IF_HAVE_PG_ARCH_2(PG_arch_2,           "arch_2"        )
 
 #define show_page_flags(flags)                                         \
        (flags) ? __print_flags(flags, "|",                             \
@@ -114,6 +121,8 @@ IF_HAVE_PG_IDLE(PG_idle,            "idle"          )
 
 #if defined(CONFIG_X86)
 #define __VM_ARCH_SPECIFIC_1 {VM_PAT,     "pat"           }
+#elif defined(CONFIG_PPC)
+#define __VM_ARCH_SPECIFIC_1 {VM_SAO,     "sao"           }
 #elif defined(CONFIG_PARISC) || defined(CONFIG_IA64)
 #define __VM_ARCH_SPECIFIC_1 {VM_GROWSUP,      "growsup"       }
 #elif !defined(CONFIG_MMU)
index 059b6e4..c33079b 100644 (file)
@@ -138,11 +138,16 @@ enum rxrpc_recvmsg_trace {
 };
 
 enum rxrpc_rtt_tx_trace {
+       rxrpc_rtt_tx_cancel,
        rxrpc_rtt_tx_data,
+       rxrpc_rtt_tx_no_slot,
        rxrpc_rtt_tx_ping,
 };
 
 enum rxrpc_rtt_rx_trace {
+       rxrpc_rtt_rx_cancel,
+       rxrpc_rtt_rx_lost,
+       rxrpc_rtt_rx_obsolete,
        rxrpc_rtt_rx_ping_response,
        rxrpc_rtt_rx_requested_ack,
 };
@@ -339,10 +344,15 @@ enum rxrpc_tx_point {
        E_(rxrpc_recvmsg_wait,                  "WAIT")
 
 #define rxrpc_rtt_tx_traces \
+       EM(rxrpc_rtt_tx_cancel,                 "CNCE") \
        EM(rxrpc_rtt_tx_data,                   "DATA") \
+       EM(rxrpc_rtt_tx_no_slot,                "FULL") \
        E_(rxrpc_rtt_tx_ping,                   "PING")
 
 #define rxrpc_rtt_rx_traces \
+       EM(rxrpc_rtt_rx_cancel,                 "CNCL") \
+       EM(rxrpc_rtt_rx_obsolete,               "OBSL") \
+       EM(rxrpc_rtt_rx_lost,                   "LOST") \
        EM(rxrpc_rtt_rx_ping_response,          "PONG") \
        E_(rxrpc_rtt_rx_requested_ack,          "RACK")
 
@@ -1087,38 +1097,43 @@ TRACE_EVENT(rxrpc_recvmsg,
 
 TRACE_EVENT(rxrpc_rtt_tx,
            TP_PROTO(struct rxrpc_call *call, enum rxrpc_rtt_tx_trace why,
-                    rxrpc_serial_t send_serial),
+                    int slot, rxrpc_serial_t send_serial),
 
-           TP_ARGS(call, why, send_serial),
+           TP_ARGS(call, why, slot, send_serial),
 
            TP_STRUCT__entry(
                    __field(unsigned int,               call            )
                    __field(enum rxrpc_rtt_tx_trace,    why             )
+                   __field(int,                        slot            )
                    __field(rxrpc_serial_t,             send_serial     )
                             ),
 
            TP_fast_assign(
                    __entry->call = call->debug_id;
                    __entry->why = why;
+                   __entry->slot = slot;
                    __entry->send_serial = send_serial;
                           ),
 
-           TP_printk("c=%08x %s sr=%08x",
+           TP_printk("c=%08x [%d] %s sr=%08x",
                      __entry->call,
+                     __entry->slot,
                      __print_symbolic(__entry->why, rxrpc_rtt_tx_traces),
                      __entry->send_serial)
            );
 
 TRACE_EVENT(rxrpc_rtt_rx,
            TP_PROTO(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why,
+                    int slot,
                     rxrpc_serial_t send_serial, rxrpc_serial_t resp_serial,
                     u32 rtt, u32 rto),
 
-           TP_ARGS(call, why, send_serial, resp_serial, rtt, rto),
+           TP_ARGS(call, why, slot, send_serial, resp_serial, rtt, rto),
 
            TP_STRUCT__entry(
                    __field(unsigned int,               call            )
                    __field(enum rxrpc_rtt_rx_trace,    why             )
+                   __field(int,                        slot            )
                    __field(rxrpc_serial_t,             send_serial     )
                    __field(rxrpc_serial_t,             resp_serial     )
                    __field(u32,                        rtt             )
@@ -1128,14 +1143,16 @@ TRACE_EVENT(rxrpc_rtt_rx,
            TP_fast_assign(
                    __entry->call = call->debug_id;
                    __entry->why = why;
+                   __entry->slot = slot;
                    __entry->send_serial = send_serial;
                    __entry->resp_serial = resp_serial;
                    __entry->rtt = rtt;
                    __entry->rto = rto;
                           ),
 
-           TP_printk("c=%08x %s sr=%08x rr=%08x rtt=%u rto=%u",
+           TP_printk("c=%08x [%d] %s sr=%08x rr=%08x rtt=%u rto=%u",
                      __entry->call,
+                     __entry->slot,
                      __print_symbolic(__entry->why, rxrpc_rtt_rx_traces),
                      __entry->send_serial,
                      __entry->resp_serial,
index fec25b9..c96a433 100644 (file)
@@ -630,6 +630,10 @@ DECLARE_TRACE(pelt_se_tp,
        TP_PROTO(struct sched_entity *se),
        TP_ARGS(se));
 
+DECLARE_TRACE(sched_cpu_capacity_tp,
+       TP_PROTO(struct rq *rq),
+       TP_ARGS(rq));
+
 DECLARE_TRACE(sched_overutilized_tp,
        TP_PROTO(struct root_domain *rd, bool overutilized),
        TP_ARGS(rd, overutilized));
index 10f5d1f..e7cbccc 100644 (file)
@@ -20,7 +20,6 @@
                {I_CLEAR,               "I_CLEAR"},             \
                {I_SYNC,                "I_SYNC"},              \
                {I_DIRTY_TIME,          "I_DIRTY_TIME"},        \
-               {I_DIRTY_TIME_EXPIRED,  "I_DIRTY_TIME_EXPIRED"}, \
                {I_REFERENCED,          "I_REFERENCED"}         \
        )
 
@@ -498,8 +497,9 @@ DEFINE_WBC_EVENT(wbc_writepage);
 TRACE_EVENT(writeback_queue_io,
        TP_PROTO(struct bdi_writeback *wb,
                 struct wb_writeback_work *work,
+                unsigned long dirtied_before,
                 int moved),
-       TP_ARGS(wb, work, moved),
+       TP_ARGS(wb, work, dirtied_before, moved),
        TP_STRUCT__entry(
                __array(char,           name, 32)
                __field(unsigned long,  older)
@@ -509,19 +509,17 @@ TRACE_EVENT(writeback_queue_io,
                __field(ino_t,          cgroup_ino)
        ),
        TP_fast_assign(
-               unsigned long *older_than_this = work->older_than_this;
                strscpy_pad(__entry->name, bdi_dev_name(wb->bdi), 32);
-               __entry->older  = older_than_this ?  *older_than_this : 0;
-               __entry->age    = older_than_this ?
-                                 (jiffies - *older_than_this) * 1000 / HZ : -1;
+               __entry->older  = dirtied_before;
+               __entry->age    = (jiffies - dirtied_before) * 1000 / HZ;
                __entry->moved  = moved;
                __entry->reason = work->reason;
                __entry->cgroup_ino     = __trace_wb_assign_cgroup(wb);
        ),
        TP_printk("bdi %s: older=%lu age=%ld enqueue=%d reason=%s cgroup_ino=%lu",
                __entry->name,
-               __entry->older, /* older_than_this in jiffies */
-               __entry->age,   /* older_than_this in relative milliseconds */
+               __entry->older, /* dirtied_before in jiffies */
+               __entry->age,   /* dirtied_before in relative milliseconds */
                __entry->moved,
                __print_symbolic(__entry->reason, WB_WORK_REASON),
                (unsigned long)__entry->cgroup_ino
index a5ccfa6..3b61b58 100644 (file)
@@ -153,26 +153,6 @@ DECLARE_EVENT_CLASS(xen_mmu__set_pte,
 
 DEFINE_XEN_MMU_SET_PTE(xen_mmu_set_pte);
 
-TRACE_EVENT(xen_mmu_set_pte_at,
-           TP_PROTO(struct mm_struct *mm, unsigned long addr,
-                    pte_t *ptep, pte_t pteval),
-           TP_ARGS(mm, addr, ptep, pteval),
-           TP_STRUCT__entry(
-                   __field(struct mm_struct *, mm)
-                   __field(unsigned long, addr)
-                   __field(pte_t *, ptep)
-                   __field(pteval_t, pteval)
-                   ),
-           TP_fast_assign(__entry->mm = mm;
-                          __entry->addr = addr;
-                          __entry->ptep = ptep;
-                          __entry->pteval = pteval.pte),
-           TP_printk("mm %p addr %lx ptep %p pteval %0*llx (raw %0*llx)",
-                     __entry->mm, __entry->addr, __entry->ptep,
-                     (int)sizeof(pteval_t) * 2, (unsigned long long)pte_val(native_make_pte(__entry->pteval)),
-                     (int)sizeof(pteval_t) * 2, (unsigned long long)__entry->pteval)
-       );
-
 TRACE_DEFINE_SIZEOF(pmdval_t);
 
 TRACE_EVENT(xen_mmu_set_pmd,
index cb3d6c2..7aacf93 100644 (file)
@@ -229,7 +229,9 @@ typedef struct siginfo {
 #define SEGV_ACCADI    5       /* ADI not enabled for mapped object */
 #define SEGV_ADIDERR   6       /* Disrupting MCD error */
 #define SEGV_ADIPERR   7       /* Precise MCD exception */
-#define NSIGSEGV       7
+#define SEGV_MTEAERR   8       /* Asynchronous ARM MTE error */
+#define SEGV_MTESERR   9       /* Synchronous ARM MTE exception */
+#define NSIGSEGV       9
 
 /*
  * SIGBUS si_codes
index 995b36c..f2b5d72 100644 (file)
@@ -140,7 +140,7 @@ __SYSCALL(__NR_renameat, sys_renameat)
 #define __NR_umount2 39
 __SYSCALL(__NR_umount2, sys_umount)
 #define __NR_mount 40
-__SC_COMP(__NR_mount, sys_mount, compat_sys_mount)
+__SYSCALL(__NR_mount, sys_mount)
 #define __NR_pivot_root 41
 __SYSCALL(__NR_pivot_root, sys_pivot_root)
 
@@ -207,9 +207,9 @@ __SYSCALL(__NR_read, sys_read)
 #define __NR_write 64
 __SYSCALL(__NR_write, sys_write)
 #define __NR_readv 65
-__SC_COMP(__NR_readv, sys_readv, compat_sys_readv)
+__SC_COMP(__NR_readv, sys_readv, sys_readv)
 #define __NR_writev 66
-__SC_COMP(__NR_writev, sys_writev, compat_sys_writev)
+__SC_COMP(__NR_writev, sys_writev, sys_writev)
 #define __NR_pread64 67
 __SC_COMP(__NR_pread64, sys_pread64, compat_sys_pread64)
 #define __NR_pwrite64 68
@@ -237,7 +237,7 @@ __SC_COMP(__NR_signalfd4, sys_signalfd4, compat_sys_signalfd4)
 
 /* fs/splice.c */
 #define __NR_vmsplice 75
-__SC_COMP(__NR_vmsplice, sys_vmsplice, compat_sys_vmsplice)
+__SYSCALL(__NR_vmsplice, sys_vmsplice)
 #define __NR_splice 76
 __SYSCALL(__NR_splice, sys_splice)
 #define __NR_tee 77
@@ -727,11 +727,9 @@ __SYSCALL(__NR_setns, sys_setns)
 #define __NR_sendmmsg 269
 __SC_COMP(__NR_sendmmsg, sys_sendmmsg, compat_sys_sendmmsg)
 #define __NR_process_vm_readv 270
-__SC_COMP(__NR_process_vm_readv, sys_process_vm_readv, \
-          compat_sys_process_vm_readv)
+__SYSCALL(__NR_process_vm_readv, sys_process_vm_readv)
 #define __NR_process_vm_writev 271
-__SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \
-          compat_sys_process_vm_writev)
+__SYSCALL(__NR_process_vm_writev, sys_process_vm_writev)
 #define __NR_kcmp 272
 __SYSCALL(__NR_kcmp, sys_kcmp)
 #define __NR_finit_module 273
index 2222094..30f68b4 100644 (file)
@@ -425,6 +425,7 @@ typedef struct elf64_shdr {
 #define NT_ARM_PAC_MASK                0x406   /* ARM pointer authentication code masks */
 #define NT_ARM_PACA_KEYS       0x407   /* ARM pointer authentication address keys */
 #define NT_ARM_PACG_KEYS       0x408   /* ARM pointer authentication generic key */
+#define NT_ARM_TAGGED_ADDR_CTRL        0x409   /* arm64 tagged address control (prctl()) */
 #define NT_ARC_V2      0x600           /* ARCv2 accumulator/extra registers */
 #define NT_VMCOREDD    0x700           /* Vmcore Device Dump Note */
 #define NT_MIPS_DSP    0x800           /* MIPS DSP ASE registers */
index 5dcd24c..72ba36b 100644 (file)
@@ -79,6 +79,7 @@ enum {
        ETHTOOL_MSG_TSINFO_GET_REPLY,
        ETHTOOL_MSG_CABLE_TEST_NTF,
        ETHTOOL_MSG_CABLE_TEST_TDR_NTF,
+       ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY,
 
        /* add new constants above here */
        __ETHTOOL_MSG_KERNEL_CNT,
index 7875709..e5de603 100644 (file)
@@ -45,7 +45,6 @@ struct fscrypt_policy_v1 {
        __u8 flags;
        __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
 };
-#define fscrypt_policy fscrypt_policy_v1
 
 /*
  * Process-subscribed "logon" key description prefix and payload format.
@@ -156,9 +155,9 @@ struct fscrypt_get_key_status_arg {
        __u32 __out_reserved[13];
 };
 
-#define FS_IOC_SET_ENCRYPTION_POLICY           _IOR('f', 19, struct fscrypt_policy)
+#define FS_IOC_SET_ENCRYPTION_POLICY           _IOR('f', 19, struct fscrypt_policy_v1)
 #define FS_IOC_GET_ENCRYPTION_PWSALT           _IOW('f', 20, __u8[16])
-#define FS_IOC_GET_ENCRYPTION_POLICY           _IOW('f', 21, struct fscrypt_policy)
+#define FS_IOC_GET_ENCRYPTION_POLICY           _IOW('f', 21, struct fscrypt_policy_v1)
 #define FS_IOC_GET_ENCRYPTION_POLICY_EX                _IOWR('f', 22, __u8[9]) /* size + version */
 #define FS_IOC_ADD_ENCRYPTION_KEY              _IOWR('f', 23, struct fscrypt_add_key_arg)
 #define FS_IOC_REMOVE_ENCRYPTION_KEY           _IOWR('f', 24, struct fscrypt_remove_key_arg)
@@ -170,6 +169,7 @@ struct fscrypt_get_key_status_arg {
 
 /* old names; don't add anything new here! */
 #ifndef __KERNEL__
+#define fscrypt_policy                 fscrypt_policy_v1
 #define FS_KEY_DESCRIPTOR_SIZE         FSCRYPT_KEY_DESCRIPTOR_SIZE
 #define FS_POLICY_FLAGS_PAD_4          FSCRYPT_POLICY_FLAGS_PAD_4
 #define FS_POLICY_FLAGS_PAD_8          FSCRYPT_POLICY_FLAGS_PAD_8
index bc2bcde..60b7c2e 100644 (file)
@@ -35,6 +35,7 @@ struct af_alg_iv {
 #define ALG_SET_OP                     3
 #define ALG_SET_AEAD_ASSOCLEN          4
 #define ALG_SET_AEAD_AUTHSIZE          5
+#define ALG_SET_DRBG_ENTROPY           6
 
 /* Operations */
 #define ALG_OP_DECRYPT                 0
index 3d0d823..7d66876 100644 (file)
@@ -135,7 +135,7 @@ struct in_addr {
  * this socket to prevent accepting spoofed ones.
  */
 #define IP_PMTUDISC_INTERFACE          4
-/* weaker version of IP_PMTUDISC_INTERFACE, which allos packets to get
+/* weaker version of IP_PMTUDISC_INTERFACE, which allows packets to get
  * fragmented if they exeed the interface mtu
  */
 #define IP_PMTUDISC_OMIT               5
index f6d8603..7d8eced 100644 (file)
@@ -790,9 +790,10 @@ struct kvm_ppc_resize_hpt {
 #define KVM_VM_PPC_HV 1
 #define KVM_VM_PPC_PR 2
 
-/* on MIPS, 0 forces trap & emulate, 1 forces VZ ASE */
-#define KVM_VM_MIPS_TE         0
+/* on MIPS, 0 indicates auto, 1 forces VZ ASE, 2 forces trap & emulate */
+#define KVM_VM_MIPS_AUTO       0
 #define KVM_VM_MIPS_VZ         1
+#define KVM_VM_MIPS_TE         2
 
 #define KVM_S390_SIE_PAGE_OFFSET 1
 
@@ -1035,6 +1036,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_LAST_CPU 184
 #define KVM_CAP_SMALLER_MAXPHYADDR 185
 #define KVM_CAP_S390_DIAG318 186
+#define KVM_CAP_STEAL_TIME 187
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
index 5891d76..7376058 100644 (file)
  *                          If this command is not implemented by an
  *                          architecture, -EINVAL is returned.
  *                          Returns 0 on success.
+ * @MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ:
+ *                          Ensure the caller thread, upon return from
+ *                          system call, that all its running thread
+ *                          siblings have any currently running rseq
+ *                          critical sections restarted if @flags
+ *                          parameter is 0; if @flags parameter is
+ *                          MEMBARRIER_CMD_FLAG_CPU,
+ *                          then this operation is performed only
+ *                          on CPU indicated by @cpu_id. If this command is
+ *                          not implemented by an architecture, -EINVAL
+ *                          is returned. A process needs to register its
+ *                          intent to use the private expedited rseq
+ *                          command prior to using it, otherwise
+ *                          this command returns -EPERM.
+ * @MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ:
+ *                          Register the process intent to use
+ *                          MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ.
+ *                          If this command is not implemented by an
+ *                          architecture, -EINVAL is returned.
+ *                          Returns 0 on success.
  * @MEMBARRIER_CMD_SHARED:
  *                          Alias to MEMBARRIER_CMD_GLOBAL. Provided for
  *                          header backward compatibility.
@@ -131,9 +151,15 @@ enum membarrier_cmd {
        MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED               = (1 << 4),
        MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE              = (1 << 5),
        MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE     = (1 << 6),
+       MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ                   = (1 << 7),
+       MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ          = (1 << 8),
 
        /* Alias for header backward compatibility. */
        MEMBARRIER_CMD_SHARED                   = MEMBARRIER_CMD_GLOBAL,
 };
 
+enum membarrier_cmd_flag {
+       MEMBARRIER_CMD_FLAG_CPU         = (1 << 0),
+};
+
 #endif /* _UAPI_LINUX_MEMBARRIER_H */
index 42f351c..2b8e12f 100644 (file)
@@ -133,7 +133,7 @@ enum nf_tables_msg_types {
  * @NFTA_LIST_ELEM: list element (NLA_NESTED)
  */
 enum nft_list_attributes {
-       NFTA_LIST_UNPEC,
+       NFTA_LIST_UNSPEC,
        NFTA_LIST_ELEM,
        __NFTA_LIST_MAX
 };
index 07b4f81..7f08277 100644 (file)
@@ -233,6 +233,15 @@ struct prctl_mm_map {
 #define PR_SET_TAGGED_ADDR_CTRL                55
 #define PR_GET_TAGGED_ADDR_CTRL                56
 # define PR_TAGGED_ADDR_ENABLE         (1UL << 0)
+/* MTE tag check fault modes */
+# define PR_MTE_TCF_SHIFT              1
+# define PR_MTE_TCF_NONE               (0UL << PR_MTE_TCF_SHIFT)
+# define PR_MTE_TCF_SYNC               (1UL << PR_MTE_TCF_SHIFT)
+# define PR_MTE_TCF_ASYNC              (2UL << PR_MTE_TCF_SHIFT)
+# define PR_MTE_TCF_MASK               (3UL << PR_MTE_TCF_SHIFT)
+/* MTE tag inclusion mask */
+# define PR_MTE_TAG_SHIFT              3
+# define PR_MTE_TAG_MASK               (0xffffUL << PR_MTE_TAG_SHIFT)
 
 /* Control reclaim behavior when allocating memory */
 #define PR_SET_IO_FLUSHER              57
index 4accfa7..8f8dc7a 100644 (file)
@@ -51,11 +51,11 @@ enum rxrpc_cmsg_type {
        RXRPC_BUSY              = 6,    /* -r: server busy received [terminal] */
        RXRPC_LOCAL_ERROR       = 7,    /* -r: local error generated [terminal] */
        RXRPC_NEW_CALL          = 8,    /* -r: [Service] new incoming call notification */
-       RXRPC_ACCEPT            = 9,    /* s-: [Service] accept request */
        RXRPC_EXCLUSIVE_CALL    = 10,   /* s-: Call should be on exclusive connection */
        RXRPC_UPGRADE_SERVICE   = 11,   /* s-: Request service upgrade for client call */
        RXRPC_TX_LENGTH         = 12,   /* s-: Total length of Tx data */
        RXRPC_SET_CALL_TIMEOUT  = 13,   /* s-: Set one or more call timeouts */
+       RXRPC_CHARGE_ACCEPT     = 14,   /* s-: Charge the accept pool with a user call ID */
        RXRPC__SUPPORTED
 };
 
index cee9f8e..f84e7bc 100644 (file)
@@ -288,6 +288,7 @@ enum
        LINUX_MIB_TCPTIMEOUTREHASH,             /* TCPTimeoutRehash */
        LINUX_MIB_TCPDUPLICATEDATAREHASH,       /* TCPDuplicateDataRehash */
        LINUX_MIB_TCPDSACKRECVSEGS,             /* TCPDSACKRecvSegs */
+       LINUX_MIB_TCPDSACKIGNOREDDUBIOUS,       /* TCPDSACKIgnoredDubious */
        __LINUX_MIB_MAX
 };
 
index c7b70ff..235db77 100644 (file)
@@ -191,8 +191,6 @@ enum v4l2_memory {
        V4L2_MEMORY_DMABUF           = 4,
 };
 
-#define V4L2_FLAG_MEMORY_NON_CONSISTENT                (1 << 0)
-
 /* see also http://vektor.theorem.ca/graphics/ycbcr/ */
 enum v4l2_colorspace {
        /*
@@ -949,10 +947,7 @@ struct v4l2_requestbuffers {
        __u32                   type;           /* enum v4l2_buf_type */
        __u32                   memory;         /* enum v4l2_memory */
        __u32                   capabilities;
-       union {
-               __u32           flags;
-               __u32           reserved[1];
-       };
+       __u32                   reserved[1];
 };
 
 /* capabilities for struct v4l2_requestbuffers and v4l2_create_buffers */
@@ -2456,9 +2451,6 @@ struct v4l2_dbg_chip_info {
  * @memory:    enum v4l2_memory; buffer memory type
  * @format:    frame format, for which buffers are requested
  * @capabilities: capabilities of this buffer type.
- * @flags:     additional buffer management attributes (ignored unless the
- *             queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability
- *             and configured for MMAP streaming I/O).
  * @reserved:  future extensions
  */
 struct v4l2_create_buffers {
@@ -2467,8 +2459,7 @@ struct v4l2_create_buffers {
        __u32                   memory;
        struct v4l2_format      format;
        __u32                   capabilities;
-       __u32                   flags;
-       __u32                   reserved[6];
+       __u32                   reserved[7];
 };
 
 /*
index d7f6af5..ac1b654 100644 (file)
@@ -76,9 +76,16 @@ static inline unsigned long bfn_to_pfn(unsigned long bfn)
 #define bfn_to_local_pfn(bfn)  bfn_to_pfn(bfn)
 
 /* VIRT <-> GUEST conversion */
-#define virt_to_gfn(v)         (pfn_to_gfn(virt_to_phys(v) >> XEN_PAGE_SHIFT))
+#define virt_to_gfn(v)                                                         \
+       ({                                                                     \
+               WARN_ON_ONCE(!virt_addr_valid(v));                              \
+               pfn_to_gfn(virt_to_phys(v) >> XEN_PAGE_SHIFT);                 \
+       })
 #define gfn_to_virt(m)         (__va(gfn_to_pfn(m) << XEN_PAGE_SHIFT))
 
+#define percpu_to_gfn(v)       \
+       (pfn_to_gfn(per_cpu_ptr_to_phys(v) >> XEN_PAGE_SHIFT))
+
 /* Only used in PV code. But ARM guests are always HVM. */
 static inline xmaddr_t arbitrary_virt_to_machine(void *vaddr)
 {
index 6fb95aa..6dbdb0b 100644 (file)
@@ -2,6 +2,8 @@
 /******************************************************************************
  * Xen balloon functionality
  */
+#ifndef _XEN_BALLOON_H
+#define _XEN_BALLOON_H
 
 #define RETRY_UNLIMITED        0
 
@@ -34,3 +36,5 @@ static inline void xen_balloon_init(void)
 {
 }
 #endif
+
+#endif /* _XEN_BALLOON_H */
index 19a72f5..43efba0 100644 (file)
@@ -52,4 +52,13 @@ bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
 extern u64 xen_saved_max_mem_size;
 #endif
 
+#ifdef CONFIG_XEN_UNPOPULATED_ALLOC
+int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages);
+void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages);
+#else
+#define xen_alloc_unpopulated_pages alloc_xenballooned_pages
+#define xen_free_unpopulated_pages free_xenballooned_pages
+#include <xen/balloon.h>
+#endif
+
 #endif /* _XEN_XEN_H */
index d6a0b31..c0f56e4 100644 (file)
@@ -1986,7 +1986,7 @@ config MMAP_ALLOW_UNINITIALIZED
          userspace.  Since that isn't generally a problem on no-MMU systems,
          it is normally safe to say Y here.
 
-         See Documentation/mm/nommu-mmap.rst for more information.
+         See Documentation/admin-guide/mm/nommu-mmap.rst for more information.
 
 config SYSTEM_DATA_VERIFICATION
        def_bool n
index e6dbfb7..1f97c03 100644 (file)
@@ -297,7 +297,7 @@ static void __init clean_path(char *path, umode_t fmode)
 {
        struct kstat st;
 
-       if (init_stat(path, &st, AT_SYMLINK_NOFOLLOW) &&
+       if (!init_stat(path, &st, AT_SYMLINK_NOFOLLOW) &&
            (st.mode ^ fmode) & S_IFMT) {
                if (S_ISDIR(st.mode))
                        init_rmdir(path);
index ae78fb6..e880b4e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/nmi.h>
 #include <linux/percpu.h>
 #include <linux/kmod.h>
+#include <linux/kprobes.h>
 #include <linux/vmalloc.h>
 #include <linux/kernel_stat.h>
 #include <linux/start_kernel.h>
@@ -303,7 +304,7 @@ static void * __init get_boot_config_from_initrd(u32 *_size, u32 *_csum)
 
 #ifdef CONFIG_BOOT_CONFIG
 
-char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
+static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
 
 #define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)
 
@@ -1402,6 +1403,7 @@ static int __ref kernel_init(void *unused)
        kernel_init_freeable();
        /* need to finish all async __init code before freeing the memory */
        async_synchronize_full();
+       kprobe_free_init_mem();
        ftrace_free_init_mem();
        free_initmem();
        mark_readonly();
index d1b8644..3f312bf 100644 (file)
@@ -85,7 +85,7 @@ static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
 }
 
 static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
-       void __user *buffer, size_t *lenp, loff_t *ppos)
+       void *buffer, size_t *lenp, loff_t *ppos)
 {
        int ret, semmni;
        struct ipc_namespace *ns = current->nsproxy->ipc_ns;
index 8c0244e..f6c30a8 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1691,7 +1691,7 @@ static long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg, int v
        case IPC_SET:
                if (copy_semid_from_user(&semid64, p, version))
                        return -EFAULT;
-               /* fall through */
+               fallthrough;
        case IPC_RMID:
                return semctl_down(ns, semid, cmd, &semid64);
        default:
@@ -1805,7 +1805,7 @@ static long compat_ksys_semctl(int semid, int semnum, int cmd, int arg, int vers
        case IPC_SET:
                if (copy_compat_semid_from_user(&semid64, p, version))
                        return -EFAULT;
-               /* fallthru */
+               fallthrough;
        case IPC_RMID:
                return semctl_down(ns, semid, cmd, &semid64);
        default:
index f1ed36e..e25c7c6 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1179,7 +1179,7 @@ static long ksys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf, int ver
        case IPC_SET:
                if (copy_shmid_from_user(&sem64, buf, version))
                        return -EFAULT;
-               /* fallthru */
+               fallthrough;
        case IPC_RMID:
                return shmctl_down(ns, shmid, cmd, &sem64);
        case SHM_LOCK:
@@ -1374,7 +1374,7 @@ static long compat_ksys_shmctl(int shmid, int cmd, void __user *uptr, int versio
        case IPC_SET:
                if (copy_compat_shmid_from_user(&sem64, uptr, version))
                        return -EFAULT;
-               /* fallthru */
+               fallthrough;
        case IPC_RMID:
                return shmctl_down(ns, shmid, cmd, &sem64);
        case SHM_LOCK:
index 9a20016..b74820d 100644 (file)
@@ -111,6 +111,7 @@ obj-$(CONFIG_CPU_PM) += cpu_pm.o
 obj-$(CONFIG_BPF) += bpf/
 obj-$(CONFIG_KCSAN) += kcsan/
 obj-$(CONFIG_SHADOW_CALL_STACK) += scs.o
+obj-$(CONFIG_HAVE_STATIC_CALL_INLINE) += static_call.o
 
 obj-$(CONFIG_PERF_EVENTS) += events/
 
index a10e299..333b3bc 100644 (file)
@@ -681,7 +681,7 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
                                data->values[i] = AUDIT_UID_UNSET;
                                break;
                        }
-                       /* fall through - if set */
+                       fallthrough;    /* if set */
                default:
                        data->values[i] = f->val;
                }
index 83ff127..e21de4f 100644 (file)
@@ -1794,7 +1794,7 @@ static bool cg_sockopt_is_valid_access(int off, int size,
                        return prog->expected_attach_type ==
                                BPF_CGROUP_GETSOCKOPT;
                case offsetof(struct bpf_sockopt, optname):
-                       /* fallthrough */
+                       fallthrough;
                case offsetof(struct bpf_sockopt, level):
                        if (size != size_default)
                                return false;
index f1c4652..6386b7b 100644 (file)
@@ -279,7 +279,7 @@ static int cpu_map_bpf_prog_run_xdp(struct bpf_cpu_map_entry *rcpu,
                        break;
                default:
                        bpf_warn_invalid_xdp_action(act);
-                       /* fallthrough */
+                       fallthrough;
                case XDP_DROP:
                        xdp_return_frame(xdpf);
                        stats->drop++;
index 78dfff6..7df28a4 100644 (file)
@@ -1622,7 +1622,6 @@ struct bpf_iter_seq_hash_map_info {
        struct bpf_map *map;
        struct bpf_htab *htab;
        void *percpu_value_buf; // non-zero means percpu hash
-       unsigned long flags;
        u32 bucket_id;
        u32 skip_elems;
 };
@@ -1632,7 +1631,6 @@ bpf_hash_map_seq_find_next(struct bpf_iter_seq_hash_map_info *info,
                           struct htab_elem *prev_elem)
 {
        const struct bpf_htab *htab = info->htab;
-       unsigned long flags = info->flags;
        u32 skip_elems = info->skip_elems;
        u32 bucket_id = info->bucket_id;
        struct hlist_nulls_head *head;
@@ -1656,19 +1654,18 @@ bpf_hash_map_seq_find_next(struct bpf_iter_seq_hash_map_info *info,
 
                /* not found, unlock and go to the next bucket */
                b = &htab->buckets[bucket_id++];
-               htab_unlock_bucket(htab, b, flags);
+               rcu_read_unlock();
                skip_elems = 0;
        }
 
        for (i = bucket_id; i < htab->n_buckets; i++) {
                b = &htab->buckets[i];
-               flags = htab_lock_bucket(htab, b);
+               rcu_read_lock();
 
                count = 0;
                head = &b->head;
                hlist_nulls_for_each_entry_rcu(elem, n, head, hash_node) {
                        if (count >= skip_elems) {
-                               info->flags = flags;
                                info->bucket_id = i;
                                info->skip_elems = count;
                                return elem;
@@ -1676,7 +1673,7 @@ bpf_hash_map_seq_find_next(struct bpf_iter_seq_hash_map_info *info,
                        count++;
                }
 
-               htab_unlock_bucket(htab, b, flags);
+               rcu_read_unlock();
                skip_elems = 0;
        }
 
@@ -1754,14 +1751,10 @@ static int bpf_hash_map_seq_show(struct seq_file *seq, void *v)
 
 static void bpf_hash_map_seq_stop(struct seq_file *seq, void *v)
 {
-       struct bpf_iter_seq_hash_map_info *info = seq->private;
-
        if (!v)
                (void)__bpf_hash_map_seq_show(seq, NULL);
        else
-               htab_unlock_bucket(info->htab,
-                                  &info->htab->buckets[info->bucket_id],
-                                  info->flags);
+               rcu_read_unlock();
 }
 
 static int bpf_iter_init_hash_map(void *priv_data,
index fb878ba..18f4969 100644 (file)
@@ -226,10 +226,12 @@ static void *map_seq_next(struct seq_file *m, void *v, loff_t *pos)
        else
                prev_key = key;
 
+       rcu_read_lock();
        if (map->ops->map_get_next_key(map, prev_key, key)) {
                map_iter(m)->done = true;
-               return NULL;
+               key = NULL;
        }
+       rcu_read_unlock();
        return key;
 }
 
index 86299a2..b999e7f 100644 (file)
@@ -2029,7 +2029,7 @@ bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
        case BPF_PROG_TYPE_EXT:
                if (expected_attach_type)
                        return -EINVAL;
-               /* fallthrough */
+               fallthrough;
        default:
                return 0;
        }
@@ -2634,7 +2634,7 @@ static int bpf_raw_tp_link_fill_link_info(const struct bpf_link *link,
        u32 ulen = info->raw_tracepoint.tp_name_len;
        size_t tp_len = strlen(tp_name);
 
-       if (ulen && !ubuf)
+       if (!ulen ^ !ubuf)
                return -EINVAL;
 
        info->raw_tracepoint.tp_name_len = tp_len + 1;
index 3b49577..11b3380 100644 (file)
@@ -30,15 +30,15 @@ static struct kobject *btf_kobj;
 
 static int __init btf_vmlinux_init(void)
 {
-       if (!__start_BTF)
+       bin_attr_btf_vmlinux.size = __stop_BTF - __start_BTF;
+
+       if (!__start_BTF || bin_attr_btf_vmlinux.size == 0)
                return 0;
 
        btf_kobj = kobject_create_and_add("btf", kernel_kobj);
        if (!btf_kobj)
                return -ENOMEM;
 
-       bin_attr_btf_vmlinux.size = __stop_BTF - __start_BTF;
-
        return sysfs_create_bin_file(btf_kobj, &bin_attr_btf_vmlinux);
 }
 
index ef938f1..fba52d9 100644 (file)
@@ -5236,7 +5236,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                                off_reg == dst_reg ? dst : src);
                        return -EACCES;
                }
-               /* fall-through */
+               fallthrough;
        default:
                break;
        }
@@ -5667,8 +5667,8 @@ static void scalar32_min_max_or(struct bpf_reg_state *dst_reg,
        bool src_known = tnum_subreg_is_const(src_reg->var_off);
        bool dst_known = tnum_subreg_is_const(dst_reg->var_off);
        struct tnum var32_off = tnum_subreg(dst_reg->var_off);
-       s32 smin_val = src_reg->smin_value;
-       u32 umin_val = src_reg->umin_value;
+       s32 smin_val = src_reg->s32_min_value;
+       u32 umin_val = src_reg->u32_min_value;
 
        /* Assuming scalar64_min_max_or will be called so it is safe
         * to skip updating register for known case.
@@ -5691,8 +5691,8 @@ static void scalar32_min_max_or(struct bpf_reg_state *dst_reg,
                /* ORing two positives gives a positive, so safe to
                 * cast result into s64.
                 */
-               dst_reg->s32_min_value = dst_reg->umin_value;
-               dst_reg->s32_max_value = dst_reg->umax_value;
+               dst_reg->s32_min_value = dst_reg->u32_min_value;
+               dst_reg->s32_max_value = dst_reg->u32_max_value;
        }
 }
 
@@ -10988,7 +10988,7 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
        default:
                if (!prog_extension)
                        return -EINVAL;
-               /* fallthrough */
+               fallthrough;
        case BPF_MODIFY_RETURN:
        case BPF_LSM_MAC:
        case BPF_TRACE_FENTRY:
index 1444f39..7c59b09 100644 (file)
@@ -93,7 +93,7 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
                break;
        case _LINUX_CAPABILITY_VERSION_2:
                warn_deprecated_v2();
-               /* fall through - v3 is otherwise equivalent to v2. */
+               fallthrough;    /* v3 is otherwise equivalent to v2 */
        case _LINUX_CAPABILITY_VERSION_3:
                *tocopy = _LINUX_CAPABILITY_U32S_3;
                break;
index b8d2800..05adfd6 100644 (file)
@@ -255,11 +255,11 @@ get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat)
                return -EFAULT;
        switch (_NSIG_WORDS) {
        case 4: set->sig[3] = v.sig[6] | (((long)v.sig[7]) << 32 );
-               /* fall through */
+               fallthrough;
        case 3: set->sig[2] = v.sig[4] | (((long)v.sig[5]) << 32 );
-               /* fall through */
+               fallthrough;
        case 2: set->sig[1] = v.sig[2] | (((long)v.sig[3]) << 32 );
-               /* fall through */
+               fallthrough;
        case 1: set->sig[0] = v.sig[0] | (((long)v.sig[1]) << 32 );
        }
 #else
index 44a2593..f7e1d0e 100644 (file)
 
 static ATOMIC_NOTIFIER_HEAD(cpu_pm_notifier_chain);
 
-static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)
+static int cpu_pm_notify(enum cpu_pm_event event)
 {
        int ret;
 
        /*
-        * __atomic_notifier_call_chain has a RCU read critical section, which
+        * atomic_notifier_call_chain has a RCU read critical section, which
         * could be disfunctional in cpu idle. Copy RCU_NONIDLE code to let
         * RCU know this.
         */
        rcu_irq_enter_irqson();
-       ret = __atomic_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL,
-               nr_to_call, nr_calls);
+       ret = atomic_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL);
+       rcu_irq_exit_irqson();
+
+       return notifier_to_errno(ret);
+}
+
+static int cpu_pm_notify_robust(enum cpu_pm_event event_up, enum cpu_pm_event event_down)
+{
+       int ret;
+
+       rcu_irq_enter_irqson();
+       ret = atomic_notifier_call_chain_robust(&cpu_pm_notifier_chain, event_up, event_down, NULL);
        rcu_irq_exit_irqson();
 
        return notifier_to_errno(ret);
@@ -80,18 +90,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
  */
 int cpu_pm_enter(void)
 {
-       int nr_calls = 0;
-       int ret = 0;
-
-       ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
-       if (ret)
-               /*
-                * Inform listeners (nr_calls - 1) about failure of CPU PM
-                * PM entry who are notified earlier to prepare for it.
-                */
-               cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
-
-       return ret;
+       return cpu_pm_notify_robust(CPU_PM_ENTER, CPU_PM_ENTER_FAILED);
 }
 EXPORT_SYMBOL_GPL(cpu_pm_enter);
 
@@ -109,7 +108,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_enter);
  */
 int cpu_pm_exit(void)
 {
-       return cpu_pm_notify(CPU_PM_EXIT, -1, NULL);
+       return cpu_pm_notify(CPU_PM_EXIT);
 }
 EXPORT_SYMBOL_GPL(cpu_pm_exit);
 
@@ -131,18 +130,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_exit);
  */
 int cpu_cluster_pm_enter(void)
 {
-       int nr_calls = 0;
-       int ret = 0;
-
-       ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
-       if (ret)
-               /*
-                * Inform listeners (nr_calls - 1) about failure of CPU cluster
-                * PM entry who are notified earlier to prepare for it.
-                */
-               cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL);
-
-       return ret;
+       return cpu_pm_notify_robust(CPU_CLUSTER_PM_ENTER, CPU_CLUSTER_PM_ENTER_FAILED);
 }
 EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
 
@@ -163,7 +151,7 @@ EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
  */
 int cpu_cluster_pm_exit(void)
 {
-       return cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL);
+       return cpu_pm_notify(CPU_CLUSTER_PM_EXIT);
 }
 EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);
 
index a790026..cc3c43d 100644 (file)
@@ -1046,14 +1046,14 @@ int gdb_serial_stub(struct kgdb_state *ks)
                                return DBG_PASS_EVENT;
                        }
 #endif
-                       /* Fall through */
+                       fallthrough;
                case 'C': /* Exception passing */
                        tmp = gdb_cmd_exception_pass(ks);
                        if (tmp > 0)
                                goto default_handle;
                        if (tmp == 0)
                                break;
-                       /* Fall through - on tmp < 0 */
+                       fallthrough;    /* on tmp < 0 */
                case 'c': /* Continue packet */
                case 's': /* Single step packet */
                        if (kgdb_contthread && kgdb_contthread != current) {
@@ -1062,7 +1062,7 @@ int gdb_serial_stub(struct kgdb_state *ks)
                                break;
                        }
                        dbg_activate_sw_breakpoints();
-                       /* Fall through - to default processing */
+                       fallthrough;    /* to default processing */
                default:
 default_handle:
                        error = kgdb_arch_handle_exception(ks->ex_vector,
index 750497b..f877a0a 100644 (file)
@@ -173,11 +173,11 @@ int kdb_get_kbd_char(void)
        case KT_LATIN:
                if (isprint(keychar))
                        break;          /* printable characters */
-               /* fall through */
+               fallthrough;
        case KT_SPEC:
                if (keychar == K_ENTER)
                        break;
-               /* fall through */
+               fallthrough;
        default:
                return -1;      /* ignore unprintables */
        }
index 004c5b6..6226502 100644 (file)
@@ -432,7 +432,7 @@ int kdb_getphysword(unsigned long *word, unsigned long addr, size_t size)
                                *word = w8;
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                diag = KDB_BADWIDTH;
                kdb_printf("kdb_getphysword: bad width %ld\n", (long) size);
@@ -481,7 +481,7 @@ int kdb_getword(unsigned long *word, unsigned long addr, size_t size)
                                *word = w8;
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                diag = KDB_BADWIDTH;
                kdb_printf("kdb_getword: bad width %ld\n", (long) size);
@@ -525,7 +525,7 @@ int kdb_putword(unsigned long addr, unsigned long word, size_t size)
                        diag = kdb_putarea(addr, w8);
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                diag = KDB_BADWIDTH;
                kdb_printf("kdb_putword: bad width %ld\n", (long) size);
index 06582b4..1281c0f 100644 (file)
@@ -84,7 +84,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
                              gfp_t gfp)
 {
        unsigned int order;
-       struct page *page;
+       struct page *page = NULL;
        void *addr;
        int ret = -ENOMEM;
 
index fcae019..145ab11 100644 (file)
@@ -60,31 +60,56 @@ static long syscall_trace_enter(struct pt_regs *regs, long syscall,
                        return ret;
        }
 
+       /* Either of the above might have changed the syscall number */
+       syscall = syscall_get_nr(current, regs);
+
        if (unlikely(ti_work & _TIF_SYSCALL_TRACEPOINT))
                trace_sys_enter(regs, syscall);
 
        syscall_enter_audit(regs, syscall);
 
-       /* The above might have changed the syscall number */
-       return ret ? : syscall_get_nr(current, regs);
+       return ret ? : syscall;
 }
 
-noinstr long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
+static __always_inline long
+__syscall_enter_from_user_work(struct pt_regs *regs, long syscall)
 {
        unsigned long ti_work;
 
-       enter_from_user_mode(regs);
-       instrumentation_begin();
-
-       local_irq_enable();
        ti_work = READ_ONCE(current_thread_info()->flags);
        if (ti_work & SYSCALL_ENTER_WORK)
                syscall = syscall_trace_enter(regs, syscall, ti_work);
-       instrumentation_end();
 
        return syscall;
 }
 
+long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
+{
+       return __syscall_enter_from_user_work(regs, syscall);
+}
+
+noinstr long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
+{
+       long ret;
+
+       enter_from_user_mode(regs);
+
+       instrumentation_begin();
+       local_irq_enable();
+       ret = __syscall_enter_from_user_work(regs, syscall);
+       instrumentation_end();
+
+       return ret;
+}
+
+noinstr void syscall_enter_from_user_mode_prepare(struct pt_regs *regs)
+{
+       enter_from_user_mode(regs);
+       instrumentation_begin();
+       local_irq_enable();
+       instrumentation_end();
+}
+
 /**
  * exit_to_user_mode - Fixup state when exiting to user mode
  *
@@ -183,7 +208,7 @@ static inline bool report_single_step(unsigned long ti_work)
 /*
  * If TIF_SYSCALL_EMU is set, then the only reason to report is when
  * TIF_SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
- * instruction has been already reported in syscall_enter_from_usermode().
+ * instruction has been already reported in syscall_enter_from_user_mode().
  */
 #define SYSEMU_STEP    (_TIF_SINGLESTEP | _TIF_SYSCALL_EMU)
 
index 5bfe8e3..da467e1 100644 (file)
@@ -99,7 +99,7 @@ static void remote_function(void *data)
  * retry due to any failures in smp_call_function_single(), such as if the
  * task_cpu() goes offline concurrently.
  *
- * returns @func return value or -ESRCH when the process isn't running
+ * returns @func return value or -ESRCH or -ENXIO when the process isn't running
  */
 static int
 task_function_call(struct task_struct *p, remote_function_f func, void *info)
@@ -115,7 +115,8 @@ task_function_call(struct task_struct *p, remote_function_f func, void *info)
        for (;;) {
                ret = smp_call_function_single(task_cpu(p), remote_function,
                                               &data, 1);
-               ret = !ret ? data.ret : -EAGAIN;
+               if (!ret)
+                       ret = data.ret;
 
                if (ret != -EAGAIN)
                        break;
@@ -382,7 +383,6 @@ static DEFINE_MUTEX(perf_sched_mutex);
 static atomic_t perf_sched_count;
 
 static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
-static DEFINE_PER_CPU(int, perf_sched_cb_usages);
 static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events);
 
 static atomic_t nr_mmap_events __read_mostly;
@@ -2133,8 +2133,24 @@ static inline struct list_head *get_event_list(struct perf_event *event)
        return event->attr.pinned ? &ctx->pinned_active : &ctx->flexible_active;
 }
 
+/*
+ * Events that have PERF_EV_CAP_SIBLING require being part of a group and
+ * cannot exist on their own, schedule them out and move them into the ERROR
+ * state. Also see _perf_event_enable(), it will not be able to recover
+ * this ERROR state.
+ */
+static inline void perf_remove_sibling_event(struct perf_event *event)
+{
+       struct perf_event_context *ctx = event->ctx;
+       struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+
+       event_sched_out(event, cpuctx, ctx);
+       perf_event_set_state(event, PERF_EVENT_STATE_ERROR);
+}
+
 static void perf_group_detach(struct perf_event *event)
 {
+       struct perf_event *leader = event->group_leader;
        struct perf_event *sibling, *tmp;
        struct perf_event_context *ctx = event->ctx;
 
@@ -2153,7 +2169,7 @@ static void perf_group_detach(struct perf_event *event)
        /*
         * If this is a sibling, remove it from its group.
         */
-       if (event->group_leader != event) {
+       if (leader != event) {
                list_del_init(&event->sibling_list);
                event->group_leader->nr_siblings--;
                goto out;
@@ -2166,6 +2182,9 @@ static void perf_group_detach(struct perf_event *event)
         */
        list_for_each_entry_safe(sibling, tmp, &event->sibling_list, sibling_list) {
 
+               if (sibling->event_caps & PERF_EV_CAP_SIBLING)
+                       perf_remove_sibling_event(sibling);
+
                sibling->group_leader = sibling;
                list_del_init(&sibling->sibling_list);
 
@@ -2183,10 +2202,10 @@ static void perf_group_detach(struct perf_event *event)
        }
 
 out:
-       perf_event__header_size(event->group_leader);
-
-       for_each_sibling_event(tmp, event->group_leader)
+       for_each_sibling_event(tmp, leader)
                perf_event__header_size(tmp);
+
+       perf_event__header_size(leader);
 }
 
 static bool is_orphaned_event(struct perf_event *event)
@@ -2979,6 +2998,7 @@ static void _perf_event_enable(struct perf_event *event)
        raw_spin_lock_irq(&ctx->lock);
        if (event->state >= PERF_EVENT_STATE_INACTIVE ||
            event->state <  PERF_EVENT_STATE_ERROR) {
+out:
                raw_spin_unlock_irq(&ctx->lock);
                return;
        }
@@ -2990,8 +3010,16 @@ static void _perf_event_enable(struct perf_event *event)
         * has gone back into error state, as distinct from the task having
         * been scheduled away before the cross-call arrived.
         */
-       if (event->state == PERF_EVENT_STATE_ERROR)
+       if (event->state == PERF_EVENT_STATE_ERROR) {
+               /*
+                * Detached SIBLING events cannot leave ERROR state.
+                */
+               if (event->event_caps & PERF_EV_CAP_SIBLING &&
+                   event->group_leader == event)
+                       goto out;
+
                event->state = PERF_EVENT_STATE_OFF;
+       }
        raw_spin_unlock_irq(&ctx->lock);
 
        event_function_call(event, __perf_event_enable, NULL);
@@ -3356,10 +3384,12 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
        struct perf_event_context *parent, *next_parent;
        struct perf_cpu_context *cpuctx;
        int do_switch = 1;
+       struct pmu *pmu;
 
        if (likely(!ctx))
                return;
 
+       pmu = ctx->pmu;
        cpuctx = __get_cpu_context(ctx);
        if (!cpuctx->task_ctx)
                return;
@@ -3389,11 +3419,15 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
                raw_spin_lock(&ctx->lock);
                raw_spin_lock_nested(&next_ctx->lock, SINGLE_DEPTH_NESTING);
                if (context_equiv(ctx, next_ctx)) {
-                       struct pmu *pmu = ctx->pmu;
 
                        WRITE_ONCE(ctx->task, next);
                        WRITE_ONCE(next_ctx->task, task);
 
+                       perf_pmu_disable(pmu);
+
+                       if (cpuctx->sched_cb_usage && pmu->sched_task)
+                               pmu->sched_task(ctx, false);
+
                        /*
                         * PMU specific parts of task perf context can require
                         * additional synchronization. As an example of such
@@ -3405,6 +3439,8 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
                        else
                                swap(ctx->task_ctx_data, next_ctx->task_ctx_data);
 
+                       perf_pmu_enable(pmu);
+
                        /*
                         * RCU_INIT_POINTER here is safe because we've not
                         * modified the ctx and the above modification of
@@ -3427,21 +3463,22 @@ unlock:
 
        if (do_switch) {
                raw_spin_lock(&ctx->lock);
+               perf_pmu_disable(pmu);
+
+               if (cpuctx->sched_cb_usage && pmu->sched_task)
+                       pmu->sched_task(ctx, false);
                task_ctx_sched_out(cpuctx, ctx, EVENT_ALL);
+
+               perf_pmu_enable(pmu);
                raw_spin_unlock(&ctx->lock);
        }
 }
 
-static DEFINE_PER_CPU(struct list_head, sched_cb_list);
-
 void perf_sched_cb_dec(struct pmu *pmu)
 {
        struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
 
-       this_cpu_dec(perf_sched_cb_usages);
-
-       if (!--cpuctx->sched_cb_usage)
-               list_del(&cpuctx->sched_cb_entry);
+       --cpuctx->sched_cb_usage;
 }
 
 
@@ -3449,10 +3486,7 @@ void perf_sched_cb_inc(struct pmu *pmu)
 {
        struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
 
-       if (!cpuctx->sched_cb_usage++)
-               list_add(&cpuctx->sched_cb_entry, this_cpu_ptr(&sched_cb_list));
-
-       this_cpu_inc(perf_sched_cb_usages);
+       cpuctx->sched_cb_usage++;
 }
 
 /*
@@ -3463,30 +3497,22 @@ void perf_sched_cb_inc(struct pmu *pmu)
  * PEBS requires this to provide PID/TID information. This requires we flush
  * all queued PEBS records before we context switch to a new task.
  */
-static void perf_pmu_sched_task(struct task_struct *prev,
-                               struct task_struct *next,
-                               bool sched_in)
+static void __perf_pmu_sched_task(struct perf_cpu_context *cpuctx, bool sched_in)
 {
-       struct perf_cpu_context *cpuctx;
        struct pmu *pmu;
 
-       if (prev == next)
-               return;
-
-       list_for_each_entry(cpuctx, this_cpu_ptr(&sched_cb_list), sched_cb_entry) {
-               pmu = cpuctx->ctx.pmu; /* software PMUs will not have sched_task */
+       pmu = cpuctx->ctx.pmu; /* software PMUs will not have sched_task */
 
-               if (WARN_ON_ONCE(!pmu->sched_task))
-                       continue;
+       if (WARN_ON_ONCE(!pmu->sched_task))
+               return;
 
-               perf_ctx_lock(cpuctx, cpuctx->task_ctx);
-               perf_pmu_disable(pmu);
+       perf_ctx_lock(cpuctx, cpuctx->task_ctx);
+       perf_pmu_disable(pmu);
 
-               pmu->sched_task(cpuctx->task_ctx, sched_in);
+       pmu->sched_task(cpuctx->task_ctx, sched_in);
 
-               perf_pmu_enable(pmu);
-               perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
-       }
+       perf_pmu_enable(pmu);
+       perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
 }
 
 static void perf_event_switch(struct task_struct *task,
@@ -3511,9 +3537,6 @@ void __perf_event_task_sched_out(struct task_struct *task,
 {
        int ctxn;
 
-       if (__this_cpu_read(perf_sched_cb_usages))
-               perf_pmu_sched_task(task, next, false);
-
        if (atomic_read(&nr_switch_events))
                perf_event_switch(task, next, false);
 
@@ -3745,10 +3768,14 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx,
                                        struct task_struct *task)
 {
        struct perf_cpu_context *cpuctx;
+       struct pmu *pmu = ctx->pmu;
 
        cpuctx = __get_cpu_context(ctx);
-       if (cpuctx->task_ctx == ctx)
+       if (cpuctx->task_ctx == ctx) {
+               if (cpuctx->sched_cb_usage)
+                       __perf_pmu_sched_task(cpuctx, true);
                return;
+       }
 
        perf_ctx_lock(cpuctx, ctx);
        /*
@@ -3758,7 +3785,7 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx,
        if (!ctx->nr_events)
                goto unlock;
 
-       perf_pmu_disable(ctx->pmu);
+       perf_pmu_disable(pmu);
        /*
         * We want to keep the following priority order:
         * cpu pinned (that don't need to move), task pinned,
@@ -3770,7 +3797,11 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx,
        if (!RB_EMPTY_ROOT(&ctx->pinned_groups.tree))
                cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
        perf_event_sched_in(cpuctx, ctx, task);
-       perf_pmu_enable(ctx->pmu);
+
+       if (cpuctx->sched_cb_usage && pmu->sched_task)
+               pmu->sched_task(cpuctx->task_ctx, true);
+
+       perf_pmu_enable(pmu);
 
 unlock:
        perf_ctx_unlock(cpuctx, ctx);
@@ -3813,9 +3844,6 @@ void __perf_event_task_sched_in(struct task_struct *prev,
 
        if (atomic_read(&nr_switch_events))
                perf_event_switch(task, prev, true);
-
-       if (__this_cpu_read(perf_sched_cb_usages))
-               perf_pmu_sched_task(prev, task, true);
 }
 
 static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
@@ -5868,11 +5896,11 @@ static void perf_pmu_output_stop(struct perf_event *event);
 static void perf_mmap_close(struct vm_area_struct *vma)
 {
        struct perf_event *event = vma->vm_file->private_data;
-
        struct perf_buffer *rb = ring_buffer_get(event);
        struct user_struct *mmap_user = rb->mmap_user;
        int mmap_locked = rb->mmap_locked;
        unsigned long size = perf_data_size(rb);
+       bool detach_rest = false;
 
        if (event->pmu->event_unmapped)
                event->pmu->event_unmapped(event, vma->vm_mm);
@@ -5903,7 +5931,8 @@ static void perf_mmap_close(struct vm_area_struct *vma)
                mutex_unlock(&event->mmap_mutex);
        }
 
-       atomic_dec(&rb->mmap_count);
+       if (atomic_dec_and_test(&rb->mmap_count))
+               detach_rest = true;
 
        if (!atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex))
                goto out_put;
@@ -5912,7 +5941,7 @@ static void perf_mmap_close(struct vm_area_struct *vma)
        mutex_unlock(&event->mmap_mutex);
 
        /* If there's still other mmap()s of this buffer, we're done. */
-       if (atomic_read(&rb->mmap_count))
+       if (!detach_rest)
                goto out_put;
 
        /*
@@ -10034,7 +10063,7 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr,
                case IF_SRC_KERNELADDR:
                case IF_SRC_KERNEL:
                        kernel = 1;
-                       /* fall through */
+                       fallthrough;
 
                case IF_SRC_FILEADDR:
                case IF_SRC_FILE:
@@ -12828,7 +12857,6 @@ static void __init perf_event_init_all_cpus(void)
 #ifdef CONFIG_CGROUP_PERF
                INIT_LIST_HEAD(&per_cpu(cgrp_cpuctx_list, cpu));
 #endif
-               INIT_LIST_HEAD(&per_cpu(sched_cb_list, cpu));
        }
 }
 
index 4d32190..da8d360 100644 (file)
@@ -589,7 +589,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
 
                mm->map_count++;
                if (!(tmp->vm_flags & VM_WIPEONFORK))
-                       retval = copy_page_range(mm, oldmm, mpnt);
+                       retval = copy_page_range(mm, oldmm, mpnt, tmp);
 
                if (tmp->vm_ops && tmp->vm_ops->open)
                        tmp->vm_ops->open(tmp);
@@ -1011,6 +1011,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
        mm_pgtables_bytes_init(mm);
        mm->map_count = 0;
        mm->locked_vm = 0;
+       atomic_set(&mm->has_pinned, 0);
        atomic64_set(&mm->pinned_vm, 0);
        memset(&mm->rss_stat, 0, sizeof(mm->rss_stat));
        spin_lock_init(&mm->page_table_lock);
@@ -3014,7 +3015,7 @@ int unshare_files(struct files_struct **displaced)
 }
 
 int sysctl_max_threads(struct ctl_table *table, int write,
-                      void __user *buffer, size_t *lenp, loff_t *ppos)
+                      void *buffer, size_t *lenp, loff_t *ppos)
 {
        struct ctl_table t;
        int ret;
index 908fdf5..53c67c8 100644 (file)
@@ -19,7 +19,9 @@
 #include <linux/vmalloc.h>
 #include "gcov.h"
 
-#if (__GNUC__ >= 7)
+#if (__GNUC__ >= 10)
+#define GCOV_COUNTERS                  8
+#elif (__GNUC__ >= 7)
 #define GCOV_COUNTERS                  9
 #elif (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
 #define GCOV_COUNTERS                  10
index 857f5f4..b9b9618 100644 (file)
@@ -945,6 +945,33 @@ void handle_percpu_devid_irq(struct irq_desc *desc)
 }
 
 /**
+ * handle_percpu_devid_fasteoi_ipi - Per CPU local IPI handler with per cpu
+ *                                  dev ids
+ * @desc:      the interrupt description structure for this irq
+ *
+ * The biggest difference with the IRQ version is that the interrupt is
+ * EOIed early, as the IPI could result in a context switch, and we need to
+ * make sure the IPI can fire again. We also assume that the arch code has
+ * registered an action. If not, we are positively doomed.
+ */
+void handle_percpu_devid_fasteoi_ipi(struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct irqaction *action = desc->action;
+       unsigned int irq = irq_desc_get_irq(desc);
+       irqreturn_t res;
+
+       __kstat_incr_irqs_this_cpu(desc);
+
+       if (chip->irq_eoi)
+               chip->irq_eoi(&desc->irq_data);
+
+       trace_irq_handler_entry(irq, action);
+       res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id));
+       trace_irq_handler_exit(irq, action, res);
+}
+
+/**
  * handle_percpu_devid_fasteoi_nmi - Per CPU local NMI handler with per cpu
  *                                  dev ids
  * @desc:      the interrupt description structure for this irq
@@ -1541,18 +1568,17 @@ EXPORT_SYMBOL_GPL(irq_chip_release_resources_parent);
  */
 int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
-       struct irq_data *pos = NULL;
+       struct irq_data *pos;
 
-#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
-       for (; data; data = data->parent_data)
-#endif
+       for (pos = NULL; !pos && data; data = irqd_get_parent_data(data)) {
                if (data->chip && data->chip->irq_compose_msi_msg)
                        pos = data;
+       }
+
        if (!pos)
                return -ENOSYS;
 
        pos->chip->irq_compose_msi_msg(pos, msg);
-
        return 0;
 }
 
index b95ff5d..e4cff35 100644 (file)
@@ -57,6 +57,7 @@ static const struct irq_bit_descr irqchip_flags[] = {
        BIT_MASK_DESCR(IRQCHIP_EOI_THREADED),
        BIT_MASK_DESCR(IRQCHIP_SUPPORTS_LEVEL_MSI),
        BIT_MASK_DESCR(IRQCHIP_SUPPORTS_NMI),
+       BIT_MASK_DESCR(IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND),
 };
 
 static void
@@ -125,6 +126,8 @@ static const struct irq_bit_descr irqdata_states[] = {
        BIT_MASK_DESCR(IRQD_DEFAULT_TRIGGER_SET),
 
        BIT_MASK_DESCR(IRQD_HANDLE_ENFORCE_IRQCTX),
+
+       BIT_MASK_DESCR(IRQD_IRQ_ENABLED_ON_SUSPEND),
 };
 
 static const struct irq_bit_descr irqdesc_states[] = {
@@ -136,6 +139,7 @@ static const struct irq_bit_descr irqdesc_states[] = {
        BIT_MASK_DESCR(_IRQ_PER_CPU_DEVID),
        BIT_MASK_DESCR(_IRQ_IS_POLLED),
        BIT_MASK_DESCR(_IRQ_DISABLE_UNLAZY),
+       BIT_MASK_DESCR(_IRQ_HIDDEN),
 };
 
 static const struct irq_bit_descr irqdesc_istates[] = {
index a8e14c8..762a928 100644 (file)
@@ -173,7 +173,7 @@ irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags
 
                        __irq_wake_thread(desc, action);
 
-                       /* Fall through - to add to randomness */
+                       fallthrough;    /* to add to randomness */
                case IRQ_HANDLED:
                        *flags |= action->flags;
                        break;
index 7db284b..5436352 100644 (file)
@@ -473,6 +473,15 @@ static inline void irq_domain_deactivate_irq(struct irq_data *data)
 }
 #endif
 
+static inline struct irq_data *irqd_get_parent_data(struct irq_data *irqd)
+{
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+       return irqd->parent_data;
+#else
+       return NULL;
+#endif
+}
+
 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
 #include <linux/debugfs.h>
 
index 76cd7eb..cf8b374 100644 (file)
@@ -1136,6 +1136,17 @@ static struct irq_data *irq_domain_insert_irq_data(struct irq_domain *domain,
        return irq_data;
 }
 
+static void __irq_domain_free_hierarchy(struct irq_data *irq_data)
+{
+       struct irq_data *tmp;
+
+       while (irq_data) {
+               tmp = irq_data;
+               irq_data = irq_data->parent_data;
+               kfree(tmp);
+       }
+}
+
 static void irq_domain_free_irq_data(unsigned int virq, unsigned int nr_irqs)
 {
        struct irq_data *irq_data, *tmp;
@@ -1147,12 +1158,83 @@ static void irq_domain_free_irq_data(unsigned int virq, unsigned int nr_irqs)
                irq_data->parent_data = NULL;
                irq_data->domain = NULL;
 
-               while (tmp) {
-                       irq_data = tmp;
-                       tmp = tmp->parent_data;
-                       kfree(irq_data);
+               __irq_domain_free_hierarchy(tmp);
+       }
+}
+
+/**
+ * irq_domain_disconnect_hierarchy - Mark the first unused level of a hierarchy
+ * @domain:    IRQ domain from which the hierarchy is to be disconnected
+ * @virq:      IRQ number where the hierarchy is to be trimmed
+ *
+ * Marks the @virq level belonging to @domain as disconnected.
+ * Returns -EINVAL if @virq doesn't have a valid irq_data pointing
+ * to @domain.
+ *
+ * Its only use is to be able to trim levels of hierarchy that do not
+ * have any real meaning for this interrupt, and that the driver marks
+ * as such from its .alloc() callback.
+ */
+int irq_domain_disconnect_hierarchy(struct irq_domain *domain,
+                                   unsigned int virq)
+{
+       struct irq_data *irqd;
+
+       irqd = irq_domain_get_irq_data(domain, virq);
+       if (!irqd)
+               return -EINVAL;
+
+       irqd->chip = ERR_PTR(-ENOTCONN);
+       return 0;
+}
+
+static int irq_domain_trim_hierarchy(unsigned int virq)
+{
+       struct irq_data *tail, *irqd, *irq_data;
+
+       irq_data = irq_get_irq_data(virq);
+       tail = NULL;
+
+       /* The first entry must have a valid irqchip */
+       if (!irq_data->chip || IS_ERR(irq_data->chip))
+               return -EINVAL;
+
+       /*
+        * Validate that the irq_data chain is sane in the presence of
+        * a hierarchy trimming marker.
+        */
+       for (irqd = irq_data->parent_data; irqd; irq_data = irqd, irqd = irqd->parent_data) {
+               /* Can't have a valid irqchip after a trim marker */
+               if (irqd->chip && tail)
+                       return -EINVAL;
+
+               /* Can't have an empty irqchip before a trim marker */
+               if (!irqd->chip && !tail)
+                       return -EINVAL;
+
+               if (IS_ERR(irqd->chip)) {
+                       /* Only -ENOTCONN is a valid trim marker */
+                       if (PTR_ERR(irqd->chip) != -ENOTCONN)
+                               return -EINVAL;
+
+                       tail = irq_data;
                }
        }
+
+       /* No trim marker, nothing to do */
+       if (!tail)
+               return 0;
+
+       pr_info("IRQ%d: trimming hierarchy from %s\n",
+               virq, tail->parent_data->domain->name);
+
+       /* Sever the inner part of the hierarchy...  */
+       irqd = tail;
+       tail = tail->parent_data;
+       irqd->parent_data = NULL;
+       __irq_domain_free_hierarchy(tail);
+
+       return 0;
 }
 
 static int irq_domain_alloc_irq_data(struct irq_domain *domain,
@@ -1362,6 +1444,15 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
                mutex_unlock(&irq_domain_mutex);
                goto out_free_irq_data;
        }
+
+       for (i = 0; i < nr_irqs; i++) {
+               ret = irq_domain_trim_hierarchy(virq + i);
+               if (ret) {
+                       mutex_unlock(&irq_domain_mutex);
+                       goto out_free_irq_data;
+               }
+       }
+       
        for (i = 0; i < nr_irqs; i++)
                irq_domain_insert_irq(virq + i);
        mutex_unlock(&irq_domain_mutex);
index 52ac539..5df903f 100644 (file)
@@ -271,7 +271,7 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
        case IRQ_SET_MASK_OK:
        case IRQ_SET_MASK_OK_DONE:
                cpumask_copy(desc->irq_common_data.affinity, mask);
-               /* fall through */
+               fallthrough;
        case IRQ_SET_MASK_OK_NOCOPY:
                irq_validate_effective_affinity(data);
                irq_set_thread_affinity(desc);
@@ -868,7 +868,7 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned long flags)
        case IRQ_SET_MASK_OK_DONE:
                irqd_clear(&desc->irq_data, IRQD_TRIGGER_MASK);
                irqd_set(&desc->irq_data, flags);
-               /* fall through */
+               fallthrough;
 
        case IRQ_SET_MASK_OK_NOCOPY:
                flags = irqd_get_trigger_type(&desc->irq_data);
index 30cc217..651a4ad 100644 (file)
@@ -380,6 +380,13 @@ int irq_matrix_alloc(struct irq_matrix *m, const struct cpumask *msk,
        unsigned int cpu, bit;
        struct cpumap *cm;
 
+       /*
+        * Not required in theory, but matrix_find_best_cpu() uses
+        * for_each_cpu() which ignores the cpumask on UP .
+        */
+       if (cpumask_empty(msk))
+               return -EINVAL;
+
        cpu = matrix_find_best_cpu(m, msk);
        if (cpu == UINT_MAX)
                return -ENOSPC;
index eb95f61..2c0c4d6 100644 (file)
@@ -187,7 +187,6 @@ static const struct irq_domain_ops msi_domain_ops = {
        .deactivate     = msi_domain_deactivate,
 };
 
-#ifdef GENERIC_MSI_DOMAIN_OPS
 static irq_hw_number_t msi_domain_ops_get_hwirq(struct msi_domain_info *info,
                                                msi_alloc_info_t *arg)
 {
@@ -206,11 +205,6 @@ static void msi_domain_ops_set_desc(msi_alloc_info_t *arg,
 {
        arg->desc = desc;
 }
-#else
-#define msi_domain_ops_get_hwirq       NULL
-#define msi_domain_ops_prepare         NULL
-#define msi_domain_ops_set_desc                NULL
-#endif /* !GENERIC_MSI_DOMAIN_OPS */
 
 static int msi_domain_ops_init(struct irq_domain *domain,
                               struct msi_domain_info *info,
@@ -235,11 +229,13 @@ static int msi_domain_ops_check(struct irq_domain *domain,
 }
 
 static struct msi_domain_ops msi_domain_ops_default = {
-       .get_hwirq      = msi_domain_ops_get_hwirq,
-       .msi_init       = msi_domain_ops_init,
-       .msi_check      = msi_domain_ops_check,
-       .msi_prepare    = msi_domain_ops_prepare,
-       .set_desc       = msi_domain_ops_set_desc,
+       .get_hwirq              = msi_domain_ops_get_hwirq,
+       .msi_init               = msi_domain_ops_init,
+       .msi_check              = msi_domain_ops_check,
+       .msi_prepare            = msi_domain_ops_prepare,
+       .set_desc               = msi_domain_ops_set_desc,
+       .domain_alloc_irqs      = __msi_domain_alloc_irqs,
+       .domain_free_irqs       = __msi_domain_free_irqs,
 };
 
 static void msi_domain_update_dom_ops(struct msi_domain_info *info)
@@ -251,6 +247,14 @@ static void msi_domain_update_dom_ops(struct msi_domain_info *info)
                return;
        }
 
+       if (ops->domain_alloc_irqs == NULL)
+               ops->domain_alloc_irqs = msi_domain_ops_default.domain_alloc_irqs;
+       if (ops->domain_free_irqs == NULL)
+               ops->domain_free_irqs = msi_domain_ops_default.domain_free_irqs;
+
+       if (!(info->flags & MSI_FLAG_USE_DEF_DOM_OPS))
+               return;
+
        if (ops->get_hwirq == NULL)
                ops->get_hwirq = msi_domain_ops_default.get_hwirq;
        if (ops->msi_init == NULL)
@@ -284,8 +288,7 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
 {
        struct irq_domain *domain;
 
-       if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
-               msi_domain_update_dom_ops(info);
+       msi_domain_update_dom_ops(info);
        if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
                msi_domain_update_chip_ops(info);
 
@@ -370,8 +373,13 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
 {
        struct msi_desc *desc;
 
-       if (domain->bus_token != DOMAIN_BUS_PCI_MSI)
+       switch(domain->bus_token) {
+       case DOMAIN_BUS_PCI_MSI:
+       case DOMAIN_BUS_VMD_MSI:
+               break;
+       default:
                return false;
+       }
 
        if (!(info->flags & MSI_FLAG_MUST_REACTIVATE))
                return false;
@@ -387,17 +395,8 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
        return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
 }
 
-/**
- * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
- * @domain:    The domain to allocate from
- * @dev:       Pointer to device struct of the device for which the interrupts
- *             are allocated
- * @nvec:      The number of interrupts to allocate
- *
- * Returns 0 on success or an error code.
- */
-int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
-                         int nvec)
+int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
+                           int nvec)
 {
        struct msi_domain_info *info = domain->host_data;
        struct msi_domain_ops *ops = info->ops;
@@ -491,12 +490,24 @@ cleanup:
 }
 
 /**
- * msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
- * @domain:    The domain to managing the interrupts
+ * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
+ * @domain:    The domain to allocate from
  * @dev:       Pointer to device struct of the device for which the interrupts
- *             are free
+ *             are allocated
+ * @nvec:      The number of interrupts to allocate
+ *
+ * Returns 0 on success or an error code.
  */
-void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
+int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
+                         int nvec)
+{
+       struct msi_domain_info *info = domain->host_data;
+       struct msi_domain_ops *ops = info->ops;
+
+       return ops->domain_alloc_irqs(domain, dev, nvec);
+}
+
+void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
 {
        struct msi_desc *desc;
 
@@ -514,6 +525,20 @@ void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
 }
 
 /**
+ * __msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
+ * @domain:    The domain to managing the interrupts
+ * @dev:       Pointer to device struct of the device for which the interrupts
+ *             are free
+ */
+void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
+{
+       struct msi_domain_info *info = domain->host_data;
+       struct msi_domain_ops *ops = info->ops;
+
+       return ops->domain_free_irqs(domain, dev);
+}
+
+/**
  * msi_get_domain_info - Get the MSI interrupt domain info for @domain
  * @domain:    The interrupt domain to retrieve data from
  *
index c6c7e18..ce0adb2 100644 (file)
@@ -69,12 +69,26 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action)
 
 static bool suspend_device_irq(struct irq_desc *desc)
 {
+       unsigned long chipflags = irq_desc_get_chip(desc)->flags;
+       struct irq_data *irqd = &desc->irq_data;
+
        if (!desc->action || irq_desc_is_chained(desc) ||
            desc->no_suspend_depth)
                return false;
 
-       if (irqd_is_wakeup_set(&desc->irq_data)) {
-               irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED);
+       if (irqd_is_wakeup_set(irqd)) {
+               irqd_set(irqd, IRQD_WAKEUP_ARMED);
+
+               if ((chipflags & IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND) &&
+                    irqd_irq_disabled(irqd)) {
+                       /*
+                        * Interrupt marked for wakeup is in disabled state.
+                        * Enable interrupt here to unmask/enable in irqchip
+                        * to be able to resume with such interrupts.
+                        */
+                       __enable_irq(desc);
+                       irqd_set(irqd, IRQD_IRQ_ENABLED_ON_SUSPEND);
+               }
                /*
                 * We return true here to force the caller to issue
                 * synchronize_irq(). We need to make sure that the
@@ -93,7 +107,7 @@ static bool suspend_device_irq(struct irq_desc *desc)
         * chip level. The chip implementation indicates that with
         * IRQCHIP_MASK_ON_SUSPEND.
         */
-       if (irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
+       if (chipflags & IRQCHIP_MASK_ON_SUSPEND)
                mask_irq(desc);
        return true;
 }
@@ -137,7 +151,19 @@ EXPORT_SYMBOL_GPL(suspend_device_irqs);
 
 static void resume_irq(struct irq_desc *desc)
 {
-       irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED);
+       struct irq_data *irqd = &desc->irq_data;
+
+       irqd_clear(irqd, IRQD_WAKEUP_ARMED);
+
+       if (irqd_is_enabled_on_suspend(irqd)) {
+               /*
+                * Interrupt marked for wakeup was enabled during suspend
+                * entry. Disable such interrupts to restore them back to
+                * original state.
+                */
+               __disable_irq(desc);
+               irqd_clear(irqd, IRQD_IRQ_ENABLED_ON_SUSPEND);
+       }
 
        if (desc->istate & IRQS_SUSPENDED)
                goto resume;
index 32c071d..72513ed 100644 (file)
@@ -485,7 +485,7 @@ int show_interrupts(struct seq_file *p, void *v)
 
        rcu_read_lock();
        desc = irq_to_desc(i);
-       if (!desc)
+       if (!desc || irq_settings_is_hidden(desc))
                goto outsparse;
 
        if (desc->kstat_irqs)
index c48ce19..8ccd32a 100644 (file)
@@ -86,6 +86,18 @@ static int irq_sw_resend(struct irq_desc *desc)
 }
 #endif
 
+static int try_retrigger(struct irq_desc *desc)
+{
+       if (desc->irq_data.chip->irq_retrigger)
+               return desc->irq_data.chip->irq_retrigger(&desc->irq_data);
+
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+       return irq_chip_retrigger_hierarchy(&desc->irq_data);
+#else
+       return 0;
+#endif
+}
+
 /*
  * IRQ resend
  *
@@ -113,8 +125,7 @@ int check_irq_resend(struct irq_desc *desc, bool inject)
 
        desc->istate &= ~IRQS_PENDING;
 
-       if (!desc->irq_data.chip->irq_retrigger ||
-           !desc->irq_data.chip->irq_retrigger(&desc->irq_data))
+       if (!try_retrigger(desc))
                err = irq_sw_resend(desc);
 
        /* If the retrigger was successfull, mark it with the REPLAY bit */
index e43795c..403378b 100644 (file)
@@ -17,6 +17,7 @@ enum {
        _IRQ_PER_CPU_DEVID      = IRQ_PER_CPU_DEVID,
        _IRQ_IS_POLLED          = IRQ_IS_POLLED,
        _IRQ_DISABLE_UNLAZY     = IRQ_DISABLE_UNLAZY,
+       _IRQ_HIDDEN             = IRQ_HIDDEN,
        _IRQF_MODIFY_MASK       = IRQF_MODIFY_MASK,
 };
 
@@ -31,6 +32,7 @@ enum {
 #define IRQ_PER_CPU_DEVID      GOT_YOU_MORON
 #define IRQ_IS_POLLED          GOT_YOU_MORON
 #define IRQ_DISABLE_UNLAZY     GOT_YOU_MORON
+#define IRQ_HIDDEN             GOT_YOU_MORON
 #undef IRQF_MODIFY_MASK
 #define IRQF_MODIFY_MASK       GOT_YOU_MORON
 
@@ -167,3 +169,8 @@ static inline void irq_settings_clr_disable_unlazy(struct irq_desc *desc)
 {
        desc->status_use_accessors &= ~_IRQ_DISABLE_UNLAZY;
 }
+
+static inline bool irq_settings_is_hidden(struct irq_desc *desc)
+{
+       return desc->status_use_accessors & _IRQ_HIDDEN;
+}
index cdb3ffa..e661c61 100644 (file)
@@ -539,19 +539,25 @@ static void static_key_set_mod(struct static_key *key,
 static int __jump_label_mod_text_reserved(void *start, void *end)
 {
        struct module *mod;
+       int ret;
 
        preempt_disable();
        mod = __module_text_address((unsigned long)start);
        WARN_ON_ONCE(__module_text_address((unsigned long)end) != mod);
+       if (!try_module_get(mod))
+               mod = NULL;
        preempt_enable();
 
        if (!mod)
                return 0;
 
-
-       return __jump_label_text_reserved(mod->jump_entries,
+       ret = __jump_label_text_reserved(mod->jump_entries,
                                mod->jump_entries + mod->num_jump_entries,
                                start, end);
+
+       module_put(mod);
+
+       return ret;
 }
 
 static void __jump_label_mod_update(struct static_key *key)
index 95cb74f..4fb15fa 100644 (file)
@@ -684,12 +684,12 @@ bool kallsyms_show_value(const struct cred *cred)
        case 0:
                if (kallsyms_for_perf())
                        return true;
-       /* fallthrough */
+               fallthrough;
        case 1:
                if (security_capable(cred, &init_user_ns, CAP_SYSLOG,
                                     CAP_OPT_NOAUDIT) == 0)
                        return true;
-       /* fallthrough */
+               fallthrough;
        default:
                return false;
        }
index 9147ff6..3994a21 100644 (file)
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
+#define pr_fmt(fmt) "kcsan: " fmt
+
 #include <linux/atomic.h>
 #include <linux/bug.h>
 #include <linux/delay.h>
@@ -98,6 +100,9 @@ static atomic_long_t watchpoints[CONFIG_KCSAN_NUM_WATCHPOINTS + NUM_SLOTS-1];
  */
 static DEFINE_PER_CPU(long, kcsan_skip);
 
+/* For kcsan_prandom_u32_max(). */
+static DEFINE_PER_CPU(struct rnd_state, kcsan_rand_state);
+
 static __always_inline atomic_long_t *find_watchpoint(unsigned long addr,
                                                      size_t size,
                                                      bool expect_write,
@@ -223,7 +228,7 @@ is_atomic(const volatile void *ptr, size_t size, int type, struct kcsan_ctx *ctx
 
        if (IS_ENABLED(CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC) &&
            (type & KCSAN_ACCESS_WRITE) && size <= sizeof(long) &&
-           IS_ALIGNED((unsigned long)ptr, size))
+           !(type & KCSAN_ACCESS_COMPOUND) && IS_ALIGNED((unsigned long)ptr, size))
                return true; /* Assume aligned writes up to word size are atomic. */
 
        if (ctx->atomic_next > 0) {
@@ -269,11 +274,28 @@ should_watch(const volatile void *ptr, size_t size, int type, struct kcsan_ctx *
        return true;
 }
 
+/*
+ * Returns a pseudo-random number in interval [0, ep_ro). See prandom_u32_max()
+ * for more details.
+ *
+ * The open-coded version here is using only safe primitives for all contexts
+ * where we can have KCSAN instrumentation. In particular, we cannot use
+ * prandom_u32() directly, as its tracepoint could cause recursion.
+ */
+static u32 kcsan_prandom_u32_max(u32 ep_ro)
+{
+       struct rnd_state *state = &get_cpu_var(kcsan_rand_state);
+       const u32 res = prandom_u32_state(state);
+
+       put_cpu_var(kcsan_rand_state);
+       return (u32)(((u64) res * ep_ro) >> 32);
+}
+
 static inline void reset_kcsan_skip(void)
 {
        long skip_count = kcsan_skip_watch -
                          (IS_ENABLED(CONFIG_KCSAN_SKIP_WATCH_RANDOMIZE) ?
-                                  prandom_u32_max(kcsan_skip_watch) :
+                                  kcsan_prandom_u32_max(kcsan_skip_watch) :
                                   0);
        this_cpu_write(kcsan_skip, skip_count);
 }
@@ -283,12 +305,18 @@ static __always_inline bool kcsan_is_enabled(void)
        return READ_ONCE(kcsan_enabled) && get_ctx()->disable_count == 0;
 }
 
-static inline unsigned int get_delay(void)
+/* Introduce delay depending on context and configuration. */
+static void delay_access(int type)
 {
        unsigned int delay = in_task() ? kcsan_udelay_task : kcsan_udelay_interrupt;
-       return delay - (IS_ENABLED(CONFIG_KCSAN_DELAY_RANDOMIZE) ?
-                               prandom_u32_max(delay) :
-                               0);
+       /* For certain access types, skew the random delay to be longer. */
+       unsigned int skew_delay_order =
+               (type & (KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_ASSERT)) ? 1 : 0;
+
+       delay -= IS_ENABLED(CONFIG_KCSAN_DELAY_RANDOMIZE) ?
+                              kcsan_prandom_u32_max(delay >> skew_delay_order) :
+                              0;
+       udelay(delay);
 }
 
 void kcsan_save_irqtrace(struct task_struct *task)
@@ -361,13 +389,13 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr,
                 * already removed the watchpoint, or another thread consumed
                 * the watchpoint before this thread.
                 */
-               kcsan_counter_inc(KCSAN_COUNTER_REPORT_RACES);
+               atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_REPORT_RACES]);
        }
 
        if ((type & KCSAN_ACCESS_ASSERT) != 0)
-               kcsan_counter_inc(KCSAN_COUNTER_ASSERT_FAILURES);
+               atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]);
        else
-               kcsan_counter_inc(KCSAN_COUNTER_DATA_RACES);
+               atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_DATA_RACES]);
 
        user_access_restore(flags);
 }
@@ -408,7 +436,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
                goto out;
 
        if (!check_encodable((unsigned long)ptr, size)) {
-               kcsan_counter_inc(KCSAN_COUNTER_UNENCODABLE_ACCESSES);
+               atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_UNENCODABLE_ACCESSES]);
                goto out;
        }
 
@@ -428,12 +456,12 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
                 * with which should_watch() returns true should be tweaked so
                 * that this case happens very rarely.
                 */
-               kcsan_counter_inc(KCSAN_COUNTER_NO_CAPACITY);
+               atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_NO_CAPACITY]);
                goto out_unlock;
        }
 
-       kcsan_counter_inc(KCSAN_COUNTER_SETUP_WATCHPOINTS);
-       kcsan_counter_inc(KCSAN_COUNTER_USED_WATCHPOINTS);
+       atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_SETUP_WATCHPOINTS]);
+       atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_USED_WATCHPOINTS]);
 
        /*
         * Read the current value, to later check and infer a race if the data
@@ -459,7 +487,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
 
        if (IS_ENABLED(CONFIG_KCSAN_DEBUG)) {
                kcsan_disable_current();
-               pr_err("KCSAN: watching %s, size: %zu, addr: %px [slot: %d, encoded: %lx]\n",
+               pr_err("watching %s, size: %zu, addr: %px [slot: %d, encoded: %lx]\n",
                       is_write ? "write" : "read", size, ptr,
                       watchpoint_slot((unsigned long)ptr),
                       encode_watchpoint((unsigned long)ptr, size, is_write));
@@ -470,7 +498,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
         * Delay this thread, to increase probability of observing a racy
         * conflicting access.
         */
-       udelay(get_delay());
+       delay_access(type);
 
        /*
         * Re-read value, and check if it is as expected; if not, we infer a
@@ -535,16 +563,16 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
                 * increment this counter.
                 */
                if (is_assert && value_change == KCSAN_VALUE_CHANGE_TRUE)
-                       kcsan_counter_inc(KCSAN_COUNTER_ASSERT_FAILURES);
+                       atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]);
 
                kcsan_report(ptr, size, type, value_change, KCSAN_REPORT_RACE_SIGNAL,
                             watchpoint - watchpoints);
        } else if (value_change == KCSAN_VALUE_CHANGE_TRUE) {
                /* Inferring a race, since the value should not have changed. */
 
-               kcsan_counter_inc(KCSAN_COUNTER_RACES_UNKNOWN_ORIGIN);
+               atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_RACES_UNKNOWN_ORIGIN]);
                if (is_assert)
-                       kcsan_counter_inc(KCSAN_COUNTER_ASSERT_FAILURES);
+                       atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]);
 
                if (IS_ENABLED(CONFIG_KCSAN_REPORT_RACE_UNKNOWN_ORIGIN) || is_assert)
                        kcsan_report(ptr, size, type, KCSAN_VALUE_CHANGE_TRUE,
@@ -557,7 +585,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
         * reused after this point.
         */
        remove_watchpoint(watchpoint);
-       kcsan_counter_dec(KCSAN_COUNTER_USED_WATCHPOINTS);
+       atomic_long_dec(&kcsan_counters[KCSAN_COUNTER_USED_WATCHPOINTS]);
 out_unlock:
        if (!kcsan_interrupt_watcher)
                local_irq_restore(irq_flags);
@@ -614,13 +642,16 @@ void __init kcsan_init(void)
        BUG_ON(!in_task());
 
        kcsan_debugfs_init();
+       prandom_seed_full_state(&kcsan_rand_state);
 
        /*
         * We are in the init task, and no other tasks should be running;
         * WRITE_ONCE without memory barrier is sufficient.
         */
-       if (kcsan_early_enable)
+       if (kcsan_early_enable) {
+               pr_info("enabled early\n");
                WRITE_ONCE(kcsan_enabled, true);
+       }
 }
 
 /* === Exported interface =================================================== */
@@ -793,7 +824,17 @@ EXPORT_SYMBOL(__kcsan_check_access);
        EXPORT_SYMBOL(__tsan_write##size);                                     \
        void __tsan_unaligned_write##size(void *ptr)                           \
                __alias(__tsan_write##size);                                   \
-       EXPORT_SYMBOL(__tsan_unaligned_write##size)
+       EXPORT_SYMBOL(__tsan_unaligned_write##size);                           \
+       void __tsan_read_write##size(void *ptr);                               \
+       void __tsan_read_write##size(void *ptr)                                \
+       {                                                                      \
+               check_access(ptr, size,                                        \
+                            KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE);      \
+       }                                                                      \
+       EXPORT_SYMBOL(__tsan_read_write##size);                                \
+       void __tsan_unaligned_read_write##size(void *ptr)                      \
+               __alias(__tsan_read_write##size);                              \
+       EXPORT_SYMBOL(__tsan_unaligned_read_write##size)
 
 DEFINE_TSAN_READ_WRITE(1);
 DEFINE_TSAN_READ_WRITE(2);
@@ -879,3 +920,130 @@ void __tsan_init(void)
 {
 }
 EXPORT_SYMBOL(__tsan_init);
+
+/*
+ * Instrumentation for atomic builtins (__atomic_*, __sync_*).
+ *
+ * Normal kernel code _should not_ be using them directly, but some
+ * architectures may implement some or all atomics using the compilers'
+ * builtins.
+ *
+ * Note: If an architecture decides to fully implement atomics using the
+ * builtins, because they are implicitly instrumented by KCSAN (and KASAN,
+ * etc.), implementing the ARCH_ATOMIC interface (to get instrumentation via
+ * atomic-instrumented) is no longer necessary.
+ *
+ * TSAN instrumentation replaces atomic accesses with calls to any of the below
+ * functions, whose job is to also execute the operation itself.
+ */
+
+#define DEFINE_TSAN_ATOMIC_LOAD_STORE(bits)                                                        \
+       u##bits __tsan_atomic##bits##_load(const u##bits *ptr, int memorder);                      \
+       u##bits __tsan_atomic##bits##_load(const u##bits *ptr, int memorder)                       \
+       {                                                                                          \
+               if (!IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) {                                    \
+                       check_access(ptr, bits / BITS_PER_BYTE, KCSAN_ACCESS_ATOMIC);              \
+               }                                                                                  \
+               return __atomic_load_n(ptr, memorder);                                             \
+       }                                                                                          \
+       EXPORT_SYMBOL(__tsan_atomic##bits##_load);                                                 \
+       void __tsan_atomic##bits##_store(u##bits *ptr, u##bits v, int memorder);                   \
+       void __tsan_atomic##bits##_store(u##bits *ptr, u##bits v, int memorder)                    \
+       {                                                                                          \
+               if (!IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) {                                    \
+                       check_access(ptr, bits / BITS_PER_BYTE,                                    \
+                                    KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC);                    \
+               }                                                                                  \
+               __atomic_store_n(ptr, v, memorder);                                                \
+       }                                                                                          \
+       EXPORT_SYMBOL(__tsan_atomic##bits##_store)
+
+#define DEFINE_TSAN_ATOMIC_RMW(op, bits, suffix)                                                   \
+       u##bits __tsan_atomic##bits##_##op(u##bits *ptr, u##bits v, int memorder);                 \
+       u##bits __tsan_atomic##bits##_##op(u##bits *ptr, u##bits v, int memorder)                  \
+       {                                                                                          \
+               if (!IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) {                                    \
+                       check_access(ptr, bits / BITS_PER_BYTE,                                    \
+                                    KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE |                  \
+                                            KCSAN_ACCESS_ATOMIC);                                 \
+               }                                                                                  \
+               return __atomic_##op##suffix(ptr, v, memorder);                                    \
+       }                                                                                          \
+       EXPORT_SYMBOL(__tsan_atomic##bits##_##op)
+
+/*
+ * Note: CAS operations are always classified as write, even in case they
+ * fail. We cannot perform check_access() after a write, as it might lead to
+ * false positives, in cases such as:
+ *
+ *     T0: __atomic_compare_exchange_n(&p->flag, &old, 1, ...)
+ *
+ *     T1: if (__atomic_load_n(&p->flag, ...)) {
+ *             modify *p;
+ *             p->flag = 0;
+ *         }
+ *
+ * The only downside is that, if there are 3 threads, with one CAS that
+ * succeeds, another CAS that fails, and an unmarked racing operation, we may
+ * point at the wrong CAS as the source of the race. However, if we assume that
+ * all CAS can succeed in some other execution, the data race is still valid.
+ */
+#define DEFINE_TSAN_ATOMIC_CMPXCHG(bits, strength, weak)                                           \
+       int __tsan_atomic##bits##_compare_exchange_##strength(u##bits *ptr, u##bits *exp,          \
+                                                             u##bits val, int mo, int fail_mo);   \
+       int __tsan_atomic##bits##_compare_exchange_##strength(u##bits *ptr, u##bits *exp,          \
+                                                             u##bits val, int mo, int fail_mo)    \
+       {                                                                                          \
+               if (!IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) {                                    \
+                       check_access(ptr, bits / BITS_PER_BYTE,                                    \
+                                    KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE |                  \
+                                            KCSAN_ACCESS_ATOMIC);                                 \
+               }                                                                                  \
+               return __atomic_compare_exchange_n(ptr, exp, val, weak, mo, fail_mo);              \
+       }                                                                                          \
+       EXPORT_SYMBOL(__tsan_atomic##bits##_compare_exchange_##strength)
+
+#define DEFINE_TSAN_ATOMIC_CMPXCHG_VAL(bits)                                                       \
+       u##bits __tsan_atomic##bits##_compare_exchange_val(u##bits *ptr, u##bits exp, u##bits val, \
+                                                          int mo, int fail_mo);                   \
+       u##bits __tsan_atomic##bits##_compare_exchange_val(u##bits *ptr, u##bits exp, u##bits val, \
+                                                          int mo, int fail_mo)                    \
+       {                                                                                          \
+               if (!IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) {                                    \
+                       check_access(ptr, bits / BITS_PER_BYTE,                                    \
+                                    KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE |                  \
+                                            KCSAN_ACCESS_ATOMIC);                                 \
+               }                                                                                  \
+               __atomic_compare_exchange_n(ptr, &exp, val, 0, mo, fail_mo);                       \
+               return exp;                                                                        \
+       }                                                                                          \
+       EXPORT_SYMBOL(__tsan_atomic##bits##_compare_exchange_val)
+
+#define DEFINE_TSAN_ATOMIC_OPS(bits)                                                               \
+       DEFINE_TSAN_ATOMIC_LOAD_STORE(bits);                                                       \
+       DEFINE_TSAN_ATOMIC_RMW(exchange, bits, _n);                                                \
+       DEFINE_TSAN_ATOMIC_RMW(fetch_add, bits, );                                                 \
+       DEFINE_TSAN_ATOMIC_RMW(fetch_sub, bits, );                                                 \
+       DEFINE_TSAN_ATOMIC_RMW(fetch_and, bits, );                                                 \
+       DEFINE_TSAN_ATOMIC_RMW(fetch_or, bits, );                                                  \
+       DEFINE_TSAN_ATOMIC_RMW(fetch_xor, bits, );                                                 \
+       DEFINE_TSAN_ATOMIC_RMW(fetch_nand, bits, );                                                \
+       DEFINE_TSAN_ATOMIC_CMPXCHG(bits, strong, 0);                                               \
+       DEFINE_TSAN_ATOMIC_CMPXCHG(bits, weak, 1);                                                 \
+       DEFINE_TSAN_ATOMIC_CMPXCHG_VAL(bits)
+
+DEFINE_TSAN_ATOMIC_OPS(8);
+DEFINE_TSAN_ATOMIC_OPS(16);
+DEFINE_TSAN_ATOMIC_OPS(32);
+DEFINE_TSAN_ATOMIC_OPS(64);
+
+void __tsan_atomic_thread_fence(int memorder);
+void __tsan_atomic_thread_fence(int memorder)
+{
+       __atomic_thread_fence(memorder);
+}
+EXPORT_SYMBOL(__tsan_atomic_thread_fence);
+
+void __tsan_atomic_signal_fence(int memorder);
+void __tsan_atomic_signal_fence(int memorder) { }
+EXPORT_SYMBOL(__tsan_atomic_signal_fence);
index 023e49c..3c8093a 100644 (file)
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
+#define pr_fmt(fmt) "kcsan: " fmt
+
 #include <linux/atomic.h>
 #include <linux/bsearch.h>
 #include <linux/bug.h>
 
 #include "kcsan.h"
 
-/*
- * Statistics counters.
- */
-static atomic_long_t counters[KCSAN_COUNTER_COUNT];
+atomic_long_t kcsan_counters[KCSAN_COUNTER_COUNT];
+static const char *const counter_names[] = {
+       [KCSAN_COUNTER_USED_WATCHPOINTS]                = "used_watchpoints",
+       [KCSAN_COUNTER_SETUP_WATCHPOINTS]               = "setup_watchpoints",
+       [KCSAN_COUNTER_DATA_RACES]                      = "data_races",
+       [KCSAN_COUNTER_ASSERT_FAILURES]                 = "assert_failures",
+       [KCSAN_COUNTER_NO_CAPACITY]                     = "no_capacity",
+       [KCSAN_COUNTER_REPORT_RACES]                    = "report_races",
+       [KCSAN_COUNTER_RACES_UNKNOWN_ORIGIN]            = "races_unknown_origin",
+       [KCSAN_COUNTER_UNENCODABLE_ACCESSES]            = "unencodable_accesses",
+       [KCSAN_COUNTER_ENCODING_FALSE_POSITIVES]        = "encoding_false_positives",
+};
+static_assert(ARRAY_SIZE(counter_names) == KCSAN_COUNTER_COUNT);
 
 /*
  * Addresses for filtering functions from reporting. This list can be used as a
@@ -39,34 +50,6 @@ static struct {
 };
 static DEFINE_SPINLOCK(report_filterlist_lock);
 
-static const char *counter_to_name(enum kcsan_counter_id id)
-{
-       switch (id) {
-       case KCSAN_COUNTER_USED_WATCHPOINTS:            return "used_watchpoints";
-       case KCSAN_COUNTER_SETUP_WATCHPOINTS:           return "setup_watchpoints";
-       case KCSAN_COUNTER_DATA_RACES:                  return "data_races";
-       case KCSAN_COUNTER_ASSERT_FAILURES:             return "assert_failures";
-       case KCSAN_COUNTER_NO_CAPACITY:                 return "no_capacity";
-       case KCSAN_COUNTER_REPORT_RACES:                return "report_races";
-       case KCSAN_COUNTER_RACES_UNKNOWN_ORIGIN:        return "races_unknown_origin";
-       case KCSAN_COUNTER_UNENCODABLE_ACCESSES:        return "unencodable_accesses";
-       case KCSAN_COUNTER_ENCODING_FALSE_POSITIVES:    return "encoding_false_positives";
-       case KCSAN_COUNTER_COUNT:
-               BUG();
-       }
-       return NULL;
-}
-
-void kcsan_counter_inc(enum kcsan_counter_id id)
-{
-       atomic_long_inc(&counters[id]);
-}
-
-void kcsan_counter_dec(enum kcsan_counter_id id)
-{
-       atomic_long_dec(&counters[id]);
-}
-
 /*
  * The microbenchmark allows benchmarking KCSAN core runtime only. To run
  * multiple threads, pipe 'microbench=<iters>' from multiple tasks into the
@@ -86,7 +69,7 @@ static noinline void microbenchmark(unsigned long iters)
         */
        WRITE_ONCE(kcsan_enabled, false);
 
-       pr_info("KCSAN: %s begin | iters: %lu\n", __func__, iters);
+       pr_info("%s begin | iters: %lu\n", __func__, iters);
 
        cycles = get_cycles();
        while (iters--) {
@@ -97,73 +80,13 @@ static noinline void microbenchmark(unsigned long iters)
        }
        cycles = get_cycles() - cycles;
 
-       pr_info("KCSAN: %s end   | cycles: %llu\n", __func__, cycles);
+       pr_info("%s end   | cycles: %llu\n", __func__, cycles);
 
        WRITE_ONCE(kcsan_enabled, was_enabled);
        /* restore context */
        current->kcsan_ctx = ctx_save;
 }
 
-/*
- * Simple test to create conflicting accesses. Write 'test=<iters>' to KCSAN's
- * debugfs file from multiple tasks to generate real conflicts and show reports.
- */
-static long test_dummy;
-static long test_flags;
-static long test_scoped;
-static noinline void test_thread(unsigned long iters)
-{
-       const long CHANGE_BITS = 0xff00ff00ff00ff00L;
-       const struct kcsan_ctx ctx_save = current->kcsan_ctx;
-       cycles_t cycles;
-
-       /* We may have been called from an atomic region; reset context. */
-       memset(&current->kcsan_ctx, 0, sizeof(current->kcsan_ctx));
-
-       pr_info("KCSAN: %s begin | iters: %lu\n", __func__, iters);
-       pr_info("test_dummy@%px, test_flags@%px, test_scoped@%px,\n",
-               &test_dummy, &test_flags, &test_scoped);
-
-       cycles = get_cycles();
-       while (iters--) {
-               /* These all should generate reports. */
-               __kcsan_check_read(&test_dummy, sizeof(test_dummy));
-               ASSERT_EXCLUSIVE_WRITER(test_dummy);
-               ASSERT_EXCLUSIVE_ACCESS(test_dummy);
-
-               ASSERT_EXCLUSIVE_BITS(test_flags, ~CHANGE_BITS); /* no report */
-               __kcsan_check_read(&test_flags, sizeof(test_flags)); /* no report */
-
-               ASSERT_EXCLUSIVE_BITS(test_flags, CHANGE_BITS); /* report */
-               __kcsan_check_read(&test_flags, sizeof(test_flags)); /* no report */
-
-               /* not actually instrumented */
-               WRITE_ONCE(test_dummy, iters);  /* to observe value-change */
-               __kcsan_check_write(&test_dummy, sizeof(test_dummy));
-
-               test_flags ^= CHANGE_BITS; /* generate value-change */
-               __kcsan_check_write(&test_flags, sizeof(test_flags));
-
-               BUG_ON(current->kcsan_ctx.scoped_accesses.prev);
-               {
-                       /* Should generate reports anywhere in this block. */
-                       ASSERT_EXCLUSIVE_WRITER_SCOPED(test_scoped);
-                       ASSERT_EXCLUSIVE_ACCESS_SCOPED(test_scoped);
-                       BUG_ON(!current->kcsan_ctx.scoped_accesses.prev);
-                       /* Unrelated accesses. */
-                       __kcsan_check_access(&cycles, sizeof(cycles), 0);
-                       __kcsan_check_access(&cycles, sizeof(cycles), KCSAN_ACCESS_ATOMIC);
-               }
-               BUG_ON(current->kcsan_ctx.scoped_accesses.prev);
-       }
-       cycles = get_cycles() - cycles;
-
-       pr_info("KCSAN: %s end   | cycles: %llu\n", __func__, cycles);
-
-       /* restore context */
-       current->kcsan_ctx = ctx_save;
-}
-
 static int cmp_filterlist_addrs(const void *rhs, const void *lhs)
 {
        const unsigned long a = *(const unsigned long *)rhs;
@@ -220,7 +143,7 @@ static ssize_t insert_report_filterlist(const char *func)
        ssize_t ret = 0;
 
        if (!addr) {
-               pr_err("KCSAN: could not find function: '%s'\n", func);
+               pr_err("could not find function: '%s'\n", func);
                return -ENOENT;
        }
 
@@ -270,9 +193,10 @@ static int show_info(struct seq_file *file, void *v)
 
        /* show stats */
        seq_printf(file, "enabled: %i\n", READ_ONCE(kcsan_enabled));
-       for (i = 0; i < KCSAN_COUNTER_COUNT; ++i)
-               seq_printf(file, "%s: %ld\n", counter_to_name(i),
-                          atomic_long_read(&counters[i]));
+       for (i = 0; i < KCSAN_COUNTER_COUNT; ++i) {
+               seq_printf(file, "%s: %ld\n", counter_names[i],
+                          atomic_long_read(&kcsan_counters[i]));
+       }
 
        /* show filter functions, and filter type */
        spin_lock_irqsave(&report_filterlist_lock, flags);
@@ -307,18 +231,12 @@ debugfs_write(struct file *file, const char __user *buf, size_t count, loff_t *o
                WRITE_ONCE(kcsan_enabled, true);
        } else if (!strcmp(arg, "off")) {
                WRITE_ONCE(kcsan_enabled, false);
-       } else if (!strncmp(arg, "microbench=", sizeof("microbench=") - 1)) {
+       } else if (str_has_prefix(arg, "microbench=")) {
                unsigned long iters;
 
-               if (kstrtoul(&arg[sizeof("microbench=") - 1], 0, &iters))
+               if (kstrtoul(&arg[strlen("microbench=")], 0, &iters))
                        return -EINVAL;
                microbenchmark(iters);
-       } else if (!strncmp(arg, "test=", sizeof("test=") - 1)) {
-               unsigned long iters;
-
-               if (kstrtoul(&arg[sizeof("test=") - 1], 0, &iters))
-                       return -EINVAL;
-               test_thread(iters);
        } else if (!strcmp(arg, "whitelist")) {
                set_report_filterlist_whitelist(true);
        } else if (!strcmp(arg, "blacklist")) {
index fed6fcb..ebe7fd2 100644 (file)
 #include <linux/types.h>
 #include <trace/events/printk.h>
 
+#ifdef CONFIG_CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE
+#define __KCSAN_ACCESS_RW(alt) (KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE)
+#else
+#define __KCSAN_ACCESS_RW(alt) (alt)
+#endif
+
 /* Points to current test-case memory access "kernels". */
 static void (*access_kernels[2])(void);
 
@@ -186,20 +192,21 @@ static bool report_matches(const struct expect_report *r)
 
        /* Access 1 & 2 */
        for (i = 0; i < 2; ++i) {
+               const int ty = r->access[i].type;
                const char *const access_type =
-                       (r->access[i].type & KCSAN_ACCESS_ASSERT) ?
-                               ((r->access[i].type & KCSAN_ACCESS_WRITE) ?
-                                        "assert no accesses" :
-                                        "assert no writes") :
-                               ((r->access[i].type & KCSAN_ACCESS_WRITE) ?
-                                        "write" :
-                                        "read");
+                       (ty & KCSAN_ACCESS_ASSERT) ?
+                                     ((ty & KCSAN_ACCESS_WRITE) ?
+                                              "assert no accesses" :
+                                              "assert no writes") :
+                                     ((ty & KCSAN_ACCESS_WRITE) ?
+                                              ((ty & KCSAN_ACCESS_COMPOUND) ?
+                                                       "read-write" :
+                                                       "write") :
+                                              "read");
                const char *const access_type_aux =
-                       (r->access[i].type & KCSAN_ACCESS_ATOMIC) ?
-                               " (marked)" :
-                               ((r->access[i].type & KCSAN_ACCESS_SCOPED) ?
-                                        " (scoped)" :
-                                        "");
+                       (ty & KCSAN_ACCESS_ATOMIC) ?
+                                     " (marked)" :
+                                     ((ty & KCSAN_ACCESS_SCOPED) ? " (scoped)" : "");
 
                if (i == 1) {
                        /* Access 2 */
@@ -277,6 +284,12 @@ static noinline void test_kernel_write_atomic(void)
        WRITE_ONCE(test_var, READ_ONCE_NOCHECK(test_sink) + 1);
 }
 
+static noinline void test_kernel_atomic_rmw(void)
+{
+       /* Use builtin, so we can set up the "bad" atomic/non-atomic scenario. */
+       __atomic_fetch_add(&test_var, 1, __ATOMIC_RELAXED);
+}
+
 __no_kcsan
 static noinline void test_kernel_write_uninstrumented(void) { test_var++; }
 
@@ -390,6 +403,15 @@ static noinline void test_kernel_seqlock_writer(void)
        write_sequnlock_irqrestore(&test_seqlock, flags);
 }
 
+static noinline void test_kernel_atomic_builtins(void)
+{
+       /*
+        * Generate concurrent accesses, expecting no reports, ensuring KCSAN
+        * treats builtin atomics as actually atomic.
+        */
+       __atomic_load_n(&test_var, __ATOMIC_RELAXED);
+}
+
 /* ===== Test cases ===== */
 
 /* Simple test with normal data race. */
@@ -430,8 +452,8 @@ static void test_concurrent_races(struct kunit *test)
        const struct expect_report expect = {
                .access = {
                        /* NULL will match any address. */
-                       { test_kernel_rmw_array, NULL, 0, KCSAN_ACCESS_WRITE },
-                       { test_kernel_rmw_array, NULL, 0, 0 },
+                       { test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(KCSAN_ACCESS_WRITE) },
+                       { test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(0) },
                },
        };
        static const struct expect_report never = {
@@ -620,6 +642,29 @@ static void test_read_plain_atomic_write(struct kunit *test)
        KUNIT_EXPECT_TRUE(test, match_expect);
 }
 
+/* Test that atomic RMWs generate correct report. */
+__no_kcsan
+static void test_read_plain_atomic_rmw(struct kunit *test)
+{
+       const struct expect_report expect = {
+               .access = {
+                       { test_kernel_read, &test_var, sizeof(test_var), 0 },
+                       { test_kernel_atomic_rmw, &test_var, sizeof(test_var),
+                               KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC },
+               },
+       };
+       bool match_expect = false;
+
+       if (IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS))
+               return;
+
+       begin_test_checks(test_kernel_read, test_kernel_atomic_rmw);
+       do {
+               match_expect = report_matches(&expect);
+       } while (!end_test_checks(match_expect));
+       KUNIT_EXPECT_TRUE(test, match_expect);
+}
+
 /* Zero-sized accesses should never cause data race reports. */
 __no_kcsan
 static void test_zero_size_access(struct kunit *test)
@@ -853,6 +898,59 @@ static void test_seqlock_noreport(struct kunit *test)
 }
 
 /*
+ * Test atomic builtins work and required instrumentation functions exist. We
+ * also test that KCSAN understands they're atomic by racing with them via
+ * test_kernel_atomic_builtins(), and expect no reports.
+ *
+ * The atomic builtins _SHOULD NOT_ be used in normal kernel code!
+ */
+static void test_atomic_builtins(struct kunit *test)
+{
+       bool match_never = false;
+
+       begin_test_checks(test_kernel_atomic_builtins, test_kernel_atomic_builtins);
+       do {
+               long tmp;
+
+               kcsan_enable_current();
+
+               __atomic_store_n(&test_var, 42L, __ATOMIC_RELAXED);
+               KUNIT_EXPECT_EQ(test, 42L, __atomic_load_n(&test_var, __ATOMIC_RELAXED));
+
+               KUNIT_EXPECT_EQ(test, 42L, __atomic_exchange_n(&test_var, 20, __ATOMIC_RELAXED));
+               KUNIT_EXPECT_EQ(test, 20L, test_var);
+
+               tmp = 20L;
+               KUNIT_EXPECT_TRUE(test, __atomic_compare_exchange_n(&test_var, &tmp, 30L,
+                                                                   0, __ATOMIC_RELAXED,
+                                                                   __ATOMIC_RELAXED));
+               KUNIT_EXPECT_EQ(test, tmp, 20L);
+               KUNIT_EXPECT_EQ(test, test_var, 30L);
+               KUNIT_EXPECT_FALSE(test, __atomic_compare_exchange_n(&test_var, &tmp, 40L,
+                                                                    1, __ATOMIC_RELAXED,
+                                                                    __ATOMIC_RELAXED));
+               KUNIT_EXPECT_EQ(test, tmp, 30L);
+               KUNIT_EXPECT_EQ(test, test_var, 30L);
+
+               KUNIT_EXPECT_EQ(test, 30L, __atomic_fetch_add(&test_var, 1, __ATOMIC_RELAXED));
+               KUNIT_EXPECT_EQ(test, 31L, __atomic_fetch_sub(&test_var, 1, __ATOMIC_RELAXED));
+               KUNIT_EXPECT_EQ(test, 30L, __atomic_fetch_and(&test_var, 0xf, __ATOMIC_RELAXED));
+               KUNIT_EXPECT_EQ(test, 14L, __atomic_fetch_xor(&test_var, 0xf, __ATOMIC_RELAXED));
+               KUNIT_EXPECT_EQ(test, 1L, __atomic_fetch_or(&test_var, 0xf0, __ATOMIC_RELAXED));
+               KUNIT_EXPECT_EQ(test, 241L, __atomic_fetch_nand(&test_var, 0xf, __ATOMIC_RELAXED));
+               KUNIT_EXPECT_EQ(test, -2L, test_var);
+
+               __atomic_thread_fence(__ATOMIC_SEQ_CST);
+               __atomic_signal_fence(__ATOMIC_SEQ_CST);
+
+               kcsan_disable_current();
+
+               match_never = report_available();
+       } while (!end_test_checks(match_never));
+       KUNIT_EXPECT_FALSE(test, match_never);
+}
+
+/*
  * Each test case is run with different numbers of threads. Until KUnit supports
  * passing arguments for each test case, we encode #threads in the test case
  * name (read by get_num_threads()). [The '-' was chosen as a stylistic
@@ -880,6 +978,7 @@ static struct kunit_case kcsan_test_cases[] = {
        KCSAN_KUNIT_CASE(test_write_write_struct_part),
        KCSAN_KUNIT_CASE(test_read_atomic_write_atomic),
        KCSAN_KUNIT_CASE(test_read_plain_atomic_write),
+       KCSAN_KUNIT_CASE(test_read_plain_atomic_rmw),
        KCSAN_KUNIT_CASE(test_zero_size_access),
        KCSAN_KUNIT_CASE(test_data_race),
        KCSAN_KUNIT_CASE(test_assert_exclusive_writer),
@@ -891,6 +990,7 @@ static struct kunit_case kcsan_test_cases[] = {
        KCSAN_KUNIT_CASE(test_assert_exclusive_access_scoped),
        KCSAN_KUNIT_CASE(test_jiffies_noreport),
        KCSAN_KUNIT_CASE(test_seqlock_noreport),
+       KCSAN_KUNIT_CASE(test_atomic_builtins),
        {},
 };
 
index 2948001..8d4bf34 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef _KERNEL_KCSAN_KCSAN_H
 #define _KERNEL_KCSAN_KCSAN_H
 
+#include <linux/atomic.h>
 #include <linux/kcsan.h>
 #include <linux/sched.h>
 
@@ -34,6 +35,10 @@ void kcsan_restore_irqtrace(struct task_struct *task);
  */
 void kcsan_debugfs_init(void);
 
+/*
+ * Statistics counters displayed via debugfs; should only be modified in
+ * slow-paths.
+ */
 enum kcsan_counter_id {
        /*
         * Number of watchpoints currently in use.
@@ -86,12 +91,7 @@ enum kcsan_counter_id {
 
        KCSAN_COUNTER_COUNT, /* number of counters */
 };
-
-/*
- * Increment/decrement counter with given id; avoid calling these in fast-path.
- */
-extern void kcsan_counter_inc(enum kcsan_counter_id id);
-extern void kcsan_counter_dec(enum kcsan_counter_id id);
+extern atomic_long_t kcsan_counters[KCSAN_COUNTER_COUNT];
 
 /*
  * Returns true if data races in the function symbol that maps to func_addr
index 9d07e17..d3bf87e 100644 (file)
@@ -228,6 +228,10 @@ static const char *get_access_type(int type)
                return "write";
        case KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC:
                return "write (marked)";
+       case KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE:
+               return "read-write";
+       case KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC:
+               return "read-write (marked)";
        case KCSAN_ACCESS_SCOPED:
                return "read (scoped)";
        case KCSAN_ACCESS_SCOPED | KCSAN_ACCESS_ATOMIC:
@@ -275,8 +279,8 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries
 
                cur = strnstr(buf, "kcsan_", len);
                if (cur) {
-                       cur += sizeof("kcsan_") - 1;
-                       if (strncmp(cur, "test", sizeof("test") - 1))
+                       cur += strlen("kcsan_");
+                       if (!str_has_prefix(cur, "test"))
                                continue; /* KCSAN runtime function. */
                        /* KCSAN related test. */
                }
@@ -555,7 +559,7 @@ static bool prepare_report_consumer(unsigned long *flags,
                 * If the actual accesses to not match, this was a false
                 * positive due to watchpoint encoding.
                 */
-               kcsan_counter_inc(KCSAN_COUNTER_ENCODING_FALSE_POSITIVES);
+               atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ENCODING_FALSE_POSITIVES]);
                goto discard;
        }
 
index d26a052..d98bc20 100644 (file)
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
+#define pr_fmt(fmt) "kcsan: " fmt
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/printk.h>
@@ -116,16 +118,16 @@ static int __init kcsan_selftest(void)
                if (do_test())                                                 \
                        ++passed;                                              \
                else                                                           \
-                       pr_err("KCSAN selftest: " #do_test " failed");         \
+                       pr_err("selftest: " #do_test " failed");               \
        } while (0)
 
        RUN_TEST(test_requires);
        RUN_TEST(test_encode_decode);
        RUN_TEST(test_matching_access);
 
-       pr_info("KCSAN selftest: %d/%d tests passed\n", passed, total);
+       pr_info("selftest: %d/%d tests passed\n", passed, total);
        if (passed != total)
-               panic("KCSAN selftests failed");
+               panic("selftests failed");
        return 0;
 }
 postcore_initcall(kcsan_selftest);
index 287b263..789002d 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/cpu.h>
 #include <linux/jump_label.h>
 #include <linux/perf_event.h>
+#include <linux/static_call.h>
 
 #include <asm/sections.h>
 #include <asm/cacheflush.h>
@@ -1223,8 +1224,7 @@ void kprobes_inc_nmissed_count(struct kprobe *p)
 }
 NOKPROBE_SYMBOL(kprobes_inc_nmissed_count);
 
-void recycle_rp_inst(struct kretprobe_instance *ri,
-                    struct hlist_head *head)
+static void recycle_rp_inst(struct kretprobe_instance *ri)
 {
        struct kretprobe *rp = ri->rp;
 
@@ -1236,12 +1236,11 @@ void recycle_rp_inst(struct kretprobe_instance *ri,
                hlist_add_head(&ri->hlist, &rp->free_instances);
                raw_spin_unlock(&rp->lock);
        } else
-               /* Unregistering */
-               hlist_add_head(&ri->hlist, head);
+               kfree_rcu(ri, rcu);
 }
 NOKPROBE_SYMBOL(recycle_rp_inst);
 
-void kretprobe_hash_lock(struct task_struct *tsk,
+static void kretprobe_hash_lock(struct task_struct *tsk,
                         struct hlist_head **head, unsigned long *flags)
 __acquires(hlist_lock)
 {
@@ -1263,7 +1262,7 @@ __acquires(hlist_lock)
 }
 NOKPROBE_SYMBOL(kretprobe_table_lock);
 
-void kretprobe_hash_unlock(struct task_struct *tsk,
+static void kretprobe_hash_unlock(struct task_struct *tsk,
                           unsigned long *flags)
 __releases(hlist_lock)
 {
@@ -1284,7 +1283,7 @@ __releases(hlist_lock)
 }
 NOKPROBE_SYMBOL(kretprobe_table_unlock);
 
-struct kprobe kprobe_busy = {
+static struct kprobe kprobe_busy = {
        .addr = (void *) get_kprobe,
 };
 
@@ -1313,7 +1312,7 @@ void kprobe_busy_end(void)
 void kprobe_flush_task(struct task_struct *tk)
 {
        struct kretprobe_instance *ri;
-       struct hlist_head *head, empty_rp;
+       struct hlist_head *head;
        struct hlist_node *tmp;
        unsigned long hash, flags = 0;
 
@@ -1323,19 +1322,14 @@ void kprobe_flush_task(struct task_struct *tk)
 
        kprobe_busy_begin();
 
-       INIT_HLIST_HEAD(&empty_rp);
        hash = hash_ptr(tk, KPROBE_HASH_BITS);
        head = &kretprobe_inst_table[hash];
        kretprobe_table_lock(hash, &flags);
        hlist_for_each_entry_safe(ri, tmp, head, hlist) {
                if (ri->task == tk)
-                       recycle_rp_inst(ri, &empty_rp);
+                       recycle_rp_inst(ri);
        }
        kretprobe_table_unlock(hash, &flags);
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
 
        kprobe_busy_end();
 }
@@ -1359,7 +1353,8 @@ static void cleanup_rp_inst(struct kretprobe *rp)
        struct hlist_node *next;
        struct hlist_head *head;
 
-       /* No race here */
+       /* To avoid recursive kretprobe by NMI, set kprobe busy here */
+       kprobe_busy_begin();
        for (hash = 0; hash < KPROBE_TABLE_SIZE; hash++) {
                kretprobe_table_lock(hash, &flags);
                head = &kretprobe_inst_table[hash];
@@ -1369,6 +1364,8 @@ static void cleanup_rp_inst(struct kretprobe *rp)
                }
                kretprobe_table_unlock(hash, &flags);
        }
+       kprobe_busy_end();
+
        free_rp_inst(rp);
 }
 NOKPROBE_SYMBOL(cleanup_rp_inst);
@@ -1634,6 +1631,7 @@ static int check_kprobe_address_safe(struct kprobe *p,
        if (!kernel_text_address((unsigned long) p->addr) ||
            within_kprobe_blacklist((unsigned long) p->addr) ||
            jump_label_text_reserved(p->addr, p->addr) ||
+           static_call_text_reserved(p->addr, p->addr) ||
            find_bug((unsigned long)p->addr)) {
                ret = -EINVAL;
                goto out;
@@ -1927,6 +1925,97 @@ unsigned long __weak arch_deref_entry_point(void *entry)
 }
 
 #ifdef CONFIG_KRETPROBES
+
+unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,
+                                            void *trampoline_address,
+                                            void *frame_pointer)
+{
+       struct kretprobe_instance *ri = NULL, *last = NULL;
+       struct hlist_head *head;
+       struct hlist_node *tmp;
+       unsigned long flags;
+       kprobe_opcode_t *correct_ret_addr = NULL;
+       bool skipped = false;
+
+       kretprobe_hash_lock(current, &head, &flags);
+
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because multiple functions in the call path have
+        * return probes installed on them, and/or more than one
+        * return probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always pushed into the head of the list
+        *     - when multiple return probes are registered for the same
+        *       function, the (chronologically) first instance's ret_addr
+        *       will be the real return address, and all the rest will
+        *       point to kretprobe_trampoline.
+        */
+       hlist_for_each_entry(ri, head, hlist) {
+               if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                       continue;
+               /*
+                * Return probes must be pushed on this hash list correct
+                * order (same as return order) so that it can be popped
+                * correctly. However, if we find it is pushed it incorrect
+                * order, this means we find a function which should not be
+                * probed, because the wrong order entry is pushed on the
+                * path of processing other kretprobe itself.
+                */
+               if (ri->fp != frame_pointer) {
+                       if (!skipped)
+                               pr_warn("kretprobe is stacked incorrectly. Trying to fixup.\n");
+                       skipped = true;
+                       continue;
+               }
+
+               correct_ret_addr = ri->ret_addr;
+               if (skipped)
+                       pr_warn("%ps must be blacklisted because of incorrect kretprobe order\n",
+                               ri->rp->kp.addr);
+
+               if (correct_ret_addr != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+
+       BUG_ON(!correct_ret_addr || (correct_ret_addr == trampoline_address));
+       last = ri;
+
+       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
+               if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                       continue;
+               if (ri->fp != frame_pointer)
+                       continue;
+
+               if (ri->rp && ri->rp->handler) {
+                       struct kprobe *prev = kprobe_running();
+
+                       __this_cpu_write(current_kprobe, &ri->rp->kp);
+                       ri->ret_addr = correct_ret_addr;
+                       ri->rp->handler(ri, regs);
+                       __this_cpu_write(current_kprobe, prev);
+               }
+
+               recycle_rp_inst(ri);
+
+               if (ri == last)
+                       break;
+       }
+
+       kretprobe_hash_unlock(current, &flags);
+
+       return (unsigned long)correct_ret_addr;
+}
+NOKPROBE_SYMBOL(__kretprobe_trampoline_handler)
+
 /*
  * This kprobe pre_handler is registered with every kretprobe. When probe
  * hits it will set up the return probe.
@@ -1937,17 +2026,6 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
        unsigned long hash, flags = 0;
        struct kretprobe_instance *ri;
 
-       /*
-        * To avoid deadlocks, prohibit return probing in NMI contexts,
-        * just skip the probe and increase the (inexact) 'nmissed'
-        * statistical counter, so that the user is informed that
-        * something happened:
-        */
-       if (unlikely(in_nmi())) {
-               rp->nmissed++;
-               return 0;
-       }
-
        /* TODO: consider to only swap the RA after the last pre_handler fired */
        hash = hash_ptr(current, KPROBE_HASH_BITS);
        raw_spin_lock_irqsave(&rp->lock, flags);
@@ -2140,6 +2218,9 @@ static void kill_kprobe(struct kprobe *p)
 
        lockdep_assert_held(&kprobe_mutex);
 
+       if (WARN_ON_ONCE(kprobe_gone(p)))
+               return;
+
        p->flags |= KPROBE_FLAG_GONE;
        if (kprobe_aggrprobe(p)) {
                /*
@@ -2159,9 +2240,10 @@ static void kill_kprobe(struct kprobe *p)
 
        /*
         * The module is going away. We should disarm the kprobe which
-        * is using ftrace.
+        * is using ftrace, because ftrace framework is still available at
+        * MODULE_STATE_GOING notification.
         */
-       if (kprobe_ftrace(p))
+       if (kprobe_ftrace(p) && !kprobe_disabled(p) && !kprobes_all_disarmed)
                disarm_kprobe_ftrace(p);
 }
 
@@ -2419,7 +2501,10 @@ static int kprobes_module_callback(struct notifier_block *nb,
        mutex_lock(&kprobe_mutex);
        for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
                head = &kprobe_table[i];
-               hlist_for_each_entry(p, head, hlist)
+               hlist_for_each_entry(p, head, hlist) {
+                       if (kprobe_gone(p))
+                               continue;
+
                        if (within_module_init((unsigned long)p->addr, mod) ||
                            (checkcore &&
                             within_module_core((unsigned long)p->addr, mod))) {
@@ -2436,6 +2521,7 @@ static int kprobes_module_callback(struct notifier_block *nb,
                                 */
                                kill_kprobe(p);
                        }
+               }
        }
        if (val == MODULE_STATE_GOING)
                remove_module_kprobe_blacklist(mod);
@@ -2452,6 +2538,28 @@ static struct notifier_block kprobe_module_nb = {
 extern unsigned long __start_kprobe_blacklist[];
 extern unsigned long __stop_kprobe_blacklist[];
 
+void kprobe_free_init_mem(void)
+{
+       void *start = (void *)(&__init_begin);
+       void *end = (void *)(&__init_end);
+       struct hlist_head *head;
+       struct kprobe *p;
+       int i;
+
+       mutex_lock(&kprobe_mutex);
+
+       /* Kill all kprobes on initmem */
+       for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
+               head = &kprobe_table[i];
+               hlist_for_each_entry(p, head, hlist) {
+                       if (start <= (void *)p->addr && (void *)p->addr < end)
+                               kill_kprobe(p);
+               }
+       }
+
+       mutex_unlock(&kprobe_mutex);
+}
+
 static int __init init_kprobes(void)
 {
        int i, err = 0;
index 2fad21d..3e99dfe 100644 (file)
@@ -76,6 +76,23 @@ module_param(lock_stat, int, 0644);
 #define lock_stat 0
 #endif
 
+DEFINE_PER_CPU(unsigned int, lockdep_recursion);
+EXPORT_PER_CPU_SYMBOL_GPL(lockdep_recursion);
+
+static inline bool lockdep_enabled(void)
+{
+       if (!debug_locks)
+               return false;
+
+       if (raw_cpu_read(lockdep_recursion))
+               return false;
+
+       if (current->lockdep_recursion)
+               return false;
+
+       return true;
+}
+
 /*
  * lockdep_lock: protects the lockdep graph, the hashes and the
  *               class/list/hash allocators.
@@ -93,7 +110,7 @@ static inline void lockdep_lock(void)
 
        arch_spin_lock(&__lock);
        __owner = current;
-       current->lockdep_recursion++;
+       __this_cpu_inc(lockdep_recursion);
 }
 
 static inline void lockdep_unlock(void)
@@ -101,7 +118,7 @@ static inline void lockdep_unlock(void)
        if (debug_locks && DEBUG_LOCKS_WARN_ON(__owner != current))
                return;
 
-       current->lockdep_recursion--;
+       __this_cpu_dec(lockdep_recursion);
        __owner = NULL;
        arch_spin_unlock(&__lock);
 }
@@ -372,6 +389,21 @@ static struct hlist_head classhash_table[CLASSHASH_SIZE];
 static struct hlist_head chainhash_table[CHAINHASH_SIZE];
 
 /*
+ * the id of held_lock
+ */
+static inline u16 hlock_id(struct held_lock *hlock)
+{
+       BUILD_BUG_ON(MAX_LOCKDEP_KEYS_BITS + 2 > 16);
+
+       return (hlock->class_idx | (hlock->read << MAX_LOCKDEP_KEYS_BITS));
+}
+
+static inline unsigned int chain_hlock_class_idx(u16 hlock_id)
+{
+       return hlock_id & (MAX_LOCKDEP_KEYS - 1);
+}
+
+/*
  * The hash key of the lock dependency chains is a hash itself too:
  * it's a hash of all locks taken up to that lock, including that lock.
  * It's a 64-bit hash, because it's important for the keys to be
@@ -393,10 +425,15 @@ void lockdep_init_task(struct task_struct *task)
        task->lockdep_recursion = 0;
 }
 
+static __always_inline void lockdep_recursion_inc(void)
+{
+       __this_cpu_inc(lockdep_recursion);
+}
+
 static __always_inline void lockdep_recursion_finish(void)
 {
-       if (WARN_ON_ONCE((--current->lockdep_recursion) & LOCKDEP_RECURSION_MASK))
-               current->lockdep_recursion = 0;
+       if (WARN_ON_ONCE(__this_cpu_dec_return(lockdep_recursion)))
+               __this_cpu_write(lockdep_recursion, 0);
 }
 
 void lockdep_set_selftest_task(struct task_struct *task)
@@ -585,6 +622,8 @@ static const char *usage_str[] =
 #include "lockdep_states.h"
 #undef LOCKDEP_STATE
        [LOCK_USED] = "INITIAL USE",
+       [LOCK_USED_READ] = "INITIAL READ USE",
+       /* abused as string storage for verify_lock_unused() */
        [LOCK_USAGE_STATES] = "IN-NMI",
 };
 #endif
@@ -1320,7 +1359,7 @@ static struct lock_list *alloc_list_entry(void)
  */
 static int add_lock_to_list(struct lock_class *this,
                            struct lock_class *links_to, struct list_head *head,
-                           unsigned long ip, int distance,
+                           unsigned long ip, u16 distance, u8 dep,
                            const struct lock_trace *trace)
 {
        struct lock_list *entry;
@@ -1334,6 +1373,7 @@ static int add_lock_to_list(struct lock_class *this,
 
        entry->class = this;
        entry->links_to = links_to;
+       entry->dep = dep;
        entry->distance = distance;
        entry->trace = trace;
        /*
@@ -1421,23 +1461,19 @@ static inline unsigned int  __cq_get_elem_count(struct circular_queue *cq)
        return (cq->rear - cq->front) & CQ_MASK;
 }
 
-static inline void mark_lock_accessed(struct lock_list *lock,
-                                       struct lock_list *parent)
+static inline void mark_lock_accessed(struct lock_list *lock)
 {
-       unsigned long nr;
+       lock->class->dep_gen_id = lockdep_dependency_gen_id;
+}
 
-       nr = lock - list_entries;
-       WARN_ON(nr >= ARRAY_SIZE(list_entries)); /* Out-of-bounds, input fail */
+static inline void visit_lock_entry(struct lock_list *lock,
+                                   struct lock_list *parent)
+{
        lock->parent = parent;
-       lock->class->dep_gen_id = lockdep_dependency_gen_id;
 }
 
 static inline unsigned long lock_accessed(struct lock_list *lock)
 {
-       unsigned long nr;
-
-       nr = lock - list_entries;
-       WARN_ON(nr >= ARRAY_SIZE(list_entries)); /* Out-of-bounds, input fail */
        return lock->class->dep_gen_id == lockdep_dependency_gen_id;
 }
 
@@ -1471,85 +1507,283 @@ static inline struct list_head *get_dep_list(struct lock_list *lock, int offset)
 
        return lock_class + offset;
 }
+/*
+ * Return values of a bfs search:
+ *
+ * BFS_E* indicates an error
+ * BFS_R* indicates a result (match or not)
+ *
+ * BFS_EINVALIDNODE: Find a invalid node in the graph.
+ *
+ * BFS_EQUEUEFULL: The queue is full while doing the bfs.
+ *
+ * BFS_RMATCH: Find the matched node in the graph, and put that node into
+ *             *@target_entry.
+ *
+ * BFS_RNOMATCH: Haven't found the matched node and keep *@target_entry
+ *               _unchanged_.
+ */
+enum bfs_result {
+       BFS_EINVALIDNODE = -2,
+       BFS_EQUEUEFULL = -1,
+       BFS_RMATCH = 0,
+       BFS_RNOMATCH = 1,
+};
+
+/*
+ * bfs_result < 0 means error
+ */
+static inline bool bfs_error(enum bfs_result res)
+{
+       return res < 0;
+}
+
+/*
+ * DEP_*_BIT in lock_list::dep
+ *
+ * For dependency @prev -> @next:
+ *
+ *   SR: @prev is shared reader (->read != 0) and @next is recursive reader
+ *       (->read == 2)
+ *   ER: @prev is exclusive locker (->read == 0) and @next is recursive reader
+ *   SN: @prev is shared reader and @next is non-recursive locker (->read != 2)
+ *   EN: @prev is exclusive locker and @next is non-recursive locker
+ *
+ * Note that we define the value of DEP_*_BITs so that:
+ *   bit0 is prev->read == 0
+ *   bit1 is next->read != 2
+ */
+#define DEP_SR_BIT (0 + (0 << 1)) /* 0 */
+#define DEP_ER_BIT (1 + (0 << 1)) /* 1 */
+#define DEP_SN_BIT (0 + (1 << 1)) /* 2 */
+#define DEP_EN_BIT (1 + (1 << 1)) /* 3 */
+
+#define DEP_SR_MASK (1U << (DEP_SR_BIT))
+#define DEP_ER_MASK (1U << (DEP_ER_BIT))
+#define DEP_SN_MASK (1U << (DEP_SN_BIT))
+#define DEP_EN_MASK (1U << (DEP_EN_BIT))
+
+static inline unsigned int
+__calc_dep_bit(struct held_lock *prev, struct held_lock *next)
+{
+       return (prev->read == 0) + ((next->read != 2) << 1);
+}
+
+static inline u8 calc_dep(struct held_lock *prev, struct held_lock *next)
+{
+       return 1U << __calc_dep_bit(prev, next);
+}
+
+/*
+ * calculate the dep_bit for backwards edges. We care about whether @prev is
+ * shared and whether @next is recursive.
+ */
+static inline unsigned int
+__calc_dep_bitb(struct held_lock *prev, struct held_lock *next)
+{
+       return (next->read != 2) + ((prev->read == 0) << 1);
+}
+
+static inline u8 calc_depb(struct held_lock *prev, struct held_lock *next)
+{
+       return 1U << __calc_dep_bitb(prev, next);
+}
+
+/*
+ * Initialize a lock_list entry @lock belonging to @class as the root for a BFS
+ * search.
+ */
+static inline void __bfs_init_root(struct lock_list *lock,
+                                  struct lock_class *class)
+{
+       lock->class = class;
+       lock->parent = NULL;
+       lock->only_xr = 0;
+}
+
+/*
+ * Initialize a lock_list entry @lock based on a lock acquisition @hlock as the
+ * root for a BFS search.
+ *
+ * ->only_xr of the initial lock node is set to @hlock->read == 2, to make sure
+ * that <prev> -> @hlock and @hlock -> <whatever __bfs() found> is not -(*R)->
+ * and -(S*)->.
+ */
+static inline void bfs_init_root(struct lock_list *lock,
+                                struct held_lock *hlock)
+{
+       __bfs_init_root(lock, hlock_class(hlock));
+       lock->only_xr = (hlock->read == 2);
+}
 
 /*
- * Forward- or backward-dependency search, used for both circular dependency
- * checking and hardirq-unsafe/softirq-unsafe checking.
+ * Similar to bfs_init_root() but initialize the root for backwards BFS.
+ *
+ * ->only_xr of the initial lock node is set to @hlock->read != 0, to make sure
+ * that <next> -> @hlock and @hlock -> <whatever backwards BFS found> is not
+ * -(*S)-> and -(R*)-> (reverse order of -(*R)-> and -(S*)->).
  */
-static int __bfs(struct lock_list *source_entry,
-                void *data,
-                int (*match)(struct lock_list *entry, void *data),
-                struct lock_list **target_entry,
-                int offset)
+static inline void bfs_init_rootb(struct lock_list *lock,
+                                 struct held_lock *hlock)
+{
+       __bfs_init_root(lock, hlock_class(hlock));
+       lock->only_xr = (hlock->read != 0);
+}
+
+static inline struct lock_list *__bfs_next(struct lock_list *lock, int offset)
 {
+       if (!lock || !lock->parent)
+               return NULL;
+
+       return list_next_or_null_rcu(get_dep_list(lock->parent, offset),
+                                    &lock->entry, struct lock_list, entry);
+}
+
+/*
+ * Breadth-First Search to find a strong path in the dependency graph.
+ *
+ * @source_entry: the source of the path we are searching for.
+ * @data: data used for the second parameter of @match function
+ * @match: match function for the search
+ * @target_entry: pointer to the target of a matched path
+ * @offset: the offset to struct lock_class to determine whether it is
+ *          locks_after or locks_before
+ *
+ * We may have multiple edges (considering different kinds of dependencies,
+ * e.g. ER and SN) between two nodes in the dependency graph. But
+ * only the strong dependency path in the graph is relevant to deadlocks. A
+ * strong dependency path is a dependency path that doesn't have two adjacent
+ * dependencies as -(*R)-> -(S*)->, please see:
+ *
+ *         Documentation/locking/lockdep-design.rst
+ *
+ * for more explanation of the definition of strong dependency paths
+ *
+ * In __bfs(), we only traverse in the strong dependency path:
+ *
+ *     In lock_list::only_xr, we record whether the previous dependency only
+ *     has -(*R)-> in the search, and if it does (prev only has -(*R)->), we
+ *     filter out any -(S*)-> in the current dependency and after that, the
+ *     ->only_xr is set according to whether we only have -(*R)-> left.
+ */
+static enum bfs_result __bfs(struct lock_list *source_entry,
+                            void *data,
+                            bool (*match)(struct lock_list *entry, void *data),
+                            struct lock_list **target_entry,
+                            int offset)
+{
+       struct circular_queue *cq = &lock_cq;
+       struct lock_list *lock = NULL;
        struct lock_list *entry;
-       struct lock_list *lock;
        struct list_head *head;
-       struct circular_queue *cq = &lock_cq;
-       int ret = 1;
+       unsigned int cq_depth;
+       bool first;
 
        lockdep_assert_locked();
 
-       if (match(source_entry, data)) {
-               *target_entry = source_entry;
-               ret = 0;
-               goto exit;
-       }
-
-       head = get_dep_list(source_entry, offset);
-       if (list_empty(head))
-               goto exit;
-
        __cq_init(cq);
        __cq_enqueue(cq, source_entry);
 
-       while ((lock = __cq_dequeue(cq))) {
+       while ((lock = __bfs_next(lock, offset)) || (lock = __cq_dequeue(cq))) {
+               if (!lock->class)
+                       return BFS_EINVALIDNODE;
+
+               /*
+                * Step 1: check whether we already finish on this one.
+                *
+                * If we have visited all the dependencies from this @lock to
+                * others (iow, if we have visited all lock_list entries in
+                * @lock->class->locks_{after,before}) we skip, otherwise go
+                * and visit all the dependencies in the list and mark this
+                * list accessed.
+                */
+               if (lock_accessed(lock))
+                       continue;
+               else
+                       mark_lock_accessed(lock);
+
+               /*
+                * Step 2: check whether prev dependency and this form a strong
+                *         dependency path.
+                */
+               if (lock->parent) { /* Parent exists, check prev dependency */
+                       u8 dep = lock->dep;
+                       bool prev_only_xr = lock->parent->only_xr;
+
+                       /*
+                        * Mask out all -(S*)-> if we only have *R in previous
+                        * step, because -(*R)-> -(S*)-> don't make up a strong
+                        * dependency.
+                        */
+                       if (prev_only_xr)
+                               dep &= ~(DEP_SR_MASK | DEP_SN_MASK);
 
-               if (!lock->class) {
-                       ret = -2;
-                       goto exit;
+                       /* If nothing left, we skip */
+                       if (!dep)
+                               continue;
+
+                       /* If there are only -(*R)-> left, set that for the next step */
+                       lock->only_xr = !(dep & (DEP_SN_MASK | DEP_EN_MASK));
                }
 
-               head = get_dep_list(lock, offset);
+               /*
+                * Step 3: we haven't visited this and there is a strong
+                *         dependency path to this, so check with @match.
+                */
+               if (match(lock, data)) {
+                       *target_entry = lock;
+                       return BFS_RMATCH;
+               }
 
+               /*
+                * Step 4: if not match, expand the path by adding the
+                *         forward or backwards dependencis in the search
+                *
+                */
+               first = true;
+               head = get_dep_list(lock, offset);
                list_for_each_entry_rcu(entry, head, entry) {
-                       if (!lock_accessed(entry)) {
-                               unsigned int cq_depth;
-                               mark_lock_accessed(entry, lock);
-                               if (match(entry, data)) {
-                                       *target_entry = entry;
-                                       ret = 0;
-                                       goto exit;
-                               }
+                       visit_lock_entry(entry, lock);
 
-                               if (__cq_enqueue(cq, entry)) {
-                                       ret = -1;
-                                       goto exit;
-                               }
-                               cq_depth = __cq_get_elem_count(cq);
-                               if (max_bfs_queue_depth < cq_depth)
-                                       max_bfs_queue_depth = cq_depth;
-                       }
+                       /*
+                        * Note we only enqueue the first of the list into the
+                        * queue, because we can always find a sibling
+                        * dependency from one (see __bfs_next()), as a result
+                        * the space of queue is saved.
+                        */
+                       if (!first)
+                               continue;
+
+                       first = false;
+
+                       if (__cq_enqueue(cq, entry))
+                               return BFS_EQUEUEFULL;
+
+                       cq_depth = __cq_get_elem_count(cq);
+                       if (max_bfs_queue_depth < cq_depth)
+                               max_bfs_queue_depth = cq_depth;
                }
        }
-exit:
-       return ret;
+
+       return BFS_RNOMATCH;
 }
 
-static inline int __bfs_forwards(struct lock_list *src_entry,
-                       void *data,
-                       int (*match)(struct lock_list *entry, void *data),
-                       struct lock_list **target_entry)
+static inline enum bfs_result
+__bfs_forwards(struct lock_list *src_entry,
+              void *data,
+              bool (*match)(struct lock_list *entry, void *data),
+              struct lock_list **target_entry)
 {
        return __bfs(src_entry, data, match, target_entry,
                     offsetof(struct lock_class, locks_after));
 
 }
 
-static inline int __bfs_backwards(struct lock_list *src_entry,
-                       void *data,
-                       int (*match)(struct lock_list *entry, void *data),
-                       struct lock_list **target_entry)
+static inline enum bfs_result
+__bfs_backwards(struct lock_list *src_entry,
+               void *data,
+               bool (*match)(struct lock_list *entry, void *data),
+               struct lock_list **target_entry)
 {
        return __bfs(src_entry, data, match, target_entry,
                     offsetof(struct lock_class, locks_before));
@@ -1659,15 +1893,72 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth,
        print_circular_bug_entry(entry, depth);
 }
 
-static inline int class_equal(struct lock_list *entry, void *data)
+/*
+ * We are about to add A -> B into the dependency graph, and in __bfs() a
+ * strong dependency path A -> .. -> B is found: hlock_class equals
+ * entry->class.
+ *
+ * If A -> .. -> B can replace A -> B in any __bfs() search (means the former
+ * is _stronger_ than or equal to the latter), we consider A -> B as redundant.
+ * For example if A -> .. -> B is -(EN)-> (i.e. A -(E*)-> .. -(*N)-> B), and A
+ * -> B is -(ER)-> or -(EN)->, then we don't need to add A -> B into the
+ * dependency graph, as any strong path ..-> A -> B ->.. we can get with
+ * having dependency A -> B, we could already get a equivalent path ..-> A ->
+ * .. -> B -> .. with A -> .. -> B. Therefore A -> B is reduntant.
+ *
+ * We need to make sure both the start and the end of A -> .. -> B is not
+ * weaker than A -> B. For the start part, please see the comment in
+ * check_redundant(). For the end part, we need:
+ *
+ * Either
+ *
+ *     a) A -> B is -(*R)-> (everything is not weaker than that)
+ *
+ * or
+ *
+ *     b) A -> .. -> B is -(*N)-> (nothing is stronger than this)
+ *
+ */
+static inline bool hlock_equal(struct lock_list *entry, void *data)
+{
+       struct held_lock *hlock = (struct held_lock *)data;
+
+       return hlock_class(hlock) == entry->class && /* Found A -> .. -> B */
+              (hlock->read == 2 ||  /* A -> B is -(*R)-> */
+               !entry->only_xr); /* A -> .. -> B is -(*N)-> */
+}
+
+/*
+ * We are about to add B -> A into the dependency graph, and in __bfs() a
+ * strong dependency path A -> .. -> B is found: hlock_class equals
+ * entry->class.
+ *
+ * We will have a deadlock case (conflict) if A -> .. -> B -> A is a strong
+ * dependency cycle, that means:
+ *
+ * Either
+ *
+ *     a) B -> A is -(E*)->
+ *
+ * or
+ *
+ *     b) A -> .. -> B is -(*N)-> (i.e. A -> .. -(*N)-> B)
+ *
+ * as then we don't have -(*R)-> -(S*)-> in the cycle.
+ */
+static inline bool hlock_conflict(struct lock_list *entry, void *data)
 {
-       return entry->class == data;
+       struct held_lock *hlock = (struct held_lock *)data;
+
+       return hlock_class(hlock) == entry->class && /* Found A -> .. -> B */
+              (hlock->read == 0 || /* B -> A is -(E*)-> */
+               !entry->only_xr); /* A -> .. -> B is -(*N)-> */
 }
 
 static noinline void print_circular_bug(struct lock_list *this,
-                                       struct lock_list *target,
-                                       struct held_lock *check_src,
-                                       struct held_lock *check_tgt)
+                               struct lock_list *target,
+                               struct held_lock *check_src,
+                               struct held_lock *check_tgt)
 {
        struct task_struct *curr = current;
        struct lock_list *parent;
@@ -1714,10 +2005,10 @@ static noinline void print_bfs_bug(int ret)
        WARN(1, "lockdep bfs error:%d\n", ret);
 }
 
-static int noop_count(struct lock_list *entry, void *data)
+static bool noop_count(struct lock_list *entry, void *data)
 {
        (*(unsigned long *)data)++;
-       return 0;
+       return false;
 }
 
 static unsigned long __lockdep_count_forward_deps(struct lock_list *this)
@@ -1734,8 +2025,7 @@ unsigned long lockdep_count_forward_deps(struct lock_class *class)
        unsigned long ret, flags;
        struct lock_list this;
 
-       this.parent = NULL;
-       this.class = class;
+       __bfs_init_root(&this, class);
 
        raw_local_irq_save(flags);
        lockdep_lock();
@@ -1761,8 +2051,7 @@ unsigned long lockdep_count_backward_deps(struct lock_class *class)
        unsigned long ret, flags;
        struct lock_list this;
 
-       this.parent = NULL;
-       this.class = class;
+       __bfs_init_root(&this, class);
 
        raw_local_irq_save(flags);
        lockdep_lock();
@@ -1775,18 +2064,18 @@ unsigned long lockdep_count_backward_deps(struct lock_class *class)
 
 /*
  * Check that the dependency graph starting at <src> can lead to
- * <target> or not. Print an error and return 0 if it does.
+ * <target> or not.
  */
-static noinline int
-check_path(struct lock_class *target, struct lock_list *src_entry,
+static noinline enum bfs_result
+check_path(struct held_lock *target, struct lock_list *src_entry,
+          bool (*match)(struct lock_list *entry, void *data),
           struct lock_list **target_entry)
 {
-       int ret;
+       enum bfs_result ret;
 
-       ret = __bfs_forwards(src_entry, (void *)target, class_equal,
-                            target_entry);
+       ret = __bfs_forwards(src_entry, target, match, target_entry);
 
-       if (unlikely(ret < 0))
+       if (unlikely(bfs_error(ret)))
                print_bfs_bug(ret);
 
        return ret;
@@ -1797,24 +2086,23 @@ check_path(struct lock_class *target, struct lock_list *src_entry,
  * lead to <target>. If it can, there is a circle when adding
  * <target> -> <src> dependency.
  *
- * Print an error and return 0 if it does.
+ * Print an error and return BFS_RMATCH if it does.
  */
-static noinline int
+static noinline enum bfs_result
 check_noncircular(struct held_lock *src, struct held_lock *target,
                  struct lock_trace **const trace)
 {
-       int ret;
+       enum bfs_result ret;
        struct lock_list *target_entry;
-       struct lock_list src_entry = {
-               .class = hlock_class(src),
-               .parent = NULL,
-       };
+       struct lock_list src_entry;
+
+       bfs_init_root(&src_entry, src);
 
        debug_atomic_inc(nr_cyclic_checks);
 
-       ret = check_path(hlock_class(target), &src_entry, &target_entry);
+       ret = check_path(target, &src_entry, hlock_conflict, &target_entry);
 
-       if (unlikely(!ret)) {
+       if (unlikely(ret == BFS_RMATCH)) {
                if (!*trace) {
                        /*
                         * If save_trace fails here, the printing might
@@ -1836,27 +2124,35 @@ check_noncircular(struct held_lock *src, struct held_lock *target,
  * <target> or not. If it can, <src> -> <target> dependency is already
  * in the graph.
  *
- * Print an error and return 2 if it does or 1 if it does not.
+ * Return BFS_RMATCH if it does, or BFS_RMATCH if it does not, return BFS_E* if
+ * any error appears in the bfs search.
  */
-static noinline int
+static noinline enum bfs_result
 check_redundant(struct held_lock *src, struct held_lock *target)
 {
-       int ret;
+       enum bfs_result ret;
        struct lock_list *target_entry;
-       struct lock_list src_entry = {
-               .class = hlock_class(src),
-               .parent = NULL,
-       };
+       struct lock_list src_entry;
+
+       bfs_init_root(&src_entry, src);
+       /*
+        * Special setup for check_redundant().
+        *
+        * To report redundant, we need to find a strong dependency path that
+        * is equal to or stronger than <src> -> <target>. So if <src> is E,
+        * we need to let __bfs() only search for a path starting at a -(E*)->,
+        * we achieve this by setting the initial node's ->only_xr to true in
+        * that case. And if <prev> is S, we set initial ->only_xr to false
+        * because both -(S*)-> (equal) and -(E*)-> (stronger) are redundant.
+        */
+       src_entry.only_xr = src->read == 0;
 
        debug_atomic_inc(nr_redundant_checks);
 
-       ret = check_path(hlock_class(target), &src_entry, &target_entry);
+       ret = check_path(target, &src_entry, hlock_equal, &target_entry);
 
-       if (!ret) {
+       if (ret == BFS_RMATCH)
                debug_atomic_inc(nr_redundant);
-               ret = 2;
-       } else if (ret < 0)
-               ret = 0;
 
        return ret;
 }
@@ -1864,39 +2160,86 @@ check_redundant(struct held_lock *src, struct held_lock *target)
 
 #ifdef CONFIG_TRACE_IRQFLAGS
 
-static inline int usage_accumulate(struct lock_list *entry, void *mask)
-{
-       *(unsigned long *)mask |= entry->class->usage_mask;
-
-       return 0;
-}
-
 /*
  * Forwards and backwards subgraph searching, for the purposes of
  * proving that two subgraphs can be connected by a new dependency
  * without creating any illegal irq-safe -> irq-unsafe lock dependency.
+ *
+ * A irq safe->unsafe deadlock happens with the following conditions:
+ *
+ * 1) We have a strong dependency path A -> ... -> B
+ *
+ * 2) and we have ENABLED_IRQ usage of B and USED_IN_IRQ usage of A, therefore
+ *    irq can create a new dependency B -> A (consider the case that a holder
+ *    of B gets interrupted by an irq whose handler will try to acquire A).
+ *
+ * 3) the dependency circle A -> ... -> B -> A we get from 1) and 2) is a
+ *    strong circle:
+ *
+ *      For the usage bits of B:
+ *        a) if A -> B is -(*N)->, then B -> A could be any type, so any
+ *           ENABLED_IRQ usage suffices.
+ *        b) if A -> B is -(*R)->, then B -> A must be -(E*)->, so only
+ *           ENABLED_IRQ_*_READ usage suffices.
+ *
+ *      For the usage bits of A:
+ *        c) if A -> B is -(E*)->, then B -> A could be any type, so any
+ *           USED_IN_IRQ usage suffices.
+ *        d) if A -> B is -(S*)->, then B -> A must be -(*N)->, so only
+ *           USED_IN_IRQ_*_READ usage suffices.
  */
 
-static inline int usage_match(struct lock_list *entry, void *mask)
+/*
+ * There is a strong dependency path in the dependency graph: A -> B, and now
+ * we need to decide which usage bit of A should be accumulated to detect
+ * safe->unsafe bugs.
+ *
+ * Note that usage_accumulate() is used in backwards search, so ->only_xr
+ * stands for whether A -> B only has -(S*)-> (in this case ->only_xr is true).
+ *
+ * As above, if only_xr is false, which means A -> B has -(E*)-> dependency
+ * path, any usage of A should be considered. Otherwise, we should only
+ * consider _READ usage.
+ */
+static inline bool usage_accumulate(struct lock_list *entry, void *mask)
 {
-       return entry->class->usage_mask & *(unsigned long *)mask;
+       if (!entry->only_xr)
+               *(unsigned long *)mask |= entry->class->usage_mask;
+       else /* Mask out _READ usage bits */
+               *(unsigned long *)mask |= (entry->class->usage_mask & LOCKF_IRQ);
+
+       return false;
+}
+
+/*
+ * There is a strong dependency path in the dependency graph: A -> B, and now
+ * we need to decide which usage bit of B conflicts with the usage bits of A,
+ * i.e. which usage bit of B may introduce safe->unsafe deadlocks.
+ *
+ * As above, if only_xr is false, which means A -> B has -(*N)-> dependency
+ * path, any usage of B should be considered. Otherwise, we should only
+ * consider _READ usage.
+ */
+static inline bool usage_match(struct lock_list *entry, void *mask)
+{
+       if (!entry->only_xr)
+               return !!(entry->class->usage_mask & *(unsigned long *)mask);
+       else /* Mask out _READ usage bits */
+               return !!((entry->class->usage_mask & LOCKF_IRQ) & *(unsigned long *)mask);
 }
 
 /*
  * Find a node in the forwards-direction dependency sub-graph starting
  * at @root->class that matches @bit.
  *
- * Return 0 if such a node exists in the subgraph, and put that node
+ * Return BFS_MATCH if such a node exists in the subgraph, and put that node
  * into *@target_entry.
- *
- * Return 1 otherwise and keep *@target_entry unchanged.
- * Return <0 on error.
  */
-static int
+static enum bfs_result
 find_usage_forwards(struct lock_list *root, unsigned long usage_mask,
                        struct lock_list **target_entry)
 {
-       int result;
+       enum bfs_result result;
 
        debug_atomic_inc(nr_find_usage_forwards_checks);
 
@@ -1908,18 +2251,12 @@ find_usage_forwards(struct lock_list *root, unsigned long usage_mask,
 /*
  * Find a node in the backwards-direction dependency sub-graph starting
  * at @root->class that matches @bit.
- *
- * Return 0 if such a node exists in the subgraph, and put that node
- * into *@target_entry.
- *
- * Return 1 otherwise and keep *@target_entry unchanged.
- * Return <0 on error.
  */
-static int
+static enum bfs_result
 find_usage_backwards(struct lock_list *root, unsigned long usage_mask,
                        struct lock_list **target_entry)
 {
-       int result;
+       enum bfs_result result;
 
        debug_atomic_inc(nr_find_usage_backwards_checks);
 
@@ -1939,7 +2276,7 @@ static void print_lock_class_header(struct lock_class *class, int depth)
 #endif
        printk(KERN_CONT " {\n");
 
-       for (bit = 0; bit < LOCK_USAGE_STATES; bit++) {
+       for (bit = 0; bit < LOCK_TRACE_STATES; bit++) {
                if (class->usage_mask & (1 << bit)) {
                        int len = depth;
 
@@ -2179,17 +2516,39 @@ static unsigned long invert_dir_mask(unsigned long mask)
 }
 
 /*
- * As above, we clear bitnr0 (LOCK_*_READ off) with bitmask ops. First, for all
- * bits with bitnr0 set (LOCK_*_READ), add those with bitnr0 cleared (LOCK_*).
- * And then mask out all bitnr0.
+ * Note that a LOCK_ENABLED_IRQ_*_READ usage and a LOCK_USED_IN_IRQ_*_READ
+ * usage may cause deadlock too, for example:
+ *
+ * P1                          P2
+ * <irq disabled>
+ * write_lock(l1);             <irq enabled>
+ *                             read_lock(l2);
+ * write_lock(l2);
+ *                             <in irq>
+ *                             read_lock(l1);
+ *
+ * , in above case, l1 will be marked as LOCK_USED_IN_IRQ_HARDIRQ_READ and l2
+ * will marked as LOCK_ENABLE_IRQ_HARDIRQ_READ, and this is a possible
+ * deadlock.
+ *
+ * In fact, all of the following cases may cause deadlocks:
+ *
+ *      LOCK_USED_IN_IRQ_* -> LOCK_ENABLED_IRQ_*
+ *      LOCK_USED_IN_IRQ_*_READ -> LOCK_ENABLED_IRQ_*
+ *      LOCK_USED_IN_IRQ_* -> LOCK_ENABLED_IRQ_*_READ
+ *      LOCK_USED_IN_IRQ_*_READ -> LOCK_ENABLED_IRQ_*_READ
+ *
+ * As a result, to calculate the "exclusive mask", first we invert the
+ * direction (USED_IN/ENABLED) of the original mask, and 1) for all bits with
+ * bitnr0 set (LOCK_*_READ), add those with bitnr0 cleared (LOCK_*). 2) for all
+ * bits with bitnr0 cleared (LOCK_*_READ), add those with bitnr0 set (LOCK_*).
  */
 static unsigned long exclusive_mask(unsigned long mask)
 {
        unsigned long excl = invert_dir_mask(mask);
 
-       /* Strip read */
        excl |= (excl & LOCKF_IRQ_READ) >> LOCK_USAGE_READ_MASK;
-       excl &= ~LOCKF_IRQ_READ;
+       excl |= (excl & LOCKF_IRQ) << LOCK_USAGE_READ_MASK;
 
        return excl;
 }
@@ -2206,6 +2565,7 @@ static unsigned long original_mask(unsigned long mask)
        unsigned long excl = invert_dir_mask(mask);
 
        /* Include read in existing usages */
+       excl |= (excl & LOCKF_IRQ_READ) >> LOCK_USAGE_READ_MASK;
        excl |= (excl & LOCKF_IRQ) << LOCK_USAGE_READ_MASK;
 
        return excl;
@@ -2220,14 +2580,24 @@ static int find_exclusive_match(unsigned long mask,
                                enum lock_usage_bit *bitp,
                                enum lock_usage_bit *excl_bitp)
 {
-       int bit, excl;
+       int bit, excl, excl_read;
 
        for_each_set_bit(bit, &mask, LOCK_USED) {
+               /*
+                * exclusive_bit() strips the read bit, however,
+                * LOCK_ENABLED_IRQ_*_READ may cause deadlocks too, so we need
+                * to search excl | LOCK_USAGE_READ_MASK as well.
+                */
                excl = exclusive_bit(bit);
+               excl_read = excl | LOCK_USAGE_READ_MASK;
                if (excl_mask & lock_flag(excl)) {
                        *bitp = bit;
                        *excl_bitp = excl;
                        return 0;
+               } else if (excl_mask & lock_flag(excl_read)) {
+                       *bitp = bit;
+                       *excl_bitp = excl_read;
+                       return 0;
                }
        }
        return -1;
@@ -2247,17 +2617,16 @@ static int check_irq_usage(struct task_struct *curr, struct held_lock *prev,
        struct lock_list *target_entry1;
        struct lock_list *target_entry;
        struct lock_list this, that;
-       int ret;
+       enum bfs_result ret;
 
        /*
         * Step 1: gather all hard/soft IRQs usages backward in an
         * accumulated usage mask.
         */
-       this.parent = NULL;
-       this.class = hlock_class(prev);
+       bfs_init_rootb(&this, prev);
 
        ret = __bfs_backwards(&this, &usage_mask, usage_accumulate, NULL);
-       if (ret < 0) {
+       if (bfs_error(ret)) {
                print_bfs_bug(ret);
                return 0;
        }
@@ -2272,16 +2641,15 @@ static int check_irq_usage(struct task_struct *curr, struct held_lock *prev,
         */
        forward_mask = exclusive_mask(usage_mask);
 
-       that.parent = NULL;
-       that.class = hlock_class(next);
+       bfs_init_root(&that, next);
 
        ret = find_usage_forwards(&that, forward_mask, &target_entry1);
-       if (ret < 0) {
+       if (bfs_error(ret)) {
                print_bfs_bug(ret);
                return 0;
        }
-       if (ret == 1)
-               return ret;
+       if (ret == BFS_RNOMATCH)
+               return 1;
 
        /*
         * Step 3: we found a bad match! Now retrieve a lock from the backward
@@ -2291,11 +2659,11 @@ static int check_irq_usage(struct task_struct *curr, struct held_lock *prev,
        backward_mask = original_mask(target_entry1->class->usage_mask);
 
        ret = find_usage_backwards(&this, backward_mask, &target_entry);
-       if (ret < 0) {
+       if (bfs_error(ret)) {
                print_bfs_bug(ret);
                return 0;
        }
-       if (DEBUG_LOCKS_WARN_ON(ret == 1))
+       if (DEBUG_LOCKS_WARN_ON(ret == BFS_RNOMATCH))
                return 1;
 
        /*
@@ -2459,11 +2827,11 @@ check_deadlock(struct task_struct *curr, struct held_lock *next)
  */
 static int
 check_prev_add(struct task_struct *curr, struct held_lock *prev,
-              struct held_lock *next, int distance,
+              struct held_lock *next, u16 distance,
               struct lock_trace **const trace)
 {
        struct lock_list *entry;
-       int ret;
+       enum bfs_result ret;
 
        if (!hlock_class(prev)->key || !hlock_class(next)->key) {
                /*
@@ -2494,23 +2862,13 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
         * in the graph whose neighbours are to be checked.
         */
        ret = check_noncircular(next, prev, trace);
-       if (unlikely(ret <= 0))
+       if (unlikely(bfs_error(ret) || ret == BFS_RMATCH))
                return 0;
 
        if (!check_irq_usage(curr, prev, next))
                return 0;
 
        /*
-        * For recursive read-locks we do all the dependency checks,
-        * but we dont store read-triggered dependencies (only
-        * write-triggered dependencies). This ensures that only the
-        * write-side dependencies matter, and that if for example a
-        * write-lock never takes any other locks, then the reads are
-        * equivalent to a NOP.
-        */
-       if (next->read == 2 || prev->read == 2)
-               return 1;
-       /*
         * Is the <prev> -> <next> dependency already present?
         *
         * (this may occur even though this is a new chain: consider
@@ -2522,7 +2880,35 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
                if (entry->class == hlock_class(next)) {
                        if (distance == 1)
                                entry->distance = 1;
-                       return 1;
+                       entry->dep |= calc_dep(prev, next);
+
+                       /*
+                        * Also, update the reverse dependency in @next's
+                        * ->locks_before list.
+                        *
+                        *  Here we reuse @entry as the cursor, which is fine
+                        *  because we won't go to the next iteration of the
+                        *  outer loop:
+                        *
+                        *  For normal cases, we return in the inner loop.
+                        *
+                        *  If we fail to return, we have inconsistency, i.e.
+                        *  <prev>::locks_after contains <next> while
+                        *  <next>::locks_before doesn't contain <prev>. In
+                        *  that case, we return after the inner and indicate
+                        *  something is wrong.
+                        */
+                       list_for_each_entry(entry, &hlock_class(next)->locks_before, entry) {
+                               if (entry->class == hlock_class(prev)) {
+                                       if (distance == 1)
+                                               entry->distance = 1;
+                                       entry->dep |= calc_depb(prev, next);
+                                       return 1;
+                               }
+                       }
+
+                       /* <prev> is not found in <next>::locks_before */
+                       return 0;
                }
        }
 
@@ -2531,8 +2917,10 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
         * Is the <prev> -> <next> link redundant?
         */
        ret = check_redundant(prev, next);
-       if (ret != 1)
-               return ret;
+       if (bfs_error(ret))
+               return 0;
+       else if (ret == BFS_RMATCH)
+               return 2;
 #endif
 
        if (!*trace) {
@@ -2547,14 +2935,18 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
         */
        ret = add_lock_to_list(hlock_class(next), hlock_class(prev),
                               &hlock_class(prev)->locks_after,
-                              next->acquire_ip, distance, *trace);
+                              next->acquire_ip, distance,
+                              calc_dep(prev, next),
+                              *trace);
 
        if (!ret)
                return 0;
 
        ret = add_lock_to_list(hlock_class(prev), hlock_class(next),
                               &hlock_class(next)->locks_before,
-                              next->acquire_ip, distance, *trace);
+                              next->acquire_ip, distance,
+                              calc_depb(prev, next),
+                              *trace);
        if (!ret)
                return 0;
 
@@ -2590,16 +2982,11 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)
                goto out_bug;
 
        for (;;) {
-               int distance = curr->lockdep_depth - depth + 1;
+               u16 distance = curr->lockdep_depth - depth + 1;
                hlock = curr->held_locks + depth - 1;
 
-               /*
-                * Only non-recursive-read entries get new dependencies
-                * added:
-                */
-               if (hlock->read != 2 && hlock->check) {
-                       int ret = check_prev_add(curr, hlock, next, distance,
-                                                &trace);
+               if (hlock->check) {
+                       int ret = check_prev_add(curr, hlock, next, distance, &trace);
                        if (!ret)
                                return 0;
 
@@ -2875,7 +3262,10 @@ static inline void free_chain_hlocks(int base, int size)
 
 struct lock_class *lock_chain_get_class(struct lock_chain *chain, int i)
 {
-       return lock_classes + chain_hlocks[chain->base + i];
+       u16 chain_hlock = chain_hlocks[chain->base + i];
+       unsigned int class_idx = chain_hlock_class_idx(chain_hlock);
+
+       return lock_classes + class_idx - 1;
 }
 
 /*
@@ -2901,12 +3291,12 @@ static inline int get_first_held_lock(struct task_struct *curr,
 /*
  * Returns the next chain_key iteration
  */
-static u64 print_chain_key_iteration(int class_idx, u64 chain_key)
+static u64 print_chain_key_iteration(u16 hlock_id, u64 chain_key)
 {
-       u64 new_chain_key = iterate_chain_key(chain_key, class_idx);
+       u64 new_chain_key = iterate_chain_key(chain_key, hlock_id);
 
-       printk(" class_idx:%d -> chain_key:%016Lx",
-               class_idx,
+       printk(" hlock_id:%d -> chain_key:%016Lx",
+               (unsigned int)hlock_id,
                (unsigned long long)new_chain_key);
        return new_chain_key;
 }
@@ -2923,12 +3313,12 @@ print_chain_keys_held_locks(struct task_struct *curr, struct held_lock *hlock_ne
                hlock_next->irq_context);
        for (; i < depth; i++) {
                hlock = curr->held_locks + i;
-               chain_key = print_chain_key_iteration(hlock->class_idx, chain_key);
+               chain_key = print_chain_key_iteration(hlock_id(hlock), chain_key);
 
                print_lock(hlock);
        }
 
-       print_chain_key_iteration(hlock_next->class_idx, chain_key);
+       print_chain_key_iteration(hlock_id(hlock_next), chain_key);
        print_lock(hlock_next);
 }
 
@@ -2936,14 +3326,14 @@ static void print_chain_keys_chain(struct lock_chain *chain)
 {
        int i;
        u64 chain_key = INITIAL_CHAIN_KEY;
-       int class_id;
+       u16 hlock_id;
 
        printk("depth: %u\n", chain->depth);
        for (i = 0; i < chain->depth; i++) {
-               class_id = chain_hlocks[chain->base + i];
-               chain_key = print_chain_key_iteration(class_id, chain_key);
+               hlock_id = chain_hlocks[chain->base + i];
+               chain_key = print_chain_key_iteration(hlock_id, chain_key);
 
-               print_lock_name(lock_classes + class_id);
+               print_lock_name(lock_classes + chain_hlock_class_idx(hlock_id) - 1);
                printk("\n");
        }
 }
@@ -2992,7 +3382,7 @@ static int check_no_collision(struct task_struct *curr,
        }
 
        for (j = 0; j < chain->depth - 1; j++, i++) {
-               id = curr->held_locks[i].class_idx;
+               id = hlock_id(&curr->held_locks[i]);
 
                if (DEBUG_LOCKS_WARN_ON(chain_hlocks[chain->base + j] != id)) {
                        print_collision(curr, hlock, chain);
@@ -3041,7 +3431,6 @@ static inline int add_chain_cache(struct task_struct *curr,
                                  struct held_lock *hlock,
                                  u64 chain_key)
 {
-       struct lock_class *class = hlock_class(hlock);
        struct hlist_head *hash_head = chainhashentry(chain_key);
        struct lock_chain *chain;
        int i, j;
@@ -3084,11 +3473,11 @@ static inline int add_chain_cache(struct task_struct *curr,
 
        chain->base = j;
        for (j = 0; j < chain->depth - 1; j++, i++) {
-               int lock_id = curr->held_locks[i].class_idx;
+               int lock_id = hlock_id(curr->held_locks + i);
 
                chain_hlocks[chain->base + j] = lock_id;
        }
-       chain_hlocks[chain->base + j] = class - lock_classes;
+       chain_hlocks[chain->base + j] = hlock_id(hlock);
        hlist_add_head_rcu(&chain->entry, hash_head);
        debug_atomic_inc(chain_lookup_misses);
        inc_chains(chain->irq_context);
@@ -3275,7 +3664,7 @@ static void check_chain_key(struct task_struct *curr)
                if (prev_hlock && (prev_hlock->irq_context !=
                                                        hlock->irq_context))
                        chain_key = INITIAL_CHAIN_KEY;
-               chain_key = iterate_chain_key(chain_key, hlock->class_idx);
+               chain_key = iterate_chain_key(chain_key, hlock_id(hlock));
                prev_hlock = hlock;
        }
        if (chain_key != curr->curr_chain_key) {
@@ -3434,24 +3823,32 @@ print_irq_inversion_bug(struct task_struct *curr,
  */
 static int
 check_usage_forwards(struct task_struct *curr, struct held_lock *this,
-                    enum lock_usage_bit bit, const char *irqclass)
+                    enum lock_usage_bit bit)
 {
-       int ret;
+       enum bfs_result ret;
        struct lock_list root;
        struct lock_list *target_entry;
+       enum lock_usage_bit read_bit = bit + LOCK_USAGE_READ_MASK;
+       unsigned usage_mask = lock_flag(bit) | lock_flag(read_bit);
 
-       root.parent = NULL;
-       root.class = hlock_class(this);
-       ret = find_usage_forwards(&root, lock_flag(bit), &target_entry);
-       if (ret < 0) {
+       bfs_init_root(&root, this);
+       ret = find_usage_forwards(&root, usage_mask, &target_entry);
+       if (bfs_error(ret)) {
                print_bfs_bug(ret);
                return 0;
        }
-       if (ret == 1)
-               return ret;
+       if (ret == BFS_RNOMATCH)
+               return 1;
+
+       /* Check whether write or read usage is the match */
+       if (target_entry->class->usage_mask & lock_flag(bit)) {
+               print_irq_inversion_bug(curr, &root, target_entry,
+                                       this, 1, state_name(bit));
+       } else {
+               print_irq_inversion_bug(curr, &root, target_entry,
+                                       this, 1, state_name(read_bit));
+       }
 
-       print_irq_inversion_bug(curr, &root, target_entry,
-                               this, 1, irqclass);
        return 0;
 }
 
@@ -3461,24 +3858,32 @@ check_usage_forwards(struct task_struct *curr, struct held_lock *this,
  */
 static int
 check_usage_backwards(struct task_struct *curr, struct held_lock *this,
-                     enum lock_usage_bit bit, const char *irqclass)
+                     enum lock_usage_bit bit)
 {
-       int ret;
+       enum bfs_result ret;
        struct lock_list root;
        struct lock_list *target_entry;
+       enum lock_usage_bit read_bit = bit + LOCK_USAGE_READ_MASK;
+       unsigned usage_mask = lock_flag(bit) | lock_flag(read_bit);
 
-       root.parent = NULL;
-       root.class = hlock_class(this);
-       ret = find_usage_backwards(&root, lock_flag(bit), &target_entry);
-       if (ret < 0) {
+       bfs_init_rootb(&root, this);
+       ret = find_usage_backwards(&root, usage_mask, &target_entry);
+       if (bfs_error(ret)) {
                print_bfs_bug(ret);
                return 0;
        }
-       if (ret == 1)
-               return ret;
+       if (ret == BFS_RNOMATCH)
+               return 1;
+
+       /* Check whether write or read usage is the match */
+       if (target_entry->class->usage_mask & lock_flag(bit)) {
+               print_irq_inversion_bug(curr, &root, target_entry,
+                                       this, 0, state_name(bit));
+       } else {
+               print_irq_inversion_bug(curr, &root, target_entry,
+                                       this, 0, state_name(read_bit));
+       }
 
-       print_irq_inversion_bug(curr, &root, target_entry,
-                               this, 0, irqclass);
        return 0;
 }
 
@@ -3517,8 +3922,6 @@ static int SOFTIRQ_verbose(struct lock_class *class)
        return 0;
 }
 
-#define STRICT_READ_CHECKS     1
-
 static int (*state_verbose_f[])(struct lock_class *class) = {
 #define LOCKDEP_STATE(__STATE) \
        __STATE##_verbose,
@@ -3544,16 +3947,6 @@ mark_lock_irq(struct task_struct *curr, struct held_lock *this,
        int dir = new_bit & LOCK_USAGE_DIR_MASK;
 
        /*
-        * mark USED_IN has to look forwards -- to ensure no dependency
-        * has ENABLED state, which would allow recursion deadlocks.
-        *
-        * mark ENABLED has to look backwards -- to ensure no dependee
-        * has USED_IN state, which, again, would allow  recursion deadlocks.
-        */
-       check_usage_f usage = dir ?
-               check_usage_backwards : check_usage_forwards;
-
-       /*
         * Validate that this particular lock does not have conflicting
         * usage states.
         */
@@ -3561,23 +3954,30 @@ mark_lock_irq(struct task_struct *curr, struct held_lock *this,
                return 0;
 
        /*
-        * Validate that the lock dependencies don't have conflicting usage
-        * states.
+        * Check for read in write conflicts
         */
-       if ((!read || STRICT_READ_CHECKS) &&
-                       !usage(curr, this, excl_bit, state_name(new_bit & ~LOCK_USAGE_READ_MASK)))
+       if (!read && !valid_state(curr, this, new_bit,
+                                 excl_bit + LOCK_USAGE_READ_MASK))
                return 0;
 
+
        /*
-        * Check for read in write conflicts
+        * Validate that the lock dependencies don't have conflicting usage
+        * states.
         */
-       if (!read) {
-               if (!valid_state(curr, this, new_bit, excl_bit + LOCK_USAGE_READ_MASK))
+       if (dir) {
+               /*
+                * mark ENABLED has to look backwards -- to ensure no dependee
+                * has USED_IN state, which, again, would allow  recursion deadlocks.
+                */
+               if (!check_usage_backwards(curr, this, excl_bit))
                        return 0;
-
-               if (STRICT_READ_CHECKS &&
-                       !usage(curr, this, excl_bit + LOCK_USAGE_READ_MASK,
-                               state_name(new_bit + LOCK_USAGE_READ_MASK)))
+       } else {
+               /*
+                * mark USED_IN has to look forwards -- to ensure no dependency
+                * has ENABLED state, which would allow recursion deadlocks.
+                */
+               if (!check_usage_forwards(curr, this, excl_bit))
                        return 0;
        }
 
@@ -3657,7 +4057,7 @@ void lockdep_hardirqs_on_prepare(unsigned long ip)
        if (unlikely(in_nmi()))
                return;
 
-       if (unlikely(current->lockdep_recursion & LOCKDEP_RECURSION_MASK))
+       if (unlikely(__this_cpu_read(lockdep_recursion)))
                return;
 
        if (unlikely(lockdep_hardirqs_enabled())) {
@@ -3693,7 +4093,7 @@ void lockdep_hardirqs_on_prepare(unsigned long ip)
 
        current->hardirq_chain_key = current->curr_chain_key;
 
-       current->lockdep_recursion++;
+       lockdep_recursion_inc();
        __trace_hardirqs_on_caller();
        lockdep_recursion_finish();
 }
@@ -3726,7 +4126,7 @@ void noinstr lockdep_hardirqs_on(unsigned long ip)
                goto skip_checks;
        }
 
-       if (unlikely(current->lockdep_recursion & LOCKDEP_RECURSION_MASK))
+       if (unlikely(__this_cpu_read(lockdep_recursion)))
                return;
 
        if (lockdep_hardirqs_enabled()) {
@@ -3756,7 +4156,7 @@ void noinstr lockdep_hardirqs_on(unsigned long ip)
 
 skip_checks:
        /* we'll do an OFF -> ON transition: */
-       this_cpu_write(hardirqs_enabled, 1);
+       __this_cpu_write(hardirqs_enabled, 1);
        trace->hardirq_enable_ip = ip;
        trace->hardirq_enable_event = ++trace->irq_events;
        debug_atomic_inc(hardirqs_on_events);
@@ -3779,7 +4179,7 @@ void noinstr lockdep_hardirqs_off(unsigned long ip)
        if (in_nmi()) {
                if (!IS_ENABLED(CONFIG_TRACE_IRQFLAGS_NMI))
                        return;
-       } else if (current->lockdep_recursion & LOCKDEP_RECURSION_MASK)
+       } else if (__this_cpu_read(lockdep_recursion))
                return;
 
        /*
@@ -3795,7 +4195,7 @@ void noinstr lockdep_hardirqs_off(unsigned long ip)
                /*
                 * We have done an ON -> OFF transition:
                 */
-               this_cpu_write(hardirqs_enabled, 0);
+               __this_cpu_write(hardirqs_enabled, 0);
                trace->hardirq_disable_ip = ip;
                trace->hardirq_disable_event = ++trace->irq_events;
                debug_atomic_inc(hardirqs_off_events);
@@ -3812,7 +4212,7 @@ void lockdep_softirqs_on(unsigned long ip)
 {
        struct irqtrace_events *trace = &current->irqtrace;
 
-       if (unlikely(!debug_locks || current->lockdep_recursion))
+       if (unlikely(!lockdep_enabled()))
                return;
 
        /*
@@ -3827,7 +4227,7 @@ void lockdep_softirqs_on(unsigned long ip)
                return;
        }
 
-       current->lockdep_recursion++;
+       lockdep_recursion_inc();
        /*
         * We'll do an OFF -> ON transition:
         */
@@ -3850,7 +4250,7 @@ void lockdep_softirqs_on(unsigned long ip)
  */
 void lockdep_softirqs_off(unsigned long ip)
 {
-       if (unlikely(!debug_locks || current->lockdep_recursion))
+       if (unlikely(!lockdep_enabled()))
                return;
 
        /*
@@ -3969,13 +4369,18 @@ static int separate_irq_context(struct task_struct *curr,
 static int mark_lock(struct task_struct *curr, struct held_lock *this,
                             enum lock_usage_bit new_bit)
 {
-       unsigned int new_mask = 1 << new_bit, ret = 1;
+       unsigned int new_mask, ret = 1;
 
        if (new_bit >= LOCK_USAGE_STATES) {
                DEBUG_LOCKS_WARN_ON(1);
                return 0;
        }
 
+       if (new_bit == LOCK_USED && this->read)
+               new_bit = LOCK_USED_READ;
+
+       new_mask = 1 << new_bit;
+
        /*
         * If already set then do not dirty the cacheline,
         * nor do any checks:
@@ -3988,26 +4393,32 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
        /*
         * Make sure we didn't race:
         */
-       if (unlikely(hlock_class(this)->usage_mask & new_mask)) {
-               graph_unlock();
-               return 1;
-       }
+       if (unlikely(hlock_class(this)->usage_mask & new_mask))
+               goto unlock;
 
        hlock_class(this)->usage_mask |= new_mask;
 
-       if (!(hlock_class(this)->usage_traces[new_bit] = save_trace()))
-               return 0;
+       if (new_bit < LOCK_TRACE_STATES) {
+               if (!(hlock_class(this)->usage_traces[new_bit] = save_trace()))
+                       return 0;
+       }
 
        switch (new_bit) {
+       case 0 ... LOCK_USED-1:
+               ret = mark_lock_irq(curr, this, new_bit);
+               if (!ret)
+                       return 0;
+               break;
+
        case LOCK_USED:
                debug_atomic_dec(nr_unused_locks);
                break;
+
        default:
-               ret = mark_lock_irq(curr, this, new_bit);
-               if (!ret)
-                       return 0;
+               break;
        }
 
+unlock:
        graph_unlock();
 
        /*
@@ -4220,11 +4631,11 @@ void lockdep_init_map_waits(struct lockdep_map *lock, const char *name,
        if (subclass) {
                unsigned long flags;
 
-               if (DEBUG_LOCKS_WARN_ON(current->lockdep_recursion))
+               if (DEBUG_LOCKS_WARN_ON(!lockdep_enabled()))
                        return;
 
                raw_local_irq_save(flags);
-               current->lockdep_recursion++;
+               lockdep_recursion_inc();
                register_lock_class(lock, subclass, 1);
                lockdep_recursion_finish();
                raw_local_irq_restore(flags);
@@ -4411,7 +4822,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
                chain_key = INITIAL_CHAIN_KEY;
                chain_head = 1;
        }
-       chain_key = iterate_chain_key(chain_key, class_idx);
+       chain_key = iterate_chain_key(chain_key, hlock_id(hlock));
 
        if (nest_lock && !__lock_is_held(nest_lock, -1)) {
                print_lock_nested_lock_not_held(curr, hlock, ip);
@@ -4907,11 +5318,11 @@ void lock_set_class(struct lockdep_map *lock, const char *name,
 {
        unsigned long flags;
 
-       if (unlikely(current->lockdep_recursion))
+       if (unlikely(!lockdep_enabled()))
                return;
 
        raw_local_irq_save(flags);
-       current->lockdep_recursion++;
+       lockdep_recursion_inc();
        check_flags(flags);
        if (__lock_set_class(lock, name, key, subclass, ip))
                check_chain_key(current);
@@ -4924,11 +5335,11 @@ void lock_downgrade(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
 
-       if (unlikely(current->lockdep_recursion))
+       if (unlikely(!lockdep_enabled()))
                return;
 
        raw_local_irq_save(flags);
-       current->lockdep_recursion++;
+       lockdep_recursion_inc();
        check_flags(flags);
        if (__lock_downgrade(lock, ip))
                check_chain_key(current);
@@ -4942,12 +5353,20 @@ static void verify_lock_unused(struct lockdep_map *lock, struct held_lock *hlock
 {
 #ifdef CONFIG_PROVE_LOCKING
        struct lock_class *class = look_up_lock_class(lock, subclass);
+       unsigned long mask = LOCKF_USED;
 
        /* if it doesn't have a class (yet), it certainly hasn't been used yet */
        if (!class)
                return;
 
-       if (!(class->usage_mask & LOCK_USED))
+       /*
+        * READ locks only conflict with USED, such that if we only ever use
+        * READ locks, there is no deadlock possible -- RCU.
+        */
+       if (!hlock->read)
+               mask |= LOCKF_USED_READ;
+
+       if (!(class->usage_mask & mask))
                return;
 
        hlock->class_idx = class - lock_classes;
@@ -4958,7 +5377,7 @@ static void verify_lock_unused(struct lockdep_map *lock, struct held_lock *hlock
 
 static bool lockdep_nmi(void)
 {
-       if (current->lockdep_recursion & LOCKDEP_RECURSION_MASK)
+       if (raw_cpu_read(lockdep_recursion))
                return false;
 
        if (!in_nmi())
@@ -4968,6 +5387,20 @@ static bool lockdep_nmi(void)
 }
 
 /*
+ * read_lock() is recursive if:
+ * 1. We force lockdep think this way in selftests or
+ * 2. The implementation is not queued read/write lock or
+ * 3. The locker is at an in_interrupt() context.
+ */
+bool read_lock_is_recursive(void)
+{
+       return force_read_lock_recursive ||
+              !IS_ENABLED(CONFIG_QUEUED_RWLOCKS) ||
+              in_interrupt();
+}
+EXPORT_SYMBOL_GPL(read_lock_is_recursive);
+
+/*
  * We are not always called with irqs disabled - do that here,
  * and also avoid lockdep recursion:
  */
@@ -4977,7 +5410,12 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 {
        unsigned long flags;
 
-       if (unlikely(current->lockdep_recursion)) {
+       trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
+
+       if (!debug_locks)
+               return;
+
+       if (unlikely(!lockdep_enabled())) {
                /* XXX allow trylock from NMI ?!? */
                if (lockdep_nmi() && !trylock) {
                        struct held_lock hlock;
@@ -5000,8 +5438,7 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        raw_local_irq_save(flags);
        check_flags(flags);
 
-       current->lockdep_recursion++;
-       trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
+       lockdep_recursion_inc();
        __lock_acquire(lock, subclass, trylock, read, check,
                       irqs_disabled_flags(flags), nest_lock, ip, 0, 0);
        lockdep_recursion_finish();
@@ -5013,13 +5450,15 @@ void lock_release(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
 
-       if (unlikely(current->lockdep_recursion))
+       trace_lock_release(lock, ip);
+
+       if (unlikely(!lockdep_enabled()))
                return;
 
        raw_local_irq_save(flags);
        check_flags(flags);
-       current->lockdep_recursion++;
-       trace_lock_release(lock, ip);
+
+       lockdep_recursion_inc();
        if (__lock_release(lock, ip))
                check_chain_key(current);
        lockdep_recursion_finish();
@@ -5032,13 +5471,13 @@ noinstr int lock_is_held_type(const struct lockdep_map *lock, int read)
        unsigned long flags;
        int ret = 0;
 
-       if (unlikely(current->lockdep_recursion))
+       if (unlikely(!lockdep_enabled()))
                return 1; /* avoid false negative lockdep_assert_held() */
 
        raw_local_irq_save(flags);
        check_flags(flags);
 
-       current->lockdep_recursion++;
+       lockdep_recursion_inc();
        ret = __lock_is_held(lock, read);
        lockdep_recursion_finish();
        raw_local_irq_restore(flags);
@@ -5053,13 +5492,13 @@ struct pin_cookie lock_pin_lock(struct lockdep_map *lock)
        struct pin_cookie cookie = NIL_COOKIE;
        unsigned long flags;
 
-       if (unlikely(current->lockdep_recursion))
+       if (unlikely(!lockdep_enabled()))
                return cookie;
 
        raw_local_irq_save(flags);
        check_flags(flags);
 
-       current->lockdep_recursion++;
+       lockdep_recursion_inc();
        cookie = __lock_pin_lock(lock);
        lockdep_recursion_finish();
        raw_local_irq_restore(flags);
@@ -5072,13 +5511,13 @@ void lock_repin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
 {
        unsigned long flags;
 
-       if (unlikely(current->lockdep_recursion))
+       if (unlikely(!lockdep_enabled()))
                return;
 
        raw_local_irq_save(flags);
        check_flags(flags);
 
-       current->lockdep_recursion++;
+       lockdep_recursion_inc();
        __lock_repin_lock(lock, cookie);
        lockdep_recursion_finish();
        raw_local_irq_restore(flags);
@@ -5089,13 +5528,13 @@ void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
 {
        unsigned long flags;
 
-       if (unlikely(current->lockdep_recursion))
+       if (unlikely(!lockdep_enabled()))
                return;
 
        raw_local_irq_save(flags);
        check_flags(flags);
 
-       current->lockdep_recursion++;
+       lockdep_recursion_inc();
        __lock_unpin_lock(lock, cookie);
        lockdep_recursion_finish();
        raw_local_irq_restore(flags);
@@ -5205,8 +5644,6 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip)
                hlock->holdtime_stamp = now;
        }
 
-       trace_lock_acquired(lock, ip);
-
        stats = get_lock_stats(hlock_class(hlock));
        if (waittime) {
                if (hlock->read)
@@ -5225,16 +5662,14 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
 
-       if (unlikely(!lock_stat || !debug_locks))
-               return;
+       trace_lock_acquired(lock, ip);
 
-       if (unlikely(current->lockdep_recursion))
+       if (unlikely(!lock_stat || !lockdep_enabled()))
                return;
 
        raw_local_irq_save(flags);
        check_flags(flags);
-       current->lockdep_recursion++;
-       trace_lock_contended(lock, ip);
+       lockdep_recursion_inc();
        __lock_contended(lock, ip);
        lockdep_recursion_finish();
        raw_local_irq_restore(flags);
@@ -5245,15 +5680,14 @@ void lock_acquired(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
 
-       if (unlikely(!lock_stat || !debug_locks))
-               return;
+       trace_lock_contended(lock, ip);
 
-       if (unlikely(current->lockdep_recursion))
+       if (unlikely(!lock_stat || !lockdep_enabled()))
                return;
 
        raw_local_irq_save(flags);
        check_flags(flags);
-       current->lockdep_recursion++;
+       lockdep_recursion_inc();
        __lock_acquired(lock, ip);
        lockdep_recursion_finish();
        raw_local_irq_restore(flags);
@@ -5292,7 +5726,7 @@ static void remove_class_from_lock_chain(struct pending_free *pf,
        int i;
 
        for (i = chain->base; i < chain->base + chain->depth; i++) {
-               if (chain_hlocks[i] != class - lock_classes)
+               if (chain_hlock_class_idx(chain_hlocks[i]) != class - lock_classes)
                        continue;
                /*
                 * Each lock class occurs at most once in a lock chain so once
index baca699..de49f9e 100644 (file)
@@ -19,9 +19,13 @@ enum lock_usage_bit {
 #include "lockdep_states.h"
 #undef LOCKDEP_STATE
        LOCK_USED,
-       LOCK_USAGE_STATES
+       LOCK_USED_READ,
+       LOCK_USAGE_STATES,
 };
 
+/* states after LOCK_USED_READ are not traced and printed */
+static_assert(LOCK_TRACE_STATES == LOCK_USAGE_STATES);
+
 #define LOCK_USAGE_READ_MASK 1
 #define LOCK_USAGE_DIR_MASK  2
 #define LOCK_USAGE_STATE_MASK (~(LOCK_USAGE_READ_MASK | LOCK_USAGE_DIR_MASK))
@@ -40,6 +44,7 @@ enum {
 #include "lockdep_states.h"
 #undef LOCKDEP_STATE
        __LOCKF(USED)
+       __LOCKF(USED_READ)
 };
 
 #define LOCKDEP_STATE(__STATE) LOCKF_ENABLED_##__STATE |
@@ -119,7 +124,7 @@ static const unsigned long LOCKF_USED_IN_IRQ_READ =
 extern struct list_head all_lock_classes;
 extern struct lock_chain lock_chains[];
 
-#define LOCK_USAGE_CHARS (1+LOCK_USAGE_STATES/2)
+#define LOCK_USAGE_CHARS (2*XXX_LOCK_USAGE_STATES + 1)
 
 extern void get_usage_chars(struct lock_class *class,
                            char usage[LOCK_USAGE_CHARS]);
index 8bbafe3..70a32a5 100644 (file)
@@ -45,7 +45,7 @@ EXPORT_SYMBOL_GPL(percpu_free_rwsem);
 
 static bool __percpu_down_read_trylock(struct percpu_rw_semaphore *sem)
 {
-       __this_cpu_inc(*sem->read_count);
+       this_cpu_inc(*sem->read_count);
 
        /*
         * Due to having preemption disabled the decrement happens on
@@ -71,7 +71,7 @@ static bool __percpu_down_read_trylock(struct percpu_rw_semaphore *sem)
        if (likely(!atomic_read_acquire(&sem->block)))
                return true;
 
-       __this_cpu_dec(*sem->read_count);
+       this_cpu_dec(*sem->read_count);
 
        /* Prod writer to re-evaluate readers_active_check() */
        rcuwait_wake_up(&sem->writer);
index 1c5cff3..c075a18 100644 (file)
@@ -3275,6 +3275,11 @@ static int find_module_sections(struct module *mod, struct load_info *info)
                                                sizeof(unsigned long),
                                                &mod->num_kprobe_blacklist);
 #endif
+#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
+       mod->static_call_sites = section_objs(info, ".static_call_sites",
+                                             sizeof(*mod->static_call_sites),
+                                             &mod->num_static_call_sites);
+#endif
        mod->extable = section_objs(info, "__ex_table",
                                    sizeof(*mod->extable), &mod->num_exentries);
 
@@ -3792,9 +3797,13 @@ static int prepare_coming_module(struct module *mod)
        if (err)
                return err;
 
-       blocking_notifier_call_chain(&module_notify_list,
-                                    MODULE_STATE_COMING, mod);
-       return 0;
+       err = blocking_notifier_call_chain_robust(&module_notify_list,
+                       MODULE_STATE_COMING, MODULE_STATE_GOING, mod);
+       err = notifier_to_errno(err);
+       if (err)
+               klp_module_going(mod);
+
+       return err;
 }
 
 static int unknown_module_param_cb(char *param, char *val, const char *modname,
index 84c987d..1b019cb 100644 (file)
@@ -94,6 +94,34 @@ static int notifier_call_chain(struct notifier_block **nl,
 }
 NOKPROBE_SYMBOL(notifier_call_chain);
 
+/**
+ * notifier_call_chain_robust - Inform the registered notifiers about an event
+ *                              and rollback on error.
+ * @nl:                Pointer to head of the blocking notifier chain
+ * @val_up:    Value passed unmodified to the notifier function
+ * @val_down:  Value passed unmodified to the notifier function when recovering
+ *              from an error on @val_up
+ * @v          Pointer passed unmodified to the notifier function
+ *
+ * NOTE:       It is important the @nl chain doesn't change between the two
+ *             invocations of notifier_call_chain() such that we visit the
+ *             exact same notifier callbacks; this rules out any RCU usage.
+ *
+ * Returns:    the return value of the @val_up call.
+ */
+static int notifier_call_chain_robust(struct notifier_block **nl,
+                                    unsigned long val_up, unsigned long val_down,
+                                    void *v)
+{
+       int ret, nr = 0;
+
+       ret = notifier_call_chain(nl, val_up, v, -1, &nr);
+       if (ret & NOTIFY_STOP_MASK)
+               notifier_call_chain(nl, val_down, v, nr-1, NULL);
+
+       return ret;
+}
+
 /*
  *     Atomic notifier chain routines.  Registration and unregistration
  *     use a spinlock, and call_chain is synchronized by RCU (no locks).
@@ -144,13 +172,30 @@ int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
 }
 EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
 
+int atomic_notifier_call_chain_robust(struct atomic_notifier_head *nh,
+               unsigned long val_up, unsigned long val_down, void *v)
+{
+       unsigned long flags;
+       int ret;
+
+       /*
+        * Musn't use RCU; because then the notifier list can
+        * change between the up and down traversal.
+        */
+       spin_lock_irqsave(&nh->lock, flags);
+       ret = notifier_call_chain_robust(&nh->head, val_up, val_down, v);
+       spin_unlock_irqrestore(&nh->lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(atomic_notifier_call_chain_robust);
+NOKPROBE_SYMBOL(atomic_notifier_call_chain_robust);
+
 /**
- *     __atomic_notifier_call_chain - Call functions in an atomic notifier chain
+ *     atomic_notifier_call_chain - Call functions in an atomic notifier chain
  *     @nh: Pointer to head of the atomic notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
- *     @nr_to_call: See the comment for notifier_call_chain.
- *     @nr_calls: See the comment for notifier_call_chain.
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in an atomic context, so they must not block.
@@ -163,24 +208,16 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
  *     Otherwise the return value is the return value
  *     of the last notifier function called.
  */
-int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
-                                unsigned long val, void *v,
-                                int nr_to_call, int *nr_calls)
+int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+                              unsigned long val, void *v)
 {
        int ret;
 
        rcu_read_lock();
-       ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
+       ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
        rcu_read_unlock();
-       return ret;
-}
-EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain);
-NOKPROBE_SYMBOL(__atomic_notifier_call_chain);
 
-int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
-                              unsigned long val, void *v)
-{
-       return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
 NOKPROBE_SYMBOL(atomic_notifier_call_chain);
@@ -250,13 +287,30 @@ int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
 }
 EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
 
+int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
+               unsigned long val_up, unsigned long val_down, void *v)
+{
+       int ret = NOTIFY_DONE;
+
+       /*
+        * We check the head outside the lock, but if this access is
+        * racy then it does not matter what the result of the test
+        * is, we re-check the list after having taken the lock anyway:
+        */
+       if (rcu_access_pointer(nh->head)) {
+               down_read(&nh->rwsem);
+               ret = notifier_call_chain_robust(&nh->head, val_up, val_down, v);
+               up_read(&nh->rwsem);
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_robust);
+
 /**
- *     __blocking_notifier_call_chain - Call functions in a blocking notifier chain
+ *     blocking_notifier_call_chain - Call functions in a blocking notifier chain
  *     @nh: Pointer to head of the blocking notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
- *     @nr_to_call: See comment for notifier_call_chain.
- *     @nr_calls: See comment for notifier_call_chain.
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in a process context, so they are allowed to block.
@@ -268,9 +322,8 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
  *     Otherwise the return value is the return value
  *     of the last notifier function called.
  */
-int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
-                                  unsigned long val, void *v,
-                                  int nr_to_call, int *nr_calls)
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+               unsigned long val, void *v)
 {
        int ret = NOTIFY_DONE;
 
@@ -281,19 +334,11 @@ int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
         */
        if (rcu_access_pointer(nh->head)) {
                down_read(&nh->rwsem);
-               ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
-                                       nr_calls);
+               ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
                up_read(&nh->rwsem);
        }
        return ret;
 }
-EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain);
-
-int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
-               unsigned long val, void *v)
-{
-       return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
-}
 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
 
 /*
@@ -335,13 +380,18 @@ int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
 }
 EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
 
+int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
+               unsigned long val_up, unsigned long val_down, void *v)
+{
+       return notifier_call_chain_robust(&nh->head, val_up, val_down, v);
+}
+EXPORT_SYMBOL_GPL(raw_notifier_call_chain_robust);
+
 /**
- *     __raw_notifier_call_chain - Call functions in a raw notifier chain
+ *     raw_notifier_call_chain - Call functions in a raw notifier chain
  *     @nh: Pointer to head of the raw notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
- *     @nr_to_call: See comment for notifier_call_chain.
- *     @nr_calls: See comment for notifier_call_chain
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in an undefined context.
@@ -354,18 +404,10 @@ EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
  *     Otherwise the return value is the return value
  *     of the last notifier function called.
  */
-int __raw_notifier_call_chain(struct raw_notifier_head *nh,
-                             unsigned long val, void *v,
-                             int nr_to_call, int *nr_calls)
-{
-       return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
-}
-EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);
-
 int raw_notifier_call_chain(struct raw_notifier_head *nh,
                unsigned long val, void *v)
 {
-       return __raw_notifier_call_chain(nh, val, v, -1, NULL);
+       return notifier_call_chain(&nh->head, val, v, -1, NULL);
 }
 EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
 
@@ -437,12 +479,10 @@ int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
 EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
 
 /**
- *     __srcu_notifier_call_chain - Call functions in an SRCU notifier chain
+ *     srcu_notifier_call_chain - Call functions in an SRCU notifier chain
  *     @nh: Pointer to head of the SRCU notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
- *     @nr_to_call: See comment for notifier_call_chain.
- *     @nr_calls: See comment for notifier_call_chain
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in a process context, so they are allowed to block.
@@ -454,25 +494,17 @@ EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
  *     Otherwise the return value is the return value
  *     of the last notifier function called.
  */
-int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
-                              unsigned long val, void *v,
-                              int nr_to_call, int *nr_calls)
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+               unsigned long val, void *v)
 {
        int ret;
        int idx;
 
        idx = srcu_read_lock(&nh->srcu);
-       ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
+       ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
        srcu_read_unlock(&nh->srcu, idx);
        return ret;
 }
-EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain);
-
-int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
-               unsigned long val, void *v)
-{
-       return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
-}
 EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
 
 /**
index 16cb894..d4d3ba6 100644 (file)
@@ -215,12 +215,13 @@ int padata_do_parallel(struct padata_shell *ps,
        padata->pd = pd;
        padata->cb_cpu = *cb_cpu;
 
-       rcu_read_unlock_bh();
-
        spin_lock(&padata_works_lock);
        padata->seq_nr = ++pd->seq_nr;
        pw = padata_work_alloc();
        spin_unlock(&padata_works_lock);
+
+       rcu_read_unlock_bh();
+
        if (pw) {
                padata_work_init(pw, padata_parallel_worker, padata, 0);
                queue_work(pinst->parallel_wq, &pw->pw_work);
index f33769f..1dee708 100644 (file)
@@ -659,7 +659,7 @@ static void power_down(void)
                break;
        case HIBERNATION_PLATFORM:
                hibernation_platform_enter();
-               /* Fall through */
+               fallthrough;
        case HIBERNATION_SHUTDOWN:
                if (pm_power_off)
                        kernel_power_off();
@@ -706,8 +706,8 @@ static int load_image_and_restore(void)
  */
 int hibernate(void)
 {
-       int error, nr_calls = 0;
        bool snapshot_test = false;
+       int error;
 
        if (!hibernation_available()) {
                pm_pr_dbg("Hibernation not available.\n");
@@ -723,11 +723,9 @@ int hibernate(void)
 
        pr_info("hibernation entry\n");
        pm_prepare_console();
-       error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
-       if (error) {
-               nr_calls--;
-               goto Exit;
-       }
+       error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);
+       if (error)
+               goto Restore;
 
        ksys_sync_helper();
 
@@ -785,7 +783,8 @@ int hibernate(void)
        /* Don't bother checking whether freezer_test_done is true */
        freezer_test_done = false;
  Exit:
-       __pm_notifier_call_chain(PM_POST_HIBERNATION, nr_calls, NULL);
+       pm_notifier_call_chain(PM_POST_HIBERNATION);
+ Restore:
        pm_restore_console();
        hibernate_release();
  Unlock:
@@ -804,7 +803,7 @@ int hibernate(void)
  */
 int hibernate_quiet_exec(int (*func)(void *data), void *data)
 {
-       int error, nr_calls = 0;
+       int error;
 
        lock_system_sleep();
 
@@ -815,11 +814,9 @@ int hibernate_quiet_exec(int (*func)(void *data), void *data)
 
        pm_prepare_console();
 
-       error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
-       if (error) {
-               nr_calls--;
-               goto exit;
-       }
+       error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);
+       if (error)
+               goto restore;
 
        error = freeze_processes();
        if (error)
@@ -880,8 +877,9 @@ thaw:
        thaw_processes();
 
 exit:
-       __pm_notifier_call_chain(PM_POST_HIBERNATION, nr_calls, NULL);
+       pm_notifier_call_chain(PM_POST_HIBERNATION);
 
+restore:
        pm_restore_console();
 
        hibernate_release();
@@ -910,7 +908,7 @@ EXPORT_SYMBOL_GPL(hibernate_quiet_exec);
  */
 static int software_resume(void)
 {
-       int error, nr_calls = 0;
+       int error;
 
        /*
         * If the user said "noresume".. bail out early.
@@ -997,11 +995,9 @@ static int software_resume(void)
 
        pr_info("resume from hibernation\n");
        pm_prepare_console();
-       error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls);
-       if (error) {
-               nr_calls--;
-               goto Close_Finish;
-       }
+       error = pm_notifier_call_chain_robust(PM_RESTORE_PREPARE, PM_POST_RESTORE);
+       if (error)
+               goto Restore;
 
        pm_pr_dbg("Preparing processes for hibernation restore.\n");
        error = freeze_processes();
@@ -1017,7 +1013,8 @@ static int software_resume(void)
        error = load_image_and_restore();
        thaw_processes();
  Finish:
-       __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
+       pm_notifier_call_chain(PM_POST_RESTORE);
+ Restore:
        pm_restore_console();
        pr_info("resume failed (%d)\n", error);
        hibernate_release();
index 40f86ec..0aefd6f 100644 (file)
@@ -80,18 +80,18 @@ int unregister_pm_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(unregister_pm_notifier);
 
-int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls)
+int pm_notifier_call_chain_robust(unsigned long val_up, unsigned long val_down)
 {
        int ret;
 
-       ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL,
-                                               nr_to_call, nr_calls);
+       ret = blocking_notifier_call_chain_robust(&pm_chain_head, val_up, val_down, NULL);
 
        return notifier_to_errno(ret);
 }
+
 int pm_notifier_call_chain(unsigned long val)
 {
-       return __pm_notifier_call_chain(val, -1, NULL);
+       return blocking_notifier_call_chain(&pm_chain_head, val, NULL);
 }
 
 /* If set, devices may be suspended and resumed asynchronously. */
index 32fc89a..24f12d5 100644 (file)
@@ -210,8 +210,7 @@ static inline void suspend_test_finish(const char *label) {}
 
 #ifdef CONFIG_PM_SLEEP
 /* kernel/power/main.c */
-extern int __pm_notifier_call_chain(unsigned long val, int nr_to_call,
-                                   int *nr_calls);
+extern int pm_notifier_call_chain_robust(unsigned long val_up, unsigned long val_down);
 extern int pm_notifier_call_chain(unsigned long val);
 #endif
 
index db0bed2..ec7e1e8 100644 (file)
@@ -119,7 +119,7 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
                 * and add, then see if the aggregate has changed.
                 */
                plist_del(node, &c->list);
-               /* fall through */
+               fallthrough;
        case PM_QOS_ADD_REQ:
                plist_node_init(node, new_value);
                plist_add(node, &c->list);
@@ -188,7 +188,7 @@ bool pm_qos_update_flags(struct pm_qos_flags *pqf,
                break;
        case PM_QOS_UPDATE_REQ:
                pm_qos_flags_remove_req(pqf, req);
-               /* fall through */
+               fallthrough;
        case PM_QOS_ADD_REQ:
                req->flags = val;
                INIT_LIST_HEAD(&req->node);
index 8b1bb5e..32391ac 100644 (file)
@@ -342,18 +342,16 @@ static int suspend_test(int level)
  */
 static int suspend_prepare(suspend_state_t state)
 {
-       int error, nr_calls = 0;
+       int error;
 
        if (!sleep_state_supported(state))
                return -EPERM;
 
        pm_prepare_console();
 
-       error = __pm_notifier_call_chain(PM_SUSPEND_PREPARE, -1, &nr_calls);
-       if (error) {
-               nr_calls--;
-               goto Finish;
-       }
+       error = pm_notifier_call_chain_robust(PM_SUSPEND_PREPARE, PM_POST_SUSPEND);
+       if (error)
+               goto Restore;
 
        trace_suspend_resume(TPS("freeze_processes"), 0, true);
        error = suspend_freeze_processes();
@@ -363,8 +361,8 @@ static int suspend_prepare(suspend_state_t state)
 
        suspend_stats.failed_freeze++;
        dpm_save_failed_step(SUSPEND_FREEZE);
- Finish:
-       __pm_notifier_call_chain(PM_POST_SUSPEND, nr_calls, NULL);
+       pm_notifier_call_chain(PM_POST_SUSPEND);
+ Restore:
        pm_restore_console();
        return error;
 }
index d5eedc2..047f598 100644 (file)
@@ -46,7 +46,7 @@ int is_hibernate_resume_dev(const struct inode *bd_inode)
 static int snapshot_open(struct inode *inode, struct file *filp)
 {
        struct snapshot_data *data;
-       int error, nr_calls = 0;
+       int error;
 
        if (!hibernation_available())
                return -EPERM;
@@ -73,9 +73,7 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                        swap_type_of(swsusp_resume_device, 0, NULL) : -1;
                data->mode = O_RDONLY;
                data->free_bitmaps = false;
-               error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
-               if (error)
-                       __pm_notifier_call_chain(PM_POST_HIBERNATION, --nr_calls, NULL);
+               error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);
        } else {
                /*
                 * Resuming.  We may need to wait for the image device to
@@ -85,15 +83,11 @@ static int snapshot_open(struct inode *inode, struct file *filp)
 
                data->swap = -1;
                data->mode = O_WRONLY;
-               error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls);
+               error = pm_notifier_call_chain_robust(PM_RESTORE_PREPARE, PM_POST_RESTORE);
                if (!error) {
                        error = create_basic_memory_bitmaps();
                        data->free_bitmaps = !error;
-               } else
-                       nr_calls--;
-
-               if (error)
-                       __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
+               }
        }
        if (error)
                hibernate_release();
index cf66a3c..e01cba5 100644 (file)
@@ -167,7 +167,7 @@ static inline unsigned long rcu_seq_diff(unsigned long new, unsigned long old)
 # define STATE_RCU_HEAD_READY  0
 # define STATE_RCU_HEAD_QUEUED 1
 
-extern struct debug_obj_descr rcuhead_debug_descr;
+extern const struct debug_obj_descr rcuhead_debug_descr;
 
 static inline int debug_rcu_head_queue(struct rcu_head *head)
 {
index 835e2df..05d3e13 100644 (file)
@@ -590,7 +590,7 @@ void exit_tasks_rcu_finish(void) __releases(&tasks_rcu_exit_srcu)
 }
 
 #else /* #ifdef CONFIG_TASKS_RCU */
-static void show_rcu_tasks_classic_gp_kthread(void) { }
+static inline void show_rcu_tasks_classic_gp_kthread(void) { }
 void exit_tasks_rcu_start(void) { }
 void exit_tasks_rcu_finish(void) { exit_tasks_rcu_finish_trace(current); }
 #endif /* #else #ifdef CONFIG_TASKS_RCU */
index 8ce77d9..f78ee75 100644 (file)
@@ -673,6 +673,7 @@ void rcu_idle_enter(void)
        lockdep_assert_irqs_disabled();
        rcu_eqs_enter(false);
 }
+EXPORT_SYMBOL_GPL(rcu_idle_enter);
 
 #ifdef CONFIG_NO_HZ_FULL
 /**
@@ -886,6 +887,7 @@ void rcu_idle_exit(void)
        rcu_eqs_exit(false);
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_idle_exit);
 
 #ifdef CONFIG_NO_HZ_FULL
 /**
index 2de49b5..3e0f4bc 100644 (file)
@@ -469,7 +469,7 @@ void destroy_rcu_head_on_stack(struct rcu_head *head)
 }
 EXPORT_SYMBOL_GPL(destroy_rcu_head_on_stack);
 
-struct debug_obj_descr rcuhead_debug_descr = {
+const struct debug_obj_descr rcuhead_debug_descr = {
        .name = "rcu_head",
        .is_static_object = rcuhead_is_static_object,
 };
index 8471a0f..8160ab5 100644 (file)
@@ -36,6 +36,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_rt_tp);
 EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_dl_tp);
 EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_irq_tp);
 EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_se_tp);
+EXPORT_TRACEPOINT_SYMBOL_GPL(sched_cpu_capacity_tp);
 EXPORT_TRACEPOINT_SYMBOL_GPL(sched_overutilized_tp);
 EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_cfs_tp);
 EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_se_tp);
@@ -940,11 +941,6 @@ static inline unsigned int uclamp_bucket_id(unsigned int clamp_value)
        return clamp_value / UCLAMP_BUCKET_DELTA;
 }
 
-static inline unsigned int uclamp_bucket_base_value(unsigned int clamp_value)
-{
-       return UCLAMP_BUCKET_DELTA * uclamp_bucket_id(clamp_value);
-}
-
 static inline unsigned int uclamp_none(enum uclamp_id clamp_id)
 {
        if (clamp_id == UCLAMP_MIN)
@@ -2320,7 +2316,7 @@ static int select_fallback_rq(int cpu, struct task_struct *p)
                                state = possible;
                                break;
                        }
-                       /* Fall-through */
+                       fallthrough;
                case possible:
                        do_set_cpus_allowed(p, cpu_possible_mask);
                        state = fail;
@@ -4551,9 +4547,12 @@ void __noreturn do_task_dead(void)
 
 static inline void sched_submit_work(struct task_struct *tsk)
 {
+       unsigned int task_flags;
+
        if (!tsk->state)
                return;
 
+       task_flags = tsk->flags;
        /*
         * If a worker went to sleep, notify and ask workqueue whether
         * it wants to wake up a task to maintain concurrency.
@@ -4562,9 +4561,9 @@ static inline void sched_submit_work(struct task_struct *tsk)
         * in the possible wakeup of a kworker and because wq_worker_sleeping()
         * requires it.
         */
-       if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
+       if (task_flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
                preempt_disable();
-               if (tsk->flags & PF_WQ_WORKER)
+               if (task_flags & PF_WQ_WORKER)
                        wq_worker_sleeping(tsk);
                else
                        io_wq_worker_sleeping(tsk);
index 3862a28..6d93f45 100644 (file)
@@ -1525,14 +1525,38 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
         */
        if (pi_task && dl_prio(pi_task->normal_prio) && p->dl.dl_boosted) {
                pi_se = &pi_task->dl;
+               /*
+                * Because of delays in the detection of the overrun of a
+                * thread's runtime, it might be the case that a thread
+                * goes to sleep in a rt mutex with negative runtime. As
+                * a consequence, the thread will be throttled.
+                *
+                * While waiting for the mutex, this thread can also be
+                * boosted via PI, resulting in a thread that is throttled
+                * and boosted at the same time.
+                *
+                * In this case, the boost overrides the throttle.
+                */
+               if (p->dl.dl_throttled) {
+                       /*
+                        * The replenish timer needs to be canceled. No
+                        * problem if it fires concurrently: boosted threads
+                        * are ignored in dl_task_timer().
+                        */
+                       hrtimer_try_to_cancel(&p->dl.dl_timer);
+                       p->dl.dl_throttled = 0;
+               }
        } else if (!dl_prio(p->normal_prio)) {
                /*
-                * Special case in which we have a !SCHED_DEADLINE task
-                * that is going to be deboosted, but exceeds its
-                * runtime while doing so. No point in replenishing
-                * it, as it's going to return back to its original
-                * scheduling class after this.
+                * Special case in which we have a !SCHED_DEADLINE task that is going
+                * to be deboosted, but exceeds its runtime while doing so. No point in
+                * replenishing it, as it's going to return back to its original
+                * scheduling class after this. If it has been throttled, we need to
+                * clear the flag, otherwise the task may wake up as throttled after
+                * being boosted again with no means to replenish the runtime and clear
+                * the throttle.
                 */
+               p->dl.dl_throttled = 0;
                BUG_ON(!p->dl.dl_boosted || flags != ENQUEUE_REPLENISH);
                return;
        }
index 36c5426..0655524 100644 (file)
@@ -245,6 +245,60 @@ set_table_entry(struct ctl_table *entry,
        entry->proc_handler = proc_handler;
 }
 
+static int sd_ctl_doflags(struct ctl_table *table, int write,
+                         void *buffer, size_t *lenp, loff_t *ppos)
+{
+       unsigned long flags = *(unsigned long *)table->data;
+       size_t data_size = 0;
+       size_t len = 0;
+       char *tmp;
+       int idx;
+
+       if (write)
+               return 0;
+
+       for_each_set_bit(idx, &flags, __SD_FLAG_CNT) {
+               char *name = sd_flag_debug[idx].name;
+
+               /* Name plus whitespace */
+               data_size += strlen(name) + 1;
+       }
+
+       if (*ppos > data_size) {
+               *lenp = 0;
+               return 0;
+       }
+
+       tmp = kcalloc(data_size + 1, sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       for_each_set_bit(idx, &flags, __SD_FLAG_CNT) {
+               char *name = sd_flag_debug[idx].name;
+
+               len += snprintf(tmp + len, strlen(name) + 2, "%s ", name);
+       }
+
+       tmp += *ppos;
+       len -= *ppos;
+
+       if (len > *lenp)
+               len = *lenp;
+       if (len)
+               memcpy(buffer, tmp, len);
+       if (len < *lenp) {
+               ((char *)buffer)[len] = '\n';
+               len++;
+       }
+
+       *lenp = len;
+       *ppos += len;
+
+       kfree(tmp);
+
+       return 0;
+}
+
 static struct ctl_table *
 sd_alloc_ctl_domain_table(struct sched_domain *sd)
 {
@@ -258,7 +312,7 @@ sd_alloc_ctl_domain_table(struct sched_domain *sd)
        set_table_entry(&table[2], "busy_factor",         &sd->busy_factor,         sizeof(int),  0644, proc_dointvec_minmax);
        set_table_entry(&table[3], "imbalance_pct",       &sd->imbalance_pct,       sizeof(int),  0644, proc_dointvec_minmax);
        set_table_entry(&table[4], "cache_nice_tries",    &sd->cache_nice_tries,    sizeof(int),  0644, proc_dointvec_minmax);
-       set_table_entry(&table[5], "flags",               &sd->flags,               sizeof(int),  0444, proc_dointvec_minmax);
+       set_table_entry(&table[5], "flags",               &sd->flags,               sizeof(int),  0444, sd_ctl_doflags);
        set_table_entry(&table[6], "max_newidle_lb_cost", &sd->max_newidle_lb_cost, sizeof(long), 0644, proc_doulongvec_minmax);
        set_table_entry(&table[7], "name",                sd->name,            CORENAME_MAX_SIZE, 0444, proc_dostring);
        /* &table[8] is terminator */
index 1a68a05..aa4c622 100644 (file)
@@ -831,7 +831,7 @@ void init_entity_runnable_average(struct sched_entity *se)
 void post_init_entity_util_avg(struct task_struct *p)
 {
 }
-static void update_tg_load_avg(struct cfs_rq *cfs_rq, int force)
+static void update_tg_load_avg(struct cfs_rq *cfs_rq)
 {
 }
 #endif /* CONFIG_SMP */
@@ -1504,6 +1504,7 @@ enum numa_type {
 /* Cached statistics for all CPUs within a node */
 struct numa_stats {
        unsigned long load;
+       unsigned long runnable;
        unsigned long util;
        /* Total compute capacity of CPUs on a node */
        unsigned long compute_capacity;
@@ -1547,19 +1548,22 @@ struct task_numa_env {
 };
 
 static unsigned long cpu_load(struct rq *rq);
+static unsigned long cpu_runnable(struct rq *rq);
 static unsigned long cpu_util(int cpu);
-static inline long adjust_numa_imbalance(int imbalance, int src_nr_running);
+static inline long adjust_numa_imbalance(int imbalance, int nr_running);
 
 static inline enum
 numa_type numa_classify(unsigned int imbalance_pct,
                         struct numa_stats *ns)
 {
        if ((ns->nr_running > ns->weight) &&
-           ((ns->compute_capacity * 100) < (ns->util * imbalance_pct)))
+           (((ns->compute_capacity * 100) < (ns->util * imbalance_pct)) ||
+            ((ns->compute_capacity * imbalance_pct) < (ns->runnable * 100))))
                return node_overloaded;
 
        if ((ns->nr_running < ns->weight) ||
-           ((ns->compute_capacity * 100) > (ns->util * imbalance_pct)))
+           (((ns->compute_capacity * 100) > (ns->util * imbalance_pct)) &&
+            ((ns->compute_capacity * imbalance_pct) > (ns->runnable * 100))))
                return node_has_spare;
 
        return node_fully_busy;
@@ -1610,6 +1614,7 @@ static void update_numa_stats(struct task_numa_env *env,
                struct rq *rq = cpu_rq(cpu);
 
                ns->load += cpu_load(rq);
+               ns->runnable += cpu_runnable(rq);
                ns->util += cpu_util(cpu);
                ns->nr_running += rq->cfs.h_nr_running;
                ns->compute_capacity += capacity_of(cpu);
@@ -1925,7 +1930,7 @@ static void task_numa_find_cpu(struct task_numa_env *env,
                src_running = env->src_stats.nr_running - 1;
                dst_running = env->dst_stats.nr_running + 1;
                imbalance = max(0, dst_running - src_running);
-               imbalance = adjust_numa_imbalance(imbalance, src_running);
+               imbalance = adjust_numa_imbalance(imbalance, dst_running);
 
                /* Use idle CPU if there is no imbalance */
                if (!imbalance) {
@@ -3084,7 +3089,7 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
                /* commit outstanding execution time */
                if (cfs_rq->curr == se)
                        update_curr(cfs_rq);
-               account_entity_dequeue(cfs_rq, se);
+               update_load_sub(&cfs_rq->load, se->load.weight);
        }
        dequeue_load_avg(cfs_rq, se);
 
@@ -3100,7 +3105,7 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
 
        enqueue_load_avg(cfs_rq, se);
        if (se->on_rq)
-               account_entity_enqueue(cfs_rq, se);
+               update_load_add(&cfs_rq->load, se->load.weight);
 
 }
 
@@ -3288,7 +3293,6 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq, int flags)
 /**
  * update_tg_load_avg - update the tg's load avg
  * @cfs_rq: the cfs_rq whose avg changed
- * @force: update regardless of how small the difference
  *
  * This function 'ensures': tg->load_avg := \Sum tg->cfs_rq[]->avg.load.
  * However, because tg->load_avg is a global value there are performance
@@ -3300,7 +3304,7 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq, int flags)
  *
  * Updating tg's load_avg is necessary before update_cfs_share().
  */
-static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force)
+static inline void update_tg_load_avg(struct cfs_rq *cfs_rq)
 {
        long delta = cfs_rq->avg.load_avg - cfs_rq->tg_load_avg_contrib;
 
@@ -3310,7 +3314,7 @@ static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force)
        if (cfs_rq->tg == &root_task_group)
                return;
 
-       if (force || abs(delta) > cfs_rq->tg_load_avg_contrib / 64) {
+       if (abs(delta) > cfs_rq->tg_load_avg_contrib / 64) {
                atomic_long_add(delta, &cfs_rq->tg->load_avg);
                cfs_rq->tg_load_avg_contrib = cfs_rq->avg.load_avg;
        }
@@ -3612,7 +3616,7 @@ static inline bool skip_blocked_update(struct sched_entity *se)
 
 #else /* CONFIG_FAIR_GROUP_SCHED */
 
-static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) {}
+static inline void update_tg_load_avg(struct cfs_rq *cfs_rq) {}
 
 static inline int propagate_entity_load_avg(struct sched_entity *se)
 {
@@ -3800,13 +3804,13 @@ static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
                 * IOW we're enqueueing a task on a new CPU.
                 */
                attach_entity_load_avg(cfs_rq, se);
-               update_tg_load_avg(cfs_rq, 0);
+               update_tg_load_avg(cfs_rq);
 
        } else if (decayed) {
                cfs_rq_util_change(cfs_rq, 0);
 
                if (flags & UPDATE_TG)
-                       update_tg_load_avg(cfs_rq, 0);
+                       update_tg_load_avg(cfs_rq);
        }
 }
 
@@ -4461,17 +4465,17 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
                        se = second;
        }
 
-       /*
-        * Prefer last buddy, try to return the CPU to a preempted task.
-        */
-       if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1)
-               se = cfs_rq->last;
-
-       /*
-        * Someone really wants this to run. If it's not unfair, run it.
-        */
-       if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1)
+       if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1) {
+               /*
+                * Someone really wants this to run. If it's not unfair, run it.
+                */
                se = cfs_rq->next;
+       } else if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1) {
+               /*
+                * Prefer last buddy, try to return the CPU to a preempted task.
+                */
+               se = cfs_rq->last;
+       }
 
        clear_buddies(cfs_rq, se);
 
@@ -6075,7 +6079,7 @@ static int select_idle_core(struct task_struct *p, struct sched_domain *sd, int
 /*
  * Scan the local SMT mask for idle CPUs.
  */
-static int select_idle_smt(struct task_struct *p, int target)
+static int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target)
 {
        int cpu;
 
@@ -6083,7 +6087,8 @@ static int select_idle_smt(struct task_struct *p, int target)
                return -1;
 
        for_each_cpu(cpu, cpu_smt_mask(target)) {
-               if (!cpumask_test_cpu(cpu, p->cpus_ptr))
+               if (!cpumask_test_cpu(cpu, p->cpus_ptr) ||
+                   !cpumask_test_cpu(cpu, sched_domain_span(sd)))
                        continue;
                if (available_idle_cpu(cpu) || sched_idle_cpu(cpu))
                        return cpu;
@@ -6099,7 +6104,7 @@ static inline int select_idle_core(struct task_struct *p, struct sched_domain *s
        return -1;
 }
 
-static inline int select_idle_smt(struct task_struct *p, int target)
+static inline int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target)
 {
        return -1;
 }
@@ -6274,7 +6279,7 @@ symmetric:
        if ((unsigned)i < nr_cpumask_bits)
                return i;
 
-       i = select_idle_smt(p, target);
+       i = select_idle_smt(p, sd, target);
        if ((unsigned)i < nr_cpumask_bits)
                return i;
 
@@ -6594,7 +6599,8 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
 
                        util = cpu_util_next(cpu, p, cpu);
                        cpu_cap = capacity_of(cpu);
-                       spare_cap = cpu_cap - util;
+                       spare_cap = cpu_cap;
+                       lsub_positive(&spare_cap, util);
 
                        /*
                         * Skip CPUs that cannot satisfy the capacity request.
@@ -7402,6 +7408,10 @@ static int task_hot(struct task_struct *p, struct lb_env *env)
        if (unlikely(task_has_idle_policy(p)))
                return 0;
 
+       /* SMT siblings share cache */
+       if (env->sd->flags & SD_SHARE_CPUCAPACITY)
+               return 0;
+
        /*
         * Buddy candidates are cache hot:
         */
@@ -7669,8 +7679,8 @@ static int detach_tasks(struct lb_env *env)
                         * scheduler fails to find a good waiting task to
                         * migrate.
                         */
-                       if (load/2 > env->imbalance &&
-                           env->sd->nr_balance_failed <= env->sd->cache_nice_tries)
+
+                       if ((load >> env->sd->nr_balance_failed) > env->imbalance)
                                goto next;
 
                        env->imbalance -= load;
@@ -7887,7 +7897,7 @@ static bool __update_blocked_fair(struct rq *rq, bool *done)
                struct sched_entity *se;
 
                if (update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq)) {
-                       update_tg_load_avg(cfs_rq, 0);
+                       update_tg_load_avg(cfs_rq);
 
                        if (cfs_rq == &rq->cfs)
                                decayed = true;
@@ -8098,6 +8108,8 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu)
                capacity = 1;
 
        cpu_rq(cpu)->cpu_capacity = capacity;
+       trace_sched_cpu_capacity_tp(cpu_rq(cpu));
+
        sdg->sgc->capacity = capacity;
        sdg->sgc->min_capacity = capacity;
        sdg->sgc->max_capacity = capacity;
@@ -8957,7 +8969,7 @@ next_group:
        }
 }
 
-static inline long adjust_numa_imbalance(int imbalance, int src_nr_running)
+static inline long adjust_numa_imbalance(int imbalance, int nr_running)
 {
        unsigned int imbalance_min;
 
@@ -8966,7 +8978,7 @@ static inline long adjust_numa_imbalance(int imbalance, int src_nr_running)
         * tasks that remain local when the source domain is almost idle.
         */
        imbalance_min = 2;
-       if (src_nr_running <= imbalance_min)
+       if (nr_running <= imbalance_min)
                return 0;
 
        return imbalance;
@@ -9780,6 +9792,15 @@ get_sd_balance_interval(struct sched_domain *sd, int cpu_busy)
 
        /* scale ms to jiffies */
        interval = msecs_to_jiffies(interval);
+
+       /*
+        * Reduce likelihood of busy balancing at higher domains racing with
+        * balancing at lower domains by preventing their balancing periods
+        * from being multiples of each other.
+        */
+       if (cpu_busy)
+               interval -= 1;
+
        interval = clamp(interval, 1UL, max_load_balance_interval);
 
        return interval;
@@ -10786,7 +10807,7 @@ static void detach_entity_cfs_rq(struct sched_entity *se)
        /* Catch up with the cfs_rq and remove our load when we leave */
        update_load_avg(cfs_rq, se, 0);
        detach_entity_load_avg(cfs_rq, se);
-       update_tg_load_avg(cfs_rq, false);
+       update_tg_load_avg(cfs_rq);
        propagate_entity_cfs_rq(se);
 }
 
@@ -10805,7 +10826,7 @@ static void attach_entity_cfs_rq(struct sched_entity *se)
        /* Synchronize entity with its cfs_rq */
        update_load_avg(cfs_rq, se, sched_feat(ATTACH_AGE_LOAD) ? 0 : SKIP_AGE_LOAD);
        attach_entity_load_avg(cfs_rq, se);
-       update_tg_load_avg(cfs_rq, false);
+       update_tg_load_avg(cfs_rq);
        propagate_entity_cfs_rq(se);
 }
 
@@ -11302,6 +11323,18 @@ int sched_trace_rq_cpu(struct rq *rq)
 }
 EXPORT_SYMBOL_GPL(sched_trace_rq_cpu);
 
+int sched_trace_rq_cpu_capacity(struct rq *rq)
+{
+       return rq ?
+#ifdef CONFIG_SMP
+               rq->cpu_capacity
+#else
+               SCHED_CAPACITY_SCALE
+#endif
+               : -1;
+}
+EXPORT_SYMBOL_GPL(sched_trace_rq_cpu_capacity);
+
 const struct cpumask *sched_trace_rd_span(struct root_domain *rd)
 {
 #ifdef CONFIG_SMP
index 7481cd9..68d369c 100644 (file)
@@ -77,7 +77,7 @@ SCHED_FEAT(WARN_DOUBLE_CLOCK, false)
 SCHED_FEAT(RT_PUSH_IPI, true)
 #endif
 
-SCHED_FEAT(RT_RUNTIME_SHARE, true)
+SCHED_FEAT(RT_RUNTIME_SHARE, false)
 SCHED_FEAT(LB_MIN, false)
 SCHED_FEAT(ATTACH_AGE_LOAD, true)
 
index 6bf3498..f324dc3 100644 (file)
@@ -54,17 +54,18 @@ __setup("hlt", cpu_idle_nopoll_setup);
 
 static noinline int __cpuidle cpu_idle_poll(void)
 {
+       trace_cpu_idle(0, smp_processor_id());
+       stop_critical_timings();
        rcu_idle_enter();
-       trace_cpu_idle_rcuidle(0, smp_processor_id());
        local_irq_enable();
-       stop_critical_timings();
 
        while (!tif_need_resched() &&
-               (cpu_idle_force_poll || tick_check_broadcast_expired()))
+              (cpu_idle_force_poll || tick_check_broadcast_expired()))
                cpu_relax();
-       start_critical_timings();
-       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
+
        rcu_idle_exit();
+       start_critical_timings();
+       trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
 
        return 1;
 }
@@ -90,9 +91,14 @@ void __cpuidle default_idle_call(void)
        if (current_clr_polling_and_test()) {
                local_irq_enable();
        } else {
+
+               trace_cpu_idle(1, smp_processor_id());
                stop_critical_timings();
+               rcu_idle_enter();
                arch_cpu_idle();
+               rcu_idle_exit();
                start_critical_timings();
+               trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
        }
 }
 
@@ -158,7 +164,6 @@ static void cpuidle_idle_call(void)
 
        if (cpuidle_not_available(drv, dev)) {
                tick_nohz_idle_stop_tick();
-               rcu_idle_enter();
 
                default_idle_call();
                goto exit_idle;
@@ -178,21 +183,17 @@ static void cpuidle_idle_call(void)
                u64 max_latency_ns;
 
                if (idle_should_enter_s2idle()) {
-                       rcu_idle_enter();
 
                        entered_state = call_cpuidle_s2idle(drv, dev);
                        if (entered_state > 0)
                                goto exit_idle;
 
-                       rcu_idle_exit();
-
                        max_latency_ns = U64_MAX;
                } else {
                        max_latency_ns = dev->forced_idle_latency_limit_ns;
                }
 
                tick_nohz_idle_stop_tick();
-               rcu_idle_enter();
 
                next_state = cpuidle_find_deepest_state(drv, dev, max_latency_ns);
                call_cpuidle(drv, dev, next_state);
@@ -209,8 +210,6 @@ static void cpuidle_idle_call(void)
                else
                        tick_nohz_idle_retain_tick();
 
-               rcu_idle_enter();
-
                entered_state = call_cpuidle(drv, dev, next_state);
                /*
                 * Give the governor an opportunity to reflect on the outcome
@@ -226,8 +225,6 @@ exit_idle:
         */
        if (WARN_ON_ONCE(irqs_disabled()))
                local_irq_enable();
-
-       rcu_idle_exit();
 }
 
 /*
index 168479a..e23e74d 100644 (file)
 #define MEMBARRIER_PRIVATE_EXPEDITED_SYNC_CORE_BITMASK 0
 #endif
 
+#ifdef CONFIG_RSEQ
+#define MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ_BITMASK          \
+       (MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ                  \
+       | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ_BITMASK)
+#else
+#define MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ_BITMASK  0
+#endif
+
 #define MEMBARRIER_CMD_BITMASK                                         \
        (MEMBARRIER_CMD_GLOBAL | MEMBARRIER_CMD_GLOBAL_EXPEDITED        \
        | MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED                      \
@@ -30,6 +38,11 @@ static void ipi_mb(void *info)
        smp_mb();       /* IPIs should be serializing but paranoid. */
 }
 
+static void ipi_rseq(void *info)
+{
+       rseq_preempt(current);
+}
+
 static void ipi_sync_rq_state(void *info)
 {
        struct mm_struct *mm = (struct mm_struct *) info;
@@ -129,19 +142,27 @@ static int membarrier_global_expedited(void)
        return 0;
 }
 
-static int membarrier_private_expedited(int flags)
+static int membarrier_private_expedited(int flags, int cpu_id)
 {
-       int cpu;
        cpumask_var_t tmpmask;
        struct mm_struct *mm = current->mm;
+       smp_call_func_t ipi_func = ipi_mb;
 
-       if (flags & MEMBARRIER_FLAG_SYNC_CORE) {
+       if (flags == MEMBARRIER_FLAG_SYNC_CORE) {
                if (!IS_ENABLED(CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE))
                        return -EINVAL;
                if (!(atomic_read(&mm->membarrier_state) &
                      MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY))
                        return -EPERM;
+       } else if (flags == MEMBARRIER_FLAG_RSEQ) {
+               if (!IS_ENABLED(CONFIG_RSEQ))
+                       return -EINVAL;
+               if (!(atomic_read(&mm->membarrier_state) &
+                     MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ_READY))
+                       return -EPERM;
+               ipi_func = ipi_rseq;
        } else {
+               WARN_ON_ONCE(flags);
                if (!(atomic_read(&mm->membarrier_state) &
                      MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY))
                        return -EPERM;
@@ -156,35 +177,59 @@ static int membarrier_private_expedited(int flags)
         */
        smp_mb();       /* system call entry is not a mb. */
 
-       if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
+       if (cpu_id < 0 && !zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
                return -ENOMEM;
 
        cpus_read_lock();
-       rcu_read_lock();
-       for_each_online_cpu(cpu) {
+
+       if (cpu_id >= 0) {
                struct task_struct *p;
 
-               /*
-                * Skipping the current CPU is OK even through we can be
-                * migrated at any point. The current CPU, at the point
-                * where we read raw_smp_processor_id(), is ensured to
-                * be in program order with respect to the caller
-                * thread. Therefore, we can skip this CPU from the
-                * iteration.
-                */
-               if (cpu == raw_smp_processor_id())
-                       continue;
-               p = rcu_dereference(cpu_rq(cpu)->curr);
-               if (p && p->mm == mm)
-                       __cpumask_set_cpu(cpu, tmpmask);
+               if (cpu_id >= nr_cpu_ids || !cpu_online(cpu_id))
+                       goto out;
+               if (cpu_id == raw_smp_processor_id())
+                       goto out;
+               rcu_read_lock();
+               p = rcu_dereference(cpu_rq(cpu_id)->curr);
+               if (!p || p->mm != mm) {
+                       rcu_read_unlock();
+                       goto out;
+               }
+               rcu_read_unlock();
+       } else {
+               int cpu;
+
+               rcu_read_lock();
+               for_each_online_cpu(cpu) {
+                       struct task_struct *p;
+
+                       /*
+                        * Skipping the current CPU is OK even through we can be
+                        * migrated at any point. The current CPU, at the point
+                        * where we read raw_smp_processor_id(), is ensured to
+                        * be in program order with respect to the caller
+                        * thread. Therefore, we can skip this CPU from the
+                        * iteration.
+                        */
+                       if (cpu == raw_smp_processor_id())
+                               continue;
+                       p = rcu_dereference(cpu_rq(cpu)->curr);
+                       if (p && p->mm == mm)
+                               __cpumask_set_cpu(cpu, tmpmask);
+               }
+               rcu_read_unlock();
        }
-       rcu_read_unlock();
 
        preempt_disable();
-       smp_call_function_many(tmpmask, ipi_mb, NULL, 1);
+       if (cpu_id >= 0)
+               smp_call_function_single(cpu_id, ipi_func, NULL, 1);
+       else
+               smp_call_function_many(tmpmask, ipi_func, NULL, 1);
        preempt_enable();
 
-       free_cpumask_var(tmpmask);
+out:
+       if (cpu_id < 0)
+               free_cpumask_var(tmpmask);
        cpus_read_unlock();
 
        /*
@@ -283,11 +328,18 @@ static int membarrier_register_private_expedited(int flags)
            set_state = MEMBARRIER_STATE_PRIVATE_EXPEDITED,
            ret;
 
-       if (flags & MEMBARRIER_FLAG_SYNC_CORE) {
+       if (flags == MEMBARRIER_FLAG_SYNC_CORE) {
                if (!IS_ENABLED(CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE))
                        return -EINVAL;
                ready_state =
                        MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY;
+       } else if (flags == MEMBARRIER_FLAG_RSEQ) {
+               if (!IS_ENABLED(CONFIG_RSEQ))
+                       return -EINVAL;
+               ready_state =
+                       MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ_READY;
+       } else {
+               WARN_ON_ONCE(flags);
        }
 
        /*
@@ -299,6 +351,8 @@ static int membarrier_register_private_expedited(int flags)
                return 0;
        if (flags & MEMBARRIER_FLAG_SYNC_CORE)
                set_state |= MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE;
+       if (flags & MEMBARRIER_FLAG_RSEQ)
+               set_state |= MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ;
        atomic_or(set_state, &mm->membarrier_state);
        ret = sync_runqueues_membarrier_state(mm);
        if (ret)
@@ -310,8 +364,15 @@ static int membarrier_register_private_expedited(int flags)
 
 /**
  * sys_membarrier - issue memory barriers on a set of threads
- * @cmd:   Takes command values defined in enum membarrier_cmd.
- * @flags: Currently needs to be 0. For future extensions.
+ * @cmd:    Takes command values defined in enum membarrier_cmd.
+ * @flags:  Currently needs to be 0 for all commands other than
+ *          MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ: in the latter
+ *          case it can be MEMBARRIER_CMD_FLAG_CPU, indicating that @cpu_id
+ *          contains the CPU on which to interrupt (= restart)
+ *          the RSEQ critical section.
+ * @cpu_id: if @flags == MEMBARRIER_CMD_FLAG_CPU, indicates the cpu on which
+ *          RSEQ CS should be interrupted (@cmd must be
+ *          MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ).
  *
  * If this system call is not implemented, -ENOSYS is returned. If the
  * command specified does not exist, not available on the running
@@ -337,10 +398,21 @@ static int membarrier_register_private_expedited(int flags)
  *        smp_mb()           X           O            O
  *        sys_membarrier()   O           O            O
  */
-SYSCALL_DEFINE2(membarrier, int, cmd, int, flags)
+SYSCALL_DEFINE3(membarrier, int, cmd, unsigned int, flags, int, cpu_id)
 {
-       if (unlikely(flags))
-               return -EINVAL;
+       switch (cmd) {
+       case MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ:
+               if (unlikely(flags && flags != MEMBARRIER_CMD_FLAG_CPU))
+                       return -EINVAL;
+               break;
+       default:
+               if (unlikely(flags))
+                       return -EINVAL;
+       }
+
+       if (!(flags & MEMBARRIER_CMD_FLAG_CPU))
+               cpu_id = -1;
+
        switch (cmd) {
        case MEMBARRIER_CMD_QUERY:
        {
@@ -362,13 +434,17 @@ SYSCALL_DEFINE2(membarrier, int, cmd, int, flags)
        case MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED:
                return membarrier_register_global_expedited();
        case MEMBARRIER_CMD_PRIVATE_EXPEDITED:
-               return membarrier_private_expedited(0);
+               return membarrier_private_expedited(0, cpu_id);
        case MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED:
                return membarrier_register_private_expedited(0);
        case MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE:
-               return membarrier_private_expedited(MEMBARRIER_FLAG_SYNC_CORE);
+               return membarrier_private_expedited(MEMBARRIER_FLAG_SYNC_CORE, cpu_id);
        case MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE:
                return membarrier_register_private_expedited(MEMBARRIER_FLAG_SYNC_CORE);
+       case MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ:
+               return membarrier_private_expedited(MEMBARRIER_FLAG_RSEQ, cpu_id);
+       case MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ:
+               return membarrier_register_private_expedited(MEMBARRIER_FLAG_RSEQ);
        default:
                return -EINVAL;
        }
index 007b0a6..dd77702 100644 (file)
@@ -25,10 +25,18 @@ static inline bool sched_debug(void)
        return sched_debug_enabled;
 }
 
+#define SD_FLAG(_name, mflags) [__##_name] = { .meta_flags = mflags, .name = #_name },
+const struct sd_flag_debug sd_flag_debug[] = {
+#include <linux/sched/sd_flags.h>
+};
+#undef SD_FLAG
+
 static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level,
                                  struct cpumask *groupmask)
 {
        struct sched_group *group = sd->groups;
+       unsigned long flags = sd->flags;
+       unsigned int idx;
 
        cpumask_clear(groupmask);
 
@@ -43,6 +51,21 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level,
                printk(KERN_ERR "ERROR: domain->groups does not contain CPU%d\n", cpu);
        }
 
+       for_each_set_bit(idx, &flags, __SD_FLAG_CNT) {
+               unsigned int flag = BIT(idx);
+               unsigned int meta_flags = sd_flag_debug[idx].meta_flags;
+
+               if ((meta_flags & SDF_SHARED_CHILD) && sd->child &&
+                   !(sd->child->flags & flag))
+                       printk(KERN_ERR "ERROR: flag %s set here but not in child\n",
+                              sd_flag_debug[idx].name);
+
+               if ((meta_flags & SDF_SHARED_PARENT) && sd->parent &&
+                   !(sd->parent->flags & flag))
+                       printk(KERN_ERR "ERROR: flag %s set here but not in parent\n",
+                              sd_flag_debug[idx].name);
+       }
+
        printk(KERN_DEBUG "%*s groups:", level + 1, "");
        do {
                if (!group) {
@@ -137,22 +160,22 @@ static inline bool sched_debug(void)
 }
 #endif /* CONFIG_SCHED_DEBUG */
 
+/* Generate a mask of SD flags with the SDF_NEEDS_GROUPS metaflag */
+#define SD_FLAG(name, mflags) (name * !!((mflags) & SDF_NEEDS_GROUPS)) |
+static const unsigned int SD_DEGENERATE_GROUPS_MASK =
+#include <linux/sched/sd_flags.h>
+0;
+#undef SD_FLAG
+
 static int sd_degenerate(struct sched_domain *sd)
 {
        if (cpumask_weight(sched_domain_span(sd)) == 1)
                return 1;
 
        /* Following flags need at least 2 groups */
-       if (sd->flags & (SD_BALANCE_NEWIDLE |
-                        SD_BALANCE_FORK |
-                        SD_BALANCE_EXEC |
-                        SD_SHARE_CPUCAPACITY |
-                        SD_ASYM_CPUCAPACITY |
-                        SD_SHARE_PKG_RESOURCES |
-                        SD_SHARE_POWERDOMAIN)) {
-               if (sd->groups != sd->groups->next)
-                       return 0;
-       }
+       if ((sd->flags & SD_DEGENERATE_GROUPS_MASK) &&
+           (sd->groups != sd->groups->next))
+               return 0;
 
        /* Following flags don't use groups */
        if (sd->flags & (SD_WAKE_AFFINE))
@@ -173,18 +196,9 @@ sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent)
                return 0;
 
        /* Flags needing groups don't count if only 1 group in parent */
-       if (parent->groups == parent->groups->next) {
-               pflags &= ~(SD_BALANCE_NEWIDLE |
-                           SD_BALANCE_FORK |
-                           SD_BALANCE_EXEC |
-                           SD_ASYM_CPUCAPACITY |
-                           SD_SHARE_CPUCAPACITY |
-                           SD_SHARE_PKG_RESOURCES |
-                           SD_PREFER_SIBLING |
-                           SD_SHARE_POWERDOMAIN);
-               if (nr_node_ids == 1)
-                       pflags &= ~SD_SERIALIZE;
-       }
+       if (parent->groups == parent->groups->next)
+               pflags &= ~SD_DEGENERATE_GROUPS_MASK;
+
        if (~cflags & pflags)
                return 0;
 
@@ -1219,13 +1233,13 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what,
        case sa_rootdomain:
                if (!atomic_read(&d->rd->refcount))
                        free_rootdomain(&d->rd->rcu);
-               /* Fall through */
+               fallthrough;
        case sa_sd:
                free_percpu(d->sd);
-               /* Fall through */
+               fallthrough;
        case sa_sd_storage:
                __sdt_free(cpu_map);
-               /* Fall through */
+               fallthrough;
        case sa_none:
                break;
        }
@@ -1292,7 +1306,6 @@ int __read_mostly         node_reclaim_distance = RECLAIM_DISTANCE;
  *   SD_SHARE_CPUCAPACITY   - describes SMT topologies
  *   SD_SHARE_PKG_RESOURCES - describes shared caches
  *   SD_NUMA                - describes NUMA topologies
- *   SD_SHARE_POWERDOMAIN   - describes shared power domain
  *
  * Odd one out, which beside describing the topology has a quirk also
  * prescribes the desired behaviour that goes along with it:
@@ -1303,8 +1316,7 @@ int __read_mostly         node_reclaim_distance = RECLAIM_DISTANCE;
        (SD_SHARE_CPUCAPACITY   |       \
         SD_SHARE_PKG_RESOURCES |       \
         SD_NUMA                |       \
-        SD_ASYM_PACKING        |       \
-        SD_SHARE_POWERDOMAIN)
+        SD_ASYM_PACKING)
 
 static struct sched_domain *
 sd_init(struct sched_domain_topology_level *tl,
@@ -1336,8 +1348,8 @@ sd_init(struct sched_domain_topology_level *tl,
        *sd = (struct sched_domain){
                .min_interval           = sd_weight,
                .max_interval           = 2*sd_weight,
-               .busy_factor            = 32,
-               .imbalance_pct          = 125,
+               .busy_factor            = 16,
+               .imbalance_pct          = 117,
 
                .cache_nice_tries       = 0,
 
@@ -1989,11 +2001,10 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att
        /* Set up domains for CPUs specified by the cpu_map: */
        for_each_cpu(i, cpu_map) {
                struct sched_domain_topology_level *tl;
+               int dflags = 0;
 
                sd = NULL;
                for_each_sd_topology(tl) {
-                       int dflags = 0;
-
                        if (tl == tl_asym) {
                                dflags |= SD_ASYM_CPUCAPACITY;
                                has_asym = true;
index 3ee59ce..676d4af 100644 (file)
@@ -1109,13 +1109,18 @@ out:
 }
 
 #ifdef CONFIG_SECCOMP_FILTER
-static int seccomp_notify_release(struct inode *inode, struct file *file)
+static void seccomp_notify_free(struct seccomp_filter *filter)
+{
+       kfree(filter->notif);
+       filter->notif = NULL;
+}
+
+static void seccomp_notify_detach(struct seccomp_filter *filter)
 {
-       struct seccomp_filter *filter = file->private_data;
        struct seccomp_knotif *knotif;
 
        if (!filter)
-               return 0;
+               return;
 
        mutex_lock(&filter->notify_lock);
 
@@ -1139,9 +1144,15 @@ static int seccomp_notify_release(struct inode *inode, struct file *file)
                complete(&knotif->ready);
        }
 
-       kfree(filter->notif);
-       filter->notif = NULL;
+       seccomp_notify_free(filter);
        mutex_unlock(&filter->notify_lock);
+}
+
+static int seccomp_notify_release(struct inode *inode, struct file *file)
+{
+       struct seccomp_filter *filter = file->private_data;
+
+       seccomp_notify_detach(filter);
        __put_seccomp_filter(filter);
        return 0;
 }
@@ -1488,7 +1499,7 @@ static struct file *init_listener(struct seccomp_filter *filter)
 
 out_notif:
        if (IS_ERR(ret))
-               kfree(filter->notif);
+               seccomp_notify_free(filter);
 out:
        return ret;
 }
@@ -1581,6 +1592,7 @@ out_put_fd:
                        listener_f->private_data = NULL;
                        fput(listener_f);
                        put_unused_fd(listener);
+                       seccomp_notify_detach(prepared);
                } else {
                        fd_install(listener, listener_f);
                        ret = listener;
index 42b67d2..a38b3ed 100644 (file)
@@ -851,7 +851,7 @@ static int check_kill_permission(int sig, struct kernel_siginfo *info,
                         */
                        if (!sid || sid == task_session(current))
                                break;
-                       /* fall through */
+                       fallthrough;
                default:
                        return -EPERM;
                }
index bf88d7f..09229ad 100644 (file)
@@ -481,6 +481,7 @@ void raise_softirq(unsigned int nr)
 
 void __raise_softirq_irqoff(unsigned int nr)
 {
+       lockdep_assert_irqs_disabled();
        trace_softirq_raise(nr);
        or_softirq_pending(1UL << nr);
 }
index a8fc9ae..ce161a8 100644 (file)
@@ -20,7 +20,7 @@
 static DEFINE_STATIC_KEY_FALSE(stack_erasing_bypass);
 
 int stack_erasing_sysctl(struct ctl_table *table, int write,
-                       void __user *buffer, size_t *lenp, loff_t *ppos)
+                       void *buffer, size_t *lenp, loff_t *ppos)
 {
        int ret = 0;
        int state = !static_branch_unlikely(&stack_erasing_bypass);
index 946f44a..9f8117c 100644 (file)
@@ -78,8 +78,7 @@ struct stacktrace_cookie {
        unsigned int    len;
 };
 
-static bool stack_trace_consume_entry(void *cookie, unsigned long addr,
-                                     bool reliable)
+static bool stack_trace_consume_entry(void *cookie, unsigned long addr)
 {
        struct stacktrace_cookie *c = cookie;
 
@@ -94,12 +93,11 @@ static bool stack_trace_consume_entry(void *cookie, unsigned long addr,
        return c->len < c->size;
 }
 
-static bool stack_trace_consume_entry_nosched(void *cookie, unsigned long addr,
-                                             bool reliable)
+static bool stack_trace_consume_entry_nosched(void *cookie, unsigned long addr)
 {
        if (in_sched_functions(addr))
                return true;
-       return stack_trace_consume_entry(cookie, addr, reliable);
+       return stack_trace_consume_entry(cookie, addr);
 }
 
 /**
diff --git a/kernel/static_call.c b/kernel/static_call.c
new file mode 100644 (file)
index 0000000..84565c2
--- /dev/null
@@ -0,0 +1,482 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/init.h>
+#include <linux/static_call.h>
+#include <linux/bug.h>
+#include <linux/smp.h>
+#include <linux/sort.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/processor.h>
+#include <asm/sections.h>
+
+extern struct static_call_site __start_static_call_sites[],
+                              __stop_static_call_sites[];
+
+static bool static_call_initialized;
+
+/* mutex to protect key modules/sites */
+static DEFINE_MUTEX(static_call_mutex);
+
+static void static_call_lock(void)
+{
+       mutex_lock(&static_call_mutex);
+}
+
+static void static_call_unlock(void)
+{
+       mutex_unlock(&static_call_mutex);
+}
+
+static inline void *static_call_addr(struct static_call_site *site)
+{
+       return (void *)((long)site->addr + (long)&site->addr);
+}
+
+
+static inline struct static_call_key *static_call_key(const struct static_call_site *site)
+{
+       return (struct static_call_key *)
+               (((long)site->key + (long)&site->key) & ~STATIC_CALL_SITE_FLAGS);
+}
+
+/* These assume the key is word-aligned. */
+static inline bool static_call_is_init(struct static_call_site *site)
+{
+       return ((long)site->key + (long)&site->key) & STATIC_CALL_SITE_INIT;
+}
+
+static inline bool static_call_is_tail(struct static_call_site *site)
+{
+       return ((long)site->key + (long)&site->key) & STATIC_CALL_SITE_TAIL;
+}
+
+static inline void static_call_set_init(struct static_call_site *site)
+{
+       site->key = ((long)static_call_key(site) | STATIC_CALL_SITE_INIT) -
+                   (long)&site->key;
+}
+
+static int static_call_site_cmp(const void *_a, const void *_b)
+{
+       const struct static_call_site *a = _a;
+       const struct static_call_site *b = _b;
+       const struct static_call_key *key_a = static_call_key(a);
+       const struct static_call_key *key_b = static_call_key(b);
+
+       if (key_a < key_b)
+               return -1;
+
+       if (key_a > key_b)
+               return 1;
+
+       return 0;
+}
+
+static void static_call_site_swap(void *_a, void *_b, int size)
+{
+       long delta = (unsigned long)_a - (unsigned long)_b;
+       struct static_call_site *a = _a;
+       struct static_call_site *b = _b;
+       struct static_call_site tmp = *a;
+
+       a->addr = b->addr  - delta;
+       a->key  = b->key   - delta;
+
+       b->addr = tmp.addr + delta;
+       b->key  = tmp.key  + delta;
+}
+
+static inline void static_call_sort_entries(struct static_call_site *start,
+                                           struct static_call_site *stop)
+{
+       sort(start, stop - start, sizeof(struct static_call_site),
+            static_call_site_cmp, static_call_site_swap);
+}
+
+static inline bool static_call_key_has_mods(struct static_call_key *key)
+{
+       return !(key->type & 1);
+}
+
+static inline struct static_call_mod *static_call_key_next(struct static_call_key *key)
+{
+       if (!static_call_key_has_mods(key))
+               return NULL;
+
+       return key->mods;
+}
+
+static inline struct static_call_site *static_call_key_sites(struct static_call_key *key)
+{
+       if (static_call_key_has_mods(key))
+               return NULL;
+
+       return (struct static_call_site *)(key->type & ~1);
+}
+
+void __static_call_update(struct static_call_key *key, void *tramp, void *func)
+{
+       struct static_call_site *site, *stop;
+       struct static_call_mod *site_mod, first;
+
+       cpus_read_lock();
+       static_call_lock();
+
+       if (key->func == func)
+               goto done;
+
+       key->func = func;
+
+       arch_static_call_transform(NULL, tramp, func, false);
+
+       /*
+        * If uninitialized, we'll not update the callsites, but they still
+        * point to the trampoline and we just patched that.
+        */
+       if (WARN_ON_ONCE(!static_call_initialized))
+               goto done;
+
+       first = (struct static_call_mod){
+               .next = static_call_key_next(key),
+               .mod = NULL,
+               .sites = static_call_key_sites(key),
+       };
+
+       for (site_mod = &first; site_mod; site_mod = site_mod->next) {
+               struct module *mod = site_mod->mod;
+
+               if (!site_mod->sites) {
+                       /*
+                        * This can happen if the static call key is defined in
+                        * a module which doesn't use it.
+                        *
+                        * It also happens in the has_mods case, where the
+                        * 'first' entry has no sites associated with it.
+                        */
+                       continue;
+               }
+
+               stop = __stop_static_call_sites;
+
+#ifdef CONFIG_MODULES
+               if (mod) {
+                       stop = mod->static_call_sites +
+                              mod->num_static_call_sites;
+               }
+#endif
+
+               for (site = site_mod->sites;
+                    site < stop && static_call_key(site) == key; site++) {
+                       void *site_addr = static_call_addr(site);
+
+                       if (static_call_is_init(site)) {
+                               /*
+                                * Don't write to call sites which were in
+                                * initmem and have since been freed.
+                                */
+                               if (!mod && system_state >= SYSTEM_RUNNING)
+                                       continue;
+                               if (mod && !within_module_init((unsigned long)site_addr, mod))
+                                       continue;
+                       }
+
+                       if (!kernel_text_address((unsigned long)site_addr)) {
+                               WARN_ONCE(1, "can't patch static call site at %pS",
+                                         site_addr);
+                               continue;
+                       }
+
+                       arch_static_call_transform(site_addr, NULL, func,
+                               static_call_is_tail(site));
+               }
+       }
+
+done:
+       static_call_unlock();
+       cpus_read_unlock();
+}
+EXPORT_SYMBOL_GPL(__static_call_update);
+
+static int __static_call_init(struct module *mod,
+                             struct static_call_site *start,
+                             struct static_call_site *stop)
+{
+       struct static_call_site *site;
+       struct static_call_key *key, *prev_key = NULL;
+       struct static_call_mod *site_mod;
+
+       if (start == stop)
+               return 0;
+
+       static_call_sort_entries(start, stop);
+
+       for (site = start; site < stop; site++) {
+               void *site_addr = static_call_addr(site);
+
+               if ((mod && within_module_init((unsigned long)site_addr, mod)) ||
+                   (!mod && init_section_contains(site_addr, 1)))
+                       static_call_set_init(site);
+
+               key = static_call_key(site);
+               if (key != prev_key) {
+                       prev_key = key;
+
+                       /*
+                        * For vmlinux (!mod) avoid the allocation by storing
+                        * the sites pointer in the key itself. Also see
+                        * __static_call_update()'s @first.
+                        *
+                        * This allows architectures (eg. x86) to call
+                        * static_call_init() before memory allocation works.
+                        */
+                       if (!mod) {
+                               key->sites = site;
+                               key->type |= 1;
+                               goto do_transform;
+                       }
+
+                       site_mod = kzalloc(sizeof(*site_mod), GFP_KERNEL);
+                       if (!site_mod)
+                               return -ENOMEM;
+
+                       /*
+                        * When the key has a direct sites pointer, extract
+                        * that into an explicit struct static_call_mod, so we
+                        * can have a list of modules.
+                        */
+                       if (static_call_key_sites(key)) {
+                               site_mod->mod = NULL;
+                               site_mod->next = NULL;
+                               site_mod->sites = static_call_key_sites(key);
+
+                               key->mods = site_mod;
+
+                               site_mod = kzalloc(sizeof(*site_mod), GFP_KERNEL);
+                               if (!site_mod)
+                                       return -ENOMEM;
+                       }
+
+                       site_mod->mod = mod;
+                       site_mod->sites = site;
+                       site_mod->next = static_call_key_next(key);
+                       key->mods = site_mod;
+               }
+
+do_transform:
+               arch_static_call_transform(site_addr, NULL, key->func,
+                               static_call_is_tail(site));
+       }
+
+       return 0;
+}
+
+static int addr_conflict(struct static_call_site *site, void *start, void *end)
+{
+       unsigned long addr = (unsigned long)static_call_addr(site);
+
+       if (addr <= (unsigned long)end &&
+           addr + CALL_INSN_SIZE > (unsigned long)start)
+               return 1;
+
+       return 0;
+}
+
+static int __static_call_text_reserved(struct static_call_site *iter_start,
+                                      struct static_call_site *iter_stop,
+                                      void *start, void *end)
+{
+       struct static_call_site *iter = iter_start;
+
+       while (iter < iter_stop) {
+               if (addr_conflict(iter, start, end))
+                       return 1;
+               iter++;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_MODULES
+
+static int __static_call_mod_text_reserved(void *start, void *end)
+{
+       struct module *mod;
+       int ret;
+
+       preempt_disable();
+       mod = __module_text_address((unsigned long)start);
+       WARN_ON_ONCE(__module_text_address((unsigned long)end) != mod);
+       if (!try_module_get(mod))
+               mod = NULL;
+       preempt_enable();
+
+       if (!mod)
+               return 0;
+
+       ret = __static_call_text_reserved(mod->static_call_sites,
+                       mod->static_call_sites + mod->num_static_call_sites,
+                       start, end);
+
+       module_put(mod);
+
+       return ret;
+}
+
+static int static_call_add_module(struct module *mod)
+{
+       return __static_call_init(mod, mod->static_call_sites,
+                                 mod->static_call_sites + mod->num_static_call_sites);
+}
+
+static void static_call_del_module(struct module *mod)
+{
+       struct static_call_site *start = mod->static_call_sites;
+       struct static_call_site *stop = mod->static_call_sites +
+                                       mod->num_static_call_sites;
+       struct static_call_key *key, *prev_key = NULL;
+       struct static_call_mod *site_mod, **prev;
+       struct static_call_site *site;
+
+       for (site = start; site < stop; site++) {
+               key = static_call_key(site);
+               if (key == prev_key)
+                       continue;
+
+               prev_key = key;
+
+               for (prev = &key->mods, site_mod = key->mods;
+                    site_mod && site_mod->mod != mod;
+                    prev = &site_mod->next, site_mod = site_mod->next)
+                       ;
+
+               if (!site_mod)
+                       continue;
+
+               *prev = site_mod->next;
+               kfree(site_mod);
+       }
+}
+
+static int static_call_module_notify(struct notifier_block *nb,
+                                    unsigned long val, void *data)
+{
+       struct module *mod = data;
+       int ret = 0;
+
+       cpus_read_lock();
+       static_call_lock();
+
+       switch (val) {
+       case MODULE_STATE_COMING:
+               ret = static_call_add_module(mod);
+               if (ret) {
+                       WARN(1, "Failed to allocate memory for static calls");
+                       static_call_del_module(mod);
+               }
+               break;
+       case MODULE_STATE_GOING:
+               static_call_del_module(mod);
+               break;
+       }
+
+       static_call_unlock();
+       cpus_read_unlock();
+
+       return notifier_from_errno(ret);
+}
+
+static struct notifier_block static_call_module_nb = {
+       .notifier_call = static_call_module_notify,
+};
+
+#else
+
+static inline int __static_call_mod_text_reserved(void *start, void *end)
+{
+       return 0;
+}
+
+#endif /* CONFIG_MODULES */
+
+int static_call_text_reserved(void *start, void *end)
+{
+       int ret = __static_call_text_reserved(__start_static_call_sites,
+                       __stop_static_call_sites, start, end);
+
+       if (ret)
+               return ret;
+
+       return __static_call_mod_text_reserved(start, end);
+}
+
+int __init static_call_init(void)
+{
+       int ret;
+
+       if (static_call_initialized)
+               return 0;
+
+       cpus_read_lock();
+       static_call_lock();
+       ret = __static_call_init(NULL, __start_static_call_sites,
+                                __stop_static_call_sites);
+       static_call_unlock();
+       cpus_read_unlock();
+
+       if (ret) {
+               pr_err("Failed to allocate memory for static_call!\n");
+               BUG();
+       }
+
+       static_call_initialized = true;
+
+#ifdef CONFIG_MODULES
+       register_module_notifier(&static_call_module_nb);
+#endif
+       return 0;
+}
+early_initcall(static_call_init);
+
+#ifdef CONFIG_STATIC_CALL_SELFTEST
+
+static int func_a(int x)
+{
+       return x+1;
+}
+
+static int func_b(int x)
+{
+       return x+2;
+}
+
+DEFINE_STATIC_CALL(sc_selftest, func_a);
+
+static struct static_call_data {
+      int (*func)(int);
+      int val;
+      int expect;
+} static_call_data [] __initdata = {
+      { NULL,   2, 3 },
+      { func_b, 2, 4 },
+      { func_a, 2, 3 }
+};
+
+static int __init test_static_call_init(void)
+{
+      int i;
+
+      for (i = 0; i < ARRAY_SIZE(static_call_data); i++ ) {
+             struct static_call_data *scd = &static_call_data[i];
+
+              if (scd->func)
+                      static_call_update(sc_selftest, scd->func);
+
+              WARN_ON(static_call(sc_selftest)(scd->val) != scd->expect);
+      }
+
+      return 0;
+}
+early_initcall(test_static_call_init);
+
+#endif /* CONFIG_STATIC_CALL_SELFTEST */
index ca11af9..ab6c409 100644 (file)
@@ -1753,7 +1753,7 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
 
                if (who == RUSAGE_CHILDREN)
                        break;
-               /* fall through */
+               fallthrough;
 
        case RUSAGE_SELF:
                thread_group_cputime_adjusted(p, &tgutime, &tgstime);
index 4d59775..c925d1e 100644 (file)
@@ -369,7 +369,6 @@ COND_SYSCALL_COMPAT(fanotify_mark);
 /* x86 */
 COND_SYSCALL(vm86old);
 COND_SYSCALL(modify_ldt);
-COND_SYSCALL_COMPAT(quotactl32);
 COND_SYSCALL(vm86);
 COND_SYSCALL(kexec_file_load);
 
index 287862f..afad085 100644 (file)
@@ -204,8 +204,7 @@ static int max_extfrag_threshold = 1000;
 
 #if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_SYSCTL)
 static int bpf_stats_handler(struct ctl_table *table, int write,
-                            void __user *buffer, size_t *lenp,
-                            loff_t *ppos)
+                            void *buffer, size_t *lenp, loff_t *ppos)
 {
        struct static_key *key = (struct static_key *)table->data;
        static int saved_val;
@@ -2913,6 +2912,14 @@ static struct ctl_table vm_table[] = {
                .proc_handler   = percpu_pagelist_fraction_sysctl_handler,
                .extra1         = SYSCTL_ZERO,
        },
+       {
+               .procname       = "page_lock_unfairness",
+               .data           = &sysctl_page_lock_unfairness,
+               .maxlen         = sizeof(sysctl_page_lock_unfairness),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = SYSCTL_ZERO,
+       },
 #ifdef CONFIG_MMU
        {
                .procname       = "max_map_count",
index ca223a8..f4ace1b 100644 (file)
@@ -908,7 +908,7 @@ static int __init alarmtimer_init(void)
        /* Initialize alarm bases */
        alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME;
        alarm_bases[ALARM_REALTIME].get_ktime = &ktime_get_real;
-       alarm_bases[ALARM_REALTIME].get_timespec = ktime_get_real_ts64,
+       alarm_bases[ALARM_REALTIME].get_timespec = ktime_get_real_ts64;
        alarm_bases[ALARM_BOOTTIME].base_clockid = CLOCK_BOOTTIME;
        alarm_bases[ALARM_BOOTTIME].get_ktime = &ktime_get_boottime;
        alarm_bases[ALARM_BOOTTIME].get_timespec = get_boottime_timespec;
index c403851..3624b9b 100644 (file)
@@ -342,7 +342,7 @@ EXPORT_SYMBOL_GPL(ktime_add_safe);
 
 #ifdef CONFIG_DEBUG_OBJECTS_TIMERS
 
-static struct debug_obj_descr hrtimer_debug_descr;
+static const struct debug_obj_descr hrtimer_debug_descr;
 
 static void *hrtimer_debug_hint(void *addr)
 {
@@ -377,7 +377,7 @@ static bool hrtimer_fixup_activate(void *addr, enum debug_obj_state state)
        switch (state) {
        case ODEBUG_STATE_ACTIVE:
                WARN_ON(1);
-               /* fall through */
+               fallthrough;
        default:
                return false;
        }
@@ -401,7 +401,7 @@ static bool hrtimer_fixup_free(void *addr, enum debug_obj_state state)
        }
 }
 
-static struct debug_obj_descr hrtimer_debug_descr = {
+static const struct debug_obj_descr hrtimer_debug_descr = {
        .name           = "hrtimer",
        .debug_hint     = hrtimer_debug_hint,
        .fixup_init     = hrtimer_fixup_init,
index 07709ac..bf540f5 100644 (file)
@@ -439,12 +439,12 @@ static struct pid *good_sigevent(sigevent_t * event)
                rtn = pid_task(pid, PIDTYPE_PID);
                if (!rtn || !same_thread_group(rtn, current))
                        return NULL;
-               /* FALLTHRU */
+               fallthrough;
        case SIGEV_SIGNAL:
        case SIGEV_THREAD:
                if (event->sigev_signo <= 0 || event->sigev_signo > SIGRTMAX)
                        return NULL;
-               /* FALLTHRU */
+               fallthrough;
        case SIGEV_NONE:
                return pid;
        default:
index 1c03eec..0642013 100644 (file)
@@ -35,7 +35,7 @@
  * into a single 64-byte cache line.
  */
 struct clock_data {
-       seqcount_t              seq;
+       seqcount_latch_t        seq;
        struct clock_read_data  read_data[2];
        ktime_t                 wrap_kt;
        unsigned long           rate;
@@ -76,7 +76,7 @@ struct clock_read_data *sched_clock_read_begin(unsigned int *seq)
 
 int sched_clock_read_retry(unsigned int seq)
 {
-       return read_seqcount_retry(&cd.seq, seq);
+       return read_seqcount_latch_retry(&cd.seq, seq);
 }
 
 unsigned long long notrace sched_clock(void)
@@ -258,7 +258,7 @@ void __init generic_sched_clock_init(void)
  */
 static u64 notrace suspended_sched_clock_read(void)
 {
-       unsigned int seq = raw_read_seqcount(&cd.seq);
+       unsigned int seq = raw_read_seqcount_latch(&cd.seq);
 
        return cd.read_data[seq & 1].epoch_cyc;
 }
index e51778c..36d7464 100644 (file)
@@ -381,7 +381,7 @@ void tick_broadcast_control(enum tick_broadcast_mode mode)
        switch (mode) {
        case TICK_BROADCAST_FORCE:
                tick_broadcast_forced = 1;
-               /* fall through */
+               fallthrough;
        case TICK_BROADCAST_ON:
                cpumask_set_cpu(cpu, tick_broadcast_on);
                if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) {
index 4c47f38..6858a31 100644 (file)
@@ -54,6 +54,9 @@ static struct {
 
 static struct timekeeper shadow_timekeeper;
 
+/* flag for if timekeeping is suspended */
+int __read_mostly timekeeping_suspended;
+
 /**
  * struct tk_fast - NMI safe timekeeper
  * @seq:       Sequence counter for protecting updates. The lowest bit
@@ -64,7 +67,7 @@ static struct timekeeper shadow_timekeeper;
  * See @update_fast_timekeeper() below.
  */
 struct tk_fast {
-       seqcount_raw_spinlock_t seq;
+       seqcount_latch_t        seq;
        struct tk_read_base     base[2];
 };
 
@@ -73,28 +76,42 @@ static u64 cycles_at_suspend;
 
 static u64 dummy_clock_read(struct clocksource *cs)
 {
-       return cycles_at_suspend;
+       if (timekeeping_suspended)
+               return cycles_at_suspend;
+       return local_clock();
 }
 
 static struct clocksource dummy_clock = {
        .read = dummy_clock_read,
 };
 
+/*
+ * Boot time initialization which allows local_clock() to be utilized
+ * during early boot when clocksources are not available. local_clock()
+ * returns nanoseconds already so no conversion is required, hence mult=1
+ * and shift=0. When the first proper clocksource is installed then
+ * the fast time keepers are updated with the correct values.
+ */
+#define FAST_TK_INIT                                           \
+       {                                                       \
+               .clock          = &dummy_clock,                 \
+               .mask           = CLOCKSOURCE_MASK(64),         \
+               .mult           = 1,                            \
+               .shift          = 0,                            \
+       }
+
 static struct tk_fast tk_fast_mono ____cacheline_aligned = {
-       .seq     = SEQCNT_RAW_SPINLOCK_ZERO(tk_fast_mono.seq, &timekeeper_lock),
-       .base[0] = { .clock = &dummy_clock, },
-       .base[1] = { .clock = &dummy_clock, },
+       .seq     = SEQCNT_LATCH_ZERO(tk_fast_mono.seq),
+       .base[0] = FAST_TK_INIT,
+       .base[1] = FAST_TK_INIT,
 };
 
 static struct tk_fast tk_fast_raw  ____cacheline_aligned = {
-       .seq     = SEQCNT_RAW_SPINLOCK_ZERO(tk_fast_raw.seq, &timekeeper_lock),
-       .base[0] = { .clock = &dummy_clock, },
-       .base[1] = { .clock = &dummy_clock, },
+       .seq     = SEQCNT_LATCH_ZERO(tk_fast_raw.seq),
+       .base[0] = FAST_TK_INIT,
+       .base[1] = FAST_TK_INIT,
 };
 
-/* flag for if timekeeping is suspended */
-int __read_mostly timekeeping_suspended;
-
 static inline void tk_normalize_xtime(struct timekeeper *tk)
 {
        while (tk->tkr_mono.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_mono.shift)) {
@@ -467,7 +484,7 @@ static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf)
                                        tk_clock_read(tkr),
                                        tkr->cycle_last,
                                        tkr->mask));
-       } while (read_seqcount_retry(&tkf->seq, seq));
+       } while (read_seqcount_latch_retry(&tkf->seq, seq));
 
        return now;
 }
@@ -513,29 +530,29 @@ u64 notrace ktime_get_boot_fast_ns(void)
 }
 EXPORT_SYMBOL_GPL(ktime_get_boot_fast_ns);
 
-
 /*
  * See comment for __ktime_get_fast_ns() vs. timestamp ordering
  */
-static __always_inline u64 __ktime_get_real_fast_ns(struct tk_fast *tkf)
+static __always_inline u64 __ktime_get_real_fast(struct tk_fast *tkf, u64 *mono)
 {
        struct tk_read_base *tkr;
+       u64 basem, baser, delta;
        unsigned int seq;
-       u64 now;
 
        do {
                seq = raw_read_seqcount_latch(&tkf->seq);
                tkr = tkf->base + (seq & 0x01);
-               now = ktime_to_ns(tkr->base_real);
+               basem = ktime_to_ns(tkr->base);
+               baser = ktime_to_ns(tkr->base_real);
 
-               now += timekeeping_delta_to_ns(tkr,
-                               clocksource_delta(
-                                       tk_clock_read(tkr),
-                                       tkr->cycle_last,
-                                       tkr->mask));
-       } while (read_seqcount_retry(&tkf->seq, seq));
+               delta = timekeeping_delta_to_ns(tkr,
+                               clocksource_delta(tk_clock_read(tkr),
+                               tkr->cycle_last, tkr->mask));
+       } while (read_seqcount_latch_retry(&tkf->seq, seq));
 
-       return now;
+       if (mono)
+               *mono = basem + delta;
+       return baser + delta;
 }
 
 /**
@@ -543,11 +560,65 @@ static __always_inline u64 __ktime_get_real_fast_ns(struct tk_fast *tkf)
  */
 u64 ktime_get_real_fast_ns(void)
 {
-       return __ktime_get_real_fast_ns(&tk_fast_mono);
+       return __ktime_get_real_fast(&tk_fast_mono, NULL);
 }
 EXPORT_SYMBOL_GPL(ktime_get_real_fast_ns);
 
 /**
+ * ktime_get_fast_timestamps: - NMI safe timestamps
+ * @snapshot:  Pointer to timestamp storage
+ *
+ * Stores clock monotonic, boottime and realtime timestamps.
+ *
+ * Boot time is a racy access on 32bit systems if the sleep time injection
+ * happens late during resume and not in timekeeping_resume(). That could
+ * be avoided by expanding struct tk_read_base with boot offset for 32bit
+ * and adding more overhead to the update. As this is a hard to observe
+ * once per resume event which can be filtered with reasonable effort using
+ * the accurate mono/real timestamps, it's probably not worth the trouble.
+ *
+ * Aside of that it might be possible on 32 and 64 bit to observe the
+ * following when the sleep time injection happens late:
+ *
+ * CPU 0                               CPU 1
+ * timekeeping_resume()
+ * ktime_get_fast_timestamps()
+ *     mono, real = __ktime_get_real_fast()
+ *                                     inject_sleep_time()
+ *                                        update boot offset
+ *     boot = mono + bootoffset;
+ *
+ * That means that boot time already has the sleep time adjustment, but
+ * real time does not. On the next readout both are in sync again.
+ *
+ * Preventing this for 64bit is not really feasible without destroying the
+ * careful cache layout of the timekeeper because the sequence count and
+ * struct tk_read_base would then need two cache lines instead of one.
+ *
+ * Access to the time keeper clock source is disabled accross the innermost
+ * steps of suspend/resume. The accessors still work, but the timestamps
+ * are frozen until time keeping is resumed which happens very early.
+ *
+ * For regular suspend/resume there is no observable difference vs. sched
+ * clock, but it might affect some of the nasty low level debug printks.
+ *
+ * OTOH, access to sched clock is not guaranteed accross suspend/resume on
+ * all systems either so it depends on the hardware in use.
+ *
+ * If that turns out to be a real problem then this could be mitigated by
+ * using sched clock in a similar way as during early boot. But it's not as
+ * trivial as on early boot because it needs some careful protection
+ * against the clock monotonic timestamp jumping backwards on resume.
+ */
+void ktime_get_fast_timestamps(struct ktime_timestamps *snapshot)
+{
+       struct timekeeper *tk = &tk_core.timekeeper;
+
+       snapshot->real = __ktime_get_real_fast(&tk_fast_mono, &snapshot->mono);
+       snapshot->boot = snapshot->mono + ktime_to_ns(data_race(tk->offs_boot));
+}
+
+/**
  * halt_fast_timekeeper - Prevent fast timekeeper from accessing clocksource.
  * @tk: Timekeeper to snapshot.
  *
index a16764b..dda05f4 100644 (file)
@@ -611,7 +611,7 @@ static void internal_add_timer(struct timer_base *base, struct timer_list *timer
 
 #ifdef CONFIG_DEBUG_OBJECTS_TIMERS
 
-static struct debug_obj_descr timer_debug_descr;
+static const struct debug_obj_descr timer_debug_descr;
 
 static void *timer_debug_hint(void *addr)
 {
@@ -666,7 +666,7 @@ static bool timer_fixup_activate(void *addr, enum debug_obj_state state)
 
        case ODEBUG_STATE_ACTIVE:
                WARN_ON(1);
-               /* fall through */
+               fallthrough;
        default:
                return false;
        }
@@ -707,7 +707,7 @@ static bool timer_fixup_assert_init(void *addr, enum debug_obj_state state)
        }
 }
 
-static struct debug_obj_descr timer_debug_descr = {
+static const struct debug_obj_descr timer_debug_descr = {
        .name                   = "timer_list",
        .debug_hint             = timer_debug_hint,
        .is_static_object       = timer_is_static_object,
@@ -794,6 +794,8 @@ static void do_init_timer(struct timer_list *timer,
 {
        timer->entry.pprev = NULL;
        timer->function = func;
+       if (WARN_ON_ONCE(flags & ~TIMER_INIT_FLAGS))
+               flags &= TIMER_INIT_FLAGS;
        timer->flags = flags | raw_smp_processor_id();
        lockdep_init_map(&timer->lockdep_map, name, key, 0);
 }
index 7ba62d6..4b3a42f 100644 (file)
@@ -745,7 +745,7 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
 #endif
        case BLKTRACESTART:
                start = 1;
-               /* fall through */
+               fallthrough;
        case BLKTRACESTOP:
                ret = __blk_trace_startstop(q, start);
                break;
index a8d4f25..2ecf789 100644 (file)
@@ -2027,10 +2027,11 @@ static int bpf_event_notify(struct notifier_block *nb, unsigned long op,
 {
        struct bpf_trace_module *btm, *tmp;
        struct module *mod = module;
+       int ret = 0;
 
        if (mod->num_bpf_raw_events == 0 ||
            (op != MODULE_STATE_COMING && op != MODULE_STATE_GOING))
-               return 0;
+               goto out;
 
        mutex_lock(&bpf_module_mutex);
 
@@ -2040,6 +2041,8 @@ static int bpf_event_notify(struct notifier_block *nb, unsigned long op,
                if (btm) {
                        btm->module = module;
                        list_add(&btm->list, &bpf_trace_modules);
+               } else {
+                       ret = -ENOMEM;
                }
                break;
        case MODULE_STATE_GOING:
@@ -2055,7 +2058,8 @@ static int bpf_event_notify(struct notifier_block *nb, unsigned long op,
 
        mutex_unlock(&bpf_module_mutex);
 
-       return 0;
+out:
+       return notifier_from_errno(ret);
 }
 
 static struct notifier_block bpf_module_nb = {
index 2754412..5414539 100644 (file)
@@ -2782,6 +2782,7 @@ static void ftrace_remove_trampoline_from_kallsyms(struct ftrace_ops *ops)
 {
        lockdep_assert_held(&ftrace_lock);
        list_del_rcu(&ops->list);
+       synchronize_rcu();
 }
 
 /*
@@ -2862,6 +2863,8 @@ int ftrace_startup(struct ftrace_ops *ops, int command)
                __unregister_ftrace_function(ops);
                ftrace_start_up--;
                ops->flags &= ~FTRACE_OPS_FL_ENABLED;
+               if (ops->flags & FTRACE_OPS_FL_DYNAMIC)
+                       ftrace_trampoline_free(ops);
                return ret;
        }
 
@@ -6990,16 +6993,14 @@ static void ftrace_ops_assist_func(unsigned long ip, unsigned long parent_ip,
 {
        int bit;
 
-       if ((op->flags & FTRACE_OPS_FL_RCU) && !rcu_is_watching())
-               return;
-
        bit = trace_test_and_set_recursion(TRACE_LIST_START, TRACE_LIST_MAX);
        if (bit < 0)
                return;
 
        preempt_disable_notrace();
 
-       op->func(ip, parent_ip, op, regs);
+       if (!(op->flags & FTRACE_OPS_FL_RCU) || rcu_is_watching())
+               op->func(ip, parent_ip, op, regs);
 
        preempt_enable_notrace();
        trace_clear_recursion(bit);
@@ -7531,8 +7532,7 @@ static bool is_permanent_ops_registered(void)
 
 int
 ftrace_enable_sysctl(struct ctl_table *table, int write,
-                    void __user *buffer, size_t *lenp,
-                    loff_t *ppos)
+                    void *buffer, size_t *lenp, loff_t *ppos)
 {
        int ret = -ENODEV;
 
index f40d850..25b72a7 100644 (file)
@@ -3546,13 +3546,15 @@ struct trace_entry *trace_find_next_entry(struct trace_iterator *iter,
        if (iter->ent && iter->ent != iter->temp) {
                if ((!iter->temp || iter->temp_size < iter->ent_size) &&
                    !WARN_ON_ONCE(iter->temp == static_temp_buf)) {
-                       kfree(iter->temp);
-                       iter->temp = kmalloc(iter->ent_size, GFP_KERNEL);
-                       if (!iter->temp)
+                       void *temp;
+                       temp = kmalloc(iter->ent_size, GFP_KERNEL);
+                       if (!temp)
                                return NULL;
+                       kfree(iter->temp);
+                       iter->temp = temp;
+                       iter->temp_size = iter->ent_size;
                }
                memcpy(iter->temp, iter->ent, iter->ent_size);
-               iter->temp_size = iter->ent_size;
                iter->ent = iter->temp;
        }
        entry = __find_next_entry(iter, ent_cpu, NULL, ent_ts);
@@ -3782,14 +3784,14 @@ unsigned long trace_total_entries(struct trace_array *tr)
 
 static void print_lat_help_header(struct seq_file *m)
 {
-       seq_puts(m, "#                  _------=> CPU#            \n"
-                   "#                 / _-----=> irqs-off        \n"
-                   "#                | / _----=> need-resched    \n"
-                   "#                || / _---=> hardirq/softirq \n"
-                   "#                ||| / _--=> preempt-depth   \n"
-                   "#                |||| /     delay            \n"
-                   "#  cmd     pid   ||||| time  |   caller      \n"
-                   "#     \\   /      |||||  \\    |   /         \n");
+       seq_puts(m, "#                    _------=> CPU#            \n"
+                   "#                   / _-----=> irqs-off        \n"
+                   "#                  | / _----=> need-resched    \n"
+                   "#                  || / _---=> hardirq/softirq \n"
+                   "#                  ||| / _--=> preempt-depth   \n"
+                   "#                  |||| /     delay            \n"
+                   "#  cmd     pid     ||||| time  |   caller      \n"
+                   "#     \\   /        |||||  \\    |   /         \n");
 }
 
 static void print_event_info(struct array_buffer *buf, struct seq_file *m)
@@ -3810,26 +3812,26 @@ static void print_func_help_header(struct array_buffer *buf, struct seq_file *m,
 
        print_event_info(buf, m);
 
-       seq_printf(m, "#           TASK-PID   %s  CPU#   TIMESTAMP  FUNCTION\n", tgid ? "TGID     " : "");
-       seq_printf(m, "#              | |     %s    |       |         |\n",      tgid ? "  |      " : "");
+       seq_printf(m, "#           TASK-PID    %s CPU#     TIMESTAMP  FUNCTION\n", tgid ? "   TGID   " : "");
+       seq_printf(m, "#              | |      %s   |         |         |\n",      tgid ? "     |    " : "");
 }
 
 static void print_func_help_header_irq(struct array_buffer *buf, struct seq_file *m,
                                       unsigned int flags)
 {
        bool tgid = flags & TRACE_ITER_RECORD_TGID;
-       const char *space = "          ";
-       int prec = tgid ? 10 : 2;
+       const char *space = "            ";
+       int prec = tgid ? 12 : 2;
 
        print_event_info(buf, m);
 
-       seq_printf(m, "#                          %.*s  _-----=> irqs-off\n", prec, space);
-       seq_printf(m, "#                          %.*s / _----=> need-resched\n", prec, space);
-       seq_printf(m, "#                          %.*s| / _---=> hardirq/softirq\n", prec, space);
-       seq_printf(m, "#                          %.*s|| / _--=> preempt-depth\n", prec, space);
-       seq_printf(m, "#                          %.*s||| /     delay\n", prec, space);
-       seq_printf(m, "#           TASK-PID %.*sCPU#  ||||    TIMESTAMP  FUNCTION\n", prec, "   TGID   ");
-       seq_printf(m, "#              | |   %.*s  |   ||||       |         |\n", prec, "     |    ");
+       seq_printf(m, "#                            %.*s  _-----=> irqs-off\n", prec, space);
+       seq_printf(m, "#                            %.*s / _----=> need-resched\n", prec, space);
+       seq_printf(m, "#                            %.*s| / _---=> hardirq/softirq\n", prec, space);
+       seq_printf(m, "#                            %.*s|| / _--=> preempt-depth\n", prec, space);
+       seq_printf(m, "#                            %.*s||| /     delay\n", prec, space);
+       seq_printf(m, "#           TASK-PID  %.*s CPU#  ||||   TIMESTAMP  FUNCTION\n", prec, "     TGID   ");
+       seq_printf(m, "#              | |    %.*s   |   ||||      |         |\n", prec, "       |    ");
 }
 
 void
@@ -9072,7 +9074,7 @@ static int trace_module_notify(struct notifier_block *self,
                break;
        }
 
-       return 0;
+       return NOTIFY_OK;
 }
 
 static struct notifier_block trace_module_nb = {
index a85effb..beebf2c 100644 (file)
@@ -2646,7 +2646,7 @@ static int trace_module_notify(struct notifier_block *self,
        mutex_unlock(&trace_types_lock);
        mutex_unlock(&event_mutex);
 
-       return 0;
+       return NOTIFY_OK;
 }
 
 static struct notifier_block trace_module_nb = {
index bf44f6b..78a678e 100644 (file)
@@ -499,7 +499,7 @@ predicate_parse(const char *str, int nr_parens, int nr_preds,
                                        ptr++;
                                        break;
                                }
-                               /* fall through */
+                               fallthrough;
                        default:
                                parse_error(pe, FILT_ERR_TOO_MANY_PREDS,
                                            next - str);
@@ -1273,7 +1273,7 @@ static int parse_pred(const char *str, void *data,
                switch (op) {
                case OP_NE:
                        pred->not = 1;
-                       /* Fall through */
+                       fallthrough;
                case OP_GLOB:
                case OP_EQ:
                        break;
index 0b93354..1b2ef64 100644 (file)
@@ -3865,7 +3865,6 @@ static int parse_var_defs(struct hist_trigger_data *hist_data)
 
                        s = kstrdup(field_str, GFP_KERNEL);
                        if (!s) {
-                               kfree(hist_data->attrs->var_defs.name[n_vars]);
                                ret = -ENOMEM;
                                goto free;
                        }
index aefb606..19c00ee 100644 (file)
@@ -106,9 +106,10 @@ static nokprobe_inline bool trace_kprobe_has_gone(struct trace_kprobe *tk)
 static nokprobe_inline bool trace_kprobe_within_module(struct trace_kprobe *tk,
                                                 struct module *mod)
 {
-       int len = strlen(mod->name);
+       int len = strlen(module_name(mod));
        const char *name = trace_kprobe_symbol(tk);
-       return strncmp(mod->name, name, len) == 0 && name[len] == ':';
+
+       return strncmp(module_name(mod), name, len) == 0 && name[len] == ':';
 }
 
 static nokprobe_inline bool trace_kprobe_module_exist(struct trace_kprobe *tk)
@@ -688,7 +689,7 @@ static int trace_kprobe_module_callback(struct notifier_block *nb,
                        if (ret)
                                pr_warn("Failed to re-register probe %s on %s: %d\n",
                                        trace_probe_name(&tk->tp),
-                                       mod->name, ret);
+                                       module_name(mod), ret);
                }
        }
        mutex_unlock(&event_mutex);
index 4d18935..000e9dc 100644 (file)
@@ -497,7 +497,7 @@ lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu)
 
        trace_find_cmdline(entry->pid, comm);
 
-       trace_seq_printf(s, "%8.8s-%-5d %3d",
+       trace_seq_printf(s, "%8.8s-%-7d %3d",
                         comm, entry->pid, cpu);
 
        return trace_print_lat_fmt(s, entry);
@@ -588,15 +588,15 @@ int trace_print_context(struct trace_iterator *iter)
 
        trace_find_cmdline(entry->pid, comm);
 
-       trace_seq_printf(s, "%16s-%-5d ", comm, entry->pid);
+       trace_seq_printf(s, "%16s-%-7d ", comm, entry->pid);
 
        if (tr->trace_flags & TRACE_ITER_RECORD_TGID) {
                unsigned int tgid = trace_find_tgid(entry->pid);
 
                if (!tgid)
-                       trace_seq_printf(s, "(-----) ");
+                       trace_seq_printf(s, "(-------) ");
                else
-                       trace_seq_printf(s, "(%5d) ", tgid);
+                       trace_seq_printf(s, "(%7d) ", tgid);
        }
 
        trace_seq_printf(s, "[%03d] ", iter->cpu);
@@ -636,7 +636,7 @@ int trace_print_lat_context(struct trace_iterator *iter)
                trace_find_cmdline(entry->pid, comm);
 
                trace_seq_printf(
-                       s, "%16s %5d %3d %d %08x %08lx ",
+                       s, "%16s %7d %3d %d %08x %08lx ",
                        comm, entry->pid, iter->cpu, entry->flags,
                        entry->preempt_count, iter->idx);
        } else {
@@ -917,7 +917,7 @@ static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
        S = task_index_to_char(field->prev_state);
        trace_find_cmdline(field->next_pid, comm);
        trace_seq_printf(&iter->seq,
-                        " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
+                        " %7d:%3d:%c %s [%03d] %7d:%3d:%c %s\n",
                         field->prev_pid,
                         field->prev_prio,
                         S, delim,
index f10073e..f493804 100644 (file)
@@ -102,14 +102,14 @@ NOKPROBE_SYMBOL(trace_hardirqs_on_caller);
 
 __visible void trace_hardirqs_off_caller(unsigned long caller_addr)
 {
+       lockdep_hardirqs_off(CALLER_ADDR0);
+
        if (!this_cpu_read(tracing_irq_cpu)) {
                this_cpu_write(tracing_irq_cpu, 1);
                tracer_hardirqs_off(CALLER_ADDR0, caller_addr);
                if (!in_nmi())
                        trace_irq_disable_rcuidle(CALLER_ADDR0, caller_addr);
        }
-
-       lockdep_hardirqs_off(CALLER_ADDR0);
 }
 EXPORT_SYMBOL(trace_hardirqs_off_caller);
 NOKPROBE_SYMBOL(trace_hardirqs_off_caller);
index d4e31e9..bb7783b 100644 (file)
@@ -96,7 +96,7 @@ static int module_trace_bprintk_format_notify(struct notifier_block *self,
                if (val == MODULE_STATE_COMING)
                        hold_module_trace_bprintk_format(start, end);
        }
-       return 0;
+       return NOTIFY_OK;
 }
 
 /*
@@ -174,7 +174,7 @@ __init static int
 module_trace_bprintk_format_notify(struct notifier_block *self,
                unsigned long val, void *data)
 {
-       return 0;
+       return NOTIFY_OK;
 }
 static inline const char **
 find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
index 73956ea..26efd22 100644 (file)
@@ -221,6 +221,29 @@ static void *func_remove(struct tracepoint_func **funcs,
        return old;
 }
 
+static void tracepoint_update_call(struct tracepoint *tp, struct tracepoint_func *tp_funcs, bool sync)
+{
+       void *func = tp->iterator;
+
+       /* Synthetic events do not have static call sites */
+       if (!tp->static_call_key)
+               return;
+
+       if (!tp_funcs[1].func) {
+               func = tp_funcs[0].func;
+               /*
+                * If going from the iterator back to a single caller,
+                * we need to synchronize with __DO_TRACE to make sure
+                * that the data passed to the callback is the one that
+                * belongs to that callback.
+                */
+               if (sync)
+                       tracepoint_synchronize_unregister();
+       }
+
+       __static_call_update(tp->static_call_key, tp->static_call_tramp, func);
+}
+
 /*
  * Add the probe function to a tracepoint.
  */
@@ -251,8 +274,9 @@ static int tracepoint_add_func(struct tracepoint *tp,
         * include/linux/tracepoint.h using rcu_dereference_sched().
         */
        rcu_assign_pointer(tp->funcs, tp_funcs);
-       if (!static_key_enabled(&tp->key))
-               static_key_slow_inc(&tp->key);
+       tracepoint_update_call(tp, tp_funcs, false);
+       static_key_enable(&tp->key);
+
        release_probes(old);
        return 0;
 }
@@ -281,10 +305,13 @@ static int tracepoint_remove_func(struct tracepoint *tp,
                if (tp->unregfunc && static_key_enabled(&tp->key))
                        tp->unregfunc();
 
-               if (static_key_enabled(&tp->key))
-                       static_key_slow_dec(&tp->key);
+               static_key_disable(&tp->key);
+               rcu_assign_pointer(tp->funcs, tp_funcs);
+       } else {
+               rcu_assign_pointer(tp->funcs, tp_funcs);
+               tracepoint_update_call(tp, tp_funcs,
+                                      tp_funcs[0].func != old[0].func);
        }
-       rcu_assign_pointer(tp->funcs, tp_funcs);
        release_probes(old);
        return 0;
 }
@@ -521,7 +548,7 @@ static int tracepoint_module_notify(struct notifier_block *self,
        case MODULE_STATE_UNFORMED:
                break;
        }
-       return ret;
+       return notifier_from_errno(ret);
 }
 
 static struct notifier_block tracepoint_module_nb = {
index fcf3ee8..3f64661 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/cred.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
+#include <linux/fs_struct.h>
 #include <linux/workqueue.h>
 #include <linux/security.h>
 #include <linux/mount.h>
@@ -72,6 +73,14 @@ static int call_usermodehelper_exec_async(void *data)
        spin_unlock_irq(&current->sighand->siglock);
 
        /*
+        * Initial kernel threads share ther FS with init, in order to
+        * get the init root directory. But we've now created a new
+        * thread that is going to execve a user process and has its own
+        * 'struct fs_struct'. Reset umask to the default.
+        */
+       current->fs->umask = 0022;
+
+       /*
         * Our parent (unbound workqueue) runs with elevated scheduling
         * priority. Avoid propagating that into the userspace child.
         */
index c41c3c1..ac088ce 100644 (file)
@@ -427,7 +427,7 @@ static void show_pwq(struct pool_workqueue *pwq);
 
 #ifdef CONFIG_DEBUG_OBJECTS_WORK
 
-static struct debug_obj_descr work_debug_descr;
+static const struct debug_obj_descr work_debug_descr;
 
 static void *work_debug_hint(void *addr)
 {
@@ -477,7 +477,7 @@ static bool work_fixup_free(void *addr, enum debug_obj_state state)
        }
 }
 
-static struct debug_obj_descr work_debug_descr = {
+static const struct debug_obj_descr work_debug_descr = {
        .name           = "work_struct",
        .debug_hint     = work_debug_hint,
        .is_static_object = work_is_static_object,
index b4b98a0..b46a9fd 100644 (file)
@@ -635,7 +635,12 @@ config UACCESS_MEMCPY
 config ARCH_HAS_UACCESS_FLUSHCACHE
        bool
 
-config ARCH_HAS_UACCESS_MCSAFE
+# arch has a concept of a recoverable synchronous exception due to a
+# memory-read error like x86 machine-check or ARM data-abort, and
+# implements copy_mc_to_{user,kernel} to abort and report
+# 'bytes-transferred' if that exception fires when accessing the source
+# buffer.
+config ARCH_HAS_COPY_MC
        bool
 
 # Temporary. Goes away when all archs are cleaned up
index e068c3c..0c781f9 100644 (file)
@@ -520,8 +520,8 @@ config DEBUG_FS_ALLOW_NONE
 endchoice
 
 source "lib/Kconfig.kgdb"
-
 source "lib/Kconfig.ubsan"
+source "lib/Kconfig.kcsan"
 
 endmenu
 
@@ -1620,8 +1620,6 @@ config PROVIDE_OHCI1394_DMA_INIT
 
 source "samples/Kconfig"
 
-source "lib/Kconfig.kcsan"
-
 config ARCH_HAS_DEVMEM_IS_ALLOWED
        bool
 
index 3d282d5..f271ff5 100644 (file)
@@ -40,6 +40,11 @@ menuconfig KCSAN
 
 if KCSAN
 
+# Compiler capabilities that should not fail the test if they are unavailable.
+config CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE
+       def_bool (CC_IS_CLANG && $(cc-option,-fsanitize=thread -mllvm -tsan-compound-read-before-write=1)) || \
+                (CC_IS_GCC && $(cc-option,-fsanitize=thread --param tsan-compound-read-before-write=1))
+
 config KCSAN_VERBOSE
        bool "Show verbose reports with more information about system state"
        depends on PROVE_LOCKING
index a5f7011..649ed44 100644 (file)
@@ -31,6 +31,8 @@ static size_t xbc_data_size __initdata;
 static struct xbc_node *last_parent __initdata;
 static const char *xbc_err_msg __initdata;
 static int xbc_err_pos __initdata;
+static int open_brace[XBC_DEPTH_MAX] __initdata;
+static int brace_index __initdata;
 
 static int __init xbc_parse_error(const char *msg, const char *p)
 {
@@ -431,27 +433,27 @@ static char *skip_spaces_until_newline(char *p)
        return p;
 }
 
-static int __init __xbc_open_brace(void)
+static int __init __xbc_open_brace(char *p)
 {
-       /* Mark the last key as open brace */
-       last_parent->next = XBC_NODE_MAX;
+       /* Push the last key as open brace */
+       open_brace[brace_index++] = xbc_node_index(last_parent);
+       if (brace_index >= XBC_DEPTH_MAX)
+               return xbc_parse_error("Exceed max depth of braces", p);
 
        return 0;
 }
 
 static int __init __xbc_close_brace(char *p)
 {
-       struct xbc_node *node;
-
-       if (!last_parent || last_parent->next != XBC_NODE_MAX)
+       brace_index--;
+       if (!last_parent || brace_index < 0 ||
+           (open_brace[brace_index] != xbc_node_index(last_parent)))
                return xbc_parse_error("Unexpected closing brace", p);
 
-       node = last_parent;
-       node->next = 0;
-       do {
-               node = xbc_node_get_parent(node);
-       } while (node && node->next != XBC_NODE_MAX);
-       last_parent = node;
+       if (brace_index == 0)
+               last_parent = NULL;
+       else
+               last_parent = &xbc_nodes[open_brace[brace_index - 1]];
 
        return 0;
 }
@@ -492,8 +494,8 @@ static int __init __xbc_parse_value(char **__v, char **__n)
                        break;
                }
                if (strchr(",;\n#}", c)) {
-                       v = strim(v);
                        *p++ = '\0';
+                       v = strim(v);
                        break;
                }
        }
@@ -661,7 +663,7 @@ static int __init xbc_open_brace(char **k, char *n)
                return ret;
        *k = n;
 
-       return __xbc_open_brace();
+       return __xbc_open_brace(n - 1);
 }
 
 static int __init xbc_close_brace(char **k, char *n)
@@ -681,6 +683,13 @@ static int __init xbc_verify_tree(void)
        int i, depth, len, wlen;
        struct xbc_node *n, *m;
 
+       /* Brace closing */
+       if (brace_index) {
+               n = &xbc_nodes[open_brace[brace_index]];
+               return xbc_parse_error("Brace is not closed",
+                                       xbc_node_get_data(n));
+       }
+
        /* Empty tree */
        if (xbc_node_num == 0) {
                xbc_parse_error("Empty config", xbc_data);
@@ -745,6 +754,7 @@ void __init xbc_destroy_all(void)
        xbc_node_num = 0;
        memblock_free(__pa(xbc_nodes), sizeof(struct xbc_node) * XBC_NODE_MAX);
        xbc_nodes = NULL;
+       brace_index = 0;
 }
 
 /**
@@ -817,7 +827,7 @@ int __init xbc_init(char *buf, const char **emsg, int *epos)
                                                        q - 2);
                                break;
                        }
-                       /* Fall through */
+                       /* fall through */
                case '=':
                        ret = xbc_parse_kv(&p, q, c);
                        break;
index c7861e8..6860d6b 100644 (file)
@@ -145,17 +145,6 @@ __sum16 ip_compute_csum(const void *buff, int len)
 }
 EXPORT_SYMBOL(ip_compute_csum);
 
-/*
- * copy from ds while checksumming, otherwise like csum_partial
- */
-__wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
-{
-       memcpy(dst, src, len);
-       return csum_partial(dst, len, sum);
-}
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
-
 #ifndef csum_tcpudp_nofold
 static inline u32 from64to32(u64 x)
 {
index 431e042..5850f3b 100644 (file)
@@ -251,9 +251,7 @@ bool chacha20poly1305_crypt_sg_inplace(struct scatterlist *src,
                        poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf));
        }
 
-       flags = SG_MITER_TO_SG;
-       if (!preemptible())
-               flags |= SG_MITER_ATOMIC;
+       flags = SG_MITER_TO_SG | SG_MITER_ATOMIC;
 
        sg_miter_start(&miter, src, sg_nents(src), flags);
 
index fe45579..9e14ae0 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/hash.h>
 #include <linux/kmemleak.h>
+#include <linux/cpu.h>
 
 #define ODEBUG_HASH_BITS       14
 #define ODEBUG_HASH_SIZE       (1 << ODEBUG_HASH_BITS)
@@ -90,7 +91,7 @@ static int                    debug_objects_pool_size __read_mostly
                                = ODEBUG_POOL_SIZE;
 static int                     debug_objects_pool_min_level __read_mostly
                                = ODEBUG_POOL_MIN_LEVEL;
-static struct debug_obj_descr  *descr_test  __read_mostly;
+static const struct debug_obj_descr *descr_test  __read_mostly;
 static struct kmem_cache       *obj_cache __read_mostly;
 
 /*
@@ -223,7 +224,7 @@ static struct debug_obj *__alloc_object(struct hlist_head *list)
  * Must be called with interrupts disabled.
  */
 static struct debug_obj *
-alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
+alloc_object(void *addr, struct debug_bucket *b, const struct debug_obj_descr *descr)
 {
        struct debug_percpu_free *percpu_pool = this_cpu_ptr(&percpu_obj_pool);
        struct debug_obj *obj;
@@ -433,6 +434,25 @@ static void free_object(struct debug_obj *obj)
        }
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int object_cpu_offline(unsigned int cpu)
+{
+       struct debug_percpu_free *percpu_pool;
+       struct hlist_node *tmp;
+       struct debug_obj *obj;
+
+       /* Remote access is safe as the CPU is dead already */
+       percpu_pool = per_cpu_ptr(&percpu_obj_pool, cpu);
+       hlist_for_each_entry_safe(obj, tmp, &percpu_pool->free_objs, node) {
+               hlist_del(&obj->node);
+               kmem_cache_free(obj_cache, obj);
+       }
+       percpu_pool->obj_free = 0;
+
+       return 0;
+}
+#endif
+
 /*
  * We run out of memory. That means we probably have tons of objects
  * allocated.
@@ -475,7 +495,7 @@ static struct debug_bucket *get_bucket(unsigned long addr)
 
 static void debug_print_object(struct debug_obj *obj, char *msg)
 {
-       struct debug_obj_descr *descr = obj->descr;
+       const struct debug_obj_descr *descr = obj->descr;
        static int limit;
 
        if (limit < 5 && descr != descr_test) {
@@ -529,7 +549,7 @@ static void debug_object_is_on_stack(void *addr, int onstack)
 }
 
 static void
-__debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack)
+__debug_object_init(void *addr, const struct debug_obj_descr *descr, int onstack)
 {
        enum debug_obj_state state;
        bool check_stack = false;
@@ -587,7 +607,7 @@ __debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack)
  * @addr:      address of the object
  * @descr:     pointer to an object specific debug description structure
  */
-void debug_object_init(void *addr, struct debug_obj_descr *descr)
+void debug_object_init(void *addr, const struct debug_obj_descr *descr)
 {
        if (!debug_objects_enabled)
                return;
@@ -602,7 +622,7 @@ EXPORT_SYMBOL_GPL(debug_object_init);
  * @addr:      address of the object
  * @descr:     pointer to an object specific debug description structure
  */
-void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr)
+void debug_object_init_on_stack(void *addr, const struct debug_obj_descr *descr)
 {
        if (!debug_objects_enabled)
                return;
@@ -617,7 +637,7 @@ EXPORT_SYMBOL_GPL(debug_object_init_on_stack);
  * @descr:     pointer to an object specific debug description structure
  * Returns 0 for success, -EINVAL for check failed.
  */
-int debug_object_activate(void *addr, struct debug_obj_descr *descr)
+int debug_object_activate(void *addr, const struct debug_obj_descr *descr)
 {
        enum debug_obj_state state;
        struct debug_bucket *db;
@@ -695,7 +715,7 @@ EXPORT_SYMBOL_GPL(debug_object_activate);
  * @addr:      address of the object
  * @descr:     pointer to an object specific debug description structure
  */
-void debug_object_deactivate(void *addr, struct debug_obj_descr *descr)
+void debug_object_deactivate(void *addr, const struct debug_obj_descr *descr)
 {
        struct debug_bucket *db;
        struct debug_obj *obj;
@@ -747,7 +767,7 @@ EXPORT_SYMBOL_GPL(debug_object_deactivate);
  * @addr:      address of the object
  * @descr:     pointer to an object specific debug description structure
  */
-void debug_object_destroy(void *addr, struct debug_obj_descr *descr)
+void debug_object_destroy(void *addr, const struct debug_obj_descr *descr)
 {
        enum debug_obj_state state;
        struct debug_bucket *db;
@@ -797,7 +817,7 @@ EXPORT_SYMBOL_GPL(debug_object_destroy);
  * @addr:      address of the object
  * @descr:     pointer to an object specific debug description structure
  */
-void debug_object_free(void *addr, struct debug_obj_descr *descr)
+void debug_object_free(void *addr, const struct debug_obj_descr *descr)
 {
        enum debug_obj_state state;
        struct debug_bucket *db;
@@ -838,7 +858,7 @@ EXPORT_SYMBOL_GPL(debug_object_free);
  * @addr:      address of the object
  * @descr:     pointer to an object specific debug description structure
  */
-void debug_object_assert_init(void *addr, struct debug_obj_descr *descr)
+void debug_object_assert_init(void *addr, const struct debug_obj_descr *descr)
 {
        struct debug_bucket *db;
        struct debug_obj *obj;
@@ -886,7 +906,7 @@ EXPORT_SYMBOL_GPL(debug_object_assert_init);
  * @next:      state to move to if expected state is found
  */
 void
-debug_object_active_state(void *addr, struct debug_obj_descr *descr,
+debug_object_active_state(void *addr, const struct debug_obj_descr *descr,
                          unsigned int expect, unsigned int next)
 {
        struct debug_bucket *db;
@@ -934,7 +954,7 @@ EXPORT_SYMBOL_GPL(debug_object_active_state);
 static void __debug_check_no_obj_freed(const void *address, unsigned long size)
 {
        unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;
-       struct debug_obj_descr *descr;
+       const struct debug_obj_descr *descr;
        enum debug_obj_state state;
        struct debug_bucket *db;
        struct hlist_node *tmp;
@@ -1052,7 +1072,7 @@ struct self_test {
        unsigned long   dummy2[3];
 };
 
-static __initdata struct debug_obj_descr descr_type_test;
+static __initconst const struct debug_obj_descr descr_type_test;
 
 static bool __init is_static_object(void *addr)
 {
@@ -1177,7 +1197,7 @@ out:
        return res;
 }
 
-static __initdata struct debug_obj_descr descr_type_test = {
+static __initconst const struct debug_obj_descr descr_type_test = {
        .name                   = "selftest",
        .is_static_object       = is_static_object,
        .fixup_init             = fixup_init,
@@ -1367,6 +1387,11 @@ void __init debug_objects_mem_init(void)
        } else
                debug_objects_selftest();
 
+#ifdef CONFIG_HOTPLUG_CPU
+       cpuhp_setup_state_nocalls(CPUHP_DEBUG_OBJ_DEAD, "object:offline", NULL,
+                                       object_cpu_offline);
+#endif
+
        /*
         * Increase the thresholds for allocating and freeing objects
         * according to the number of possible CPUs available in the system.
index 1d012e5..2d4dfd4 100644 (file)
@@ -353,8 +353,7 @@ static int check_set(const char **dest, char *src, char *name)
 
 /*
  * Parse words[] as a ddebug query specification, which is a series
- * of (keyword, value) pairs or combined keyword=value terms,
- * chosen from these possibilities:
+ * of (keyword, value) pairs chosen from these possibilities:
  *
  * func <function-name>
  * file <full-pathname>
@@ -373,34 +372,22 @@ static int ddebug_parse_query(char *words[], int nwords,
        unsigned int i;
        int rc = 0;
        char *fline;
-       char *keyword, *arg;
+
+       /* check we have an even number of words */
+       if (nwords % 2 != 0) {
+               pr_err("expecting pairs of match-spec <value>\n");
+               return -EINVAL;
+       }
 
        if (modname)
                /* support $modname.dyndbg=<multiple queries> */
                query->module = modname;
 
-       for (i = 0; i < nwords; i++) {
-               /* accept keyword=arg */
-               vpr_info("%d w:%s\n", i, words[i]);
-
-               keyword = words[i];
-               arg = strchr(keyword, '=');
-               if (arg) {
-                       *arg++ = '\0';
-               } else {
-                       i++; /* next word is arg */
-                       if (!(i < nwords)) {
-                               pr_err("missing arg to keyword: %s\n", keyword);
-                               return -EINVAL;
-                       }
-                       arg = words[i];
-               }
-               vpr_info("%d key:%s arg:%s\n", i, keyword, arg);
-
-               if (!strcmp(keyword, "func")) {
-                       rc = check_set(&query->function, arg, "func");
-               } else if (!strcmp(keyword, "file")) {
-                       if (check_set(&query->filename, arg, "file"))
+       for (i = 0; i < nwords; i += 2) {
+               if (!strcmp(words[i], "func")) {
+                       rc = check_set(&query->function, words[i+1], "func");
+               } else if (!strcmp(words[i], "file")) {
+                       if (check_set(&query->filename, words[i+1], "file"))
                                return -EINVAL;
 
                        /* tail :$info is function or line-range */
@@ -416,18 +403,18 @@ static int ddebug_parse_query(char *words[], int nwords,
                                if (parse_linerange(query, fline))
                                        return -EINVAL;
                        }
-               } else if (!strcmp(keyword, "module")) {
-                       rc = check_set(&query->module, arg, "module");
-               } else if (!strcmp(keyword, "format")) {
-                       string_unescape_inplace(arg, UNESCAPE_SPACE |
+               } else if (!strcmp(words[i], "module")) {
+                       rc = check_set(&query->module, words[i+1], "module");
+               } else if (!strcmp(words[i], "format")) {
+                       string_unescape_inplace(words[i+1], UNESCAPE_SPACE |
                                                            UNESCAPE_OCTAL |
                                                            UNESCAPE_SPECIAL);
-                       rc = check_set(&query->format, arg, "format");
-               } else if (!strcmp(keyword, "line")) {
-                       if (parse_linerange(query, arg))
+                       rc = check_set(&query->format, words[i+1], "format");
+               } else if (!strcmp(words[i], "line")) {
+                       if (parse_linerange(query, words[i+1]))
                                return -EINVAL;
                } else {
-                       pr_err("unknown keyword \"%s\"\n", keyword);
+                       pr_err("unknown keyword \"%s\"\n", words[i]);
                        return -EINVAL;
                }
                if (rc)
@@ -525,7 +512,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
    last error or number of matching callsites.  Module name is either
    in param (for boot arg) or perhaps in query string.
 */
-int ddebug_exec_queries(char *query, const char *modname)
+static int ddebug_exec_queries(char *query, const char *modname)
 {
        char *split;
        int i, errs = 0, exitcode = 0, rc, nfound = 0;
@@ -557,7 +544,30 @@ int ddebug_exec_queries(char *query, const char *modname)
                return exitcode;
        return nfound;
 }
-EXPORT_SYMBOL_GPL(ddebug_exec_queries);
+
+/**
+ * dynamic_debug_exec_queries - select and change dynamic-debug prints
+ * @query: query-string described in admin-guide/dynamic-debug-howto
+ * @modname: string containing module name, usually &module.mod_name
+ *
+ * This uses the >/proc/dynamic_debug/control reader, allowing module
+ * authors to modify their dynamic-debug callsites. The modname is
+ * canonically struct module.mod_name, but can also be null or a
+ * module-wildcard, for example: "drm*".
+ */
+int dynamic_debug_exec_queries(const char *query, const char *modname)
+{
+       int rc;
+       char *qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
+
+       if (!query)
+               return -ENOMEM;
+
+       rc = ddebug_exec_queries(qry, modname);
+       kfree(qry);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(dynamic_debug_exec_queries);
 
 #define PREFIX_SIZE 64
 
@@ -947,7 +957,7 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
        list_add(&dt->link, &ddebug_tables);
        mutex_unlock(&ddebug_lock);
 
-       v2pr_info("%u debug prints in module %s\n", n, dt->mod_name);
+       v2pr_info("%3u debug prints in module %s\n", n, dt->mod_name);
        return 0;
 }
 
index 532f0ff..0e2deac 100644 (file)
@@ -8,8 +8,8 @@
 
 #define FONTDATAMAX 9216
 
-static const unsigned char fontdata_10x18[FONTDATAMAX] = {
-
+static struct font_data fontdata_10x18 = {
+       { 0, 0, FONTDATAMAX, 0 }, {
        /* 0 0x00 '^@' */
        0x00, 0x00, /* 0000000000 */
        0x00, 0x00, /* 0000000000 */
@@ -5129,8 +5129,7 @@ static const unsigned char fontdata_10x18[FONTDATAMAX] = {
        0x00, 0x00, /* 0000000000 */
        0x00, 0x00, /* 0000000000 */
        0x00, 0x00, /* 0000000000 */
-
-};
+} };
 
 
 const struct font_desc font_10x18 = {
@@ -5138,7 +5137,7 @@ const struct font_desc font_10x18 = {
        .name   = "10x18",
        .width  = 10,
        .height = 18,
-       .data   = fontdata_10x18,
+       .data   = fontdata_10x18.data,
 #ifdef __sparc__
        .pref   = 5,
 #else
index 09b2cc0..87da8ac 100644 (file)
@@ -1,8 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/font.h>
 
-static const unsigned char fontdata_6x10[] = {
+#define FONTDATAMAX 2560
 
+static struct font_data fontdata_6x10 = {
+       { 0, 0, FONTDATAMAX, 0 }, {
        /* 0 0x00 '^@' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -3074,14 +3076,13 @@ static const unsigned char fontdata_6x10[] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-};
+} };
 
 const struct font_desc font_6x10 = {
        .idx    = FONT6x10_IDX,
        .name   = "6x10",
        .width  = 6,
        .height = 10,
-       .data   = fontdata_6x10,
+       .data   = fontdata_6x10.data,
        .pref   = 0,
 };
index d7136c3..5e975df 100644 (file)
@@ -9,8 +9,8 @@
 
 #define FONTDATAMAX (11*256)
 
-static const unsigned char fontdata_6x11[FONTDATAMAX] = {
-
+static struct font_data fontdata_6x11 = {
+       { 0, 0, FONTDATAMAX, 0 }, {
        /* 0 0x00 '^@' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -3338,8 +3338,7 @@ static const unsigned char fontdata_6x11[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-};
+} };
 
 
 const struct font_desc font_vga_6x11 = {
@@ -3347,7 +3346,7 @@ const struct font_desc font_vga_6x11 = {
        .name   = "ProFont6x11",
        .width  = 6,
        .height = 11,
-       .data   = fontdata_6x11,
+       .data   = fontdata_6x11.data,
        /* Try avoiding this font if possible unless on MAC */
        .pref   = -2000,
 };
index 89752d0..86d298f 100644 (file)
@@ -8,8 +8,8 @@
 
 #define FONTDATAMAX 3584
 
-static const unsigned char fontdata_7x14[FONTDATAMAX] = {
-
+static struct font_data fontdata_7x14 = {
+       { 0, 0, FONTDATAMAX, 0 }, {
        /* 0 0x00 '^@' */
        0x00, /* 0000000 */
        0x00, /* 0000000 */
@@ -4105,8 +4105,7 @@ static const unsigned char fontdata_7x14[FONTDATAMAX] = {
        0x00, /* 0000000 */
        0x00, /* 0000000 */
        0x00, /* 0000000 */
-
-};
+} };
 
 
 const struct font_desc font_7x14 = {
@@ -4114,6 +4113,6 @@ const struct font_desc font_7x14 = {
        .name   = "7x14",
        .width  = 7,
        .height = 14,
-       .data   = fontdata_7x14,
+       .data   = fontdata_7x14.data,
        .pref   = 0,
 };
index b7ab1f5..37cedd3 100644 (file)
@@ -10,8 +10,8 @@
 
 #define FONTDATAMAX 4096
 
-static const unsigned char fontdata_8x16[FONTDATAMAX] = {
-
+static struct font_data fontdata_8x16 = {
+       { 0, 0, FONTDATAMAX, 0 }, {
        /* 0 0x00 '^@' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -4619,8 +4619,7 @@ static const unsigned char fontdata_8x16[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-};
+} };
 
 
 const struct font_desc font_vga_8x16 = {
@@ -4628,7 +4627,7 @@ const struct font_desc font_vga_8x16 = {
        .name   = "VGA8x16",
        .width  = 8,
        .height = 16,
-       .data   = fontdata_8x16,
+       .data   = fontdata_8x16.data,
        .pref   = 0,
 };
 EXPORT_SYMBOL(font_vga_8x16);
index 2328ebc..8ab6955 100644 (file)
@@ -9,8 +9,8 @@
 
 #define FONTDATAMAX 2048
 
-static const unsigned char fontdata_8x8[FONTDATAMAX] = {
-
+static struct font_data fontdata_8x8 = {
+       { 0, 0, FONTDATAMAX, 0 }, {
        /* 0 0x00 '^@' */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
@@ -2570,8 +2570,7 @@ static const unsigned char fontdata_8x8[FONTDATAMAX] = {
        0x00, /* 00000000 */
        0x00, /* 00000000 */
        0x00, /* 00000000 */
-
-};
+} };
 
 
 const struct font_desc font_vga_8x8 = {
@@ -2579,6 +2578,6 @@ const struct font_desc font_vga_8x8 = {
        .name   = "VGA8x8",
        .width  = 8,
        .height = 8,
-       .data   = fontdata_8x8,
+       .data   = fontdata_8x8.data,
        .pref   = 0,
 };
index 0ff0e85..069b3e8 100644 (file)
@@ -3,7 +3,10 @@
 
 #include <linux/font.h>
 
-static const unsigned char acorndata_8x8[] = {
+#define FONTDATAMAX 2048
+
+static struct font_data acorndata_8x8 = {
+{ 0, 0, FONTDATAMAX, 0 }, {
 /* 00 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */
 /* 01 */  0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */
 /* 02 */  0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */
@@ -260,14 +263,14 @@ static const unsigned char acorndata_8x8[] = {
 /* FD */  0x38, 0x04, 0x18, 0x20, 0x3c, 0x00, 0x00, 0x00,
 /* FE */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
 /* FF */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
+} };
 
 const struct font_desc font_acorn_8x8 = {
        .idx    = ACORN8x8_IDX,
        .name   = "Acorn8x8",
        .width  = 8,
        .height = 8,
-       .data   = acorndata_8x8,
+       .data   = acorndata_8x8.data,
 #ifdef CONFIG_ARCH_ACORN
        .pref   = 20,
 #else
index 838caa1..1449876 100644 (file)
@@ -43,8 +43,8 @@ __END__;
 
 #define FONTDATAMAX 1536
 
-static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
-
+static struct font_data fontdata_mini_4x6 = {
+       { 0, 0, FONTDATAMAX, 0 }, {
        /*{*/
                /*   Char 0: ' '  */
        0xee,   /*=  [*** ]       */
@@ -2145,14 +2145,14 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
        0xee,   /*=   [*** ]        */
        0x00,   /*=   [    ]        */
        /*}*/
-};
+} };
 
 const struct font_desc font_mini_4x6 = {
        .idx    = MINI4x6_IDX,
        .name   = "MINI4x6",
        .width  = 4,
        .height = 6,
-       .data   = fontdata_mini_4x6,
+       .data   = fontdata_mini_4x6.data,
        .pref   = 3,
 };
 
index b15d3c3..32d6555 100644 (file)
@@ -14,8 +14,8 @@
 
 #define FONTDATAMAX 2048
 
-static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
-
+static struct font_data fontdata_pearl8x8 = {
+   { 0, 0, FONTDATAMAX, 0 }, {
    /* 0 0x00 '^@' */
    0x00, /* 00000000 */
    0x00, /* 00000000 */
@@ -2575,14 +2575,13 @@ static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
    0x00, /* 00000000 */
    0x00, /* 00000000 */
    0x00, /* 00000000 */
-
-};
+} };
 
 const struct font_desc font_pearl_8x8 = {
        .idx    = PEARL8x8_IDX,
        .name   = "PEARL8x8",
        .width  = 8,
        .height = 8,
-       .data   = fontdata_pearl8x8,
+       .data   = fontdata_pearl8x8.data,
        .pref   = 2,
 };
index 955d6ee..641a6b4 100644 (file)
@@ -3,8 +3,8 @@
 
 #define FONTDATAMAX 11264
 
-static const unsigned char fontdata_sun12x22[FONTDATAMAX] = {
-
+static struct font_data fontdata_sun12x22 = {
+       { 0, 0, FONTDATAMAX, 0 }, {
        /* 0 0x00 '^@' */
        0x00, 0x00, /* 000000000000 */
        0x00, 0x00, /* 000000000000 */
@@ -6148,8 +6148,7 @@ static const unsigned char fontdata_sun12x22[FONTDATAMAX] = {
        0x00, 0x00, /* 000000000000 */
        0x00, 0x00, /* 000000000000 */
        0x00, 0x00, /* 000000000000 */
-
-};
+} };
 
 
 const struct font_desc font_sun_12x22 = {
@@ -6157,7 +6156,7 @@ const struct font_desc font_sun_12x22 = {
        .name   = "SUN12x22",
        .width  = 12,
        .height = 22,
-       .data   = fontdata_sun12x22,
+       .data   = fontdata_sun12x22.data,
 #ifdef __sparc__
        .pref   = 5,
 #else
index 03d71e5..193fe6d 100644 (file)
@@ -3,7 +3,8 @@
 
 #define FONTDATAMAX 4096
 
-static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
+static struct font_data fontdata_sun8x16 = {
+{ 0, 0, FONTDATAMAX, 0 }, {
 /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 /* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00,
 /* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00,
@@ -260,14 +261,14 @@ static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
 /* */ 0x00,0x70,0xd8,0x30,0x60,0xc8,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 /* */ 0x00,0x00,0x00,0x00,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,
 /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-};
+} };
 
 const struct font_desc font_sun_8x16 = {
        .idx    = SUN8x16_IDX,
        .name   = "SUN8x16",
        .width  = 8,
        .height = 16,
-       .data   = fontdata_sun8x16,
+       .data   = fontdata_sun8x16.data,
 #ifdef __sparc__
        .pref   = 10,
 #else
index 3f0cf1c..91b9c28 100644 (file)
@@ -4,8 +4,8 @@
 
 #define FONTDATAMAX 16384
 
-static const unsigned char fontdata_ter16x32[FONTDATAMAX] = {
-
+static struct font_data fontdata_ter16x32 = {
+       { 0, 0, FONTDATAMAX, 0 }, {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
        0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
@@ -2054,8 +2054,7 @@ static const unsigned char fontdata_ter16x32[FONTDATAMAX] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 255 */
-
-};
+} };
 
 
 const struct font_desc font_ter_16x32 = {
@@ -2063,7 +2062,7 @@ const struct font_desc font_ter_16x32 = {
        .name   = "TER16x32",
        .width  = 16,
        .height = 32,
-       .data   = fontdata_ter16x32,
+       .data   = fontdata_ter16x32.data,
 #ifdef __sparc__
        .pref   = 5,
 #else
index 0ba3ea8..52e3ed7 100644 (file)
@@ -102,7 +102,7 @@ bool __pure glob_match(char const *pat, char const *str)
                        break;
                case '\\':
                        d = *pat++;
-                       /*FALLTHROUGH*/
+                       /* fall through */
                default:        /* Literal character */
 literal:
                        if (c == d) {
index 5e40786..14cae25 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/splice.h>
+#include <linux/compat.h>
 #include <net/checksum.h>
 #include <linux/scatterlist.h>
 #include <linux/instrumented.h>
@@ -581,7 +582,7 @@ static size_t copy_pipe_to_iter(const void *addr, size_t bytes,
 static __wsum csum_and_memcpy(void *to, const void *from, size_t len,
                              __wsum sum, size_t off)
 {
-       __wsum next = csum_partial_copy_nocheck(from, to, len, 0);
+       __wsum next = csum_partial_copy_nocheck(from, to, len);
        return csum_block_add(sum, next, off);
 }
 
@@ -637,30 +638,30 @@ size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
 }
 EXPORT_SYMBOL(_copy_to_iter);
 
-#ifdef CONFIG_ARCH_HAS_UACCESS_MCSAFE
-static int copyout_mcsafe(void __user *to, const void *from, size_t n)
+#ifdef CONFIG_ARCH_HAS_COPY_MC
+static int copyout_mc(void __user *to, const void *from, size_t n)
 {
        if (access_ok(to, n)) {
                instrument_copy_to_user(to, from, n);
-               n = copy_to_user_mcsafe((__force void *) to, from, n);
+               n = copy_mc_to_user((__force void *) to, from, n);
        }
        return n;
 }
 
-static unsigned long memcpy_mcsafe_to_page(struct page *page, size_t offset,
+static unsigned long copy_mc_to_page(struct page *page, size_t offset,
                const char *from, size_t len)
 {
        unsigned long ret;
        char *to;
 
        to = kmap_atomic(page);
-       ret = memcpy_mcsafe(to + offset, from, len);
+       ret = copy_mc_to_kernel(to + offset, from, len);
        kunmap_atomic(to);
 
        return ret;
 }
 
-static size_t copy_pipe_to_iter_mcsafe(const void *addr, size_t bytes,
+static size_t copy_mc_pipe_to_iter(const void *addr, size_t bytes,
                                struct iov_iter *i)
 {
        struct pipe_inode_info *pipe = i->pipe;
@@ -678,7 +679,7 @@ static size_t copy_pipe_to_iter_mcsafe(const void *addr, size_t bytes,
                size_t chunk = min_t(size_t, n, PAGE_SIZE - off);
                unsigned long rem;
 
-               rem = memcpy_mcsafe_to_page(pipe->bufs[i_head & p_mask].page,
+               rem = copy_mc_to_page(pipe->bufs[i_head & p_mask].page,
                                            off, addr, chunk);
                i->head = i_head;
                i->iov_offset = off + chunk - rem;
@@ -695,18 +696,17 @@ static size_t copy_pipe_to_iter_mcsafe(const void *addr, size_t bytes,
 }
 
 /**
- * _copy_to_iter_mcsafe - copy to user with source-read error exception handling
+ * _copy_mc_to_iter - copy to iter with source memory error exception handling
  * @addr: source kernel address
  * @bytes: total transfer length
  * @iter: destination iterator
  *
- * The pmem driver arranges for filesystem-dax to use this facility via
- * dax_copy_to_iter() for protecting read/write to persistent memory.
- * Unless / until an architecture can guarantee identical performance
- * between _copy_to_iter_mcsafe() and _copy_to_iter() it would be a
- * performance regression to switch more users to the mcsafe version.
+ * The pmem driver deploys this for the dax operation
+ * (dax_copy_to_iter()) for dax reads (bypass page-cache and the
+ * block-layer). Upon #MC read(2) aborts and returns EIO or the bytes
+ * successfully copied.
  *
- * Otherwise, the main differences between this and typical _copy_to_iter().
+ * The main differences between this and typical _copy_to_iter().
  *
  * * Typical tail/residue handling after a fault retries the copy
  *   byte-by-byte until the fault happens again. Re-triggering machine
@@ -717,23 +717,22 @@ static size_t copy_pipe_to_iter_mcsafe(const void *addr, size_t bytes,
  * * ITER_KVEC, ITER_PIPE, and ITER_BVEC can return short copies.
  *   Compare to copy_to_iter() where only ITER_IOVEC attempts might return
  *   a short copy.
- *
- * See MCSAFE_TEST for self-test.
  */
-size_t _copy_to_iter_mcsafe(const void *addr, size_t bytes, struct iov_iter *i)
+size_t _copy_mc_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
 {
        const char *from = addr;
        unsigned long rem, curr_addr, s_addr = (unsigned long) addr;
 
        if (unlikely(iov_iter_is_pipe(i)))
-               return copy_pipe_to_iter_mcsafe(addr, bytes, i);
+               return copy_mc_pipe_to_iter(addr, bytes, i);
        if (iter_is_iovec(i))
                might_fault();
        iterate_and_advance(i, bytes, v,
-               copyout_mcsafe(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len),
+               copyout_mc(v.iov_base, (from += v.iov_len) - v.iov_len,
+                          v.iov_len),
                ({
-               rem = memcpy_mcsafe_to_page(v.bv_page, v.bv_offset,
-                               (from += v.bv_len) - v.bv_len, v.bv_len);
+               rem = copy_mc_to_page(v.bv_page, v.bv_offset,
+                                     (from += v.bv_len) - v.bv_len, v.bv_len);
                if (rem) {
                        curr_addr = (unsigned long) from;
                        bytes = curr_addr - s_addr - rem;
@@ -741,8 +740,8 @@ size_t _copy_to_iter_mcsafe(const void *addr, size_t bytes, struct iov_iter *i)
                }
                }),
                ({
-               rem = memcpy_mcsafe(v.iov_base, (from += v.iov_len) - v.iov_len,
-                               v.iov_len);
+               rem = copy_mc_to_kernel(v.iov_base, (from += v.iov_len)
+                                       - v.iov_len, v.iov_len);
                if (rem) {
                        curr_addr = (unsigned long) from;
                        bytes = curr_addr - s_addr - rem;
@@ -753,8 +752,8 @@ size_t _copy_to_iter_mcsafe(const void *addr, size_t bytes, struct iov_iter *i)
 
        return bytes;
 }
-EXPORT_SYMBOL_GPL(_copy_to_iter_mcsafe);
-#endif /* CONFIG_ARCH_HAS_UACCESS_MCSAFE */
+EXPORT_SYMBOL_GPL(_copy_mc_to_iter);
+#endif /* CONFIG_ARCH_HAS_COPY_MC */
 
 size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
 {
@@ -1449,15 +1448,14 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
                return 0;
        }
        iterate_and_advance(i, bytes, v, ({
-               int err = 0;
                next = csum_and_copy_from_user(v.iov_base,
                                               (to += v.iov_len) - v.iov_len,
-                                              v.iov_len, 0, &err);
-               if (!err) {
+                                              v.iov_len);
+               if (next) {
                        sum = csum_block_add(sum, next, off);
                        off += v.iov_len;
                }
-               err ? v.iov_len : 0;
+               next ? 0 : v.iov_len;
        }), ({
                char *p = kmap_atomic(v.bv_page);
                sum = csum_and_memcpy((to += v.bv_len) - v.bv_len,
@@ -1491,11 +1489,10 @@ bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum,
        if (unlikely(i->count < bytes))
                return false;
        iterate_all_kinds(i, bytes, v, ({
-               int err = 0;
                next = csum_and_copy_from_user(v.iov_base,
                                               (to += v.iov_len) - v.iov_len,
-                                              v.iov_len, 0, &err);
-               if (err)
+                                              v.iov_len);
+               if (!next)
                        return false;
                sum = csum_block_add(sum, next, off);
                off += v.iov_len;
@@ -1537,15 +1534,14 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, void *csump,
                return 0;
        }
        iterate_and_advance(i, bytes, v, ({
-               int err = 0;
                next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
                                             v.iov_base,
-                                            v.iov_len, 0, &err);
-               if (!err) {
+                                            v.iov_len);
+               if (next) {
                        sum = csum_block_add(sum, next, off);
                        off += v.iov_len;
                }
-               err ? v.iov_len : 0;
+               next ? 0 : v.iov_len;
        }), ({
                char *p = kmap_atomic(v.bv_page);
                sum = csum_and_memcpy(p + v.bv_offset,
@@ -1650,16 +1646,145 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
 }
 EXPORT_SYMBOL(dup_iter);
 
+static int copy_compat_iovec_from_user(struct iovec *iov,
+               const struct iovec __user *uvec, unsigned long nr_segs)
+{
+       const struct compat_iovec __user *uiov =
+               (const struct compat_iovec __user *)uvec;
+       int ret = -EFAULT, i;
+
+       if (!user_access_begin(uvec, nr_segs * sizeof(*uvec)))
+               return -EFAULT;
+
+       for (i = 0; i < nr_segs; i++) {
+               compat_uptr_t buf;
+               compat_ssize_t len;
+
+               unsafe_get_user(len, &uiov[i].iov_len, uaccess_end);
+               unsafe_get_user(buf, &uiov[i].iov_base, uaccess_end);
+
+               /* check for compat_size_t not fitting in compat_ssize_t .. */
+               if (len < 0) {
+                       ret = -EINVAL;
+                       goto uaccess_end;
+               }
+               iov[i].iov_base = compat_ptr(buf);
+               iov[i].iov_len = len;
+       }
+
+       ret = 0;
+uaccess_end:
+       user_access_end();
+       return ret;
+}
+
+static int copy_iovec_from_user(struct iovec *iov,
+               const struct iovec __user *uvec, unsigned long nr_segs)
+{
+       unsigned long seg;
+
+       if (copy_from_user(iov, uvec, nr_segs * sizeof(*uvec)))
+               return -EFAULT;
+       for (seg = 0; seg < nr_segs; seg++) {
+               if ((ssize_t)iov[seg].iov_len < 0)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+struct iovec *iovec_from_user(const struct iovec __user *uvec,
+               unsigned long nr_segs, unsigned long fast_segs,
+               struct iovec *fast_iov, bool compat)
+{
+       struct iovec *iov = fast_iov;
+       int ret;
+
+       /*
+        * SuS says "The readv() function *may* fail if the iovcnt argument was
+        * less than or equal to 0, or greater than {IOV_MAX}.  Linux has
+        * traditionally returned zero for zero segments, so...
+        */
+       if (nr_segs == 0)
+               return iov;
+       if (nr_segs > UIO_MAXIOV)
+               return ERR_PTR(-EINVAL);
+       if (nr_segs > fast_segs) {
+               iov = kmalloc_array(nr_segs, sizeof(struct iovec), GFP_KERNEL);
+               if (!iov)
+                       return ERR_PTR(-ENOMEM);
+       }
+
+       if (compat)
+               ret = copy_compat_iovec_from_user(iov, uvec, nr_segs);
+       else
+               ret = copy_iovec_from_user(iov, uvec, nr_segs);
+       if (ret) {
+               if (iov != fast_iov)
+                       kfree(iov);
+               return ERR_PTR(ret);
+       }
+
+       return iov;
+}
+
+ssize_t __import_iovec(int type, const struct iovec __user *uvec,
+                unsigned nr_segs, unsigned fast_segs, struct iovec **iovp,
+                struct iov_iter *i, bool compat)
+{
+       ssize_t total_len = 0;
+       unsigned long seg;
+       struct iovec *iov;
+
+       iov = iovec_from_user(uvec, nr_segs, fast_segs, *iovp, compat);
+       if (IS_ERR(iov)) {
+               *iovp = NULL;
+               return PTR_ERR(iov);
+       }
+
+       /*
+        * According to the Single Unix Specification we should return EINVAL if
+        * an element length is < 0 when cast to ssize_t or if the total length
+        * would overflow the ssize_t return value of the system call.
+        *
+        * Linux caps all read/write calls to MAX_RW_COUNT, and avoids the
+        * overflow case.
+        */
+       for (seg = 0; seg < nr_segs; seg++) {
+               ssize_t len = (ssize_t)iov[seg].iov_len;
+
+               if (!access_ok(iov[seg].iov_base, len)) {
+                       if (iov != *iovp)
+                               kfree(iov);
+                       *iovp = NULL;
+                       return -EFAULT;
+               }
+
+               if (len > MAX_RW_COUNT - total_len) {
+                       len = MAX_RW_COUNT - total_len;
+                       iov[seg].iov_len = len;
+               }
+               total_len += len;
+       }
+
+       iov_iter_init(i, type, iov, nr_segs, total_len);
+       if (iov == *iovp)
+               *iovp = NULL;
+       else
+               *iovp = iov;
+       return total_len;
+}
+
 /**
  * import_iovec() - Copy an array of &struct iovec from userspace
  *     into the kernel, check that it is valid, and initialize a new
  *     &struct iov_iter iterator to access it.
  *
  * @type: One of %READ or %WRITE.
- * @uvector: Pointer to the userspace array.
+ * @uvec: Pointer to the userspace array.
  * @nr_segs: Number of elements in userspace array.
  * @fast_segs: Number of elements in @iov.
- * @iov: (input and output parameter) Pointer to pointer to (usually small
+ * @iovp: (input and output parameter) Pointer to pointer to (usually small
  *     on-stack) kernel array.
  * @i: Pointer to iterator that will be initialized on success.
  *
@@ -1672,51 +1797,15 @@ EXPORT_SYMBOL(dup_iter);
  *
  * Return: Negative error code on error, bytes imported on success
  */
-ssize_t import_iovec(int type, const struct iovec __user * uvector,
+ssize_t import_iovec(int type, const struct iovec __user *uvec,
                 unsigned nr_segs, unsigned fast_segs,
-                struct iovec **iov, struct iov_iter *i)
+                struct iovec **iovp, struct iov_iter *i)
 {
-       ssize_t n;
-       struct iovec *p;
-       n = rw_copy_check_uvector(type, uvector, nr_segs, fast_segs,
-                                 *iov, &p);
-       if (n < 0) {
-               if (p != *iov)
-                       kfree(p);
-               *iov = NULL;
-               return n;
-       }
-       iov_iter_init(i, type, p, nr_segs, n);
-       *iov = p == *iov ? NULL : p;
-       return n;
+       return __import_iovec(type, uvec, nr_segs, fast_segs, iovp, i,
+                             in_compat_syscall());
 }
 EXPORT_SYMBOL(import_iovec);
 
-#ifdef CONFIG_COMPAT
-#include <linux/compat.h>
-
-ssize_t compat_import_iovec(int type,
-               const struct compat_iovec __user * uvector,
-               unsigned nr_segs, unsigned fast_segs,
-               struct iovec **iov, struct iov_iter *i)
-{
-       ssize_t n;
-       struct iovec *p;
-       n = compat_rw_copy_check_uvector(type, uvector, nr_segs, fast_segs,
-                                 *iov, &p);
-       if (n < 0) {
-               if (p != *iov)
-                       kfree(p);
-               *iov = NULL;
-               return n;
-       }
-       iov_iter_init(i, type, p, nr_segs, n);
-       *iov = p == *iov ? NULL : p;
-       return n;
-}
-EXPORT_SYMBOL(compat_import_iovec);
-#endif
-
 int import_single_range(int rw, void __user *buf, size_t len,
                 struct iovec *iov, struct iov_iter *i)
 {
index 3afb939..ea53b30 100644 (file)
@@ -604,9 +604,6 @@ static void __kobject_del(struct kobject *kobj)
        struct kernfs_node *sd;
        const struct kobj_type *ktype;
 
-       if (!kobj)
-               return;
-
        sd = kobj->sd;
        ktype = get_ktype(kobj);
 
@@ -637,8 +634,12 @@ static void __kobject_del(struct kobject *kobj)
  */
 void kobject_del(struct kobject *kobj)
 {
-       struct kobject *parent = kobj->parent;
+       struct kobject *parent;
+
+       if (!kobj)
+               return;
 
+       parent = kobj->parent;
        __kobject_del(kobj);
        kobject_put(parent);
 }
index 14f44f5..a899b3f 100644 (file)
@@ -28,6 +28,7 @@
  * Change this to 1 if you want to see the failure printouts:
  */
 static unsigned int debug_locks_verbose;
+unsigned int force_read_lock_recursive;
 
 static DEFINE_WD_CLASS(ww_lockdep);
 
@@ -399,6 +400,49 @@ static void rwsem_ABBA1(void)
  * read_lock(A)
  * spin_lock(B)
  *             spin_lock(B)
+ *             write_lock(A)
+ *
+ * This test case is aimed at poking whether the chain cache prevents us from
+ * detecting a read-lock/lock-write deadlock: if the chain cache doesn't differ
+ * read/write locks, the following case may happen
+ *
+ *     { read_lock(A)->lock(B) dependency exists }
+ *
+ *     P0:
+ *     lock(B);
+ *     read_lock(A);
+ *
+ *     { Not a deadlock, B -> A is added in the chain cache }
+ *
+ *     P1:
+ *     lock(B);
+ *     write_lock(A);
+ *
+ *     { B->A found in chain cache, not reported as a deadlock }
+ *
+ */
+static void rlock_chaincache_ABBA1(void)
+{
+       RL(X1);
+       L(Y1);
+       U(Y1);
+       RU(X1);
+
+       L(Y1);
+       RL(X1);
+       RU(X1);
+       U(Y1);
+
+       L(Y1);
+       WL(X1);
+       WU(X1);
+       U(Y1); // should fail
+}
+
+/*
+ * read_lock(A)
+ * spin_lock(B)
+ *             spin_lock(B)
  *             read_lock(A)
  */
 static void rlock_ABBA2(void)
@@ -991,6 +1035,133 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_wlock)
 #undef E3
 
 /*
+ * write-read / write-read / write-read deadlock even if read is recursive
+ */
+
+#define E1()                           \
+                                       \
+       WL(X1);                         \
+       RL(Y1);                         \
+       RU(Y1);                         \
+       WU(X1);
+
+#define E2()                           \
+                                       \
+       WL(Y1);                         \
+       RL(Z1);                         \
+       RU(Z1);                         \
+       WU(Y1);
+
+#define E3()                           \
+                                       \
+       WL(Z1);                         \
+       RL(X1);                         \
+       RU(X1);                         \
+       WU(Z1);
+
+#include "locking-selftest-rlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(W1R2_W2R3_W3R1)
+
+#undef E1
+#undef E2
+#undef E3
+
+/*
+ * write-write / read-read / write-read deadlock even if read is recursive
+ */
+
+#define E1()                           \
+                                       \
+       WL(X1);                         \
+       WL(Y1);                         \
+       WU(Y1);                         \
+       WU(X1);
+
+#define E2()                           \
+                                       \
+       RL(Y1);                         \
+       RL(Z1);                         \
+       RU(Z1);                         \
+       RU(Y1);
+
+#define E3()                           \
+                                       \
+       WL(Z1);                         \
+       RL(X1);                         \
+       RU(X1);                         \
+       WU(Z1);
+
+#include "locking-selftest-rlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(W1W2_R2R3_W3R1)
+
+#undef E1
+#undef E2
+#undef E3
+
+/*
+ * write-write / read-read / read-write is not deadlock when read is recursive
+ */
+
+#define E1()                           \
+                                       \
+       WL(X1);                         \
+       WL(Y1);                         \
+       WU(Y1);                         \
+       WU(X1);
+
+#define E2()                           \
+                                       \
+       RL(Y1);                         \
+       RL(Z1);                         \
+       RU(Z1);                         \
+       RU(Y1);
+
+#define E3()                           \
+                                       \
+       RL(Z1);                         \
+       WL(X1);                         \
+       WU(X1);                         \
+       RU(Z1);
+
+#include "locking-selftest-rlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(W1R2_R2R3_W3W1)
+
+#undef E1
+#undef E2
+#undef E3
+
+/*
+ * write-read / read-read / write-write is not deadlock when read is recursive
+ */
+
+#define E1()                           \
+                                       \
+       WL(X1);                         \
+       RL(Y1);                         \
+       RU(Y1);                         \
+       WU(X1);
+
+#define E2()                           \
+                                       \
+       RL(Y1);                         \
+       RL(Z1);                         \
+       RU(Z1);                         \
+       RU(Y1);
+
+#define E3()                           \
+                                       \
+       WL(Z1);                         \
+       WL(X1);                         \
+       WU(X1);                         \
+       WU(Z1);
+
+#include "locking-selftest-rlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(W1W2_R2R3_R3W1)
+
+#undef E1
+#undef E2
+#undef E3
+/*
  * read-lock / write-lock recursion that is actually safe.
  */
 
@@ -1009,20 +1180,28 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_wlock)
 #define E3()                           \
                                        \
        IRQ_ENTER();                    \
-       RL(A);                          \
+       LOCK(A);                        \
        L(B);                           \
        U(B);                           \
-       RU(A);                          \
+       UNLOCK(A);                      \
        IRQ_EXIT();
 
 /*
- * Generate 12 testcases:
+ * Generate 24 testcases:
  */
 #include "locking-selftest-hardirq.h"
-GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_hard)
+#include "locking-selftest-rlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_hard_rlock)
+
+#include "locking-selftest-wlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_hard_wlock)
 
 #include "locking-selftest-softirq.h"
-GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft)
+#include "locking-selftest-rlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft_rlock)
+
+#include "locking-selftest-wlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft_wlock)
 
 #undef E1
 #undef E2
@@ -1036,8 +1215,8 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft)
                                        \
        IRQ_DISABLE();                  \
        L(B);                           \
-       WL(A);                          \
-       WU(A);                          \
+       LOCK(A);                        \
+       UNLOCK(A);                      \
        U(B);                           \
        IRQ_ENABLE();
 
@@ -1054,13 +1233,75 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft)
        IRQ_EXIT();
 
 /*
- * Generate 12 testcases:
+ * Generate 24 testcases:
  */
 #include "locking-selftest-hardirq.h"
-// GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_hard)
+#include "locking-selftest-rlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_hard_rlock)
+
+#include "locking-selftest-wlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_hard_wlock)
 
 #include "locking-selftest-softirq.h"
-// GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_soft)
+#include "locking-selftest-rlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_soft_rlock)
+
+#include "locking-selftest-wlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_soft_wlock)
+
+#undef E1
+#undef E2
+#undef E3
+/*
+ * read-lock / write-lock recursion that is unsafe.
+ *
+ * A is a ENABLED_*_READ lock
+ * B is a USED_IN_*_READ lock
+ *
+ * read_lock(A);
+ *                     write_lock(B);
+ * <interrupt>
+ * read_lock(B);
+ *                     write_lock(A); // if this one is read_lock(), no deadlock
+ */
+
+#define E1()                           \
+                                       \
+       IRQ_DISABLE();                  \
+       WL(B);                          \
+       LOCK(A);                        \
+       UNLOCK(A);                      \
+       WU(B);                          \
+       IRQ_ENABLE();
+
+#define E2()                           \
+                                       \
+       RL(A);                          \
+       RU(A);                          \
+
+#define E3()                           \
+                                       \
+       IRQ_ENTER();                    \
+       RL(B);                          \
+       RU(B);                          \
+       IRQ_EXIT();
+
+/*
+ * Generate 24 testcases:
+ */
+#include "locking-selftest-hardirq.h"
+#include "locking-selftest-rlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_hard_rlock)
+
+#include "locking-selftest-wlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_hard_wlock)
+
+#include "locking-selftest-softirq.h"
+#include "locking-selftest-rlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_soft_rlock)
+
+#include "locking-selftest-wlock.h"
+GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_soft_wlock)
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # define I_SPINLOCK(x) lockdep_reset_lock(&lock_##x.dep_map)
@@ -1199,6 +1440,19 @@ static inline void print_testname(const char *testname)
        dotest(name##_##nr, FAILURE, LOCKTYPE_RWLOCK);          \
        pr_cont("\n");
 
+#define DO_TESTCASE_1RR(desc, name, nr)                                \
+       print_testname(desc"/"#nr);                             \
+       pr_cont("             |");                              \
+       dotest(name##_##nr, SUCCESS, LOCKTYPE_RWLOCK);          \
+       pr_cont("\n");
+
+#define DO_TESTCASE_1RRB(desc, name, nr)                       \
+       print_testname(desc"/"#nr);                             \
+       pr_cont("             |");                              \
+       dotest(name##_##nr, FAILURE, LOCKTYPE_RWLOCK);          \
+       pr_cont("\n");
+
+
 #define DO_TESTCASE_3(desc, name, nr)                          \
        print_testname(desc"/"#nr);                             \
        dotest(name##_spin_##nr, FAILURE, LOCKTYPE_SPIN);       \
@@ -1213,6 +1467,25 @@ static inline void print_testname(const char *testname)
        dotest(name##_rlock_##nr, SUCCESS, LOCKTYPE_RWLOCK);    \
        pr_cont("\n");
 
+#define DO_TESTCASE_2RW(desc, name, nr)                                \
+       print_testname(desc"/"#nr);                             \
+       pr_cont("      |");                                     \
+       dotest(name##_wlock_##nr, FAILURE, LOCKTYPE_RWLOCK);    \
+       dotest(name##_rlock_##nr, SUCCESS, LOCKTYPE_RWLOCK);    \
+       pr_cont("\n");
+
+#define DO_TESTCASE_2x2RW(desc, name, nr)                      \
+       DO_TESTCASE_2RW("hard-"desc, name##_hard, nr)           \
+       DO_TESTCASE_2RW("soft-"desc, name##_soft, nr)           \
+
+#define DO_TESTCASE_6x2x2RW(desc, name)                                \
+       DO_TESTCASE_2x2RW(desc, name, 123);                     \
+       DO_TESTCASE_2x2RW(desc, name, 132);                     \
+       DO_TESTCASE_2x2RW(desc, name, 213);                     \
+       DO_TESTCASE_2x2RW(desc, name, 231);                     \
+       DO_TESTCASE_2x2RW(desc, name, 312);                     \
+       DO_TESTCASE_2x2RW(desc, name, 321);
+
 #define DO_TESTCASE_6(desc, name)                              \
        print_testname(desc);                                   \
        dotest(name##_spin, FAILURE, LOCKTYPE_SPIN);            \
@@ -1289,6 +1562,22 @@ static inline void print_testname(const char *testname)
        DO_TESTCASE_2IB(desc, name, 312);                       \
        DO_TESTCASE_2IB(desc, name, 321);
 
+#define DO_TESTCASE_6x1RR(desc, name)                          \
+       DO_TESTCASE_1RR(desc, name, 123);                       \
+       DO_TESTCASE_1RR(desc, name, 132);                       \
+       DO_TESTCASE_1RR(desc, name, 213);                       \
+       DO_TESTCASE_1RR(desc, name, 231);                       \
+       DO_TESTCASE_1RR(desc, name, 312);                       \
+       DO_TESTCASE_1RR(desc, name, 321);
+
+#define DO_TESTCASE_6x1RRB(desc, name)                         \
+       DO_TESTCASE_1RRB(desc, name, 123);                      \
+       DO_TESTCASE_1RRB(desc, name, 132);                      \
+       DO_TESTCASE_1RRB(desc, name, 213);                      \
+       DO_TESTCASE_1RRB(desc, name, 231);                      \
+       DO_TESTCASE_1RRB(desc, name, 312);                      \
+       DO_TESTCASE_1RRB(desc, name, 321);
+
 #define DO_TESTCASE_6x6(desc, name)                            \
        DO_TESTCASE_6I(desc, name, 123);                        \
        DO_TESTCASE_6I(desc, name, 132);                        \
@@ -1966,6 +2255,108 @@ static void ww_tests(void)
        pr_cont("\n");
 }
 
+
+/*
+ * <in hardirq handler>
+ * read_lock(&A);
+ *                     <hardirq disable>
+ *                     spin_lock(&B);
+ * spin_lock(&B);
+ *                     read_lock(&A);
+ *
+ * is a deadlock.
+ */
+static void queued_read_lock_hardirq_RE_Er(void)
+{
+       HARDIRQ_ENTER();
+       read_lock(&rwlock_A);
+       LOCK(B);
+       UNLOCK(B);
+       read_unlock(&rwlock_A);
+       HARDIRQ_EXIT();
+
+       HARDIRQ_DISABLE();
+       LOCK(B);
+       read_lock(&rwlock_A);
+       read_unlock(&rwlock_A);
+       UNLOCK(B);
+       HARDIRQ_ENABLE();
+}
+
+/*
+ * <in hardirq handler>
+ * spin_lock(&B);
+ *                     <hardirq disable>
+ *                     read_lock(&A);
+ * read_lock(&A);
+ *                     spin_lock(&B);
+ *
+ * is not a deadlock.
+ */
+static void queued_read_lock_hardirq_ER_rE(void)
+{
+       HARDIRQ_ENTER();
+       LOCK(B);
+       read_lock(&rwlock_A);
+       read_unlock(&rwlock_A);
+       UNLOCK(B);
+       HARDIRQ_EXIT();
+
+       HARDIRQ_DISABLE();
+       read_lock(&rwlock_A);
+       LOCK(B);
+       UNLOCK(B);
+       read_unlock(&rwlock_A);
+       HARDIRQ_ENABLE();
+}
+
+/*
+ * <hardirq disable>
+ * spin_lock(&B);
+ *                     read_lock(&A);
+ *                     <in hardirq handler>
+ *                     spin_lock(&B);
+ * read_lock(&A);
+ *
+ * is a deadlock. Because the two read_lock()s are both non-recursive readers.
+ */
+static void queued_read_lock_hardirq_inversion(void)
+{
+
+       HARDIRQ_ENTER();
+       LOCK(B);
+       UNLOCK(B);
+       HARDIRQ_EXIT();
+
+       HARDIRQ_DISABLE();
+       LOCK(B);
+       read_lock(&rwlock_A);
+       read_unlock(&rwlock_A);
+       UNLOCK(B);
+       HARDIRQ_ENABLE();
+
+       read_lock(&rwlock_A);
+       read_unlock(&rwlock_A);
+}
+
+static void queued_read_lock_tests(void)
+{
+       printk("  --------------------------------------------------------------------------\n");
+       printk("  | queued read lock tests |\n");
+       printk("  ---------------------------\n");
+       print_testname("hardirq read-lock/lock-read");
+       dotest(queued_read_lock_hardirq_RE_Er, FAILURE, LOCKTYPE_RWLOCK);
+       pr_cont("\n");
+
+       print_testname("hardirq lock-read/read-lock");
+       dotest(queued_read_lock_hardirq_ER_rE, SUCCESS, LOCKTYPE_RWLOCK);
+       pr_cont("\n");
+
+       print_testname("hardirq inversion");
+       dotest(queued_read_lock_hardirq_inversion, FAILURE, LOCKTYPE_RWLOCK);
+       pr_cont("\n");
+}
+
 void locking_selftest(void)
 {
        /*
@@ -1979,6 +2370,11 @@ void locking_selftest(void)
        }
 
        /*
+        * treats read_lock() as recursive read locks for testing purpose
+        */
+       force_read_lock_recursive = 1;
+
+       /*
         * Run the testsuite:
         */
        printk("------------------------\n");
@@ -2033,14 +2429,6 @@ void locking_selftest(void)
        print_testname("mixed read-lock/lock-write ABBA");
        pr_cont("             |");
        dotest(rlock_ABBA1, FAILURE, LOCKTYPE_RWLOCK);
-#ifdef CONFIG_PROVE_LOCKING
-       /*
-        * Lockdep does indeed fail here, but there's nothing we can do about
-        * that now.  Don't kill lockdep for it.
-        */
-       unexpected_testcase_failures--;
-#endif
-
        pr_cont("             |");
        dotest(rwsem_ABBA1, FAILURE, LOCKTYPE_RWSEM);
 
@@ -2056,6 +2444,15 @@ void locking_selftest(void)
        pr_cont("             |");
        dotest(rwsem_ABBA3, FAILURE, LOCKTYPE_RWSEM);
 
+       print_testname("chain cached mixed R-L/L-W ABBA");
+       pr_cont("             |");
+       dotest(rlock_chaincache_ABBA1, FAILURE, LOCKTYPE_RWLOCK);
+
+       DO_TESTCASE_6x1RRB("rlock W1R2/W2R3/W3R1", W1R2_W2R3_W3R1);
+       DO_TESTCASE_6x1RRB("rlock W1W2/R2R3/W3R1", W1W2_R2R3_W3R1);
+       DO_TESTCASE_6x1RR("rlock W1W2/R2R3/R3W1", W1W2_R2R3_R3W1);
+       DO_TESTCASE_6x1RR("rlock W1R2/R2R3/W3W1", W1R2_R2R3_W3W1);
+
        printk("  --------------------------------------------------------------------------\n");
 
        /*
@@ -2068,11 +2465,19 @@ void locking_selftest(void)
        DO_TESTCASE_6x6("safe-A + unsafe-B #2", irqsafe4);
        DO_TESTCASE_6x6RW("irq lock-inversion", irq_inversion);
 
-       DO_TESTCASE_6x2("irq read-recursion", irq_read_recursion);
-//     DO_TESTCASE_6x2B("irq read-recursion #2", irq_read_recursion2);
+       DO_TESTCASE_6x2x2RW("irq read-recursion", irq_read_recursion);
+       DO_TESTCASE_6x2x2RW("irq read-recursion #2", irq_read_recursion2);
+       DO_TESTCASE_6x2x2RW("irq read-recursion #3", irq_read_recursion3);
 
        ww_tests();
 
+       force_read_lock_recursive = 0;
+       /*
+        * queued_read_lock() specific test cases can be put here
+        */
+       if (IS_ENABLED(CONFIG_QUEUED_RWLOCKS))
+               queued_read_lock_tests();
+
        if (unexpected_testcase_failures) {
                printk("-----------------------------------------------------------------\n");
                debug_locks = 0;
index 77c85b5..be5cfa5 100644 (file)
@@ -2,6 +2,7 @@
 /* identifiers for device / performance-differentiated memory regions */
 #include <linux/idr.h>
 #include <linux/types.h>
+#include <linux/memregion.h>
 
 static DEFINE_IDA(memregion_ids);
 
index 43b8fce..6e6ef9a 100644 (file)
@@ -13,10 +13,16 @@ mpi-y = \
        generic_mpih-rshift.o           \
        generic_mpih-sub1.o             \
        generic_mpih-add1.o             \
+       ec.o                            \
        mpicoder.o                      \
+       mpi-add.o                       \
        mpi-bit.o                       \
        mpi-cmp.o                       \
        mpi-sub-ui.o                    \
+       mpi-div.o                       \
+       mpi-inv.o                       \
+       mpi-mod.o                       \
+       mpi-mul.o                       \
        mpih-cmp.o                      \
        mpih-div.o                      \
        mpih-mul.o                      \
diff --git a/lib/mpi/ec.c b/lib/mpi/ec.c
new file mode 100644 (file)
index 0000000..c214701
--- /dev/null
@@ -0,0 +1,1509 @@
+/* ec.c -  Elliptic Curve functions
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mpi-internal.h"
+#include "longlong.h"
+
+#define point_init(a)  mpi_point_init((a))
+#define point_free(a)  mpi_point_free_parts((a))
+
+#define log_error(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
+#define log_fatal(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
+
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+
+
+/* Create a new point option.  NBITS gives the size in bits of one
+ * coordinate; it is only used to pre-allocate some resources and
+ * might also be passed as 0 to use a default value.
+ */
+MPI_POINT mpi_point_new(unsigned int nbits)
+{
+       MPI_POINT p;
+
+       (void)nbits;  /* Currently not used.  */
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (p)
+               mpi_point_init(p);
+       return p;
+}
+EXPORT_SYMBOL_GPL(mpi_point_new);
+
+/* Release the point object P.  P may be NULL. */
+void mpi_point_release(MPI_POINT p)
+{
+       if (p) {
+               mpi_point_free_parts(p);
+               kfree(p);
+       }
+}
+EXPORT_SYMBOL_GPL(mpi_point_release);
+
+/* Initialize the fields of a point object.  gcry_mpi_point_free_parts
+ * may be used to release the fields.
+ */
+void mpi_point_init(MPI_POINT p)
+{
+       p->x = mpi_new(0);
+       p->y = mpi_new(0);
+       p->z = mpi_new(0);
+}
+EXPORT_SYMBOL_GPL(mpi_point_init);
+
+/* Release the parts of a point object. */
+void mpi_point_free_parts(MPI_POINT p)
+{
+       mpi_free(p->x); p->x = NULL;
+       mpi_free(p->y); p->y = NULL;
+       mpi_free(p->z); p->z = NULL;
+}
+EXPORT_SYMBOL_GPL(mpi_point_free_parts);
+
+/* Set the value from S into D.  */
+static void point_set(MPI_POINT d, MPI_POINT s)
+{
+       mpi_set(d->x, s->x);
+       mpi_set(d->y, s->y);
+       mpi_set(d->z, s->z);
+}
+
+static void point_resize(MPI_POINT p, struct mpi_ec_ctx *ctx)
+{
+       size_t nlimbs = ctx->p->nlimbs;
+
+       mpi_resize(p->x, nlimbs);
+       p->x->nlimbs = nlimbs;
+       mpi_resize(p->z, nlimbs);
+       p->z->nlimbs = nlimbs;
+
+       if (ctx->model != MPI_EC_MONTGOMERY) {
+               mpi_resize(p->y, nlimbs);
+               p->y->nlimbs = nlimbs;
+       }
+}
+
+static void point_swap_cond(MPI_POINT d, MPI_POINT s, unsigned long swap,
+               struct mpi_ec_ctx *ctx)
+{
+       mpi_swap_cond(d->x, s->x, swap);
+       if (ctx->model != MPI_EC_MONTGOMERY)
+               mpi_swap_cond(d->y, s->y, swap);
+       mpi_swap_cond(d->z, s->z, swap);
+}
+
+
+/* W = W mod P.  */
+static void ec_mod(MPI w, struct mpi_ec_ctx *ec)
+{
+       if (ec->t.p_barrett)
+               mpi_mod_barrett(w, w, ec->t.p_barrett);
+       else
+               mpi_mod(w, w, ec->p);
+}
+
+static void ec_addm(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
+{
+       mpi_add(w, u, v);
+       ec_mod(w, ctx);
+}
+
+static void ec_subm(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ec)
+{
+       mpi_sub(w, u, v);
+       while (w->sign)
+               mpi_add(w, w, ec->p);
+       /*ec_mod(w, ec);*/
+}
+
+static void ec_mulm(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
+{
+       mpi_mul(w, u, v);
+       ec_mod(w, ctx);
+}
+
+/* W = 2 * U mod P.  */
+static void ec_mul2(MPI w, MPI u, struct mpi_ec_ctx *ctx)
+{
+       mpi_lshift(w, u, 1);
+       ec_mod(w, ctx);
+}
+
+static void ec_powm(MPI w, const MPI b, const MPI e,
+               struct mpi_ec_ctx *ctx)
+{
+       mpi_powm(w, b, e, ctx->p);
+       /* mpi_abs(w); */
+}
+
+/* Shortcut for
+ * ec_powm(B, B, mpi_const(MPI_C_TWO), ctx);
+ * for easier optimization.
+ */
+static void ec_pow2(MPI w, const MPI b, struct mpi_ec_ctx *ctx)
+{
+       /* Using mpi_mul is slightly faster (at least on amd64).  */
+       /* mpi_powm(w, b, mpi_const(MPI_C_TWO), ctx->p); */
+       ec_mulm(w, b, b, ctx);
+}
+
+/* Shortcut for
+ * ec_powm(B, B, mpi_const(MPI_C_THREE), ctx);
+ * for easier optimization.
+ */
+static void ec_pow3(MPI w, const MPI b, struct mpi_ec_ctx *ctx)
+{
+       mpi_powm(w, b, mpi_const(MPI_C_THREE), ctx->p);
+}
+
+static void ec_invm(MPI x, MPI a, struct mpi_ec_ctx *ctx)
+{
+       if (!mpi_invm(x, a, ctx->p))
+               log_error("ec_invm: inverse does not exist:\n");
+}
+
+static void mpih_set_cond(mpi_ptr_t wp, mpi_ptr_t up,
+               mpi_size_t usize, unsigned long set)
+{
+       mpi_size_t i;
+       mpi_limb_t mask = ((mpi_limb_t)0) - set;
+       mpi_limb_t x;
+
+       for (i = 0; i < usize; i++) {
+               x = mask & (wp[i] ^ up[i]);
+               wp[i] = wp[i] ^ x;
+       }
+}
+
+/* Routines for 2^255 - 19.  */
+
+#define LIMB_SIZE_25519 ((256+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB)
+
+static void ec_addm_25519(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
+{
+       mpi_ptr_t wp, up, vp;
+       mpi_size_t wsize = LIMB_SIZE_25519;
+       mpi_limb_t n[LIMB_SIZE_25519];
+       mpi_limb_t borrow;
+
+       if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
+               log_bug("addm_25519: different sizes\n");
+
+       memset(n, 0, sizeof(n));
+       up = u->d;
+       vp = v->d;
+       wp = w->d;
+
+       mpihelp_add_n(wp, up, vp, wsize);
+       borrow = mpihelp_sub_n(wp, wp, ctx->p->d, wsize);
+       mpih_set_cond(n, ctx->p->d, wsize, (borrow != 0UL));
+       mpihelp_add_n(wp, wp, n, wsize);
+       wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB));
+}
+
+static void ec_subm_25519(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
+{
+       mpi_ptr_t wp, up, vp;
+       mpi_size_t wsize = LIMB_SIZE_25519;
+       mpi_limb_t n[LIMB_SIZE_25519];
+       mpi_limb_t borrow;
+
+       if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
+               log_bug("subm_25519: different sizes\n");
+
+       memset(n, 0, sizeof(n));
+       up = u->d;
+       vp = v->d;
+       wp = w->d;
+
+       borrow = mpihelp_sub_n(wp, up, vp, wsize);
+       mpih_set_cond(n, ctx->p->d, wsize, (borrow != 0UL));
+       mpihelp_add_n(wp, wp, n, wsize);
+       wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB));
+}
+
+static void ec_mulm_25519(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
+{
+       mpi_ptr_t wp, up, vp;
+       mpi_size_t wsize = LIMB_SIZE_25519;
+       mpi_limb_t n[LIMB_SIZE_25519*2];
+       mpi_limb_t m[LIMB_SIZE_25519+1];
+       mpi_limb_t cy;
+       int msb;
+
+       (void)ctx;
+       if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
+               log_bug("mulm_25519: different sizes\n");
+
+       up = u->d;
+       vp = v->d;
+       wp = w->d;
+
+       mpihelp_mul_n(n, up, vp, wsize);
+       memcpy(wp, n, wsize * BYTES_PER_MPI_LIMB);
+       wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB));
+
+       memcpy(m, n+LIMB_SIZE_25519-1, (wsize+1) * BYTES_PER_MPI_LIMB);
+       mpihelp_rshift(m, m, LIMB_SIZE_25519+1, (255 % BITS_PER_MPI_LIMB));
+
+       memcpy(n, m, wsize * BYTES_PER_MPI_LIMB);
+       cy = mpihelp_lshift(m, m, LIMB_SIZE_25519, 4);
+       m[LIMB_SIZE_25519] = cy;
+       cy = mpihelp_add_n(m, m, n, wsize);
+       m[LIMB_SIZE_25519] += cy;
+       cy = mpihelp_add_n(m, m, n, wsize);
+       m[LIMB_SIZE_25519] += cy;
+       cy = mpihelp_add_n(m, m, n, wsize);
+       m[LIMB_SIZE_25519] += cy;
+
+       cy = mpihelp_add_n(wp, wp, m, wsize);
+       m[LIMB_SIZE_25519] += cy;
+
+       memset(m, 0, wsize * BYTES_PER_MPI_LIMB);
+       msb = (wp[LIMB_SIZE_25519-1] >> (255 % BITS_PER_MPI_LIMB));
+       m[0] = (m[LIMB_SIZE_25519] * 2 + msb) * 19;
+       wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB));
+       mpihelp_add_n(wp, wp, m, wsize);
+
+       m[0] = 0;
+       cy = mpihelp_sub_n(wp, wp, ctx->p->d, wsize);
+       mpih_set_cond(m, ctx->p->d, wsize, (cy != 0UL));
+       mpihelp_add_n(wp, wp, m, wsize);
+}
+
+static void ec_mul2_25519(MPI w, MPI u, struct mpi_ec_ctx *ctx)
+{
+       ec_addm_25519(w, u, u, ctx);
+}
+
+static void ec_pow2_25519(MPI w, const MPI b, struct mpi_ec_ctx *ctx)
+{
+       ec_mulm_25519(w, b, b, ctx);
+}
+
+/* Routines for 2^448 - 2^224 - 1.  */
+
+#define LIMB_SIZE_448 ((448+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB)
+#define LIMB_SIZE_HALF_448 ((LIMB_SIZE_448+1)/2)
+
+static void ec_addm_448(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
+{
+       mpi_ptr_t wp, up, vp;
+       mpi_size_t wsize = LIMB_SIZE_448;
+       mpi_limb_t n[LIMB_SIZE_448];
+       mpi_limb_t cy;
+
+       if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
+               log_bug("addm_448: different sizes\n");
+
+       memset(n, 0, sizeof(n));
+       up = u->d;
+       vp = v->d;
+       wp = w->d;
+
+       cy = mpihelp_add_n(wp, up, vp, wsize);
+       mpih_set_cond(n, ctx->p->d, wsize, (cy != 0UL));
+       mpihelp_sub_n(wp, wp, n, wsize);
+}
+
+static void ec_subm_448(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
+{
+       mpi_ptr_t wp, up, vp;
+       mpi_size_t wsize = LIMB_SIZE_448;
+       mpi_limb_t n[LIMB_SIZE_448];
+       mpi_limb_t borrow;
+
+       if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
+               log_bug("subm_448: different sizes\n");
+
+       memset(n, 0, sizeof(n));
+       up = u->d;
+       vp = v->d;
+       wp = w->d;
+
+       borrow = mpihelp_sub_n(wp, up, vp, wsize);
+       mpih_set_cond(n, ctx->p->d, wsize, (borrow != 0UL));
+       mpihelp_add_n(wp, wp, n, wsize);
+}
+
+static void ec_mulm_448(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
+{
+       mpi_ptr_t wp, up, vp;
+       mpi_size_t wsize = LIMB_SIZE_448;
+       mpi_limb_t n[LIMB_SIZE_448*2];
+       mpi_limb_t a2[LIMB_SIZE_HALF_448];
+       mpi_limb_t a3[LIMB_SIZE_HALF_448];
+       mpi_limb_t b0[LIMB_SIZE_HALF_448];
+       mpi_limb_t b1[LIMB_SIZE_HALF_448];
+       mpi_limb_t cy;
+       int i;
+#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
+       mpi_limb_t b1_rest, a3_rest;
+#endif
+
+       if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
+               log_bug("mulm_448: different sizes\n");
+
+       up = u->d;
+       vp = v->d;
+       wp = w->d;
+
+       mpihelp_mul_n(n, up, vp, wsize);
+
+       for (i = 0; i < (wsize + 1) / 2; i++) {
+               b0[i] = n[i];
+               b1[i] = n[i+wsize/2];
+               a2[i] = n[i+wsize];
+               a3[i] = n[i+wsize+wsize/2];
+       }
+
+#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
+       b0[LIMB_SIZE_HALF_448-1] &= ((mpi_limb_t)1UL << 32)-1;
+       a2[LIMB_SIZE_HALF_448-1] &= ((mpi_limb_t)1UL << 32)-1;
+
+       b1_rest = 0;
+       a3_rest = 0;
+
+       for (i = (wsize + 1) / 2 - 1; i >= 0; i--) {
+               mpi_limb_t b1v, a3v;
+               b1v = b1[i];
+               a3v = a3[i];
+               b1[i] = (b1_rest << 32) | (b1v >> 32);
+               a3[i] = (a3_rest << 32) | (a3v >> 32);
+               b1_rest = b1v & (((mpi_limb_t)1UL << 32)-1);
+               a3_rest = a3v & (((mpi_limb_t)1UL << 32)-1);
+       }
+#endif
+
+       cy = mpihelp_add_n(b0, b0, a2, LIMB_SIZE_HALF_448);
+       cy += mpihelp_add_n(b0, b0, a3, LIMB_SIZE_HALF_448);
+       for (i = 0; i < (wsize + 1) / 2; i++)
+               wp[i] = b0[i];
+#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
+       wp[LIMB_SIZE_HALF_448-1] &= (((mpi_limb_t)1UL << 32)-1);
+#endif
+
+#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
+       cy = b0[LIMB_SIZE_HALF_448-1] >> 32;
+#endif
+
+       cy = mpihelp_add_1(b1, b1, LIMB_SIZE_HALF_448, cy);
+       cy += mpihelp_add_n(b1, b1, a2, LIMB_SIZE_HALF_448);
+       cy += mpihelp_add_n(b1, b1, a3, LIMB_SIZE_HALF_448);
+       cy += mpihelp_add_n(b1, b1, a3, LIMB_SIZE_HALF_448);
+#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
+       b1_rest = 0;
+       for (i = (wsize + 1) / 2 - 1; i >= 0; i--) {
+               mpi_limb_t b1v = b1[i];
+               b1[i] = (b1_rest << 32) | (b1v >> 32);
+               b1_rest = b1v & (((mpi_limb_t)1UL << 32)-1);
+       }
+       wp[LIMB_SIZE_HALF_448-1] |= (b1_rest << 32);
+#endif
+       for (i = 0; i < wsize / 2; i++)
+               wp[i+(wsize + 1) / 2] = b1[i];
+
+#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
+       cy = b1[LIMB_SIZE_HALF_448-1];
+#endif
+
+       memset(n, 0, wsize * BYTES_PER_MPI_LIMB);
+
+#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
+       n[LIMB_SIZE_HALF_448-1] = cy << 32;
+#else
+       n[LIMB_SIZE_HALF_448] = cy;
+#endif
+       n[0] = cy;
+       mpihelp_add_n(wp, wp, n, wsize);
+
+       memset(n, 0, wsize * BYTES_PER_MPI_LIMB);
+       cy = mpihelp_sub_n(wp, wp, ctx->p->d, wsize);
+       mpih_set_cond(n, ctx->p->d, wsize, (cy != 0UL));
+       mpihelp_add_n(wp, wp, n, wsize);
+}
+
+static void ec_mul2_448(MPI w, MPI u, struct mpi_ec_ctx *ctx)
+{
+       ec_addm_448(w, u, u, ctx);
+}
+
+static void ec_pow2_448(MPI w, const MPI b, struct mpi_ec_ctx *ctx)
+{
+       ec_mulm_448(w, b, b, ctx);
+}
+
+struct field_table {
+       const char *p;
+
+       /* computation routines for the field.  */
+       void (*addm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx);
+       void (*subm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx);
+       void (*mulm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx);
+       void (*mul2)(MPI w, MPI u, struct mpi_ec_ctx *ctx);
+       void (*pow2)(MPI w, const MPI b, struct mpi_ec_ctx *ctx);
+};
+
+static const struct field_table field_table[] = {
+       {
+               "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
+               ec_addm_25519,
+               ec_subm_25519,
+               ec_mulm_25519,
+               ec_mul2_25519,
+               ec_pow2_25519
+       },
+       {
+               "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE"
+               "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+               ec_addm_448,
+               ec_subm_448,
+               ec_mulm_448,
+               ec_mul2_448,
+               ec_pow2_448
+       },
+       { NULL, NULL, NULL, NULL, NULL, NULL },
+};
+
+/* Force recomputation of all helper variables.  */
+static void mpi_ec_get_reset(struct mpi_ec_ctx *ec)
+{
+       ec->t.valid.a_is_pminus3 = 0;
+       ec->t.valid.two_inv_p = 0;
+}
+
+/* Accessor for helper variable.  */
+static int ec_get_a_is_pminus3(struct mpi_ec_ctx *ec)
+{
+       MPI tmp;
+
+       if (!ec->t.valid.a_is_pminus3) {
+               ec->t.valid.a_is_pminus3 = 1;
+               tmp = mpi_alloc_like(ec->p);
+               mpi_sub_ui(tmp, ec->p, 3);
+               ec->t.a_is_pminus3 = !mpi_cmp(ec->a, tmp);
+               mpi_free(tmp);
+       }
+
+       return ec->t.a_is_pminus3;
+}
+
+/* Accessor for helper variable.  */
+static MPI ec_get_two_inv_p(struct mpi_ec_ctx *ec)
+{
+       if (!ec->t.valid.two_inv_p) {
+               ec->t.valid.two_inv_p = 1;
+               if (!ec->t.two_inv_p)
+                       ec->t.two_inv_p = mpi_alloc(0);
+               ec_invm(ec->t.two_inv_p, mpi_const(MPI_C_TWO), ec);
+       }
+       return ec->t.two_inv_p;
+}
+
+static const char *const curve25519_bad_points[] = {
+       "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed",
+       "0x0000000000000000000000000000000000000000000000000000000000000000",
+       "0x0000000000000000000000000000000000000000000000000000000000000001",
+       "0x00b8495f16056286fdb1329ceb8d09da6ac49ff1fae35616aeb8413b7c7aebe0",
+       "0x57119fd0dd4e22d8868e1c58c45c44045bef839c55b1d0b1248c50a3bc959c5f",
+       "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec",
+       "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee",
+       NULL
+};
+
+static const char *const curve448_bad_points[] = {
+       "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+       "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+       "0x00000000000000000000000000000000000000000000000000000000"
+       "00000000000000000000000000000000000000000000000000000000",
+       "0x00000000000000000000000000000000000000000000000000000000"
+       "00000000000000000000000000000000000000000000000000000001",
+       "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+       "fffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
+       "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+       "00000000000000000000000000000000000000000000000000000000",
+       NULL
+};
+
+static const char *const *bad_points_table[] = {
+       curve25519_bad_points,
+       curve448_bad_points,
+};
+
+static void mpi_ec_coefficient_normalize(MPI a, MPI p)
+{
+       if (a->sign) {
+               mpi_resize(a, p->nlimbs);
+               mpihelp_sub_n(a->d, p->d, a->d, p->nlimbs);
+               a->nlimbs = p->nlimbs;
+               a->sign = 0;
+       }
+}
+
+/* This function initialized a context for elliptic curve based on the
+ * field GF(p).  P is the prime specifying this field, A is the first
+ * coefficient.  CTX is expected to be zeroized.
+ */
+void mpi_ec_init(struct mpi_ec_ctx *ctx, enum gcry_mpi_ec_models model,
+                       enum ecc_dialects dialect,
+                       int flags, MPI p, MPI a, MPI b)
+{
+       int i;
+       static int use_barrett = -1 /* TODO: 1 or -1 */;
+
+       mpi_ec_coefficient_normalize(a, p);
+       mpi_ec_coefficient_normalize(b, p);
+
+       /* Fixme: Do we want to check some constraints? e.g.  a < p  */
+
+       ctx->model = model;
+       ctx->dialect = dialect;
+       ctx->flags = flags;
+       if (dialect == ECC_DIALECT_ED25519)
+               ctx->nbits = 256;
+       else
+               ctx->nbits = mpi_get_nbits(p);
+       ctx->p = mpi_copy(p);
+       ctx->a = mpi_copy(a);
+       ctx->b = mpi_copy(b);
+
+       ctx->t.p_barrett = use_barrett > 0 ? mpi_barrett_init(ctx->p, 0) : NULL;
+
+       mpi_ec_get_reset(ctx);
+
+       if (model == MPI_EC_MONTGOMERY) {
+               for (i = 0; i < DIM(bad_points_table); i++) {
+                       MPI p_candidate = mpi_scanval(bad_points_table[i][0]);
+                       int match_p = !mpi_cmp(ctx->p, p_candidate);
+                       int j;
+
+                       mpi_free(p_candidate);
+                       if (!match_p)
+                               continue;
+
+                       for (j = 0; i < DIM(ctx->t.scratch) && bad_points_table[i][j]; j++)
+                               ctx->t.scratch[j] = mpi_scanval(bad_points_table[i][j]);
+               }
+       } else {
+               /* Allocate scratch variables.  */
+               for (i = 0; i < DIM(ctx->t.scratch); i++)
+                       ctx->t.scratch[i] = mpi_alloc_like(ctx->p);
+       }
+
+       ctx->addm = ec_addm;
+       ctx->subm = ec_subm;
+       ctx->mulm = ec_mulm;
+       ctx->mul2 = ec_mul2;
+       ctx->pow2 = ec_pow2;
+
+       for (i = 0; field_table[i].p; i++) {
+               MPI f_p;
+
+               f_p = mpi_scanval(field_table[i].p);
+               if (!f_p)
+                       break;
+
+               if (!mpi_cmp(p, f_p)) {
+                       ctx->addm = field_table[i].addm;
+                       ctx->subm = field_table[i].subm;
+                       ctx->mulm = field_table[i].mulm;
+                       ctx->mul2 = field_table[i].mul2;
+                       ctx->pow2 = field_table[i].pow2;
+                       mpi_free(f_p);
+
+                       mpi_resize(ctx->a, ctx->p->nlimbs);
+                       ctx->a->nlimbs = ctx->p->nlimbs;
+
+                       mpi_resize(ctx->b, ctx->p->nlimbs);
+                       ctx->b->nlimbs = ctx->p->nlimbs;
+
+                       for (i = 0; i < DIM(ctx->t.scratch) && ctx->t.scratch[i]; i++)
+                               ctx->t.scratch[i]->nlimbs = ctx->p->nlimbs;
+
+                       break;
+               }
+
+               mpi_free(f_p);
+       }
+}
+EXPORT_SYMBOL_GPL(mpi_ec_init);
+
+void mpi_ec_deinit(struct mpi_ec_ctx *ctx)
+{
+       int i;
+
+       mpi_barrett_free(ctx->t.p_barrett);
+
+       /* Domain parameter.  */
+       mpi_free(ctx->p);
+       mpi_free(ctx->a);
+       mpi_free(ctx->b);
+       mpi_point_release(ctx->G);
+       mpi_free(ctx->n);
+
+       /* The key.  */
+       mpi_point_release(ctx->Q);
+       mpi_free(ctx->d);
+
+       /* Private data of ec.c.  */
+       mpi_free(ctx->t.two_inv_p);
+
+       for (i = 0; i < DIM(ctx->t.scratch); i++)
+               mpi_free(ctx->t.scratch[i]);
+}
+EXPORT_SYMBOL_GPL(mpi_ec_deinit);
+
+/* Compute the affine coordinates from the projective coordinates in
+ * POINT.  Set them into X and Y.  If one coordinate is not required,
+ * X or Y may be passed as NULL.  CTX is the usual context. Returns: 0
+ * on success or !0 if POINT is at infinity.
+ */
+int mpi_ec_get_affine(MPI x, MPI y, MPI_POINT point, struct mpi_ec_ctx *ctx)
+{
+       if (!mpi_cmp_ui(point->z, 0))
+               return -1;
+
+       switch (ctx->model) {
+       case MPI_EC_WEIERSTRASS: /* Using Jacobian coordinates.  */
+               {
+                       MPI z1, z2, z3;
+
+                       z1 = mpi_new(0);
+                       z2 = mpi_new(0);
+                       ec_invm(z1, point->z, ctx);  /* z1 = z^(-1) mod p  */
+                       ec_mulm(z2, z1, z1, ctx);    /* z2 = z^(-2) mod p  */
+
+                       if (x)
+                               ec_mulm(x, point->x, z2, ctx);
+
+                       if (y) {
+                               z3 = mpi_new(0);
+                               ec_mulm(z3, z2, z1, ctx);      /* z3 = z^(-3) mod p */
+                               ec_mulm(y, point->y, z3, ctx);
+                               mpi_free(z3);
+                       }
+
+                       mpi_free(z2);
+                       mpi_free(z1);
+               }
+               return 0;
+
+       case MPI_EC_MONTGOMERY:
+               {
+                       if (x)
+                               mpi_set(x, point->x);
+
+                       if (y) {
+                               log_fatal("%s: Getting Y-coordinate on %s is not supported\n",
+                                               "mpi_ec_get_affine", "Montgomery");
+                               return -1;
+                       }
+               }
+               return 0;
+
+       case MPI_EC_EDWARDS:
+               {
+                       MPI z;
+
+                       z = mpi_new(0);
+                       ec_invm(z, point->z, ctx);
+
+                       mpi_resize(z, ctx->p->nlimbs);
+                       z->nlimbs = ctx->p->nlimbs;
+
+                       if (x) {
+                               mpi_resize(x, ctx->p->nlimbs);
+                               x->nlimbs = ctx->p->nlimbs;
+                               ctx->mulm(x, point->x, z, ctx);
+                       }
+                       if (y) {
+                               mpi_resize(y, ctx->p->nlimbs);
+                               y->nlimbs = ctx->p->nlimbs;
+                               ctx->mulm(y, point->y, z, ctx);
+                       }
+
+                       mpi_free(z);
+               }
+               return 0;
+
+       default:
+               return -1;
+       }
+}
+EXPORT_SYMBOL_GPL(mpi_ec_get_affine);
+
+/*  RESULT = 2 * POINT  (Weierstrass version). */
+static void dup_point_weierstrass(MPI_POINT result,
+               MPI_POINT point, struct mpi_ec_ctx *ctx)
+{
+#define x3 (result->x)
+#define y3 (result->y)
+#define z3 (result->z)
+#define t1 (ctx->t.scratch[0])
+#define t2 (ctx->t.scratch[1])
+#define t3 (ctx->t.scratch[2])
+#define l1 (ctx->t.scratch[3])
+#define l2 (ctx->t.scratch[4])
+#define l3 (ctx->t.scratch[5])
+
+       if (!mpi_cmp_ui(point->y, 0) || !mpi_cmp_ui(point->z, 0)) {
+               /* P_y == 0 || P_z == 0 => [1:1:0] */
+               mpi_set_ui(x3, 1);
+               mpi_set_ui(y3, 1);
+               mpi_set_ui(z3, 0);
+       } else {
+               if (ec_get_a_is_pminus3(ctx)) {
+                       /* Use the faster case.  */
+                       /* L1 = 3(X - Z^2)(X + Z^2) */
+                       /*                          T1: used for Z^2. */
+                       /*                          T2: used for the right term. */
+                       ec_pow2(t1, point->z, ctx);
+                       ec_subm(l1, point->x, t1, ctx);
+                       ec_mulm(l1, l1, mpi_const(MPI_C_THREE), ctx);
+                       ec_addm(t2, point->x, t1, ctx);
+                       ec_mulm(l1, l1, t2, ctx);
+               } else {
+                       /* Standard case. */
+                       /* L1 = 3X^2 + aZ^4 */
+                       /*                          T1: used for aZ^4. */
+                       ec_pow2(l1, point->x, ctx);
+                       ec_mulm(l1, l1, mpi_const(MPI_C_THREE), ctx);
+                       ec_powm(t1, point->z, mpi_const(MPI_C_FOUR), ctx);
+                       ec_mulm(t1, t1, ctx->a, ctx);
+                       ec_addm(l1, l1, t1, ctx);
+               }
+               /* Z3 = 2YZ */
+               ec_mulm(z3, point->y, point->z, ctx);
+               ec_mul2(z3, z3, ctx);
+
+               /* L2 = 4XY^2 */
+               /*                              T2: used for Y2; required later. */
+               ec_pow2(t2, point->y, ctx);
+               ec_mulm(l2, t2, point->x, ctx);
+               ec_mulm(l2, l2, mpi_const(MPI_C_FOUR), ctx);
+
+               /* X3 = L1^2 - 2L2 */
+               /*                              T1: used for L2^2. */
+               ec_pow2(x3, l1, ctx);
+               ec_mul2(t1, l2, ctx);
+               ec_subm(x3, x3, t1, ctx);
+
+               /* L3 = 8Y^4 */
+               /*                              T2: taken from above. */
+               ec_pow2(t2, t2, ctx);
+               ec_mulm(l3, t2, mpi_const(MPI_C_EIGHT), ctx);
+
+               /* Y3 = L1(L2 - X3) - L3 */
+               ec_subm(y3, l2, x3, ctx);
+               ec_mulm(y3, y3, l1, ctx);
+               ec_subm(y3, y3, l3, ctx);
+       }
+
+#undef x3
+#undef y3
+#undef z3
+#undef t1
+#undef t2
+#undef t3
+#undef l1
+#undef l2
+#undef l3
+}
+
+/*  RESULT = 2 * POINT  (Montgomery version). */
+static void dup_point_montgomery(MPI_POINT result,
+                               MPI_POINT point, struct mpi_ec_ctx *ctx)
+{
+       (void)result;
+       (void)point;
+       (void)ctx;
+       log_fatal("%s: %s not yet supported\n",
+                       "mpi_ec_dup_point", "Montgomery");
+}
+
+/*  RESULT = 2 * POINT  (Twisted Edwards version). */
+static void dup_point_edwards(MPI_POINT result,
+               MPI_POINT point, struct mpi_ec_ctx *ctx)
+{
+#define X1 (point->x)
+#define Y1 (point->y)
+#define Z1 (point->z)
+#define X3 (result->x)
+#define Y3 (result->y)
+#define Z3 (result->z)
+#define B (ctx->t.scratch[0])
+#define C (ctx->t.scratch[1])
+#define D (ctx->t.scratch[2])
+#define E (ctx->t.scratch[3])
+#define F (ctx->t.scratch[4])
+#define H (ctx->t.scratch[5])
+#define J (ctx->t.scratch[6])
+
+       /* Compute: (X_3 : Y_3 : Z_3) = 2( X_1 : Y_1 : Z_1 ) */
+
+       /* B = (X_1 + Y_1)^2  */
+       ctx->addm(B, X1, Y1, ctx);
+       ctx->pow2(B, B, ctx);
+
+       /* C = X_1^2 */
+       /* D = Y_1^2 */
+       ctx->pow2(C, X1, ctx);
+       ctx->pow2(D, Y1, ctx);
+
+       /* E = aC */
+       if (ctx->dialect == ECC_DIALECT_ED25519)
+               ctx->subm(E, ctx->p, C, ctx);
+       else
+               ctx->mulm(E, ctx->a, C, ctx);
+
+       /* F = E + D */
+       ctx->addm(F, E, D, ctx);
+
+       /* H = Z_1^2 */
+       ctx->pow2(H, Z1, ctx);
+
+       /* J = F - 2H */
+       ctx->mul2(J, H, ctx);
+       ctx->subm(J, F, J, ctx);
+
+       /* X_3 = (B - C - D) · J */
+       ctx->subm(X3, B, C, ctx);
+       ctx->subm(X3, X3, D, ctx);
+       ctx->mulm(X3, X3, J, ctx);
+
+       /* Y_3 = F · (E - D) */
+       ctx->subm(Y3, E, D, ctx);
+       ctx->mulm(Y3, Y3, F, ctx);
+
+       /* Z_3 = F · J */
+       ctx->mulm(Z3, F, J, ctx);
+
+#undef X1
+#undef Y1
+#undef Z1
+#undef X3
+#undef Y3
+#undef Z3
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef H
+#undef J
+}
+
+/*  RESULT = 2 * POINT  */
+static void
+mpi_ec_dup_point(MPI_POINT result, MPI_POINT point, struct mpi_ec_ctx *ctx)
+{
+       switch (ctx->model) {
+       case MPI_EC_WEIERSTRASS:
+               dup_point_weierstrass(result, point, ctx);
+               break;
+       case MPI_EC_MONTGOMERY:
+               dup_point_montgomery(result, point, ctx);
+               break;
+       case MPI_EC_EDWARDS:
+               dup_point_edwards(result, point, ctx);
+               break;
+       }
+}
+
+/* RESULT = P1 + P2  (Weierstrass version).*/
+static void add_points_weierstrass(MPI_POINT result,
+               MPI_POINT p1, MPI_POINT p2,
+               struct mpi_ec_ctx *ctx)
+{
+#define x1 (p1->x)
+#define y1 (p1->y)
+#define z1 (p1->z)
+#define x2 (p2->x)
+#define y2 (p2->y)
+#define z2 (p2->z)
+#define x3 (result->x)
+#define y3 (result->y)
+#define z3 (result->z)
+#define l1 (ctx->t.scratch[0])
+#define l2 (ctx->t.scratch[1])
+#define l3 (ctx->t.scratch[2])
+#define l4 (ctx->t.scratch[3])
+#define l5 (ctx->t.scratch[4])
+#define l6 (ctx->t.scratch[5])
+#define l7 (ctx->t.scratch[6])
+#define l8 (ctx->t.scratch[7])
+#define l9 (ctx->t.scratch[8])
+#define t1 (ctx->t.scratch[9])
+#define t2 (ctx->t.scratch[10])
+
+       if ((!mpi_cmp(x1, x2)) && (!mpi_cmp(y1, y2)) && (!mpi_cmp(z1, z2))) {
+               /* Same point; need to call the duplicate function.  */
+               mpi_ec_dup_point(result, p1, ctx);
+       } else if (!mpi_cmp_ui(z1, 0)) {
+               /* P1 is at infinity.  */
+               mpi_set(x3, p2->x);
+               mpi_set(y3, p2->y);
+               mpi_set(z3, p2->z);
+       } else if (!mpi_cmp_ui(z2, 0)) {
+               /* P2 is at infinity.  */
+               mpi_set(x3, p1->x);
+               mpi_set(y3, p1->y);
+               mpi_set(z3, p1->z);
+       } else {
+               int z1_is_one = !mpi_cmp_ui(z1, 1);
+               int z2_is_one = !mpi_cmp_ui(z2, 1);
+
+               /* l1 = x1 z2^2  */
+               /* l2 = x2 z1^2  */
+               if (z2_is_one)
+                       mpi_set(l1, x1);
+               else {
+                       ec_pow2(l1, z2, ctx);
+                       ec_mulm(l1, l1, x1, ctx);
+               }
+               if (z1_is_one)
+                       mpi_set(l2, x2);
+               else {
+                       ec_pow2(l2, z1, ctx);
+                       ec_mulm(l2, l2, x2, ctx);
+               }
+               /* l3 = l1 - l2 */
+               ec_subm(l3, l1, l2, ctx);
+               /* l4 = y1 z2^3  */
+               ec_powm(l4, z2, mpi_const(MPI_C_THREE), ctx);
+               ec_mulm(l4, l4, y1, ctx);
+               /* l5 = y2 z1^3  */
+               ec_powm(l5, z1, mpi_const(MPI_C_THREE), ctx);
+               ec_mulm(l5, l5, y2, ctx);
+               /* l6 = l4 - l5  */
+               ec_subm(l6, l4, l5, ctx);
+
+               if (!mpi_cmp_ui(l3, 0)) {
+                       if (!mpi_cmp_ui(l6, 0)) {
+                               /* P1 and P2 are the same - use duplicate function. */
+                               mpi_ec_dup_point(result, p1, ctx);
+                       } else {
+                               /* P1 is the inverse of P2.  */
+                               mpi_set_ui(x3, 1);
+                               mpi_set_ui(y3, 1);
+                               mpi_set_ui(z3, 0);
+                       }
+               } else {
+                       /* l7 = l1 + l2  */
+                       ec_addm(l7, l1, l2, ctx);
+                       /* l8 = l4 + l5  */
+                       ec_addm(l8, l4, l5, ctx);
+                       /* z3 = z1 z2 l3  */
+                       ec_mulm(z3, z1, z2, ctx);
+                       ec_mulm(z3, z3, l3, ctx);
+                       /* x3 = l6^2 - l7 l3^2  */
+                       ec_pow2(t1, l6, ctx);
+                       ec_pow2(t2, l3, ctx);
+                       ec_mulm(t2, t2, l7, ctx);
+                       ec_subm(x3, t1, t2, ctx);
+                       /* l9 = l7 l3^2 - 2 x3  */
+                       ec_mul2(t1, x3, ctx);
+                       ec_subm(l9, t2, t1, ctx);
+                       /* y3 = (l9 l6 - l8 l3^3)/2  */
+                       ec_mulm(l9, l9, l6, ctx);
+                       ec_powm(t1, l3, mpi_const(MPI_C_THREE), ctx); /* fixme: Use saved value*/
+                       ec_mulm(t1, t1, l8, ctx);
+                       ec_subm(y3, l9, t1, ctx);
+                       ec_mulm(y3, y3, ec_get_two_inv_p(ctx), ctx);
+               }
+       }
+
+#undef x1
+#undef y1
+#undef z1
+#undef x2
+#undef y2
+#undef z2
+#undef x3
+#undef y3
+#undef z3
+#undef l1
+#undef l2
+#undef l3
+#undef l4
+#undef l5
+#undef l6
+#undef l7
+#undef l8
+#undef l9
+#undef t1
+#undef t2
+}
+
+/* RESULT = P1 + P2  (Montgomery version).*/
+static void add_points_montgomery(MPI_POINT result,
+               MPI_POINT p1, MPI_POINT p2,
+               struct mpi_ec_ctx *ctx)
+{
+       (void)result;
+       (void)p1;
+       (void)p2;
+       (void)ctx;
+       log_fatal("%s: %s not yet supported\n",
+                       "mpi_ec_add_points", "Montgomery");
+}
+
+/* RESULT = P1 + P2  (Twisted Edwards version).*/
+static void add_points_edwards(MPI_POINT result,
+               MPI_POINT p1, MPI_POINT p2,
+               struct mpi_ec_ctx *ctx)
+{
+#define X1 (p1->x)
+#define Y1 (p1->y)
+#define Z1 (p1->z)
+#define X2 (p2->x)
+#define Y2 (p2->y)
+#define Z2 (p2->z)
+#define X3 (result->x)
+#define Y3 (result->y)
+#define Z3 (result->z)
+#define A (ctx->t.scratch[0])
+#define B (ctx->t.scratch[1])
+#define C (ctx->t.scratch[2])
+#define D (ctx->t.scratch[3])
+#define E (ctx->t.scratch[4])
+#define F (ctx->t.scratch[5])
+#define G (ctx->t.scratch[6])
+#define tmp (ctx->t.scratch[7])
+
+       point_resize(result, ctx);
+
+       /* Compute: (X_3 : Y_3 : Z_3) = (X_1 : Y_1 : Z_1) + (X_2 : Y_2 : Z_3) */
+
+       /* A = Z1 · Z2 */
+       ctx->mulm(A, Z1, Z2, ctx);
+
+       /* B = A^2 */
+       ctx->pow2(B, A, ctx);
+
+       /* C = X1 · X2 */
+       ctx->mulm(C, X1, X2, ctx);
+
+       /* D = Y1 · Y2 */
+       ctx->mulm(D, Y1, Y2, ctx);
+
+       /* E = d · C · D */
+       ctx->mulm(E, ctx->b, C, ctx);
+       ctx->mulm(E, E, D, ctx);
+
+       /* F = B - E */
+       ctx->subm(F, B, E, ctx);
+
+       /* G = B + E */
+       ctx->addm(G, B, E, ctx);
+
+       /* X_3 = A · F · ((X_1 + Y_1) · (X_2 + Y_2) - C - D) */
+       ctx->addm(tmp, X1, Y1, ctx);
+       ctx->addm(X3, X2, Y2, ctx);
+       ctx->mulm(X3, X3, tmp, ctx);
+       ctx->subm(X3, X3, C, ctx);
+       ctx->subm(X3, X3, D, ctx);
+       ctx->mulm(X3, X3, F, ctx);
+       ctx->mulm(X3, X3, A, ctx);
+
+       /* Y_3 = A · G · (D - aC) */
+       if (ctx->dialect == ECC_DIALECT_ED25519) {
+               ctx->addm(Y3, D, C, ctx);
+       } else {
+               ctx->mulm(Y3, ctx->a, C, ctx);
+               ctx->subm(Y3, D, Y3, ctx);
+       }
+       ctx->mulm(Y3, Y3, G, ctx);
+       ctx->mulm(Y3, Y3, A, ctx);
+
+       /* Z_3 = F · G */
+       ctx->mulm(Z3, F, G, ctx);
+
+
+#undef X1
+#undef Y1
+#undef Z1
+#undef X2
+#undef Y2
+#undef Z2
+#undef X3
+#undef Y3
+#undef Z3
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef tmp
+}
+
+/* Compute a step of Montgomery Ladder (only use X and Z in the point).
+ * Inputs:  P1, P2, and x-coordinate of DIF = P1 - P1.
+ * Outputs: PRD = 2 * P1 and  SUM = P1 + P2.
+ */
+static void montgomery_ladder(MPI_POINT prd, MPI_POINT sum,
+               MPI_POINT p1, MPI_POINT p2, MPI dif_x,
+               struct mpi_ec_ctx *ctx)
+{
+       ctx->addm(sum->x, p2->x, p2->z, ctx);
+       ctx->subm(p2->z, p2->x, p2->z, ctx);
+       ctx->addm(prd->x, p1->x, p1->z, ctx);
+       ctx->subm(p1->z, p1->x, p1->z, ctx);
+       ctx->mulm(p2->x, p1->z, sum->x, ctx);
+       ctx->mulm(p2->z, prd->x, p2->z, ctx);
+       ctx->pow2(p1->x, prd->x, ctx);
+       ctx->pow2(p1->z, p1->z, ctx);
+       ctx->addm(sum->x, p2->x, p2->z, ctx);
+       ctx->subm(p2->z, p2->x, p2->z, ctx);
+       ctx->mulm(prd->x, p1->x, p1->z, ctx);
+       ctx->subm(p1->z, p1->x, p1->z, ctx);
+       ctx->pow2(sum->x, sum->x, ctx);
+       ctx->pow2(sum->z, p2->z, ctx);
+       ctx->mulm(prd->z, p1->z, ctx->a, ctx); /* CTX->A: (a-2)/4 */
+       ctx->mulm(sum->z, sum->z, dif_x, ctx);
+       ctx->addm(prd->z, p1->x, prd->z, ctx);
+       ctx->mulm(prd->z, prd->z, p1->z, ctx);
+}
+
+/* RESULT = P1 + P2 */
+void mpi_ec_add_points(MPI_POINT result,
+               MPI_POINT p1, MPI_POINT p2,
+               struct mpi_ec_ctx *ctx)
+{
+       switch (ctx->model) {
+       case MPI_EC_WEIERSTRASS:
+               add_points_weierstrass(result, p1, p2, ctx);
+               break;
+       case MPI_EC_MONTGOMERY:
+               add_points_montgomery(result, p1, p2, ctx);
+               break;
+       case MPI_EC_EDWARDS:
+               add_points_edwards(result, p1, p2, ctx);
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(mpi_ec_add_points);
+
+/* Scalar point multiplication - the main function for ECC.  If takes
+ * an integer SCALAR and a POINT as well as the usual context CTX.
+ * RESULT will be set to the resulting point.
+ */
+void mpi_ec_mul_point(MPI_POINT result,
+                       MPI scalar, MPI_POINT point,
+                       struct mpi_ec_ctx *ctx)
+{
+       MPI x1, y1, z1, k, h, yy;
+       unsigned int i, loops;
+       struct gcry_mpi_point p1, p2, p1inv;
+
+       if (ctx->model == MPI_EC_EDWARDS) {
+               /* Simple left to right binary method.  Algorithm 3.27 from
+                * {author={Hankerson, Darrel and Menezes, Alfred J. and Vanstone, Scott},
+                *  title = {Guide to Elliptic Curve Cryptography},
+                *  year = {2003}, isbn = {038795273X},
+                *  url = {http://www.cacr.math.uwaterloo.ca/ecc/},
+                *  publisher = {Springer-Verlag New York, Inc.}}
+                */
+               unsigned int nbits;
+               int j;
+
+               if (mpi_cmp(scalar, ctx->p) >= 0)
+                       nbits = mpi_get_nbits(scalar);
+               else
+                       nbits = mpi_get_nbits(ctx->p);
+
+               mpi_set_ui(result->x, 0);
+               mpi_set_ui(result->y, 1);
+               mpi_set_ui(result->z, 1);
+               point_resize(point, ctx);
+
+               point_resize(result, ctx);
+               point_resize(point, ctx);
+
+               for (j = nbits-1; j >= 0; j--) {
+                       mpi_ec_dup_point(result, result, ctx);
+                       if (mpi_test_bit(scalar, j))
+                               mpi_ec_add_points(result, result, point, ctx);
+               }
+               return;
+       } else if (ctx->model == MPI_EC_MONTGOMERY) {
+               unsigned int nbits;
+               int j;
+               struct gcry_mpi_point p1_, p2_;
+               MPI_POINT q1, q2, prd, sum;
+               unsigned long sw;
+               mpi_size_t rsize;
+               int scalar_copied = 0;
+
+               /* Compute scalar point multiplication with Montgomery Ladder.
+                * Note that we don't use Y-coordinate in the points at all.
+                * RESULT->Y will be filled by zero.
+                */
+
+               nbits = mpi_get_nbits(scalar);
+               point_init(&p1);
+               point_init(&p2);
+               point_init(&p1_);
+               point_init(&p2_);
+               mpi_set_ui(p1.x, 1);
+               mpi_free(p2.x);
+               p2.x = mpi_copy(point->x);
+               mpi_set_ui(p2.z, 1);
+
+               point_resize(&p1, ctx);
+               point_resize(&p2, ctx);
+               point_resize(&p1_, ctx);
+               point_resize(&p2_, ctx);
+
+               mpi_resize(point->x, ctx->p->nlimbs);
+               point->x->nlimbs = ctx->p->nlimbs;
+
+               q1 = &p1;
+               q2 = &p2;
+               prd = &p1_;
+               sum = &p2_;
+
+               for (j = nbits-1; j >= 0; j--) {
+                       MPI_POINT t;
+
+                       sw = mpi_test_bit(scalar, j);
+                       point_swap_cond(q1, q2, sw, ctx);
+                       montgomery_ladder(prd, sum, q1, q2, point->x, ctx);
+                       point_swap_cond(prd, sum, sw, ctx);
+                       t = q1;  q1 = prd;  prd = t;
+                       t = q2;  q2 = sum;  sum = t;
+               }
+
+               mpi_clear(result->y);
+               sw = (nbits & 1);
+               point_swap_cond(&p1, &p1_, sw, ctx);
+
+               rsize = p1.z->nlimbs;
+               MPN_NORMALIZE(p1.z->d, rsize);
+               if (rsize == 0) {
+                       mpi_set_ui(result->x, 1);
+                       mpi_set_ui(result->z, 0);
+               } else {
+                       z1 = mpi_new(0);
+                       ec_invm(z1, p1.z, ctx);
+                       ec_mulm(result->x, p1.x, z1, ctx);
+                       mpi_set_ui(result->z, 1);
+                       mpi_free(z1);
+               }
+
+               point_free(&p1);
+               point_free(&p2);
+               point_free(&p1_);
+               point_free(&p2_);
+               if (scalar_copied)
+                       mpi_free(scalar);
+               return;
+       }
+
+       x1 = mpi_alloc_like(ctx->p);
+       y1 = mpi_alloc_like(ctx->p);
+       h  = mpi_alloc_like(ctx->p);
+       k  = mpi_copy(scalar);
+       yy = mpi_copy(point->y);
+
+       if (mpi_has_sign(k)) {
+               k->sign = 0;
+               ec_invm(yy, yy, ctx);
+       }
+
+       if (!mpi_cmp_ui(point->z, 1)) {
+               mpi_set(x1, point->x);
+               mpi_set(y1, yy);
+       } else {
+               MPI z2, z3;
+
+               z2 = mpi_alloc_like(ctx->p);
+               z3 = mpi_alloc_like(ctx->p);
+               ec_mulm(z2, point->z, point->z, ctx);
+               ec_mulm(z3, point->z, z2, ctx);
+               ec_invm(z2, z2, ctx);
+               ec_mulm(x1, point->x, z2, ctx);
+               ec_invm(z3, z3, ctx);
+               ec_mulm(y1, yy, z3, ctx);
+               mpi_free(z2);
+               mpi_free(z3);
+       }
+       z1 = mpi_copy(mpi_const(MPI_C_ONE));
+
+       mpi_mul(h, k, mpi_const(MPI_C_THREE)); /* h = 3k */
+       loops = mpi_get_nbits(h);
+       if (loops < 2) {
+               /* If SCALAR is zero, the above mpi_mul sets H to zero and thus
+                * LOOPs will be zero.  To avoid an underflow of I in the main
+                * loop we set LOOP to 2 and the result to (0,0,0).
+                */
+               loops = 2;
+               mpi_clear(result->x);
+               mpi_clear(result->y);
+               mpi_clear(result->z);
+       } else {
+               mpi_set(result->x, point->x);
+               mpi_set(result->y, yy);
+               mpi_set(result->z, point->z);
+       }
+       mpi_free(yy); yy = NULL;
+
+       p1.x = x1; x1 = NULL;
+       p1.y = y1; y1 = NULL;
+       p1.z = z1; z1 = NULL;
+       point_init(&p2);
+       point_init(&p1inv);
+
+       /* Invert point: y = p - y mod p  */
+       point_set(&p1inv, &p1);
+       ec_subm(p1inv.y, ctx->p, p1inv.y, ctx);
+
+       for (i = loops-2; i > 0; i--) {
+               mpi_ec_dup_point(result, result, ctx);
+               if (mpi_test_bit(h, i) == 1 && mpi_test_bit(k, i) == 0) {
+                       point_set(&p2, result);
+                       mpi_ec_add_points(result, &p2, &p1, ctx);
+               }
+               if (mpi_test_bit(h, i) == 0 && mpi_test_bit(k, i) == 1) {
+                       point_set(&p2, result);
+                       mpi_ec_add_points(result, &p2, &p1inv, ctx);
+               }
+       }
+
+       point_free(&p1);
+       point_free(&p2);
+       point_free(&p1inv);
+       mpi_free(h);
+       mpi_free(k);
+}
+EXPORT_SYMBOL_GPL(mpi_ec_mul_point);
+
+/* Return true if POINT is on the curve described by CTX.  */
+int mpi_ec_curve_point(MPI_POINT point, struct mpi_ec_ctx *ctx)
+{
+       int res = 0;
+       MPI x, y, w;
+
+       x = mpi_new(0);
+       y = mpi_new(0);
+       w = mpi_new(0);
+
+       /* Check that the point is in range.  This needs to be done here and
+        * not after conversion to affine coordinates.
+        */
+       if (mpi_cmpabs(point->x, ctx->p) >= 0)
+               goto leave;
+       if (mpi_cmpabs(point->y, ctx->p) >= 0)
+               goto leave;
+       if (mpi_cmpabs(point->z, ctx->p) >= 0)
+               goto leave;
+
+       switch (ctx->model) {
+       case MPI_EC_WEIERSTRASS:
+               {
+                       MPI xxx;
+
+                       if (mpi_ec_get_affine(x, y, point, ctx))
+                               goto leave;
+
+                       xxx = mpi_new(0);
+
+                       /* y^2 == x^3 + a·x + b */
+                       ec_pow2(y, y, ctx);
+
+                       ec_pow3(xxx, x, ctx);
+                       ec_mulm(w, ctx->a, x, ctx);
+                       ec_addm(w, w, ctx->b, ctx);
+                       ec_addm(w, w, xxx, ctx);
+
+                       if (!mpi_cmp(y, w))
+                               res = 1;
+
+                       mpi_free(xxx);
+               }
+               break;
+
+       case MPI_EC_MONTGOMERY:
+               {
+#define xx y
+                       /* With Montgomery curve, only X-coordinate is valid. */
+                       if (mpi_ec_get_affine(x, NULL, point, ctx))
+                               goto leave;
+
+                       /* The equation is: b * y^2 == x^3 + a · x^2 + x */
+                       /* We check if right hand is quadratic residue or not by
+                        * Euler's criterion.
+                        */
+                       /* CTX->A has (a-2)/4 and CTX->B has b^-1 */
+                       ec_mulm(w, ctx->a, mpi_const(MPI_C_FOUR), ctx);
+                       ec_addm(w, w, mpi_const(MPI_C_TWO), ctx);
+                       ec_mulm(w, w, x, ctx);
+                       ec_pow2(xx, x, ctx);
+                       ec_addm(w, w, xx, ctx);
+                       ec_addm(w, w, mpi_const(MPI_C_ONE), ctx);
+                       ec_mulm(w, w, x, ctx);
+                       ec_mulm(w, w, ctx->b, ctx);
+#undef xx
+                       /* Compute Euler's criterion: w^(p-1)/2 */
+#define p_minus1 y
+                       ec_subm(p_minus1, ctx->p, mpi_const(MPI_C_ONE), ctx);
+                       mpi_rshift(p_minus1, p_minus1, 1);
+                       ec_powm(w, w, p_minus1, ctx);
+
+                       res = !mpi_cmp_ui(w, 1);
+#undef p_minus1
+               }
+               break;
+
+       case MPI_EC_EDWARDS:
+               {
+                       if (mpi_ec_get_affine(x, y, point, ctx))
+                               goto leave;
+
+                       mpi_resize(w, ctx->p->nlimbs);
+                       w->nlimbs = ctx->p->nlimbs;
+
+                       /* a · x^2 + y^2 - 1 - b · x^2 · y^2 == 0 */
+                       ctx->pow2(x, x, ctx);
+                       ctx->pow2(y, y, ctx);
+                       if (ctx->dialect == ECC_DIALECT_ED25519)
+                               ctx->subm(w, ctx->p, x, ctx);
+                       else
+                               ctx->mulm(w, ctx->a, x, ctx);
+                       ctx->addm(w, w, y, ctx);
+                       ctx->mulm(x, x, y, ctx);
+                       ctx->mulm(x, x, ctx->b, ctx);
+                       ctx->subm(w, w, x, ctx);
+                       if (!mpi_cmp_ui(w, 1))
+                               res = 1;
+               }
+               break;
+       }
+
+leave:
+       mpi_free(w);
+       mpi_free(x);
+       mpi_free(y);
+
+       return res;
+}
+EXPORT_SYMBOL_GPL(mpi_ec_curve_point);
diff --git a/lib/mpi/mpi-add.c b/lib/mpi/mpi-add.c
new file mode 100644 (file)
index 0000000..2cdae54
--- /dev/null
@@ -0,0 +1,155 @@
+/* mpi-add.c  -  MPI functions
+ * Copyright (C) 1994, 1996, 1998, 2001, 2002,
+ *               2003 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ */
+
+#include "mpi-internal.h"
+
+/****************
+ * Add the unsigned integer V to the mpi-integer U and store the
+ * result in W. U and V may be the same.
+ */
+void mpi_add_ui(MPI w, MPI u, unsigned long v)
+{
+       mpi_ptr_t wp, up;
+       mpi_size_t usize, wsize;
+       int usign, wsign;
+
+       usize = u->nlimbs;
+       usign = u->sign;
+       wsign = 0;
+
+       /* If not space for W (and possible carry), increase space.  */
+       wsize = usize + 1;
+       if (w->alloced < wsize)
+               mpi_resize(w, wsize);
+
+       /* These must be after realloc (U may be the same as W).  */
+       up = u->d;
+       wp = w->d;
+
+       if (!usize) {  /* simple */
+               wp[0] = v;
+               wsize = v ? 1:0;
+       } else if (!usign) {  /* mpi is not negative */
+               mpi_limb_t cy;
+               cy = mpihelp_add_1(wp, up, usize, v);
+               wp[usize] = cy;
+               wsize = usize + cy;
+       } else {
+               /* The signs are different.  Need exact comparison to determine
+                * which operand to subtract from which.
+                */
+               if (usize == 1 && up[0] < v) {
+                       wp[0] = v - up[0];
+                       wsize = 1;
+               } else {
+                       mpihelp_sub_1(wp, up, usize, v);
+                       /* Size can decrease with at most one limb. */
+                       wsize = usize - (wp[usize-1] == 0);
+                       wsign = 1;
+               }
+       }
+
+       w->nlimbs = wsize;
+       w->sign   = wsign;
+}
+
+
+void mpi_add(MPI w, MPI u, MPI v)
+{
+       mpi_ptr_t wp, up, vp;
+       mpi_size_t usize, vsize, wsize;
+       int usign, vsign, wsign;
+
+       if (u->nlimbs < v->nlimbs) { /* Swap U and V. */
+               usize = v->nlimbs;
+               usign = v->sign;
+               vsize = u->nlimbs;
+               vsign = u->sign;
+               wsize = usize + 1;
+               RESIZE_IF_NEEDED(w, wsize);
+               /* These must be after realloc (u or v may be the same as w).  */
+               up = v->d;
+               vp = u->d;
+       } else {
+               usize = u->nlimbs;
+               usign = u->sign;
+               vsize = v->nlimbs;
+               vsign = v->sign;
+               wsize = usize + 1;
+               RESIZE_IF_NEEDED(w, wsize);
+               /* These must be after realloc (u or v may be the same as w).  */
+               up = u->d;
+               vp = v->d;
+       }
+       wp = w->d;
+       wsign = 0;
+
+       if (!vsize) {  /* simple */
+               MPN_COPY(wp, up, usize);
+               wsize = usize;
+               wsign = usign;
+       } else if (usign != vsign) { /* different sign */
+               /* This test is right since USIZE >= VSIZE */
+               if (usize != vsize) {
+                       mpihelp_sub(wp, up, usize, vp, vsize);
+                       wsize = usize;
+                       MPN_NORMALIZE(wp, wsize);
+                       wsign = usign;
+               } else if (mpihelp_cmp(up, vp, usize) < 0) {
+                       mpihelp_sub_n(wp, vp, up, usize);
+                       wsize = usize;
+                       MPN_NORMALIZE(wp, wsize);
+                       if (!usign)
+                               wsign = 1;
+               } else {
+                       mpihelp_sub_n(wp, up, vp, usize);
+                       wsize = usize;
+                       MPN_NORMALIZE(wp, wsize);
+                       if (usign)
+                               wsign = 1;
+               }
+       } else { /* U and V have same sign. Add them. */
+               mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize);
+               wp[usize] = cy;
+               wsize = usize + cy;
+               if (usign)
+                       wsign = 1;
+       }
+
+       w->nlimbs = wsize;
+       w->sign = wsign;
+}
+EXPORT_SYMBOL_GPL(mpi_add);
+
+void mpi_sub(MPI w, MPI u, MPI v)
+{
+       MPI vv = mpi_copy(v);
+       vv->sign = !vv->sign;
+       mpi_add(w, u, vv);
+       mpi_free(vv);
+}
+
+
+void mpi_addm(MPI w, MPI u, MPI v, MPI m)
+{
+       mpi_add(w, u, v);
+       mpi_mod(w, w, m);
+}
+EXPORT_SYMBOL_GPL(mpi_addm);
+
+void mpi_subm(MPI w, MPI u, MPI v, MPI m)
+{
+       mpi_sub(w, u, v);
+       mpi_mod(w, w, m);
+}
+EXPORT_SYMBOL_GPL(mpi_subm);
index 503537e..a5119a2 100644 (file)
@@ -32,6 +32,7 @@ void mpi_normalize(MPI a)
        for (; a->nlimbs && !a->d[a->nlimbs - 1]; a->nlimbs--)
                ;
 }
+EXPORT_SYMBOL_GPL(mpi_normalize);
 
 /****************
  * Return the number of bits in A.
@@ -54,3 +55,253 @@ unsigned mpi_get_nbits(MPI a)
        return n;
 }
 EXPORT_SYMBOL_GPL(mpi_get_nbits);
+
+/****************
+ * Test whether bit N is set.
+ */
+int mpi_test_bit(MPI a, unsigned int n)
+{
+       unsigned int limbno, bitno;
+       mpi_limb_t limb;
+
+       limbno = n / BITS_PER_MPI_LIMB;
+       bitno  = n % BITS_PER_MPI_LIMB;
+
+       if (limbno >= a->nlimbs)
+               return 0; /* too far left: this is a 0 */
+       limb = a->d[limbno];
+       return (limb & (A_LIMB_1 << bitno)) ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(mpi_test_bit);
+
+/****************
+ * Set bit N of A.
+ */
+void mpi_set_bit(MPI a, unsigned int n)
+{
+       unsigned int i, limbno, bitno;
+
+       limbno = n / BITS_PER_MPI_LIMB;
+       bitno  = n % BITS_PER_MPI_LIMB;
+
+       if (limbno >= a->nlimbs) {
+               for (i = a->nlimbs; i < a->alloced; i++)
+                       a->d[i] = 0;
+               mpi_resize(a, limbno+1);
+               a->nlimbs = limbno+1;
+       }
+       a->d[limbno] |= (A_LIMB_1<<bitno);
+}
+
+/****************
+ * Set bit N of A. and clear all bits above
+ */
+void mpi_set_highbit(MPI a, unsigned int n)
+{
+       unsigned int i, limbno, bitno;
+
+       limbno = n / BITS_PER_MPI_LIMB;
+       bitno  = n % BITS_PER_MPI_LIMB;
+
+       if (limbno >= a->nlimbs) {
+               for (i = a->nlimbs; i < a->alloced; i++)
+                       a->d[i] = 0;
+               mpi_resize(a, limbno+1);
+               a->nlimbs = limbno+1;
+       }
+       a->d[limbno] |= (A_LIMB_1<<bitno);
+       for (bitno++; bitno < BITS_PER_MPI_LIMB; bitno++)
+               a->d[limbno] &= ~(A_LIMB_1 << bitno);
+       a->nlimbs = limbno+1;
+}
+EXPORT_SYMBOL_GPL(mpi_set_highbit);
+
+/****************
+ * clear bit N of A and all bits above
+ */
+void mpi_clear_highbit(MPI a, unsigned int n)
+{
+       unsigned int limbno, bitno;
+
+       limbno = n / BITS_PER_MPI_LIMB;
+       bitno  = n % BITS_PER_MPI_LIMB;
+
+       if (limbno >= a->nlimbs)
+               return; /* not allocated, therefore no need to clear bits :-) */
+
+       for ( ; bitno < BITS_PER_MPI_LIMB; bitno++)
+               a->d[limbno] &= ~(A_LIMB_1 << bitno);
+       a->nlimbs = limbno+1;
+}
+
+/****************
+ * Clear bit N of A.
+ */
+void mpi_clear_bit(MPI a, unsigned int n)
+{
+       unsigned int limbno, bitno;
+
+       limbno = n / BITS_PER_MPI_LIMB;
+       bitno  = n % BITS_PER_MPI_LIMB;
+
+       if (limbno >= a->nlimbs)
+               return; /* Don't need to clear this bit, it's far too left.  */
+       a->d[limbno] &= ~(A_LIMB_1 << bitno);
+}
+EXPORT_SYMBOL_GPL(mpi_clear_bit);
+
+
+/****************
+ * Shift A by COUNT limbs to the right
+ * This is used only within the MPI library
+ */
+void mpi_rshift_limbs(MPI a, unsigned int count)
+{
+       mpi_ptr_t ap = a->d;
+       mpi_size_t n = a->nlimbs;
+       unsigned int i;
+
+       if (count >= n) {
+               a->nlimbs = 0;
+               return;
+       }
+
+       for (i = 0; i < n - count; i++)
+               ap[i] = ap[i+count];
+       ap[i] = 0;
+       a->nlimbs -= count;
+}
+
+/*
+ * Shift A by N bits to the right.
+ */
+void mpi_rshift(MPI x, MPI a, unsigned int n)
+{
+       mpi_size_t xsize;
+       unsigned int i;
+       unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
+       unsigned int nbits = (n%BITS_PER_MPI_LIMB);
+
+       if (x == a) {
+               /* In-place operation.  */
+               if (nlimbs >= x->nlimbs) {
+                       x->nlimbs = 0;
+                       return;
+               }
+
+               if (nlimbs) {
+                       for (i = 0; i < x->nlimbs - nlimbs; i++)
+                               x->d[i] = x->d[i+nlimbs];
+                       x->d[i] = 0;
+                       x->nlimbs -= nlimbs;
+               }
+               if (x->nlimbs && nbits)
+                       mpihelp_rshift(x->d, x->d, x->nlimbs, nbits);
+       } else if (nlimbs) {
+               /* Copy and shift by more or equal bits than in a limb. */
+               xsize = a->nlimbs;
+               x->sign = a->sign;
+               RESIZE_IF_NEEDED(x, xsize);
+               x->nlimbs = xsize;
+               for (i = 0; i < a->nlimbs; i++)
+                       x->d[i] = a->d[i];
+               x->nlimbs = i;
+
+               if (nlimbs >= x->nlimbs) {
+                       x->nlimbs = 0;
+                       return;
+               }
+
+               if (nlimbs) {
+                       for (i = 0; i < x->nlimbs - nlimbs; i++)
+                               x->d[i] = x->d[i+nlimbs];
+                       x->d[i] = 0;
+                       x->nlimbs -= nlimbs;
+               }
+
+               if (x->nlimbs && nbits)
+                       mpihelp_rshift(x->d, x->d, x->nlimbs, nbits);
+       } else {
+               /* Copy and shift by less than bits in a limb.  */
+               xsize = a->nlimbs;
+               x->sign = a->sign;
+               RESIZE_IF_NEEDED(x, xsize);
+               x->nlimbs = xsize;
+
+               if (xsize) {
+                       if (nbits)
+                               mpihelp_rshift(x->d, a->d, x->nlimbs, nbits);
+                       else {
+                               /* The rshift helper function is not specified for
+                                * NBITS==0, thus we do a plain copy here.
+                                */
+                               for (i = 0; i < x->nlimbs; i++)
+                                       x->d[i] = a->d[i];
+                       }
+               }
+       }
+       MPN_NORMALIZE(x->d, x->nlimbs);
+}
+
+/****************
+ * Shift A by COUNT limbs to the left
+ * This is used only within the MPI library
+ */
+void mpi_lshift_limbs(MPI a, unsigned int count)
+{
+       mpi_ptr_t ap;
+       int n = a->nlimbs;
+       int i;
+
+       if (!count || !n)
+               return;
+
+       RESIZE_IF_NEEDED(a, n+count);
+
+       ap = a->d;
+       for (i = n-1; i >= 0; i--)
+               ap[i+count] = ap[i];
+       for (i = 0; i < count; i++)
+               ap[i] = 0;
+       a->nlimbs += count;
+}
+
+/*
+ * Shift A by N bits to the left.
+ */
+void mpi_lshift(MPI x, MPI a, unsigned int n)
+{
+       unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
+       unsigned int nbits = (n%BITS_PER_MPI_LIMB);
+
+       if (x == a && !n)
+               return;  /* In-place shift with an amount of zero.  */
+
+       if (x != a) {
+               /* Copy A to X.  */
+               unsigned int alimbs = a->nlimbs;
+               int asign = a->sign;
+               mpi_ptr_t xp, ap;
+
+               RESIZE_IF_NEEDED(x, alimbs+nlimbs+1);
+               xp = x->d;
+               ap = a->d;
+               MPN_COPY(xp, ap, alimbs);
+               x->nlimbs = alimbs;
+               x->flags = a->flags;
+               x->sign = asign;
+       }
+
+       if (nlimbs && !nbits) {
+               /* Shift a full number of limbs.  */
+               mpi_lshift_limbs(x, nlimbs);
+       } else if (n) {
+               /* We use a very dump approach: Shift left by the number of
+                * limbs plus one and than fix it up by an rshift.
+                */
+               mpi_lshift_limbs(x, nlimbs+1);
+               mpi_rshift(x, x, BITS_PER_MPI_LIMB - nbits);
+       }
+
+       MPN_NORMALIZE(x->d, x->nlimbs);
+}
index d25e9e9..c4cfa3f 100644 (file)
@@ -41,28 +41,54 @@ int mpi_cmp_ui(MPI u, unsigned long v)
 }
 EXPORT_SYMBOL_GPL(mpi_cmp_ui);
 
-int mpi_cmp(MPI u, MPI v)
+static int do_mpi_cmp(MPI u, MPI v, int absmode)
 {
-       mpi_size_t usize, vsize;
+       mpi_size_t usize;
+       mpi_size_t vsize;
+       int usign;
+       int vsign;
        int cmp;
 
        mpi_normalize(u);
        mpi_normalize(v);
+
        usize = u->nlimbs;
        vsize = v->nlimbs;
-       if (!u->sign && v->sign)
+       usign = absmode ? 0 : u->sign;
+       vsign = absmode ? 0 : v->sign;
+
+       /* Compare sign bits.  */
+
+       if (!usign && vsign)
                return 1;
-       if (u->sign && !v->sign)
+       if (usign && !vsign)
                return -1;
-       if (usize != vsize && !u->sign && !v->sign)
+
+       /* U and V are either both positive or both negative.  */
+
+       if (usize != vsize && !usign && !vsign)
                return usize - vsize;
-       if (usize != vsize && u->sign && v->sign)
-               return vsize - usize;
+       if (usize != vsize && usign && vsign)
+               return vsize + usize;
        if (!usize)
                return 0;
        cmp = mpihelp_cmp(u->d, v->d, usize);
-       if (u->sign)
-               return -cmp;
-       return cmp;
+       if (!cmp)
+               return 0;
+       if ((cmp < 0?1:0) == (usign?1:0))
+               return 1;
+
+       return -1;
+}
+
+int mpi_cmp(MPI u, MPI v)
+{
+       return do_mpi_cmp(u, v, 0);
 }
 EXPORT_SYMBOL_GPL(mpi_cmp);
+
+int mpi_cmpabs(MPI u, MPI v)
+{
+       return do_mpi_cmp(u, v, 1);
+}
+EXPORT_SYMBOL_GPL(mpi_cmpabs);
diff --git a/lib/mpi/mpi-div.c b/lib/mpi/mpi-div.c
new file mode 100644 (file)
index 0000000..45beab8
--- /dev/null
@@ -0,0 +1,234 @@
+/* mpi-div.c  -  MPI functions
+ * Copyright (C) 1994, 1996, 1998, 2001, 2002,
+ *               2003 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ */
+
+#include "mpi-internal.h"
+#include "longlong.h"
+
+void mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den);
+void mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor);
+
+void mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor)
+{
+       int divisor_sign = divisor->sign;
+       MPI temp_divisor = NULL;
+
+       /* We need the original value of the divisor after the remainder has been
+        * preliminary calculated.      We have to copy it to temporary space if it's
+        * the same variable as REM.
+        */
+       if (rem == divisor) {
+               temp_divisor = mpi_copy(divisor);
+               divisor = temp_divisor;
+       }
+
+       mpi_tdiv_r(rem, dividend, divisor);
+
+       if (((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs)
+               mpi_add(rem, rem, divisor);
+
+       if (temp_divisor)
+               mpi_free(temp_divisor);
+}
+
+void mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor)
+{
+       MPI tmp = mpi_alloc(mpi_get_nlimbs(quot));
+       mpi_fdiv_qr(quot, tmp, dividend, divisor);
+       mpi_free(tmp);
+}
+
+void mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor)
+{
+       int divisor_sign = divisor->sign;
+       MPI temp_divisor = NULL;
+
+       if (quot == divisor || rem == divisor) {
+               temp_divisor = mpi_copy(divisor);
+               divisor = temp_divisor;
+       }
+
+       mpi_tdiv_qr(quot, rem, dividend, divisor);
+
+       if ((divisor_sign ^ dividend->sign) && rem->nlimbs) {
+               mpi_sub_ui(quot, quot, 1);
+               mpi_add(rem, rem, divisor);
+       }
+
+       if (temp_divisor)
+               mpi_free(temp_divisor);
+}
+
+/* If den == quot, den needs temporary storage.
+ * If den == rem, den needs temporary storage.
+ * If num == quot, num needs temporary storage.
+ * If den has temporary storage, it can be normalized while being copied,
+ *   i.e no extra storage should be allocated.
+ */
+
+void mpi_tdiv_r(MPI rem, MPI num, MPI den)
+{
+       mpi_tdiv_qr(NULL, rem, num, den);
+}
+
+void mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den)
+{
+       mpi_ptr_t np, dp;
+       mpi_ptr_t qp, rp;
+       mpi_size_t nsize = num->nlimbs;
+       mpi_size_t dsize = den->nlimbs;
+       mpi_size_t qsize, rsize;
+       mpi_size_t sign_remainder = num->sign;
+       mpi_size_t sign_quotient = num->sign ^ den->sign;
+       unsigned int normalization_steps;
+       mpi_limb_t q_limb;
+       mpi_ptr_t marker[5];
+       int markidx = 0;
+
+       /* Ensure space is enough for quotient and remainder.
+        * We need space for an extra limb in the remainder, because it's
+        * up-shifted (normalized) below.
+        */
+       rsize = nsize + 1;
+       mpi_resize(rem, rsize);
+
+       qsize = rsize - dsize;    /* qsize cannot be bigger than this.  */
+       if (qsize <= 0) {
+               if (num != rem) {
+                       rem->nlimbs = num->nlimbs;
+                       rem->sign = num->sign;
+                       MPN_COPY(rem->d, num->d, nsize);
+               }
+               if (quot) {
+                       /* This needs to follow the assignment to rem, in case the
+                        * numerator and quotient are the same.
+                        */
+                       quot->nlimbs = 0;
+                       quot->sign = 0;
+               }
+               return;
+       }
+
+       if (quot)
+               mpi_resize(quot, qsize);
+
+       /* Read pointers here, when reallocation is finished.  */
+       np = num->d;
+       dp = den->d;
+       rp = rem->d;
+
+       /* Optimize division by a single-limb divisor.  */
+       if (dsize == 1) {
+               mpi_limb_t rlimb;
+               if (quot) {
+                       qp = quot->d;
+                       rlimb = mpihelp_divmod_1(qp, np, nsize, dp[0]);
+                       qsize -= qp[qsize - 1] == 0;
+                       quot->nlimbs = qsize;
+                       quot->sign = sign_quotient;
+               } else
+                       rlimb = mpihelp_mod_1(np, nsize, dp[0]);
+               rp[0] = rlimb;
+               rsize = rlimb != 0?1:0;
+               rem->nlimbs = rsize;
+               rem->sign = sign_remainder;
+               return;
+       }
+
+
+       if (quot) {
+               qp = quot->d;
+               /* Make sure QP and NP point to different objects.  Otherwise the
+                * numerator would be gradually overwritten by the quotient limbs.
+                */
+               if (qp == np) { /* Copy NP object to temporary space.  */
+                       np = marker[markidx++] = mpi_alloc_limb_space(nsize);
+                       MPN_COPY(np, qp, nsize);
+               }
+       } else /* Put quotient at top of remainder. */
+               qp = rp + dsize;
+
+       normalization_steps = count_leading_zeros(dp[dsize - 1]);
+
+       /* Normalize the denominator, i.e. make its most significant bit set by
+        * shifting it NORMALIZATION_STEPS bits to the left.  Also shift the
+        * numerator the same number of steps (to keep the quotient the same!).
+        */
+       if (normalization_steps) {
+               mpi_ptr_t tp;
+               mpi_limb_t nlimb;
+
+               /* Shift up the denominator setting the most significant bit of
+                * the most significant word.  Use temporary storage not to clobber
+                * the original contents of the denominator.
+                */
+               tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
+               mpihelp_lshift(tp, dp, dsize, normalization_steps);
+               dp = tp;
+
+               /* Shift up the numerator, possibly introducing a new most
+                * significant word.  Move the shifted numerator in the remainder
+                * meanwhile.
+                */
+               nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps);
+               if (nlimb) {
+                       rp[nsize] = nlimb;
+                       rsize = nsize + 1;
+               } else
+                       rsize = nsize;
+       } else {
+               /* The denominator is already normalized, as required.  Copy it to
+                * temporary space if it overlaps with the quotient or remainder.
+                */
+               if (dp == rp || (quot && (dp == qp))) {
+                       mpi_ptr_t tp;
+
+                       tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
+                       MPN_COPY(tp, dp, dsize);
+                       dp = tp;
+               }
+
+               /* Move the numerator to the remainder.  */
+               if (rp != np)
+                       MPN_COPY(rp, np, nsize);
+
+               rsize = nsize;
+       }
+
+       q_limb = mpihelp_divrem(qp, 0, rp, rsize, dp, dsize);
+
+       if (quot) {
+               qsize = rsize - dsize;
+               if (q_limb) {
+                       qp[qsize] = q_limb;
+                       qsize += 1;
+               }
+
+               quot->nlimbs = qsize;
+               quot->sign = sign_quotient;
+       }
+
+       rsize = dsize;
+       MPN_NORMALIZE(rp, rsize);
+
+       if (normalization_steps && rsize) {
+               mpihelp_rshift(rp, rp, rsize, normalization_steps);
+               rsize -= rp[rsize - 1] == 0?1:0;
+       }
+
+       rem->nlimbs = rsize;
+       rem->sign       = sign_remainder;
+       while (markidx) {
+               markidx--;
+               mpi_free_limb_space(marker[markidx]);
+       }
+}
index 91df5f0..5540021 100644 (file)
 typedef mpi_limb_t *mpi_ptr_t; /* pointer to a limb */
 typedef int mpi_size_t;                /* (must be a signed type) */
 
+#define RESIZE_IF_NEEDED(a, b)                 \
+       do {                                    \
+               if ((a)->alloced < (b))         \
+                       mpi_resize((a), (b));   \
+       } while (0)
+
 /* Copy N limbs from S to D.  */
 #define MPN_COPY(d, s, n) \
        do {                                    \
@@ -60,6 +66,14 @@ typedef int mpi_size_t;              /* (must be a signed type) */
                        (d)[_i] = (s)[_i];      \
        } while (0)
 
+#define MPN_COPY_INCR(d, s, n)         \
+       do {                                    \
+               mpi_size_t _i;                  \
+               for (_i = 0; _i < (n); _i++)    \
+                       (d)[_i] = (s)[_i];      \
+       } while (0)
+
+
 #define MPN_COPY_DECR(d, s, n) \
        do {                                    \
                mpi_size_t _i;                  \
@@ -92,6 +106,38 @@ typedef int mpi_size_t;             /* (must be a signed type) */
                        mul_n(prodp, up, vp, size, tspace);     \
        } while (0);
 
+/* Divide the two-limb number in (NH,,NL) by D, with DI being the largest
+ * limb not larger than (2**(2*BITS_PER_MP_LIMB))/D - (2**BITS_PER_MP_LIMB).
+ * If this would yield overflow, DI should be the largest possible number
+ * (i.e., only ones).  For correct operation, the most significant bit of D
+ * has to be set.  Put the quotient in Q and the remainder in R.
+ */
+#define UDIV_QRNND_PREINV(q, r, nh, nl, d, di)                         \
+       do {                                                            \
+               mpi_limb_t _ql __maybe_unused;                          \
+               mpi_limb_t _q, _r;                                      \
+               mpi_limb_t _xh, _xl;                                    \
+               umul_ppmm(_q, _ql, (nh), (di));                         \
+               _q += (nh);     /* DI is 2**BITS_PER_MPI_LIMB too small */ \
+               umul_ppmm(_xh, _xl, _q, (d));                           \
+               sub_ddmmss(_xh, _r, (nh), (nl), _xh, _xl);              \
+               if (_xh) {                                              \
+                       sub_ddmmss(_xh, _r, _xh, _r, 0, (d));           \
+                       _q++;                                           \
+                       if (_xh) {                                      \
+                               sub_ddmmss(_xh, _r, _xh, _r, 0, (d));   \
+                               _q++;                                   \
+                       }                                               \
+               }                                                       \
+               if (_r >= (d)) {                                        \
+                       _r -= (d);                                      \
+                       _q++;                                           \
+               }                                                       \
+               (r) = _r;                                               \
+               (q) = _q;                                               \
+       } while (0)
+
+
 /*-- mpiutil.c --*/
 mpi_ptr_t mpi_alloc_limb_space(unsigned nlimbs);
 void mpi_free_limb_space(mpi_ptr_t a);
@@ -135,6 +181,8 @@ int mpihelp_mul(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize,
 void mpih_sqr_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size);
 void mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size,
                mpi_ptr_t tspace);
+void mpihelp_mul_n(mpi_ptr_t prodp,
+               mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size);
 
 int mpihelp_mul_karatsuba_case(mpi_ptr_t prodp,
                               mpi_ptr_t up, mpi_size_t usize,
@@ -146,9 +194,14 @@ mpi_limb_t mpihelp_mul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
                         mpi_size_t s1_size, mpi_limb_t s2_limb);
 
 /*-- mpih-div.c --*/
+mpi_limb_t mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+                        mpi_limb_t divisor_limb);
 mpi_limb_t mpihelp_divrem(mpi_ptr_t qp, mpi_size_t qextra_limbs,
                          mpi_ptr_t np, mpi_size_t nsize,
                          mpi_ptr_t dp, mpi_size_t dsize);
+mpi_limb_t mpihelp_divmod_1(mpi_ptr_t quot_ptr,
+                           mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+                           mpi_limb_t divisor_limb);
 
 /*-- generic_mpih-[lr]shift.c --*/
 mpi_limb_t mpihelp_lshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
diff --git a/lib/mpi/mpi-inv.c b/lib/mpi/mpi-inv.c
new file mode 100644 (file)
index 0000000..61e37d1
--- /dev/null
@@ -0,0 +1,143 @@
+/* mpi-inv.c  -  MPI functions
+ *     Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mpi-internal.h"
+
+/****************
+ * Calculate the multiplicative inverse X of A mod N
+ * That is: Find the solution x for
+ *             1 = (a*x) mod n
+ */
+int mpi_invm(MPI x, MPI a, MPI n)
+{
+       /* Extended Euclid's algorithm (See TAOCP Vol II, 4.5.2, Alg X)
+        * modified according to Michael Penk's solution for Exercise 35
+        * with further enhancement
+        */
+       MPI u, v, u1, u2 = NULL, u3, v1, v2 = NULL, v3, t1, t2 = NULL, t3;
+       unsigned int k;
+       int sign;
+       int odd;
+
+       if (!mpi_cmp_ui(a, 0))
+               return 0; /* Inverse does not exists.  */
+       if (!mpi_cmp_ui(n, 1))
+               return 0; /* Inverse does not exists.  */
+
+       u = mpi_copy(a);
+       v = mpi_copy(n);
+
+       for (k = 0; !mpi_test_bit(u, 0) && !mpi_test_bit(v, 0); k++) {
+               mpi_rshift(u, u, 1);
+               mpi_rshift(v, v, 1);
+       }
+       odd = mpi_test_bit(v, 0);
+
+       u1 = mpi_alloc_set_ui(1);
+       if (!odd)
+               u2 = mpi_alloc_set_ui(0);
+       u3 = mpi_copy(u);
+       v1 = mpi_copy(v);
+       if (!odd) {
+               v2 = mpi_alloc(mpi_get_nlimbs(u));
+               mpi_sub(v2, u1, u); /* U is used as const 1 */
+       }
+       v3 = mpi_copy(v);
+       if (mpi_test_bit(u, 0)) { /* u is odd */
+               t1 = mpi_alloc_set_ui(0);
+               if (!odd) {
+                       t2 = mpi_alloc_set_ui(1);
+                       t2->sign = 1;
+               }
+               t3 = mpi_copy(v);
+               t3->sign = !t3->sign;
+               goto Y4;
+       } else {
+               t1 = mpi_alloc_set_ui(1);
+               if (!odd)
+                       t2 = mpi_alloc_set_ui(0);
+               t3 = mpi_copy(u);
+       }
+
+       do {
+               do {
+                       if (!odd) {
+                               if (mpi_test_bit(t1, 0) || mpi_test_bit(t2, 0)) {
+                                       /* one is odd */
+                                       mpi_add(t1, t1, v);
+                                       mpi_sub(t2, t2, u);
+                               }
+                               mpi_rshift(t1, t1, 1);
+                               mpi_rshift(t2, t2, 1);
+                               mpi_rshift(t3, t3, 1);
+                       } else {
+                               if (mpi_test_bit(t1, 0))
+                                       mpi_add(t1, t1, v);
+                               mpi_rshift(t1, t1, 1);
+                               mpi_rshift(t3, t3, 1);
+                       }
+Y4:
+                       ;
+               } while (!mpi_test_bit(t3, 0)); /* while t3 is even */
+
+               if (!t3->sign) {
+                       mpi_set(u1, t1);
+                       if (!odd)
+                               mpi_set(u2, t2);
+                       mpi_set(u3, t3);
+               } else {
+                       mpi_sub(v1, v, t1);
+                       sign = u->sign; u->sign = !u->sign;
+                       if (!odd)
+                               mpi_sub(v2, u, t2);
+                       u->sign = sign;
+                       sign = t3->sign; t3->sign = !t3->sign;
+                       mpi_set(v3, t3);
+                       t3->sign = sign;
+               }
+               mpi_sub(t1, u1, v1);
+               if (!odd)
+                       mpi_sub(t2, u2, v2);
+               mpi_sub(t3, u3, v3);
+               if (t1->sign) {
+                       mpi_add(t1, t1, v);
+                       if (!odd)
+                               mpi_sub(t2, t2, u);
+               }
+       } while (mpi_cmp_ui(t3, 0)); /* while t3 != 0 */
+       /* mpi_lshift( u3, k ); */
+       mpi_set(x, u1);
+
+       mpi_free(u1);
+       mpi_free(v1);
+       mpi_free(t1);
+       if (!odd) {
+               mpi_free(u2);
+               mpi_free(v2);
+               mpi_free(t2);
+       }
+       mpi_free(u3);
+       mpi_free(v3);
+       mpi_free(t3);
+
+       mpi_free(u);
+       mpi_free(v);
+       return 1;
+}
+EXPORT_SYMBOL_GPL(mpi_invm);
diff --git a/lib/mpi/mpi-mod.c b/lib/mpi/mpi-mod.c
new file mode 100644 (file)
index 0000000..47bc59e
--- /dev/null
@@ -0,0 +1,155 @@
+/* mpi-mod.c -  Modular reduction
+ * Copyright (C) 1998, 1999, 2001, 2002, 2003,
+ *               2007  Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ */
+
+
+#include "mpi-internal.h"
+#include "longlong.h"
+
+/* Context used with Barrett reduction.  */
+struct barrett_ctx_s {
+       MPI m;   /* The modulus - may not be modified. */
+       int m_copied;   /* If true, M needs to be released.  */
+       int k;
+       MPI y;
+       MPI r1;  /* Helper MPI. */
+       MPI r2;  /* Helper MPI. */
+       MPI r3;  /* Helper MPI allocated on demand. */
+};
+
+
+
+void mpi_mod(MPI rem, MPI dividend, MPI divisor)
+{
+       mpi_fdiv_r(rem, dividend, divisor);
+}
+
+/* This function returns a new context for Barrett based operations on
+ * the modulus M.  This context needs to be released using
+ * _gcry_mpi_barrett_free.  If COPY is true M will be transferred to
+ * the context and the user may change M.  If COPY is false, M may not
+ * be changed until gcry_mpi_barrett_free has been called.
+ */
+mpi_barrett_t mpi_barrett_init(MPI m, int copy)
+{
+       mpi_barrett_t ctx;
+       MPI tmp;
+
+       mpi_normalize(m);
+       ctx = kcalloc(1, sizeof(*ctx), GFP_KERNEL);
+
+       if (copy) {
+               ctx->m = mpi_copy(m);
+               ctx->m_copied = 1;
+       } else
+               ctx->m = m;
+
+       ctx->k = mpi_get_nlimbs(m);
+       tmp = mpi_alloc(ctx->k + 1);
+
+       /* Barrett precalculation: y = floor(b^(2k) / m). */
+       mpi_set_ui(tmp, 1);
+       mpi_lshift_limbs(tmp, 2 * ctx->k);
+       mpi_fdiv_q(tmp, tmp, m);
+
+       ctx->y  = tmp;
+       ctx->r1 = mpi_alloc(2 * ctx->k + 1);
+       ctx->r2 = mpi_alloc(2 * ctx->k + 1);
+
+       return ctx;
+}
+
+void mpi_barrett_free(mpi_barrett_t ctx)
+{
+       if (ctx) {
+               mpi_free(ctx->y);
+               mpi_free(ctx->r1);
+               mpi_free(ctx->r2);
+               if (ctx->r3)
+                       mpi_free(ctx->r3);
+               if (ctx->m_copied)
+                       mpi_free(ctx->m);
+               kfree(ctx);
+       }
+}
+
+
+/* R = X mod M
+ *
+ * Using Barrett reduction.  Before using this function
+ * _gcry_mpi_barrett_init must have been called to do the
+ * precalculations.  CTX is the context created by this precalculation
+ * and also conveys M.  If the Barret reduction could no be done a
+ * straightforward reduction method is used.
+ *
+ * We assume that these conditions are met:
+ * Input:  x =(x_2k-1 ...x_0)_b
+ *     m =(m_k-1 ....m_0)_b      with m_k-1 != 0
+ * Output: r = x mod m
+ */
+void mpi_mod_barrett(MPI r, MPI x, mpi_barrett_t ctx)
+{
+       MPI m = ctx->m;
+       int k = ctx->k;
+       MPI y = ctx->y;
+       MPI r1 = ctx->r1;
+       MPI r2 = ctx->r2;
+       int sign;
+
+       mpi_normalize(x);
+       if (mpi_get_nlimbs(x) > 2*k) {
+               mpi_mod(r, x, m);
+               return;
+       }
+
+       sign = x->sign;
+       x->sign = 0;
+
+       /* 1. q1 = floor( x / b^k-1)
+        *    q2 = q1 * y
+        *    q3 = floor( q2 / b^k+1 )
+        * Actually, we don't need qx, we can work direct on r2
+        */
+       mpi_set(r2, x);
+       mpi_rshift_limbs(r2, k-1);
+       mpi_mul(r2, r2, y);
+       mpi_rshift_limbs(r2, k+1);
+
+       /* 2. r1 = x mod b^k+1
+        *      r2 = q3 * m mod b^k+1
+        *      r  = r1 - r2
+        * 3. if r < 0 then  r = r + b^k+1
+        */
+       mpi_set(r1, x);
+       if (r1->nlimbs > k+1) /* Quick modulo operation.  */
+               r1->nlimbs = k+1;
+       mpi_mul(r2, r2, m);
+       if (r2->nlimbs > k+1) /* Quick modulo operation. */
+               r2->nlimbs = k+1;
+       mpi_sub(r, r1, r2);
+
+       if (mpi_has_sign(r)) {
+               if (!ctx->r3) {
+                       ctx->r3 = mpi_alloc(k + 2);
+                       mpi_set_ui(ctx->r3, 1);
+                       mpi_lshift_limbs(ctx->r3, k + 1);
+               }
+               mpi_add(r, r, ctx->r3);
+       }
+
+       /* 4. while r >= m do r = r - m */
+       while (mpi_cmp(r, m) >= 0)
+               mpi_sub(r, r, m);
+
+       x->sign = sign;
+}
+
+
+void mpi_mul_barrett(MPI w, MPI u, MPI v, mpi_barrett_t ctx)
+{
+       mpi_mul(w, u, v);
+       mpi_mod_barrett(w, w, ctx);
+}
diff --git a/lib/mpi/mpi-mul.c b/lib/mpi/mpi-mul.c
new file mode 100644 (file)
index 0000000..8f5fa20
--- /dev/null
@@ -0,0 +1,91 @@
+/* mpi-mul.c  -  MPI functions
+ * Copyright (C) 1994, 1996, 1998, 2001, 2002,
+ *               2003 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ */
+
+#include "mpi-internal.h"
+
+void mpi_mul(MPI w, MPI u, MPI v)
+{
+       mpi_size_t usize, vsize, wsize;
+       mpi_ptr_t up, vp, wp;
+       mpi_limb_t cy;
+       int usign, vsign, sign_product;
+       int assign_wp = 0;
+       mpi_ptr_t tmp_limb = NULL;
+
+       if (u->nlimbs < v->nlimbs) {
+               /* Swap U and V. */
+               usize = v->nlimbs;
+               usign = v->sign;
+               up    = v->d;
+               vsize = u->nlimbs;
+               vsign = u->sign;
+               vp    = u->d;
+       } else {
+               usize = u->nlimbs;
+               usign = u->sign;
+               up    = u->d;
+               vsize = v->nlimbs;
+               vsign = v->sign;
+               vp    = v->d;
+       }
+       sign_product = usign ^ vsign;
+       wp = w->d;
+
+       /* Ensure W has space enough to store the result.  */
+       wsize = usize + vsize;
+       if (w->alloced < wsize) {
+               if (wp == up || wp == vp) {
+                       wp = mpi_alloc_limb_space(wsize);
+                       assign_wp = 1;
+               } else {
+                       mpi_resize(w, wsize);
+                       wp = w->d;
+               }
+       } else { /* Make U and V not overlap with W.    */
+               if (wp == up) {
+                       /* W and U are identical.  Allocate temporary space for U. */
+                       up = tmp_limb = mpi_alloc_limb_space(usize);
+                       /* Is V identical too?  Keep it identical with U.  */
+                       if (wp == vp)
+                               vp = up;
+                       /* Copy to the temporary space.  */
+                       MPN_COPY(up, wp, usize);
+               } else if (wp == vp) {
+                       /* W and V are identical.  Allocate temporary space for V. */
+                       vp = tmp_limb = mpi_alloc_limb_space(vsize);
+                       /* Copy to the temporary space.  */
+                       MPN_COPY(vp, wp, vsize);
+               }
+       }
+
+       if (!vsize)
+               wsize = 0;
+       else {
+               mpihelp_mul(wp, up, usize, vp, vsize, &cy);
+               wsize -= cy ? 0:1;
+       }
+
+       if (assign_wp)
+               mpi_assign_limb_space(w, wp, wsize);
+       w->nlimbs = wsize;
+       w->sign = sign_product;
+       if (tmp_limb)
+               mpi_free_limb_space(tmp_limb);
+}
+
+void mpi_mulm(MPI w, MPI u, MPI v, MPI m)
+{
+       mpi_mul(w, u, v);
+       mpi_tdiv_r(w, w, m);
+}
+EXPORT_SYMBOL_GPL(mpi_mulm);
index eead4b3..7ea225b 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/string.h>
 #include "mpi-internal.h"
 
+#define MAX_EXTERN_SCAN_BYTES (16*1024*1024)
 #define MAX_EXTERN_MPI_BITS 16384
 
 /**
@@ -109,6 +110,112 @@ MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread)
 }
 EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
 
+/****************
+ * Fill the mpi VAL from the hex string in STR.
+ */
+int mpi_fromstr(MPI val, const char *str)
+{
+       int sign = 0;
+       int prepend_zero = 0;
+       int i, j, c, c1, c2;
+       unsigned int nbits, nbytes, nlimbs;
+       mpi_limb_t a;
+
+       if (*str == '-') {
+               sign = 1;
+               str++;
+       }
+
+       /* Skip optional hex prefix.  */
+       if (*str == '0' && str[1] == 'x')
+               str += 2;
+
+       nbits = strlen(str);
+       if (nbits > MAX_EXTERN_SCAN_BYTES) {
+               mpi_clear(val);
+               return -EINVAL;
+       }
+       nbits *= 4;
+       if ((nbits % 8))
+               prepend_zero = 1;
+
+       nbytes = (nbits+7) / 8;
+       nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+
+       if (val->alloced < nlimbs)
+               mpi_resize(val, nlimbs);
+
+       i = BYTES_PER_MPI_LIMB - (nbytes % BYTES_PER_MPI_LIMB);
+       i %= BYTES_PER_MPI_LIMB;
+       j = val->nlimbs = nlimbs;
+       val->sign = sign;
+       for (; j > 0; j--) {
+               a = 0;
+               for (; i < BYTES_PER_MPI_LIMB; i++) {
+                       if (prepend_zero) {
+                               c1 = '0';
+                               prepend_zero = 0;
+                       } else
+                               c1 = *str++;
+
+                       if (!c1) {
+                               mpi_clear(val);
+                               return -EINVAL;
+                       }
+                       c2 = *str++;
+                       if (!c2) {
+                               mpi_clear(val);
+                               return -EINVAL;
+                       }
+                       if (c1 >= '0' && c1 <= '9')
+                               c = c1 - '0';
+                       else if (c1 >= 'a' && c1 <= 'f')
+                               c = c1 - 'a' + 10;
+                       else if (c1 >= 'A' && c1 <= 'F')
+                               c = c1 - 'A' + 10;
+                       else {
+                               mpi_clear(val);
+                               return -EINVAL;
+                       }
+                       c <<= 4;
+                       if (c2 >= '0' && c2 <= '9')
+                               c |= c2 - '0';
+                       else if (c2 >= 'a' && c2 <= 'f')
+                               c |= c2 - 'a' + 10;
+                       else if (c2 >= 'A' && c2 <= 'F')
+                               c |= c2 - 'A' + 10;
+                       else {
+                               mpi_clear(val);
+                               return -EINVAL;
+                       }
+                       a <<= 8;
+                       a |= c;
+               }
+               i = 0;
+               val->d[j-1] = a;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mpi_fromstr);
+
+MPI mpi_scanval(const char *string)
+{
+       MPI a;
+
+       a = mpi_alloc(0);
+       if (!a)
+               return NULL;
+
+       if (mpi_fromstr(a, string)) {
+               mpi_free(a);
+               return NULL;
+       }
+       mpi_normalize(a);
+       return a;
+}
+EXPORT_SYMBOL_GPL(mpi_scanval);
+
 static int count_lzeros(MPI a)
 {
        mpi_limb_t alimb;
@@ -413,3 +520,232 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes)
        return val;
 }
 EXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl);
+
+/* Perform a two's complement operation on buffer P of size N bytes.  */
+static void twocompl(unsigned char *p, unsigned int n)
+{
+       int i;
+
+       for (i = n-1; i >= 0 && !p[i]; i--)
+               ;
+       if (i >= 0) {
+               if ((p[i] & 0x01))
+                       p[i] = (((p[i] ^ 0xfe) | 0x01) & 0xff);
+               else if ((p[i] & 0x02))
+                       p[i] = (((p[i] ^ 0xfc) | 0x02) & 0xfe);
+               else if ((p[i] & 0x04))
+                       p[i] = (((p[i] ^ 0xf8) | 0x04) & 0xfc);
+               else if ((p[i] & 0x08))
+                       p[i] = (((p[i] ^ 0xf0) | 0x08) & 0xf8);
+               else if ((p[i] & 0x10))
+                       p[i] = (((p[i] ^ 0xe0) | 0x10) & 0xf0);
+               else if ((p[i] & 0x20))
+                       p[i] = (((p[i] ^ 0xc0) | 0x20) & 0xe0);
+               else if ((p[i] & 0x40))
+                       p[i] = (((p[i] ^ 0x80) | 0x40) & 0xc0);
+               else
+                       p[i] = 0x80;
+
+               for (i--; i >= 0; i--)
+                       p[i] ^= 0xff;
+       }
+}
+
+int mpi_print(enum gcry_mpi_format format, unsigned char *buffer,
+                       size_t buflen, size_t *nwritten, MPI a)
+{
+       unsigned int nbits = mpi_get_nbits(a);
+       size_t len;
+       size_t dummy_nwritten;
+       int negative;
+
+       if (!nwritten)
+               nwritten = &dummy_nwritten;
+
+       /* Libgcrypt does no always care to set clear the sign if the value
+        * is 0.  For printing this is a bit of a surprise, in particular
+        * because if some of the formats don't support negative numbers but
+        * should be able to print a zero.  Thus we need this extra test
+        * for a negative number.
+        */
+       if (a->sign && mpi_cmp_ui(a, 0))
+               negative = 1;
+       else
+               negative = 0;
+
+       len = buflen;
+       *nwritten = 0;
+       if (format == GCRYMPI_FMT_STD) {
+               unsigned char *tmp;
+               int extra = 0;
+               unsigned int n;
+
+               tmp = mpi_get_buffer(a, &n, NULL);
+               if (!tmp)
+                       return -EINVAL;
+
+               if (negative) {
+                       twocompl(tmp, n);
+                       if (!(*tmp & 0x80)) {
+                               /* Need to extend the sign.  */
+                               n++;
+                               extra = 2;
+                       }
+               } else if (n && (*tmp & 0x80)) {
+                       /* Positive but the high bit of the returned buffer is set.
+                        * Thus we need to print an extra leading 0x00 so that the
+                        * output is interpreted as a positive number.
+                        */
+                       n++;
+                       extra = 1;
+               }
+
+               if (buffer && n > len) {
+                       /* The provided buffer is too short. */
+                       kfree(tmp);
+                       return -E2BIG;
+               }
+               if (buffer) {
+                       unsigned char *s = buffer;
+
+                       if (extra == 1)
+                               *s++ = 0;
+                       else if (extra)
+                               *s++ = 0xff;
+                       memcpy(s, tmp, n-!!extra);
+               }
+               kfree(tmp);
+               *nwritten = n;
+               return 0;
+       } else if (format == GCRYMPI_FMT_USG) {
+               unsigned int n = (nbits + 7)/8;
+
+               /* Note:  We ignore the sign for this format.  */
+               /* FIXME: for performance reasons we should put this into
+                * mpi_aprint because we can then use the buffer directly.
+                */
+
+               if (buffer && n > len)
+                       return -E2BIG;
+               if (buffer) {
+                       unsigned char *tmp;
+
+                       tmp = mpi_get_buffer(a, &n, NULL);
+                       if (!tmp)
+                               return -EINVAL;
+                       memcpy(buffer, tmp, n);
+                       kfree(tmp);
+               }
+               *nwritten = n;
+               return 0;
+       } else if (format == GCRYMPI_FMT_PGP) {
+               unsigned int n = (nbits + 7)/8;
+
+               /* The PGP format can only handle unsigned integers.  */
+               if (negative)
+                       return -EINVAL;
+
+               if (buffer && n+2 > len)
+                       return -E2BIG;
+
+               if (buffer) {
+                       unsigned char *tmp;
+                       unsigned char *s = buffer;
+
+                       s[0] = nbits >> 8;
+                       s[1] = nbits;
+
+                       tmp = mpi_get_buffer(a, &n, NULL);
+                       if (!tmp)
+                               return -EINVAL;
+                       memcpy(s+2, tmp, n);
+                       kfree(tmp);
+               }
+               *nwritten = n+2;
+               return 0;
+       } else if (format == GCRYMPI_FMT_SSH) {
+               unsigned char *tmp;
+               int extra = 0;
+               unsigned int n;
+
+               tmp = mpi_get_buffer(a, &n, NULL);
+               if (!tmp)
+                       return -EINVAL;
+
+               if (negative) {
+                       twocompl(tmp, n);
+                       if (!(*tmp & 0x80)) {
+                               /* Need to extend the sign.  */
+                               n++;
+                               extra = 2;
+                       }
+               } else if (n && (*tmp & 0x80)) {
+                       n++;
+                       extra = 1;
+               }
+
+               if (buffer && n+4 > len) {
+                       kfree(tmp);
+                       return -E2BIG;
+               }
+
+               if (buffer) {
+                       unsigned char *s = buffer;
+
+                       *s++ = n >> 24;
+                       *s++ = n >> 16;
+                       *s++ = n >> 8;
+                       *s++ = n;
+                       if (extra == 1)
+                               *s++ = 0;
+                       else if (extra)
+                               *s++ = 0xff;
+                       memcpy(s, tmp, n-!!extra);
+               }
+               kfree(tmp);
+               *nwritten = 4+n;
+               return 0;
+       } else if (format == GCRYMPI_FMT_HEX) {
+               unsigned char *tmp;
+               int i;
+               int extra = 0;
+               unsigned int n = 0;
+
+               tmp = mpi_get_buffer(a, &n, NULL);
+               if (!tmp)
+                       return -EINVAL;
+               if (!n || (*tmp & 0x80))
+                       extra = 2;
+
+               if (buffer && 2*n + extra + negative + 1 > len) {
+                       kfree(tmp);
+                       return -E2BIG;
+               }
+               if (buffer) {
+                       unsigned char *s = buffer;
+
+                       if (negative)
+                               *s++ = '-';
+                       if (extra) {
+                               *s++ = '0';
+                               *s++ = '0';
+                       }
+
+                       for (i = 0; i < n; i++) {
+                               unsigned int c = tmp[i];
+
+                               *s++ = (c >> 4) < 10 ? '0'+(c>>4) : 'A'+(c>>4)-10;
+                               c &= 15;
+                               *s++ = c < 10 ? '0'+c : 'A'+c-10;
+                       }
+                       *s++ = 0;
+                       *nwritten = s - buffer;
+               } else {
+                       *nwritten = 2*n + extra + negative + 1;
+               }
+               kfree(tmp);
+               return 0;
+       } else
+               return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mpi_print);
index 913a519..be70ee2 100644 (file)
 #define UDIV_TIME UMUL_TIME
 #endif
 
+
+mpi_limb_t
+mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+                       mpi_limb_t divisor_limb)
+{
+       mpi_size_t i;
+       mpi_limb_t n1, n0, r;
+       mpi_limb_t dummy __maybe_unused;
+
+       /* Botch: Should this be handled at all?  Rely on callers?      */
+       if (!dividend_size)
+               return 0;
+
+       /* If multiplication is much faster than division, and the
+        * dividend is large, pre-invert the divisor, and use
+        * only multiplications in the inner loop.
+        *
+        * This test should be read:
+        *       Does it ever help to use udiv_qrnnd_preinv?
+        *         && Does what we save compensate for the inversion overhead?
+        */
+       if (UDIV_TIME > (2 * UMUL_TIME + 6)
+                       && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) {
+               int normalization_steps;
+
+               normalization_steps = count_leading_zeros(divisor_limb);
+               if (normalization_steps) {
+                       mpi_limb_t divisor_limb_inverted;
+
+                       divisor_limb <<= normalization_steps;
+
+                       /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
+                        * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+                        * most significant bit (with weight 2**N) implicit.
+                        *
+                        * Special case for DIVISOR_LIMB == 100...000.
+                        */
+                       if (!(divisor_limb << 1))
+                               divisor_limb_inverted = ~(mpi_limb_t)0;
+                       else
+                               udiv_qrnnd(divisor_limb_inverted, dummy,
+                                               -divisor_limb, 0, divisor_limb);
+
+                       n1 = dividend_ptr[dividend_size - 1];
+                       r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+                       /* Possible optimization:
+                        * if (r == 0
+                        * && divisor_limb > ((n1 << normalization_steps)
+                        *                     | (dividend_ptr[dividend_size - 2] >> ...)))
+                        * ...one division less...
+                        */
+                       for (i = dividend_size - 2; i >= 0; i--) {
+                               n0 = dividend_ptr[i];
+                               UDIV_QRNND_PREINV(dummy, r, r,
+                                               ((n1 << normalization_steps)
+                                                | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+                                               divisor_limb, divisor_limb_inverted);
+                               n1 = n0;
+                       }
+                       UDIV_QRNND_PREINV(dummy, r, r,
+                                       n1 << normalization_steps,
+                                       divisor_limb, divisor_limb_inverted);
+                       return r >> normalization_steps;
+               } else {
+                       mpi_limb_t divisor_limb_inverted;
+
+                       /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
+                        * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+                        * most significant bit (with weight 2**N) implicit.
+                        *
+                        * Special case for DIVISOR_LIMB == 100...000.
+                        */
+                       if (!(divisor_limb << 1))
+                               divisor_limb_inverted = ~(mpi_limb_t)0;
+                       else
+                               udiv_qrnnd(divisor_limb_inverted, dummy,
+                                               -divisor_limb, 0, divisor_limb);
+
+                       i = dividend_size - 1;
+                       r = dividend_ptr[i];
+
+                       if (r >= divisor_limb)
+                               r = 0;
+                       else
+                               i--;
+
+                       for ( ; i >= 0; i--) {
+                               n0 = dividend_ptr[i];
+                               UDIV_QRNND_PREINV(dummy, r, r,
+                                               n0, divisor_limb, divisor_limb_inverted);
+                       }
+                       return r;
+               }
+       } else {
+               if (UDIV_NEEDS_NORMALIZATION) {
+                       int normalization_steps;
+
+                       normalization_steps = count_leading_zeros(divisor_limb);
+                       if (normalization_steps) {
+                               divisor_limb <<= normalization_steps;
+
+                               n1 = dividend_ptr[dividend_size - 1];
+                               r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+                               /* Possible optimization:
+                                * if (r == 0
+                                * && divisor_limb > ((n1 << normalization_steps)
+                                *                 | (dividend_ptr[dividend_size - 2] >> ...)))
+                                * ...one division less...
+                                */
+                               for (i = dividend_size - 2; i >= 0; i--) {
+                                       n0 = dividend_ptr[i];
+                                       udiv_qrnnd(dummy, r, r,
+                                               ((n1 << normalization_steps)
+                                                | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+                                               divisor_limb);
+                                       n1 = n0;
+                               }
+                               udiv_qrnnd(dummy, r, r,
+                                               n1 << normalization_steps,
+                                               divisor_limb);
+                               return r >> normalization_steps;
+                       }
+               }
+               /* No normalization needed, either because udiv_qrnnd doesn't require
+                * it, or because DIVISOR_LIMB is already normalized.
+                */
+               i = dividend_size - 1;
+               r = dividend_ptr[i];
+
+               if (r >= divisor_limb)
+                       r = 0;
+               else
+                       i--;
+
+               for (; i >= 0; i--) {
+                       n0 = dividend_ptr[i];
+                       udiv_qrnnd(dummy, r, r, n0, divisor_limb);
+               }
+               return r;
+       }
+}
+
 /* Divide num (NP/NSIZE) by den (DP/DSIZE) and write
  * the NSIZE-DSIZE least significant quotient limbs at QP
  * and the DSIZE long remainder at NP. If QEXTRA_LIMBS is
@@ -221,3 +365,153 @@ q_test:
 
        return most_significant_q_limb;
 }
+
+/****************
+ * Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB.
+ * Write DIVIDEND_SIZE limbs of quotient at QUOT_PTR.
+ * Return the single-limb remainder.
+ * There are no constraints on the value of the divisor.
+ *
+ * QUOT_PTR and DIVIDEND_PTR might point to the same limb.
+ */
+
+mpi_limb_t
+mpihelp_divmod_1(mpi_ptr_t quot_ptr,
+               mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+               mpi_limb_t divisor_limb)
+{
+       mpi_size_t i;
+       mpi_limb_t n1, n0, r;
+       mpi_limb_t dummy __maybe_unused;
+
+       if (!dividend_size)
+               return 0;
+
+       /* If multiplication is much faster than division, and the
+        * dividend is large, pre-invert the divisor, and use
+        * only multiplications in the inner loop.
+        *
+        * This test should be read:
+        * Does it ever help to use udiv_qrnnd_preinv?
+        * && Does what we save compensate for the inversion overhead?
+        */
+       if (UDIV_TIME > (2 * UMUL_TIME + 6)
+                       && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) {
+               int normalization_steps;
+
+               normalization_steps = count_leading_zeros(divisor_limb);
+               if (normalization_steps) {
+                       mpi_limb_t divisor_limb_inverted;
+
+                       divisor_limb <<= normalization_steps;
+
+                       /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
+                        * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+                        * most significant bit (with weight 2**N) implicit.
+                        */
+                       /* Special case for DIVISOR_LIMB == 100...000.  */
+                       if (!(divisor_limb << 1))
+                               divisor_limb_inverted = ~(mpi_limb_t)0;
+                       else
+                               udiv_qrnnd(divisor_limb_inverted, dummy,
+                                               -divisor_limb, 0, divisor_limb);
+
+                       n1 = dividend_ptr[dividend_size - 1];
+                       r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+                       /* Possible optimization:
+                        * if (r == 0
+                        * && divisor_limb > ((n1 << normalization_steps)
+                        *                     | (dividend_ptr[dividend_size - 2] >> ...)))
+                        * ...one division less...
+                        */
+                       for (i = dividend_size - 2; i >= 0; i--) {
+                               n0 = dividend_ptr[i];
+                               UDIV_QRNND_PREINV(quot_ptr[i + 1], r, r,
+                                               ((n1 << normalization_steps)
+                                                | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+                                               divisor_limb, divisor_limb_inverted);
+                               n1 = n0;
+                       }
+                       UDIV_QRNND_PREINV(quot_ptr[0], r, r,
+                                       n1 << normalization_steps,
+                                       divisor_limb, divisor_limb_inverted);
+                       return r >> normalization_steps;
+               } else {
+                       mpi_limb_t divisor_limb_inverted;
+
+                       /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
+                        * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+                        * most significant bit (with weight 2**N) implicit.
+                        */
+                       /* Special case for DIVISOR_LIMB == 100...000.  */
+                       if (!(divisor_limb << 1))
+                               divisor_limb_inverted = ~(mpi_limb_t) 0;
+                       else
+                               udiv_qrnnd(divisor_limb_inverted, dummy,
+                                               -divisor_limb, 0, divisor_limb);
+
+                       i = dividend_size - 1;
+                       r = dividend_ptr[i];
+
+                       if (r >= divisor_limb)
+                               r = 0;
+                       else
+                               quot_ptr[i--] = 0;
+
+                       for ( ; i >= 0; i--) {
+                               n0 = dividend_ptr[i];
+                               UDIV_QRNND_PREINV(quot_ptr[i], r, r,
+                                               n0, divisor_limb, divisor_limb_inverted);
+                       }
+                       return r;
+               }
+       } else {
+               if (UDIV_NEEDS_NORMALIZATION) {
+                       int normalization_steps;
+
+                       normalization_steps = count_leading_zeros(divisor_limb);
+                       if (normalization_steps) {
+                               divisor_limb <<= normalization_steps;
+
+                               n1 = dividend_ptr[dividend_size - 1];
+                               r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+                               /* Possible optimization:
+                                * if (r == 0
+                                * && divisor_limb > ((n1 << normalization_steps)
+                                *                 | (dividend_ptr[dividend_size - 2] >> ...)))
+                                * ...one division less...
+                                */
+                               for (i = dividend_size - 2; i >= 0; i--) {
+                                       n0 = dividend_ptr[i];
+                                       udiv_qrnnd(quot_ptr[i + 1], r, r,
+                                               ((n1 << normalization_steps)
+                                                | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+                                               divisor_limb);
+                                       n1 = n0;
+                               }
+                               udiv_qrnnd(quot_ptr[0], r, r,
+                                               n1 << normalization_steps,
+                                               divisor_limb);
+                               return r >> normalization_steps;
+                       }
+               }
+               /* No normalization needed, either because udiv_qrnnd doesn't require
+                * it, or because DIVISOR_LIMB is already normalized.
+                */
+               i = dividend_size - 1;
+               r = dividend_ptr[i];
+
+               if (r >= divisor_limb)
+                       r = 0;
+               else
+                       quot_ptr[i--] = 0;
+
+               for (; i >= 0; i--) {
+                       n0 = dividend_ptr[i];
+                       udiv_qrnnd(quot_ptr[i], r, r, n0, divisor_limb);
+               }
+               return r;
+       }
+}
index a936475..e5f1c84 100644 (file)
@@ -317,6 +317,31 @@ mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace)
        }
 }
 
+
+void mpihelp_mul_n(mpi_ptr_t prodp,
+               mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size)
+{
+       if (up == vp) {
+               if (size < KARATSUBA_THRESHOLD)
+                       mpih_sqr_n_basecase(prodp, up, size);
+               else {
+                       mpi_ptr_t tspace;
+                       tspace = mpi_alloc_limb_space(2 * size);
+                       mpih_sqr_n(prodp, up, size, tspace);
+                       mpi_free_limb_space(tspace);
+               }
+       } else {
+               if (size < KARATSUBA_THRESHOLD)
+                       mul_n_basecase(prodp, up, vp, size);
+               else {
+                       mpi_ptr_t tspace;
+                       tspace = mpi_alloc_limb_space(2 * size);
+                       mul_n(prodp, up, vp, size, tspace);
+                       mpi_free_limb_space(tspace);
+               }
+       }
+}
+
 int
 mpihelp_mul_karatsuba_case(mpi_ptr_t prodp,
                           mpi_ptr_t up, mpi_size_t usize,
index 4cd2b33..3c63710 100644 (file)
 
 #include "mpi-internal.h"
 
+/* Constants allocated right away at startup.  */
+static MPI constants[MPI_NUMBER_OF_CONSTANTS];
+
+/* Initialize the MPI subsystem.  This is called early and allows to
+ * do some initialization without taking care of threading issues.
+ */
+static int __init mpi_init(void)
+{
+       int idx;
+       unsigned long value;
+
+       for (idx = 0; idx < MPI_NUMBER_OF_CONSTANTS; idx++) {
+               switch (idx) {
+               case MPI_C_ZERO:
+                       value = 0;
+                       break;
+               case MPI_C_ONE:
+                       value = 1;
+                       break;
+               case MPI_C_TWO:
+                       value = 2;
+                       break;
+               case MPI_C_THREE:
+                       value = 3;
+                       break;
+               case MPI_C_FOUR:
+                       value = 4;
+                       break;
+               case MPI_C_EIGHT:
+                       value = 8;
+                       break;
+               default:
+                       pr_err("MPI: invalid mpi_const selector %d\n", idx);
+                       return -EFAULT;
+               }
+               constants[idx] = mpi_alloc_set_ui(value);
+               constants[idx]->flags = (16|32);
+       }
+
+       return 0;
+}
+postcore_initcall(mpi_init);
+
+/* Return a constant MPI descripbed by NO which is one of the
+ * MPI_C_xxx macros.  There is no need to copy this returned value; it
+ * may be used directly.
+ */
+MPI mpi_const(enum gcry_mpi_constants no)
+{
+       if ((int)no < 0 || no > MPI_NUMBER_OF_CONSTANTS)
+               pr_err("MPI: invalid mpi_const selector %d\n", no);
+       if (!constants[no])
+               pr_err("MPI: MPI subsystem not initialized\n");
+       return constants[no];
+}
+EXPORT_SYMBOL_GPL(mpi_const);
+
 /****************
  * Note:  It was a bad idea to use the number of limbs to allocate
  *       because on a alpha the limbs are large but we normally need
@@ -106,6 +163,15 @@ int mpi_resize(MPI a, unsigned nlimbs)
        return 0;
 }
 
+void mpi_clear(MPI a)
+{
+       if (!a)
+               return;
+       a->nlimbs = 0;
+       a->flags = 0;
+}
+EXPORT_SYMBOL_GPL(mpi_clear);
+
 void mpi_free(MPI a)
 {
        if (!a)
@@ -122,5 +188,143 @@ void mpi_free(MPI a)
 }
 EXPORT_SYMBOL_GPL(mpi_free);
 
+/****************
+ * Note: This copy function should not interpret the MPI
+ *      but copy it transparently.
+ */
+MPI mpi_copy(MPI a)
+{
+       int i;
+       MPI b;
+
+       if (a) {
+               b = mpi_alloc(a->nlimbs);
+               b->nlimbs = a->nlimbs;
+               b->sign = a->sign;
+               b->flags = a->flags;
+               b->flags &= ~(16|32); /* Reset the immutable and constant flags. */
+               for (i = 0; i < b->nlimbs; i++)
+                       b->d[i] = a->d[i];
+       } else
+               b = NULL;
+       return b;
+}
+
+/****************
+ * This function allocates an MPI which is optimized to hold
+ * a value as large as the one given in the argument and allocates it
+ * with the same flags as A.
+ */
+MPI mpi_alloc_like(MPI a)
+{
+       MPI b;
+
+       if (a) {
+               b = mpi_alloc(a->nlimbs);
+               b->nlimbs = 0;
+               b->sign = 0;
+               b->flags = a->flags;
+       } else
+               b = NULL;
+
+       return b;
+}
+
+
+/* Set U into W and release U.  If W is NULL only U will be released. */
+void mpi_snatch(MPI w, MPI u)
+{
+       if (w) {
+               mpi_assign_limb_space(w, u->d, u->alloced);
+               w->nlimbs = u->nlimbs;
+               w->sign   = u->sign;
+               w->flags  = u->flags;
+               u->alloced = 0;
+               u->nlimbs = 0;
+               u->d = NULL;
+       }
+       mpi_free(u);
+}
+
+
+MPI mpi_set(MPI w, MPI u)
+{
+       mpi_ptr_t wp, up;
+       mpi_size_t usize = u->nlimbs;
+       int usign = u->sign;
+
+       if (!w)
+               w = mpi_alloc(mpi_get_nlimbs(u));
+       RESIZE_IF_NEEDED(w, usize);
+       wp = w->d;
+       up = u->d;
+       MPN_COPY(wp, up, usize);
+       w->nlimbs = usize;
+       w->flags = u->flags;
+       w->flags &= ~(16|32); /* Reset the immutable and constant flags.  */
+       w->sign = usign;
+       return w;
+}
+EXPORT_SYMBOL_GPL(mpi_set);
+
+MPI mpi_set_ui(MPI w, unsigned long u)
+{
+       if (!w)
+               w = mpi_alloc(1);
+       /* FIXME: If U is 0 we have no need to resize and thus possible
+        * allocating the the limbs.
+        */
+       RESIZE_IF_NEEDED(w, 1);
+       w->d[0] = u;
+       w->nlimbs = u ? 1 : 0;
+       w->sign = 0;
+       w->flags = 0;
+       return w;
+}
+EXPORT_SYMBOL_GPL(mpi_set_ui);
+
+MPI mpi_alloc_set_ui(unsigned long u)
+{
+       MPI w = mpi_alloc(1);
+       w->d[0] = u;
+       w->nlimbs = u ? 1 : 0;
+       w->sign = 0;
+       return w;
+}
+
+/****************
+ * Swap the value of A and B, when SWAP is 1.
+ * Leave the value when SWAP is 0.
+ * This implementation should be constant-time regardless of SWAP.
+ */
+void mpi_swap_cond(MPI a, MPI b, unsigned long swap)
+{
+       mpi_size_t i;
+       mpi_size_t nlimbs;
+       mpi_limb_t mask = ((mpi_limb_t)0) - swap;
+       mpi_limb_t x;
+
+       if (a->alloced > b->alloced)
+               nlimbs = b->alloced;
+       else
+               nlimbs = a->alloced;
+       if (a->nlimbs > nlimbs || b->nlimbs > nlimbs)
+               return;
+
+       for (i = 0; i < nlimbs; i++) {
+               x = mask & (a->d[i] ^ b->d[i]);
+               a->d[i] = a->d[i] ^ x;
+               b->d[i] = b->d[i] ^ x;
+       }
+
+       x = mask & (a->nlimbs ^ b->nlimbs);
+       a->nlimbs = a->nlimbs ^ x;
+       b->nlimbs = b->nlimbs ^ x;
+
+       x = mask & (a->sign ^ b->sign);
+       a->sign = a->sign ^ x;
+       b->sign = b->sign ^ x;
+}
+
 MODULE_DESCRIPTION("Multiprecision maths library");
 MODULE_LICENSE("GPL");
index a2345de..f61689a 100644 (file)
@@ -17,7 +17,7 @@ static DEFINE_SPINLOCK(percpu_counters_lock);
 
 #ifdef CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER
 
-static struct debug_obj_descr percpu_counter_debug_descr;
+static const struct debug_obj_descr percpu_counter_debug_descr;
 
 static bool percpu_counter_fixup_free(void *addr, enum debug_obj_state state)
 {
@@ -33,7 +33,7 @@ static bool percpu_counter_fixup_free(void *addr, enum debug_obj_state state)
        }
 }
 
-static struct debug_obj_descr percpu_counter_debug_descr = {
+static const struct debug_obj_descr percpu_counter_debug_descr = {
        .name           = "percpu_counter",
        .fixup_free     = percpu_counter_fixup_free,
 };
index 9323453..dfb9981 100644 (file)
@@ -49,7 +49,7 @@ static inline void prandom_state_selftest(void)
 }
 #endif
 
-DEFINE_PER_CPU(struct rnd_state, net_rand_state);
+DEFINE_PER_CPU(struct rnd_state, net_rand_state)  __latent_entropy;
 
 /**
  *     prandom_u32_state - seeded pseudo-random number generator.
index 6012c38..4288e01 100644 (file)
@@ -272,6 +272,30 @@ ssize_t strscpy_pad(char *dest, const char *src, size_t count)
 }
 EXPORT_SYMBOL(strscpy_pad);
 
+/**
+ * stpcpy - copy a string from src to dest returning a pointer to the new end
+ *          of dest, including src's %NUL-terminator. May overrun dest.
+ * @dest: pointer to end of string being copied into. Must be large enough
+ *        to receive copy.
+ * @src: pointer to the beginning of string being copied from. Must not overlap
+ *       dest.
+ *
+ * stpcpy differs from strcpy in a key way: the return value is a pointer
+ * to the new %NUL-terminating character in @dest. (For strcpy, the return
+ * value is a pointer to the start of @dest). This interface is considered
+ * unsafe as it doesn't perform bounds checking of the inputs. As such it's
+ * not recommended for usage. Instead, its definition is provided in case
+ * the compiler lowers other libcalls to stpcpy.
+ */
+char *stpcpy(char *__restrict__ dest, const char *__restrict__ src);
+char *stpcpy(char *__restrict__ dest, const char *__restrict__ src)
+{
+       while ((*dest++ = *src++) != '\0')
+               /* nothing */;
+       return --dest;
+}
+EXPORT_SYMBOL(stpcpy);
+
 #ifndef __HAVE_ARCH_STRCAT
 /**
  * strcat - Append one %NUL-terminated string to another
index 9fee2b9..06c9550 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/vmalloc.h>
 #include <linux/efi_embedded_fw.h>
 
+MODULE_IMPORT_NS(TEST_FIRMWARE);
+
 #define TEST_FIRMWARE_NAME     "test-firmware.bin"
 #define TEST_FIRMWARE_NUM_REQS 4
 #define TEST_FIRMWARE_BUF_SIZE SZ_1K
@@ -489,6 +491,9 @@ out:
 static DEVICE_ATTR_WO(trigger_request);
 
 #ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
+extern struct list_head efi_embedded_fw_list;
+extern bool efi_embedded_fw_checked;
+
 static ssize_t trigger_request_platform_store(struct device *dev,
                                              struct device_attribute *attr,
                                              const char *buf, size_t count)
@@ -501,6 +506,7 @@ static ssize_t trigger_request_platform_store(struct device *dev,
        };
        struct efi_embedded_fw efi_embedded_fw;
        const struct firmware *firmware = NULL;
+       bool saved_efi_embedded_fw_checked;
        char *name;
        int rc;
 
@@ -513,6 +519,8 @@ static ssize_t trigger_request_platform_store(struct device *dev,
        efi_embedded_fw.data = (void *)test_data;
        efi_embedded_fw.length = sizeof(test_data);
        list_add(&efi_embedded_fw.list, &efi_embedded_fw_list);
+       saved_efi_embedded_fw_checked = efi_embedded_fw_checked;
+       efi_embedded_fw_checked = true;
 
        pr_info("loading '%s'\n", name);
        rc = firmware_request_platform(&firmware, name, dev);
@@ -530,6 +538,7 @@ static ssize_t trigger_request_platform_store(struct device *dev,
        rc = count;
 
 out:
+       efi_embedded_fw_checked = saved_efi_embedded_fw_checked;
        release_firmware(firmware);
        list_del(&efi_embedded_fw.list);
        kfree(name);
index c5a6fef..76c607e 100644 (file)
@@ -434,7 +434,7 @@ static int __init test_rhltable(unsigned int entries)
                } else {
                        if (WARN(err != -ENOENT, "removed non-existent element, error %d not %d",
                                 err, -ENOENT))
-                       continue;
+                               continue;
                }
        }
 
index c155769..afb9521 100644 (file)
@@ -1681,7 +1681,8 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
 
        switch (*(++fmt)) {
        case 'L':
-               uc = true;              /* fall-through */
+               uc = true;
+               /* fall through */
        case 'l':
                index = guid_index;
                break;
@@ -2218,7 +2219,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
        case 'S':
        case 's':
                ptr = dereference_symbol_descriptor(ptr);
-               /* Fallthrough */
+               /* fall through */
        case 'B':
                return symbol_string(buf, end, ptr, spec, fmt);
        case 'R':
@@ -2467,7 +2468,7 @@ qualifier:
                 * utility, treat it as any other invalid or
                 * unsupported format specifier.
                 */
-               /* Fall-through */
+               /* fall through */
 
        default:
                WARN_ONCE(1, "Please remove unsupported %%%c in format string\n", *fmt);
index 9f336bc..65a1aad 100644 (file)
@@ -1043,7 +1043,7 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
 
                        s->lzma2.sequence = SEQ_LZMA_PREPARE;
 
-               /* Fall through */
+                       /* fall through */
 
                case SEQ_LZMA_PREPARE:
                        if (s->lzma2.compressed < RC_INIT_BYTES)
@@ -1055,7 +1055,7 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
                        s->lzma2.compressed -= RC_INIT_BYTES;
                        s->lzma2.sequence = SEQ_LZMA_RUN;
 
-               /* Fall through */
+                       /* fall through */
 
                case SEQ_LZMA_RUN:
                        /*
index bd1d182..32ab2a0 100644 (file)
@@ -583,7 +583,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
                        if (ret != XZ_OK)
                                return ret;
 
-               /* Fall through */
+                       /* fall through */
 
                case SEQ_BLOCK_START:
                        /* We need one byte of input to continue. */
@@ -608,7 +608,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
                        s->temp.pos = 0;
                        s->sequence = SEQ_BLOCK_HEADER;
 
-               /* Fall through */
+                       /* fall through */
 
                case SEQ_BLOCK_HEADER:
                        if (!fill_temp(s, b))
@@ -620,7 +620,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
 
                        s->sequence = SEQ_BLOCK_UNCOMPRESS;
 
-               /* Fall through */
+                       /* fall through */
 
                case SEQ_BLOCK_UNCOMPRESS:
                        ret = dec_block(s, b);
@@ -629,7 +629,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
 
                        s->sequence = SEQ_BLOCK_PADDING;
 
-               /* Fall through */
+                       /* fall through */
 
                case SEQ_BLOCK_PADDING:
                        /*
@@ -651,7 +651,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
 
                        s->sequence = SEQ_BLOCK_CHECK;
 
-               /* Fall through */
+                       /* fall through */
 
                case SEQ_BLOCK_CHECK:
                        if (s->check_type == XZ_CHECK_CRC32) {
@@ -675,7 +675,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
 
                        s->sequence = SEQ_INDEX_PADDING;
 
-               /* Fall through */
+                       /* fall through */
 
                case SEQ_INDEX_PADDING:
                        while ((s->index.size + (b->in_pos - s->in_start))
@@ -699,7 +699,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
 
                        s->sequence = SEQ_INDEX_CRC32;
 
-               /* Fall through */
+                       /* fall through */
 
                case SEQ_INDEX_CRC32:
                        ret = crc32_validate(s, b);
@@ -709,7 +709,7 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
                        s->temp.size = STREAM_HEADER_SIZE;
                        s->sequence = SEQ_STREAM_FOOTER;
 
-               /* Fall through */
+                       /* fall through */
 
                case SEQ_STREAM_FOOTER:
                        if (!fill_temp(s, b))
index 269ee9a..db6761e 100644 (file)
@@ -442,7 +442,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx *dctx, const void *src, size_t srcSize
                case set_repeat:
                        if (dctx->litEntropy == 0)
                                return ERROR(dictionary_corrupted);
-               /* fall-through */
+                       /* fall through */
                case set_compressed:
                        if (srcSize < 5)
                                return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */
@@ -2309,7 +2309,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inB
                switch (zds->stage) {
                case zdss_init:
                        ZSTD_resetDStream(zds); /* transparent reset on starting decoding a new frame */
-                                               /* fall-through */
+                       /* fall through */
 
                case zdss_loadHeader: {
                        size_t const hSize = ZSTD_getFrameParams(&zds->fParams, zds->headerBuffer, zds->lhSize);
@@ -2376,7 +2376,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inB
                        }
                        zds->stage = zdss_read;
                }
-               /* fall through */
+                       /* fall through */
 
                case zdss_read: {
                        size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
@@ -2405,7 +2405,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inB
                        zds->stage = zdss_load;
                        /* pass-through */
                }
-               /* fall through */
+                       /* fall through */
 
                case zdss_load: {
                        size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
@@ -2438,7 +2438,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inB
                                /* pass-through */
                        }
                }
-               /* fall through */
+                       /* fall through */
 
                case zdss_flush: {
                        size_t const toFlushSize = zds->outEnd - zds->outStart;
index 6c97488..e3ee7b3 100644 (file)
@@ -383,7 +383,7 @@ config NOMMU_INITIAL_TRIM_EXCESS
          This option specifies the initial value of this option.  The default
          of 1 says that all excess pages should be trimmed.
 
-         See Documentation/mm/nommu-mmap.rst for more information.
+         See Documentation/admin-guide/mm/nommu-mmap.rst for more information.
 
 config TRANSPARENT_HUGEPAGE
        bool "Transparent Hugepage Support"
index 1aaea26..99c49ee 100644 (file)
@@ -988,9 +988,43 @@ void __init pagecache_init(void)
        page_writeback_init();
 }
 
+/*
+ * The page wait code treats the "wait->flags" somewhat unusually, because
+ * we have multiple different kinds of waits, not just the usual "exclusive"
+ * one.
+ *
+ * We have:
+ *
+ *  (a) no special bits set:
+ *
+ *     We're just waiting for the bit to be released, and when a waker
+ *     calls the wakeup function, we set WQ_FLAG_WOKEN and wake it up,
+ *     and remove it from the wait queue.
+ *
+ *     Simple and straightforward.
+ *
+ *  (b) WQ_FLAG_EXCLUSIVE:
+ *
+ *     The waiter is waiting to get the lock, and only one waiter should
+ *     be woken up to avoid any thundering herd behavior. We'll set the
+ *     WQ_FLAG_WOKEN bit, wake it up, and remove it from the wait queue.
+ *
+ *     This is the traditional exclusive wait.
+ *
+ *  (c) WQ_FLAG_EXCLUSIVE | WQ_FLAG_CUSTOM:
+ *
+ *     The waiter is waiting to get the bit, and additionally wants the
+ *     lock to be transferred to it for fair lock behavior. If the lock
+ *     cannot be taken, we stop walking the wait queue without waking
+ *     the waiter.
+ *
+ *     This is the "fair lock handoff" case, and in addition to setting
+ *     WQ_FLAG_WOKEN, we set WQ_FLAG_DONE to let the waiter easily see
+ *     that it now has the lock.
+ */
 static int wake_page_function(wait_queue_entry_t *wait, unsigned mode, int sync, void *arg)
 {
-       int ret;
+       unsigned int flags;
        struct wait_page_key *key = arg;
        struct wait_page_queue *wait_page
                = container_of(wait, struct wait_page_queue, wait);
@@ -999,35 +1033,44 @@ static int wake_page_function(wait_queue_entry_t *wait, unsigned mode, int sync,
                return 0;
 
        /*
-        * If it's an exclusive wait, we get the bit for it, and
-        * stop walking if we can't.
-        *
-        * If it's a non-exclusive wait, then the fact that this
-        * wake function was called means that the bit already
-        * was cleared, and we don't care if somebody then
-        * re-took it.
+        * If it's a lock handoff wait, we get the bit for it, and
+        * stop walking (and do not wake it up) if we can't.
         */
-       ret = 0;
-       if (wait->flags & WQ_FLAG_EXCLUSIVE) {
-               if (test_and_set_bit(key->bit_nr, &key->page->flags))
+       flags = wait->flags;
+       if (flags & WQ_FLAG_EXCLUSIVE) {
+               if (test_bit(key->bit_nr, &key->page->flags))
                        return -1;
-               ret = 1;
+               if (flags & WQ_FLAG_CUSTOM) {
+                       if (test_and_set_bit(key->bit_nr, &key->page->flags))
+                               return -1;
+                       flags |= WQ_FLAG_DONE;
+               }
        }
-       wait->flags |= WQ_FLAG_WOKEN;
 
+       /*
+        * We are holding the wait-queue lock, but the waiter that
+        * is waiting for this will be checking the flags without
+        * any locking.
+        *
+        * So update the flags atomically, and wake up the waiter
+        * afterwards to avoid any races. This store-release pairs
+        * with the load-acquire in wait_on_page_bit_common().
+        */
+       smp_store_release(&wait->flags, flags | WQ_FLAG_WOKEN);
        wake_up_state(wait->private, mode);
 
        /*
         * Ok, we have successfully done what we're waiting for,
         * and we can unconditionally remove the wait entry.
         *
-        * Note that this has to be the absolute last thing we do,
-        * since after list_del_init(&wait->entry) the wait entry
+        * Note that this pairs with the "finish_wait()" in the
+        * waiter, and has to be the absolute last thing we do.
+        * After this list_del_init(&wait->entry) the wait entry
         * might be de-allocated and the process might even have
         * exited.
         */
        list_del_init_careful(&wait->entry);
-       return ret;
+       return (flags & WQ_FLAG_EXCLUSIVE) != 0;
 }
 
 static void wake_up_page_bit(struct page *page, int bit_nr)
@@ -1107,8 +1150,8 @@ enum behavior {
 };
 
 /*
- * Attempt to check (or get) the page bit, and mark the
- * waiter woken if successful.
+ * Attempt to check (or get) the page bit, and mark us done
+ * if successful.
  */
 static inline bool trylock_page_bit_common(struct page *page, int bit_nr,
                                        struct wait_queue_entry *wait)
@@ -1119,13 +1162,17 @@ static inline bool trylock_page_bit_common(struct page *page, int bit_nr,
        } else if (test_bit(bit_nr, &page->flags))
                return false;
 
-       wait->flags |= WQ_FLAG_WOKEN;
+       wait->flags |= WQ_FLAG_WOKEN | WQ_FLAG_DONE;
        return true;
 }
 
+/* How many times do we accept lock stealing from under a waiter? */
+int sysctl_page_lock_unfairness = 5;
+
 static inline int wait_on_page_bit_common(wait_queue_head_t *q,
        struct page *page, int bit_nr, int state, enum behavior behavior)
 {
+       int unfairness = sysctl_page_lock_unfairness;
        struct wait_page_queue wait_page;
        wait_queue_entry_t *wait = &wait_page.wait;
        bool thrashing = false;
@@ -1143,11 +1190,18 @@ static inline int wait_on_page_bit_common(wait_queue_head_t *q,
        }
 
        init_wait(wait);
-       wait->flags = behavior == EXCLUSIVE ? WQ_FLAG_EXCLUSIVE : 0;
        wait->func = wake_page_function;
        wait_page.page = page;
        wait_page.bit_nr = bit_nr;
 
+repeat:
+       wait->flags = 0;
+       if (behavior == EXCLUSIVE) {
+               wait->flags = WQ_FLAG_EXCLUSIVE;
+               if (--unfairness < 0)
+                       wait->flags |= WQ_FLAG_CUSTOM;
+       }
+
        /*
         * Do one last check whether we can get the
         * page bit synchronously.
@@ -1170,27 +1224,63 @@ static inline int wait_on_page_bit_common(wait_queue_head_t *q,
 
        /*
         * From now on, all the logic will be based on
-        * the WQ_FLAG_WOKEN flag, and the and the page
-        * bit testing (and setting) will be - or has
-        * already been - done by the wake function.
+        * the WQ_FLAG_WOKEN and WQ_FLAG_DONE flag, to
+        * see whether the page bit testing has already
+        * been done by the wake function.
         *
         * We can drop our reference to the page.
         */
        if (behavior == DROP)
                put_page(page);
 
+       /*
+        * Note that until the "finish_wait()", or until
+        * we see the WQ_FLAG_WOKEN flag, we need to
+        * be very careful with the 'wait->flags', because
+        * we may race with a waker that sets them.
+        */
        for (;;) {
+               unsigned int flags;
+
                set_current_state(state);
 
-               if (signal_pending_state(state, current))
+               /* Loop until we've been woken or interrupted */
+               flags = smp_load_acquire(&wait->flags);
+               if (!(flags & WQ_FLAG_WOKEN)) {
+                       if (signal_pending_state(state, current))
+                               break;
+
+                       io_schedule();
+                       continue;
+               }
+
+               /* If we were non-exclusive, we're done */
+               if (behavior != EXCLUSIVE)
                        break;
 
-               if (wait->flags & WQ_FLAG_WOKEN)
+               /* If the waker got the lock for us, we're done */
+               if (flags & WQ_FLAG_DONE)
                        break;
 
-               io_schedule();
+               /*
+                * Otherwise, if we're getting the lock, we need to
+                * try to get it ourselves.
+                *
+                * And if that fails, we'll have to retry this all.
+                */
+               if (unlikely(test_and_set_bit(bit_nr, &page->flags)))
+                       goto repeat;
+
+               wait->flags |= WQ_FLAG_DONE;
+               break;
        }
 
+       /*
+        * If a signal happened, this 'finish_wait()' may remove the last
+        * waiter from the wait-queues, but the PageWaiters bit will remain
+        * set. That's ok. The next wakeup will take care of it, and trying
+        * to do it here would be difficult and prone to races.
+        */
        finish_wait(q, wait);
 
        if (thrashing) {
@@ -1200,12 +1290,20 @@ static inline int wait_on_page_bit_common(wait_queue_head_t *q,
        }
 
        /*
-        * A signal could leave PageWaiters set. Clearing it here if
-        * !waitqueue_active would be possible (by open-coding finish_wait),
-        * but still fail to catch it in the case of wait hash collision. We
-        * already can fail to clear wait hash collision cases, so don't
-        * bother with signals either.
+        * NOTE! The wait->flags weren't stable until we've done the
+        * 'finish_wait()', and we could have exited the loop above due
+        * to a signal, and had a wakeup event happen after the signal
+        * test but before the 'finish_wait()'.
+        *
+        * So only after the finish_wait() can we reliably determine
+        * if we got woken up or not, so we can now figure out the final
+        * return value based on that state without races.
+        *
+        * Also note that WQ_FLAG_WOKEN is sufficient for a non-exclusive
+        * waiter, but an exclusive one requires WQ_FLAG_DONE.
         */
+       if (behavior == EXCLUSIVE)
+               return wait->flags & WQ_FLAG_DONE ? 0 : -EINTR;
 
        return wait->flags & WQ_FLAG_WOKEN ? 0 : -EINTR;
 }
@@ -2267,7 +2365,11 @@ readpage:
                }
 
                if (!PageUptodate(page)) {
-                       error = lock_page_killable(page);
+                       if (iocb->ki_flags & IOCB_WAITQ)
+                               error = lock_page_async(page, iocb->ki_waitq);
+                       else
+                               error = lock_page_killable(page);
+
                        if (unlikely(error))
                                goto readpage_error;
                        if (!PageUptodate(page)) {
index ae096ea..e869c63 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -381,22 +381,13 @@ static int follow_pfn_pte(struct vm_area_struct *vma, unsigned long address,
 }
 
 /*
- * FOLL_FORCE or a forced COW break can write even to unwritable pte's,
- * but only after we've gone through a COW cycle and they are dirty.
+ * FOLL_FORCE can write to even unwritable pte's, but only
+ * after we've gone through a COW cycle and they are dirty.
  */
 static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
 {
-       return pte_write(pte) || ((flags & FOLL_COW) && pte_dirty(pte));
-}
-
-/*
- * A (separate) COW fault might break the page the other way and
- * get_user_pages() would return the page from what is now the wrong
- * VM. So we need to force a COW break at GUP time even for reads.
- */
-static inline bool should_force_cow_break(struct vm_area_struct *vma, unsigned int flags)
-{
-       return is_cow_mapping(vma->vm_flags) && (flags & (FOLL_GET | FOLL_PIN));
+       return pte_write(pte) ||
+               ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
 }
 
 static struct page *follow_page_pte(struct vm_area_struct *vma,
@@ -843,7 +834,7 @@ static int get_gate_page(struct mm_struct *mm, unsigned long address,
                        goto unmap;
                *page = pte_page(*pte);
        }
-       if (unlikely(!try_get_page(*page))) {
+       if (unlikely(!try_grab_page(*page, gup_flags))) {
                ret = -ENOMEM;
                goto unmap;
        }
@@ -1067,11 +1058,9 @@ static long __get_user_pages(struct mm_struct *mm,
                                goto out;
                        }
                        if (is_vm_hugetlb_page(vma)) {
-                               if (should_force_cow_break(vma, foll_flags))
-                                       foll_flags |= FOLL_WRITE;
                                i = follow_hugetlb_page(mm, vma, pages, vmas,
                                                &start, &nr_pages, i,
-                                               foll_flags, locked);
+                                               gup_flags, locked);
                                if (locked && *locked == 0) {
                                        /*
                                         * We've got a VM_FAULT_RETRY
@@ -1085,10 +1074,6 @@ static long __get_user_pages(struct mm_struct *mm,
                                continue;
                        }
                }
-
-               if (should_force_cow_break(vma, foll_flags))
-                       foll_flags |= FOLL_WRITE;
-
 retry:
                /*
                 * If we have a pending SIGKILL, don't keep faulting pages and
@@ -1270,6 +1255,9 @@ static __always_inline long __get_user_pages_locked(struct mm_struct *mm,
                BUG_ON(*locked != 1);
        }
 
+       if (flags & FOLL_PIN)
+               atomic_set(&mm->has_pinned, 1);
+
        /*
         * FOLL_PIN and FOLL_GET are mutually exclusive. Traditional behavior
         * is to set FOLL_GET if the caller wants pages[] filled in (but has
@@ -2500,13 +2488,13 @@ static int gup_huge_pgd(pgd_t orig, pgd_t *pgdp, unsigned long addr,
        return 1;
 }
 
-static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
+static int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, unsigned long end,
                unsigned int flags, struct page **pages, int *nr)
 {
        unsigned long next;
        pmd_t *pmdp;
 
-       pmdp = pmd_offset(&pud, addr);
+       pmdp = pmd_offset_lockless(pudp, pud, addr);
        do {
                pmd_t pmd = READ_ONCE(*pmdp);
 
@@ -2543,13 +2531,13 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
        return 1;
 }
 
-static int gup_pud_range(p4d_t p4d, unsigned long addr, unsigned long end,
+static int gup_pud_range(p4d_t *p4dp, p4d_t p4d, unsigned long addr, unsigned long end,
                         unsigned int flags, struct page **pages, int *nr)
 {
        unsigned long next;
        pud_t *pudp;
 
-       pudp = pud_offset(&p4d, addr);
+       pudp = pud_offset_lockless(p4dp, p4d, addr);
        do {
                pud_t pud = READ_ONCE(*pudp);
 
@@ -2564,20 +2552,20 @@ static int gup_pud_range(p4d_t p4d, unsigned long addr, unsigned long end,
                        if (!gup_huge_pd(__hugepd(pud_val(pud)), addr,
                                         PUD_SHIFT, next, flags, pages, nr))
                                return 0;
-               } else if (!gup_pmd_range(pud, addr, next, flags, pages, nr))
+               } else if (!gup_pmd_range(pudp, pud, addr, next, flags, pages, nr))
                        return 0;
        } while (pudp++, addr = next, addr != end);
 
        return 1;
 }
 
-static int gup_p4d_range(pgd_t pgd, unsigned long addr, unsigned long end,
+static int gup_p4d_range(pgd_t *pgdp, pgd_t pgd, unsigned long addr, unsigned long end,
                         unsigned int flags, struct page **pages, int *nr)
 {
        unsigned long next;
        p4d_t *p4dp;
 
-       p4dp = p4d_offset(&pgd, addr);
+       p4dp = p4d_offset_lockless(pgdp, pgd, addr);
        do {
                p4d_t p4d = READ_ONCE(*p4dp);
 
@@ -2589,7 +2577,7 @@ static int gup_p4d_range(pgd_t pgd, unsigned long addr, unsigned long end,
                        if (!gup_huge_pd(__hugepd(p4d_val(p4d)), addr,
                                         P4D_SHIFT, next, flags, pages, nr))
                                return 0;
-               } else if (!gup_pud_range(p4d, addr, next, flags, pages, nr))
+               } else if (!gup_pud_range(p4dp, p4d, addr, next, flags, pages, nr))
                        return 0;
        } while (p4dp++, addr = next, addr != end);
 
@@ -2617,7 +2605,7 @@ static void gup_pgd_range(unsigned long addr, unsigned long end,
                        if (!gup_huge_pd(__hugepd(pgd_val(pgd)), addr,
                                         PGDIR_SHIFT, next, flags, pages, nr))
                                return;
-               } else if (!gup_p4d_range(pgd, addr, next, flags, pages, nr))
+               } else if (!gup_p4d_range(pgdp, pgd, addr, next, flags, pages, nr))
                        return;
        } while (pgdp++, addr = next, addr != end);
 }
@@ -2675,6 +2663,9 @@ static int internal_get_user_pages_fast(unsigned long start, int nr_pages,
                                       FOLL_FAST_ONLY)))
                return -EINVAL;
 
+       if (gup_flags & FOLL_PIN)
+               atomic_set(&current->mm->has_pinned, 1);
+
        if (!(gup_flags & FOLL_FAST_ONLY))
                might_lock_read(&current->mm->mmap_lock);
 
@@ -2689,19 +2680,6 @@ static int internal_get_user_pages_fast(unsigned long start, int nr_pages,
                return -EFAULT;
 
        /*
-        * The FAST_GUP case requires FOLL_WRITE even for pure reads,
-        * because get_user_pages() may need to cause an early COW in
-        * order to avoid confusing the normal COW routines. So only
-        * targets that are already writable are safe to do by just
-        * looking at the page tables.
-        *
-        * NOTE! With FOLL_FAST_ONLY we allow read-only gup_fast() here,
-        * because there is no slow path to fall back on. But you'd
-        * better be careful about possible COW pages - you'll get _a_
-        * COW page, but not necessarily the one you intended to get
-        * depending on what COW event happens after this. COW may break
-        * the page copy in a random direction.
-        *
         * Disable interrupts. The nested form is used, in order to allow
         * full, general purpose use of this routine.
         *
@@ -2714,8 +2692,6 @@ static int internal_get_user_pages_fast(unsigned long start, int nr_pages,
         */
        if (IS_ENABLED(CONFIG_HAVE_FAST_GUP) && gup_fast_permitted(start, end)) {
                unsigned long fast_flags = gup_flags;
-               if (!(gup_flags & FOLL_FAST_ONLY))
-                       fast_flags |= FOLL_WRITE;
 
                local_irq_save(flags);
                gup_pgd_range(addr, end, fast_flags, pages, &nr_pinned);
index 2ccff84..ec0f0cc 100644 (file)
@@ -1074,6 +1074,24 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 
        src_page = pmd_page(pmd);
        VM_BUG_ON_PAGE(!PageHead(src_page), src_page);
+
+       /*
+        * If this page is a potentially pinned page, split and retry the fault
+        * with smaller page size.  Normally this should not happen because the
+        * userspace should use MADV_DONTFORK upon pinned regions.  This is a
+        * best effort that the pinned pages won't be replaced by another
+        * random page during the coming copy-on-write.
+        */
+       if (unlikely(is_cow_mapping(vma->vm_flags) &&
+                    atomic_read(&src_mm->has_pinned) &&
+                    page_maybe_dma_pinned(src_page))) {
+               pte_free(dst_mm, pgtable);
+               spin_unlock(src_ptl);
+               spin_unlock(dst_ptl);
+               __split_huge_pmd(vma, src_pmd, addr, false, NULL);
+               return -EAGAIN;
+       }
+
        get_page(src_page);
        page_dup_rmap(src_page, true);
        add_mm_counter(dst_mm, MM_ANONPAGES, HPAGE_PMD_NR);
@@ -1177,6 +1195,16 @@ int copy_huge_pud(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                /* No huge zero pud yet */
        }
 
+       /* Please refer to comments in copy_huge_pmd() */
+       if (unlikely(is_cow_mapping(vma->vm_flags) &&
+                    atomic_read(&src_mm->has_pinned) &&
+                    page_maybe_dma_pinned(pud_page(pud)))) {
+               spin_unlock(src_ptl);
+               spin_unlock(dst_ptl);
+               __split_huge_pud(vma, src_pud, addr);
+               return -EAGAIN;
+       }
+
        pudp_set_wrprotect(src_mm, addr, src_pud);
        pud = pud_mkold(pud_wrprotect(pud));
        set_pud_at(dst_mm, addr, dst_pud, pud);
@@ -1291,12 +1319,13 @@ fallback:
 }
 
 /*
- * FOLL_FORCE or a forced COW break can write even to unwritable pmd's,
- * but only after we've gone through a COW cycle and they are dirty.
+ * FOLL_FORCE can write to even unwritable pmd's, but only
+ * after we've gone through a COW cycle and they are dirty.
  */
 static inline bool can_follow_write_pmd(pmd_t pmd, unsigned int flags)
 {
-       return pmd_write(pmd) || ((flags & FOLL_COW) && pmd_dirty(pmd));
+       return pmd_write(pmd) ||
+              ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pmd_dirty(pmd));
 }
 
 struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
@@ -2021,7 +2050,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
                put_page(page);
                add_mm_counter(mm, mm_counter_file(page), -HPAGE_PMD_NR);
                return;
-       } else if (is_huge_zero_pmd(*pmd)) {
+       } else if (pmd_trans_huge(*pmd) && is_huge_zero_pmd(*pmd)) {
                /*
                 * FIXME: Do we want to invalidate secondary mmu by calling
                 * mmu_notifier_invalidate_range() see comments below inside
@@ -2115,30 +2144,34 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
                pte = pte_offset_map(&_pmd, addr);
                BUG_ON(!pte_none(*pte));
                set_pte_at(mm, addr, pte, entry);
-               atomic_inc(&page[i]._mapcount);
-               pte_unmap(pte);
-       }
-
-       /*
-        * Set PG_double_map before dropping compound_mapcount to avoid
-        * false-negative page_mapped().
-        */
-       if (compound_mapcount(page) > 1 && !TestSetPageDoubleMap(page)) {
-               for (i = 0; i < HPAGE_PMD_NR; i++)
+               if (!pmd_migration)
                        atomic_inc(&page[i]._mapcount);
+               pte_unmap(pte);
        }
 
-       lock_page_memcg(page);
-       if (atomic_add_negative(-1, compound_mapcount_ptr(page))) {
-               /* Last compound_mapcount is gone. */
-               __dec_lruvec_page_state(page, NR_ANON_THPS);
-               if (TestClearPageDoubleMap(page)) {
-                       /* No need in mapcount reference anymore */
+       if (!pmd_migration) {
+               /*
+                * Set PG_double_map before dropping compound_mapcount to avoid
+                * false-negative page_mapped().
+                */
+               if (compound_mapcount(page) > 1 &&
+                   !TestSetPageDoubleMap(page)) {
                        for (i = 0; i < HPAGE_PMD_NR; i++)
-                               atomic_dec(&page[i]._mapcount);
+                               atomic_inc(&page[i]._mapcount);
                }
+
+               lock_page_memcg(page);
+               if (atomic_add_negative(-1, compound_mapcount_ptr(page))) {
+                       /* Last compound_mapcount is gone. */
+                       __dec_lruvec_page_state(page, NR_ANON_THPS);
+                       if (TestClearPageDoubleMap(page)) {
+                               /* No need in mapcount reference anymore */
+                               for (i = 0; i < HPAGE_PMD_NR; i++)
+                                       atomic_dec(&page[i]._mapcount);
+                       }
+               }
+               unlock_page_memcg(page);
        }
-       unlock_page_memcg(page);
 
        smp_wmb(); /* make pte visible before pmd */
        pmd_populate(mm, pmd, pgtable);
@@ -2337,6 +2370,9 @@ static void __split_huge_page_tail(struct page *head, int tail,
                         (1L << PG_workingset) |
                         (1L << PG_locked) |
                         (1L << PG_unevictable) |
+#ifdef CONFIG_64BIT
+                        (1L << PG_arch_2) |
+#endif
                         (1L << PG_dirty)));
 
        /* ->mapping in first tail page is compound_mapcount */
index a301c2d..67fc638 100644 (file)
@@ -1250,21 +1250,32 @@ static struct page *alloc_gigantic_page(struct hstate *h, gfp_t gfp_mask,
                int nid, nodemask_t *nodemask)
 {
        unsigned long nr_pages = 1UL << huge_page_order(h);
+       if (nid == NUMA_NO_NODE)
+               nid = numa_mem_id();
 
 #ifdef CONFIG_CMA
        {
                struct page *page;
                int node;
 
-               for_each_node_mask(node, *nodemask) {
-                       if (!hugetlb_cma[node])
-                               continue;
-
-                       page = cma_alloc(hugetlb_cma[node], nr_pages,
-                                        huge_page_order(h), true);
+               if (hugetlb_cma[nid]) {
+                       page = cma_alloc(hugetlb_cma[nid], nr_pages,
+                                       huge_page_order(h), true);
                        if (page)
                                return page;
                }
+
+               if (!(gfp_mask & __GFP_THISNODE)) {
+                       for_each_node_mask(node, *nodemask) {
+                               if (node == nid || !hugetlb_cma[node])
+                                       continue;
+
+                               page = cma_alloc(hugetlb_cma[node], nr_pages,
+                                               huge_page_order(h), true);
+                               if (page)
+                                       return page;
+                       }
+               }
        }
 #endif
 
@@ -3454,6 +3465,22 @@ static unsigned int allowed_mems_nr(struct hstate *h)
 }
 
 #ifdef CONFIG_SYSCTL
+static int proc_hugetlb_doulongvec_minmax(struct ctl_table *table, int write,
+                                         void *buffer, size_t *length,
+                                         loff_t *ppos, unsigned long *out)
+{
+       struct ctl_table dup_table;
+
+       /*
+        * In order to avoid races with __do_proc_doulongvec_minmax(), we
+        * can duplicate the @table and alter the duplicate of it.
+        */
+       dup_table = *table;
+       dup_table.data = out;
+
+       return proc_doulongvec_minmax(&dup_table, write, buffer, length, ppos);
+}
+
 static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
                         struct ctl_table *table, int write,
                         void *buffer, size_t *length, loff_t *ppos)
@@ -3465,9 +3492,8 @@ static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
        if (!hugepages_supported())
                return -EOPNOTSUPP;
 
-       table->data = &tmp;
-       table->maxlen = sizeof(unsigned long);
-       ret = proc_doulongvec_minmax(table, write, buffer, length, ppos);
+       ret = proc_hugetlb_doulongvec_minmax(table, write, buffer, length, ppos,
+                                            &tmp);
        if (ret)
                goto out;
 
@@ -3510,9 +3536,8 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write,
        if (write && hstate_is_gigantic(h))
                return -EINVAL;
 
-       table->data = &tmp;
-       table->maxlen = sizeof(unsigned long);
-       ret = proc_doulongvec_minmax(table, write, buffer, length, ppos);
+       ret = proc_hugetlb_doulongvec_minmax(table, write, buffer, length, ppos,
+                                            &tmp);
        if (ret)
                goto out;
 
index e749e56..58b0d9c 100644 (file)
@@ -56,6 +56,9 @@ enum scan_result {
 #define CREATE_TRACE_POINTS
 #include <trace/events/huge_memory.h>
 
+static struct task_struct *khugepaged_thread __read_mostly;
+static DEFINE_MUTEX(khugepaged_mutex);
+
 /* default scan 8*512 pte (or vmas) every 30 second */
 static unsigned int khugepaged_pages_to_scan __read_mostly;
 static unsigned int khugepaged_pages_collapsed;
@@ -914,6 +917,18 @@ static struct page *khugepaged_alloc_hugepage(bool *wait)
 
 static bool khugepaged_prealloc_page(struct page **hpage, bool *wait)
 {
+       /*
+        * If the hpage allocated earlier was briefly exposed in page cache
+        * before collapse_file() failed, it is possible that racing lookups
+        * have not yet completed, and would then be unpleasantly surprised by
+        * finding the hpage reused for the same mapping at a different offset.
+        * Just release the previous allocation if there is any danger of that.
+        */
+       if (*hpage && page_count(*hpage) > 1) {
+               put_page(*hpage);
+               *hpage = NULL;
+       }
+
        if (!*hpage)
                *hpage = khugepaged_alloc_hugepage(wait);
 
@@ -1709,7 +1724,7 @@ static void collapse_file(struct mm_struct *mm,
                                xas_unlock_irq(&xas);
                                page_cache_sync_readahead(mapping, &file->f_ra,
                                                          file, index,
-                                                         PAGE_SIZE);
+                                                         end - index);
                                /* drain pagevecs to help isolate_lru_page() */
                                lru_add_drain();
                                page = find_lock_page(mapping, index);
@@ -2292,8 +2307,6 @@ static void set_recommended_min_free_kbytes(void)
 
 int start_stop_khugepaged(void)
 {
-       static struct task_struct *khugepaged_thread __read_mostly;
-       static DEFINE_MUTEX(khugepaged_mutex);
        int err = 0;
 
        mutex_lock(&khugepaged_mutex);
@@ -2320,3 +2333,11 @@ fail:
        mutex_unlock(&khugepaged_mutex);
        return err;
 }
+
+void khugepaged_min_free_kbytes_update(void)
+{
+       mutex_lock(&khugepaged_mutex);
+       if (khugepaged_enabled() && khugepaged_thread)
+               set_recommended_min_free_kbytes();
+       mutex_unlock(&khugepaged_mutex);
+}
index 0aa2247..9afccc3 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -2453,6 +2453,10 @@ int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
                if (vma_is_dax(vma))
                        return 0;
 
+#ifdef VM_SAO
+               if (*vm_flags & VM_SAO)
+                       return 0;
+#endif
 #ifdef VM_SPARC_ADI
                if (*vm_flags & VM_SPARC_ADI)
                        return 0;
@@ -2582,6 +2586,10 @@ struct page *ksm_might_need_to_copy(struct page *page,
                return page;            /* let do_swap_page report the error */
 
        new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
+       if (new_page && mem_cgroup_charge(new_page, vma->vm_mm, GFP_KERNEL)) {
+               put_page(new_page);
+               new_page = NULL;
+       }
        if (new_page) {
                copy_user_highpage(new_page, page, address, vma);
 
@@ -2657,31 +2665,6 @@ again:
                goto again;
 }
 
-bool reuse_ksm_page(struct page *page,
-                   struct vm_area_struct *vma,
-                   unsigned long address)
-{
-#ifdef CONFIG_DEBUG_VM
-       if (WARN_ON(is_zero_pfn(page_to_pfn(page))) ||
-                       WARN_ON(!page_mapped(page)) ||
-                       WARN_ON(!PageLocked(page))) {
-               dump_page(page, "reuse_ksm_page");
-               return false;
-       }
-#endif
-
-       if (PageSwapCache(page) || !page_stable_node(page))
-               return false;
-       /* Prohibit parallel get_ksm_page() */
-       if (!page_ref_freeze(page, 1))
-               return false;
-
-       page_move_anon_rmap(page, vma);
-       page->index = linear_page_index(vma, address);
-       page_ref_unfreeze(page, 1);
-
-       return true;
-}
 #ifdef CONFIG_MIGRATION
 void ksm_migrate_page(struct page *newpage, struct page *oldpage)
 {
index dd1d43c..0e0d610 100644 (file)
@@ -289,9 +289,9 @@ static long madvise_willneed(struct vm_area_struct *vma,
         */
        *prev = NULL;   /* tell sys_madvise we drop mmap_lock */
        get_file(file);
-       mmap_read_unlock(current->mm);
        offset = (loff_t)(start - vma->vm_start)
                        + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
+       mmap_read_unlock(current->mm);
        vfs_fadvise(file, offset, end - start, POSIX_FADV_WILLNEED);
        fput(file);
        mmap_read_lock(current->mm);
@@ -381,9 +381,9 @@ huge_unlock:
                return 0;
        }
 
+regular_page:
        if (pmd_trans_unstable(pmd))
                return 0;
-regular_page:
 #endif
        tlb_change_page_size(tlb, PAGE_SIZE);
        orig_pte = pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
index b807952..6877c76 100644 (file)
@@ -1538,9 +1538,9 @@ static char *memory_stat_format(struct mem_cgroup *memcg)
                       memcg_page_state(memcg, WORKINGSET_ACTIVATE_ANON));
        seq_buf_printf(&s, "workingset_activate_file %lu\n",
                       memcg_page_state(memcg, WORKINGSET_ACTIVATE_FILE));
-       seq_buf_printf(&s, "workingset_restore %lu\n",
+       seq_buf_printf(&s, "workingset_restore_anon %lu\n",
                       memcg_page_state(memcg, WORKINGSET_RESTORE_ANON));
-       seq_buf_printf(&s, "workingset_restore %lu\n",
+       seq_buf_printf(&s, "workingset_restore_file %lu\n",
                       memcg_page_state(memcg, WORKINGSET_RESTORE_FILE));
        seq_buf_printf(&s, "workingset_nodereclaim %lu\n",
                       memcg_page_state(memcg, WORKINGSET_NODERECLAIM));
@@ -6774,6 +6774,9 @@ static void uncharge_batch(const struct uncharge_gather *ug)
        __this_cpu_add(ug->memcg->vmstats_percpu->nr_page_events, ug->nr_pages);
        memcg_check_events(ug->memcg, ug->dummy_page);
        local_irq_restore(flags);
+
+       /* drop reference from uncharge_page */
+       css_put(&ug->memcg->css);
 }
 
 static void uncharge_page(struct page *page, struct uncharge_gather *ug)
@@ -6797,6 +6800,9 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
                        uncharge_gather_clear(ug);
                }
                ug->memcg = page->mem_cgroup;
+
+               /* pairs with css_put in uncharge_batch */
+               css_get(&ug->memcg->css);
        }
 
        nr_pages = compound_nr(page);
index 602f428..eeae590 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/numa.h>
 #include <linux/perf_event.h>
 #include <linux/ptrace.h>
+#include <linux/vmalloc.h>
 
 #include <trace/events/kmem.h>
 
@@ -83,6 +84,7 @@
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 
+#include "pgalloc-track.h"
 #include "internal.h"
 
 #if defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) && !defined(CONFIG_COMPILE_TEST)
@@ -693,84 +695,185 @@ out:
  * covered by this vma.
  */
 
-static inline unsigned long
-copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
+static unsigned long
+copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                pte_t *dst_pte, pte_t *src_pte, struct vm_area_struct *vma,
                unsigned long addr, int *rss)
 {
        unsigned long vm_flags = vma->vm_flags;
        pte_t pte = *src_pte;
        struct page *page;
+       swp_entry_t entry = pte_to_swp_entry(pte);
+
+       if (likely(!non_swap_entry(entry))) {
+               if (swap_duplicate(entry) < 0)
+                       return entry.val;
+
+               /* make sure dst_mm is on swapoff's mmlist. */
+               if (unlikely(list_empty(&dst_mm->mmlist))) {
+                       spin_lock(&mmlist_lock);
+                       if (list_empty(&dst_mm->mmlist))
+                               list_add(&dst_mm->mmlist,
+                                               &src_mm->mmlist);
+                       spin_unlock(&mmlist_lock);
+               }
+               rss[MM_SWAPENTS]++;
+       } else if (is_migration_entry(entry)) {
+               page = migration_entry_to_page(entry);
 
-       /* pte contains position in swap or file, so copy. */
-       if (unlikely(!pte_present(pte))) {
-               swp_entry_t entry = pte_to_swp_entry(pte);
-
-               if (likely(!non_swap_entry(entry))) {
-                       if (swap_duplicate(entry) < 0)
-                               return entry.val;
-
-                       /* make sure dst_mm is on swapoff's mmlist. */
-                       if (unlikely(list_empty(&dst_mm->mmlist))) {
-                               spin_lock(&mmlist_lock);
-                               if (list_empty(&dst_mm->mmlist))
-                                       list_add(&dst_mm->mmlist,
-                                                       &src_mm->mmlist);
-                               spin_unlock(&mmlist_lock);
-                       }
-                       rss[MM_SWAPENTS]++;
-               } else if (is_migration_entry(entry)) {
-                       page = migration_entry_to_page(entry);
-
-                       rss[mm_counter(page)]++;
-
-                       if (is_write_migration_entry(entry) &&
-                                       is_cow_mapping(vm_flags)) {
-                               /*
-                                * COW mappings require pages in both
-                                * parent and child to be set to read.
-                                */
-                               make_migration_entry_read(&entry);
-                               pte = swp_entry_to_pte(entry);
-                               if (pte_swp_soft_dirty(*src_pte))
-                                       pte = pte_swp_mksoft_dirty(pte);
-                               if (pte_swp_uffd_wp(*src_pte))
-                                       pte = pte_swp_mkuffd_wp(pte);
-                               set_pte_at(src_mm, addr, src_pte, pte);
-                       }
-               } else if (is_device_private_entry(entry)) {
-                       page = device_private_entry_to_page(entry);
+               rss[mm_counter(page)]++;
 
+               if (is_write_migration_entry(entry) &&
+                               is_cow_mapping(vm_flags)) {
                        /*
-                        * Update rss count even for unaddressable pages, as
-                        * they should treated just like normal pages in this
-                        * respect.
-                        *
-                        * We will likely want to have some new rss counters
-                        * for unaddressable pages, at some point. But for now
-                        * keep things as they are.
+                        * COW mappings require pages in both
+                        * parent and child to be set to read.
                         */
-                       get_page(page);
-                       rss[mm_counter(page)]++;
-                       page_dup_rmap(page, false);
+                       make_migration_entry_read(&entry);
+                       pte = swp_entry_to_pte(entry);
+                       if (pte_swp_soft_dirty(*src_pte))
+                               pte = pte_swp_mksoft_dirty(pte);
+                       if (pte_swp_uffd_wp(*src_pte))
+                               pte = pte_swp_mkuffd_wp(pte);
+                       set_pte_at(src_mm, addr, src_pte, pte);
+               }
+       } else if (is_device_private_entry(entry)) {
+               page = device_private_entry_to_page(entry);
 
-                       /*
-                        * We do not preserve soft-dirty information, because so
-                        * far, checkpoint/restore is the only feature that
-                        * requires that. And checkpoint/restore does not work
-                        * when a device driver is involved (you cannot easily
-                        * save and restore device driver state).
-                        */
-                       if (is_write_device_private_entry(entry) &&
-                           is_cow_mapping(vm_flags)) {
-                               make_device_private_entry_read(&entry);
-                               pte = swp_entry_to_pte(entry);
-                               if (pte_swp_uffd_wp(*src_pte))
-                                       pte = pte_swp_mkuffd_wp(pte);
-                               set_pte_at(src_mm, addr, src_pte, pte);
-                       }
+               /*
+                * Update rss count even for unaddressable pages, as
+                * they should treated just like normal pages in this
+                * respect.
+                *
+                * We will likely want to have some new rss counters
+                * for unaddressable pages, at some point. But for now
+                * keep things as they are.
+                */
+               get_page(page);
+               rss[mm_counter(page)]++;
+               page_dup_rmap(page, false);
+
+               /*
+                * We do not preserve soft-dirty information, because so
+                * far, checkpoint/restore is the only feature that
+                * requires that. And checkpoint/restore does not work
+                * when a device driver is involved (you cannot easily
+                * save and restore device driver state).
+                */
+               if (is_write_device_private_entry(entry) &&
+                   is_cow_mapping(vm_flags)) {
+                       make_device_private_entry_read(&entry);
+                       pte = swp_entry_to_pte(entry);
+                       if (pte_swp_uffd_wp(*src_pte))
+                               pte = pte_swp_mkuffd_wp(pte);
+                       set_pte_at(src_mm, addr, src_pte, pte);
                }
-               goto out_set_pte;
+       }
+       set_pte_at(dst_mm, addr, dst_pte, pte);
+       return 0;
+}
+
+/*
+ * Copy a present and normal page if necessary.
+ *
+ * NOTE! The usual case is that this doesn't need to do
+ * anything, and can just return a positive value. That
+ * will let the caller know that it can just increase
+ * the page refcount and re-use the pte the traditional
+ * way.
+ *
+ * But _if_ we need to copy it because it needs to be
+ * pinned in the parent (and the child should get its own
+ * copy rather than just a reference to the same page),
+ * we'll do that here and return zero to let the caller
+ * know we're done.
+ *
+ * And if we need a pre-allocated page but don't yet have
+ * one, return a negative error to let the preallocation
+ * code know so that it can do so outside the page table
+ * lock.
+ */
+static inline int
+copy_present_page(struct mm_struct *dst_mm, struct mm_struct *src_mm,
+               pte_t *dst_pte, pte_t *src_pte,
+               struct vm_area_struct *vma, struct vm_area_struct *new,
+               unsigned long addr, int *rss, struct page **prealloc,
+               pte_t pte, struct page *page)
+{
+       struct page *new_page;
+
+       if (!is_cow_mapping(vma->vm_flags))
+               return 1;
+
+       /*
+        * What we want to do is to check whether this page may
+        * have been pinned by the parent process.  If so,
+        * instead of wrprotect the pte on both sides, we copy
+        * the page immediately so that we'll always guarantee
+        * the pinned page won't be randomly replaced in the
+        * future.
+        *
+        * The page pinning checks are just "has this mm ever
+        * seen pinning", along with the (inexact) check of
+        * the page count. That might give false positives for
+        * for pinning, but it will work correctly.
+        */
+       if (likely(!atomic_read(&src_mm->has_pinned)))
+               return 1;
+       if (likely(!page_maybe_dma_pinned(page)))
+               return 1;
+
+       new_page = *prealloc;
+       if (!new_page)
+               return -EAGAIN;
+
+       /*
+        * We have a prealloc page, all good!  Take it
+        * over and copy the page & arm it.
+        */
+       *prealloc = NULL;
+       copy_user_highpage(new_page, page, addr, vma);
+       __SetPageUptodate(new_page);
+       page_add_new_anon_rmap(new_page, new, addr, false);
+       lru_cache_add_inactive_or_unevictable(new_page, new);
+       rss[mm_counter(new_page)]++;
+
+       /* All done, just insert the new page copy in the child */
+       pte = mk_pte(new_page, new->vm_page_prot);
+       pte = maybe_mkwrite(pte_mkdirty(pte), new);
+       set_pte_at(dst_mm, addr, dst_pte, pte);
+       return 0;
+}
+
+/*
+ * Copy one pte.  Returns 0 if succeeded, or -EAGAIN if one preallocated page
+ * is required to copy this pte.
+ */
+static inline int
+copy_present_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
+               pte_t *dst_pte, pte_t *src_pte, struct vm_area_struct *vma,
+               struct vm_area_struct *new,
+               unsigned long addr, int *rss, struct page **prealloc)
+{
+       unsigned long vm_flags = vma->vm_flags;
+       pte_t pte = *src_pte;
+       struct page *page;
+
+       page = vm_normal_page(vma, addr, pte);
+       if (page) {
+               int retval;
+
+               retval = copy_present_page(dst_mm, src_mm,
+                       dst_pte, src_pte,
+                       vma, new,
+                       addr, rss, prealloc,
+                       pte, page);
+               if (retval <= 0)
+                       return retval;
+
+               get_page(page);
+               page_dup_rmap(page, false);
+               rss[mm_counter(page)]++;
        }
 
        /*
@@ -798,35 +901,51 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
        if (!(vm_flags & VM_UFFD_WP))
                pte = pte_clear_uffd_wp(pte);
 
-       page = vm_normal_page(vma, addr, pte);
-       if (page) {
-               get_page(page);
-               page_dup_rmap(page, false);
-               rss[mm_counter(page)]++;
-       }
-
-out_set_pte:
        set_pte_at(dst_mm, addr, dst_pte, pte);
        return 0;
 }
 
+static inline struct page *
+page_copy_prealloc(struct mm_struct *src_mm, struct vm_area_struct *vma,
+                  unsigned long addr)
+{
+       struct page *new_page;
+
+       new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, addr);
+       if (!new_page)
+               return NULL;
+
+       if (mem_cgroup_charge(new_page, src_mm, GFP_KERNEL)) {
+               put_page(new_page);
+               return NULL;
+       }
+       cgroup_throttle_swaprate(new_page, GFP_KERNEL);
+
+       return new_page;
+}
+
 static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                   pmd_t *dst_pmd, pmd_t *src_pmd, struct vm_area_struct *vma,
+                  struct vm_area_struct *new,
                   unsigned long addr, unsigned long end)
 {
        pte_t *orig_src_pte, *orig_dst_pte;
        pte_t *src_pte, *dst_pte;
        spinlock_t *src_ptl, *dst_ptl;
-       int progress = 0;
+       int progress, ret = 0;
        int rss[NR_MM_COUNTERS];
        swp_entry_t entry = (swp_entry_t){0};
+       struct page *prealloc = NULL;
 
 again:
+       progress = 0;
        init_rss_vec(rss);
 
        dst_pte = pte_alloc_map_lock(dst_mm, dst_pmd, addr, &dst_ptl);
-       if (!dst_pte)
-               return -ENOMEM;
+       if (!dst_pte) {
+               ret = -ENOMEM;
+               goto out;
+       }
        src_pte = pte_offset_map(src_pmd, addr);
        src_ptl = pte_lockptr(src_mm, src_pmd);
        spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
@@ -849,10 +968,34 @@ again:
                        progress++;
                        continue;
                }
-               entry.val = copy_one_pte(dst_mm, src_mm, dst_pte, src_pte,
+               if (unlikely(!pte_present(*src_pte))) {
+                       entry.val = copy_nonpresent_pte(dst_mm, src_mm,
+                                                       dst_pte, src_pte,
                                                        vma, addr, rss);
-               if (entry.val)
+                       if (entry.val)
+                               break;
+                       progress += 8;
+                       continue;
+               }
+               /* copy_present_pte() will clear `*prealloc' if consumed */
+               ret = copy_present_pte(dst_mm, src_mm, dst_pte, src_pte,
+                                      vma, new, addr, rss, &prealloc);
+               /*
+                * If we need a pre-allocated page for this pte, drop the
+                * locks, allocate, and try again.
+                */
+               if (unlikely(ret == -EAGAIN))
                        break;
+               if (unlikely(prealloc)) {
+                       /*
+                        * pre-alloc page cannot be reused by next time so as
+                        * to strictly follow mempolicy (e.g., alloc_page_vma()
+                        * will allocate page according to address).  This
+                        * could only happen if one pinned pte changed.
+                        */
+                       put_page(prealloc);
+                       prealloc = NULL;
+               }
                progress += 8;
        } while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
 
@@ -864,17 +1007,30 @@ again:
        cond_resched();
 
        if (entry.val) {
-               if (add_swap_count_continuation(entry, GFP_KERNEL) < 0)
+               if (add_swap_count_continuation(entry, GFP_KERNEL) < 0) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               entry.val = 0;
+       } else if (ret) {
+               WARN_ON_ONCE(ret != -EAGAIN);
+               prealloc = page_copy_prealloc(src_mm, vma, addr);
+               if (!prealloc)
                        return -ENOMEM;
-               progress = 0;
+               /* We've captured and resolved the error. Reset, try again. */
+               ret = 0;
        }
        if (addr != end)
                goto again;
-       return 0;
+out:
+       if (unlikely(prealloc))
+               put_page(prealloc);
+       return ret;
 }
 
 static inline int copy_pmd_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                pud_t *dst_pud, pud_t *src_pud, struct vm_area_struct *vma,
+               struct vm_area_struct *new,
                unsigned long addr, unsigned long end)
 {
        pmd_t *src_pmd, *dst_pmd;
@@ -901,7 +1057,7 @@ static inline int copy_pmd_range(struct mm_struct *dst_mm, struct mm_struct *src
                if (pmd_none_or_clear_bad(src_pmd))
                        continue;
                if (copy_pte_range(dst_mm, src_mm, dst_pmd, src_pmd,
-                                               vma, addr, next))
+                                  vma, new, addr, next))
                        return -ENOMEM;
        } while (dst_pmd++, src_pmd++, addr = next, addr != end);
        return 0;
@@ -909,6 +1065,7 @@ static inline int copy_pmd_range(struct mm_struct *dst_mm, struct mm_struct *src
 
 static inline int copy_pud_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                p4d_t *dst_p4d, p4d_t *src_p4d, struct vm_area_struct *vma,
+               struct vm_area_struct *new,
                unsigned long addr, unsigned long end)
 {
        pud_t *src_pud, *dst_pud;
@@ -935,7 +1092,7 @@ static inline int copy_pud_range(struct mm_struct *dst_mm, struct mm_struct *src
                if (pud_none_or_clear_bad(src_pud))
                        continue;
                if (copy_pmd_range(dst_mm, src_mm, dst_pud, src_pud,
-                                               vma, addr, next))
+                                  vma, new, addr, next))
                        return -ENOMEM;
        } while (dst_pud++, src_pud++, addr = next, addr != end);
        return 0;
@@ -943,6 +1100,7 @@ static inline int copy_pud_range(struct mm_struct *dst_mm, struct mm_struct *src
 
 static inline int copy_p4d_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                pgd_t *dst_pgd, pgd_t *src_pgd, struct vm_area_struct *vma,
+               struct vm_area_struct *new,
                unsigned long addr, unsigned long end)
 {
        p4d_t *src_p4d, *dst_p4d;
@@ -957,14 +1115,14 @@ static inline int copy_p4d_range(struct mm_struct *dst_mm, struct mm_struct *src
                if (p4d_none_or_clear_bad(src_p4d))
                        continue;
                if (copy_pud_range(dst_mm, src_mm, dst_p4d, src_p4d,
-                                               vma, addr, next))
+                                  vma, new, addr, next))
                        return -ENOMEM;
        } while (dst_p4d++, src_p4d++, addr = next, addr != end);
        return 0;
 }
 
 int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
-               struct vm_area_struct *vma)
+                   struct vm_area_struct *vma, struct vm_area_struct *new)
 {
        pgd_t *src_pgd, *dst_pgd;
        unsigned long next;
@@ -1019,7 +1177,7 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                if (pgd_none_or_clear_bad(src_pgd))
                        continue;
                if (unlikely(copy_p4d_range(dst_mm, src_mm, dst_pgd, src_pgd,
-                                           vma, addr, next))) {
+                                           vma, new, addr, next))) {
                        ret = -ENOMEM;
                        break;
                }
@@ -2206,7 +2364,8 @@ EXPORT_SYMBOL(vm_iomap_memory);
 
 static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
                                     unsigned long addr, unsigned long end,
-                                    pte_fn_t fn, void *data, bool create)
+                                    pte_fn_t fn, void *data, bool create,
+                                    pgtbl_mod_mask *mask)
 {
        pte_t *pte;
        int err = 0;
@@ -2214,7 +2373,7 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
 
        if (create) {
                pte = (mm == &init_mm) ?
-                       pte_alloc_kernel(pmd, addr) :
+                       pte_alloc_kernel_track(pmd, addr, mask) :
                        pte_alloc_map_lock(mm, pmd, addr, &ptl);
                if (!pte)
                        return -ENOMEM;
@@ -2235,6 +2394,7 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
                                break;
                }
        } while (addr += PAGE_SIZE, addr != end);
+       *mask |= PGTBL_PTE_MODIFIED;
 
        arch_leave_lazy_mmu_mode();
 
@@ -2245,7 +2405,8 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
 
 static int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud,
                                     unsigned long addr, unsigned long end,
-                                    pte_fn_t fn, void *data, bool create)
+                                    pte_fn_t fn, void *data, bool create,
+                                    pgtbl_mod_mask *mask)
 {
        pmd_t *pmd;
        unsigned long next;
@@ -2254,7 +2415,7 @@ static int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud,
        BUG_ON(pud_huge(*pud));
 
        if (create) {
-               pmd = pmd_alloc(mm, pud, addr);
+               pmd = pmd_alloc_track(mm, pud, addr, mask);
                if (!pmd)
                        return -ENOMEM;
        } else {
@@ -2264,7 +2425,7 @@ static int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud,
                next = pmd_addr_end(addr, end);
                if (create || !pmd_none_or_clear_bad(pmd)) {
                        err = apply_to_pte_range(mm, pmd, addr, next, fn, data,
-                                                create);
+                                                create, mask);
                        if (err)
                                break;
                }
@@ -2274,14 +2435,15 @@ static int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud,
 
 static int apply_to_pud_range(struct mm_struct *mm, p4d_t *p4d,
                                     unsigned long addr, unsigned long end,
-                                    pte_fn_t fn, void *data, bool create)
+                                    pte_fn_t fn, void *data, bool create,
+                                    pgtbl_mod_mask *mask)
 {
        pud_t *pud;
        unsigned long next;
        int err = 0;
 
        if (create) {
-               pud = pud_alloc(mm, p4d, addr);
+               pud = pud_alloc_track(mm, p4d, addr, mask);
                if (!pud)
                        return -ENOMEM;
        } else {
@@ -2291,7 +2453,7 @@ static int apply_to_pud_range(struct mm_struct *mm, p4d_t *p4d,
                next = pud_addr_end(addr, end);
                if (create || !pud_none_or_clear_bad(pud)) {
                        err = apply_to_pmd_range(mm, pud, addr, next, fn, data,
-                                                create);
+                                                create, mask);
                        if (err)
                                break;
                }
@@ -2301,14 +2463,15 @@ static int apply_to_pud_range(struct mm_struct *mm, p4d_t *p4d,
 
 static int apply_to_p4d_range(struct mm_struct *mm, pgd_t *pgd,
                                     unsigned long addr, unsigned long end,
-                                    pte_fn_t fn, void *data, bool create)
+                                    pte_fn_t fn, void *data, bool create,
+                                    pgtbl_mod_mask *mask)
 {
        p4d_t *p4d;
        unsigned long next;
        int err = 0;
 
        if (create) {
-               p4d = p4d_alloc(mm, pgd, addr);
+               p4d = p4d_alloc_track(mm, pgd, addr, mask);
                if (!p4d)
                        return -ENOMEM;
        } else {
@@ -2318,7 +2481,7 @@ static int apply_to_p4d_range(struct mm_struct *mm, pgd_t *pgd,
                next = p4d_addr_end(addr, end);
                if (create || !p4d_none_or_clear_bad(p4d)) {
                        err = apply_to_pud_range(mm, p4d, addr, next, fn, data,
-                                                create);
+                                                create, mask);
                        if (err)
                                break;
                }
@@ -2331,8 +2494,9 @@ static int __apply_to_page_range(struct mm_struct *mm, unsigned long addr,
                                 void *data, bool create)
 {
        pgd_t *pgd;
-       unsigned long next;
+       unsigned long start = addr, next;
        unsigned long end = addr + size;
+       pgtbl_mod_mask mask = 0;
        int err = 0;
 
        if (WARN_ON(addr >= end))
@@ -2343,11 +2507,14 @@ static int __apply_to_page_range(struct mm_struct *mm, unsigned long addr,
                next = pgd_addr_end(addr, end);
                if (!create && pgd_none_or_clear_bad(pgd))
                        continue;
-               err = apply_to_p4d_range(mm, pgd, addr, next, fn, data, create);
+               err = apply_to_p4d_range(mm, pgd, addr, next, fn, data, create, &mask);
                if (err)
                        break;
        } while (pgd++, addr = next, addr != end);
 
+       if (mask & ARCH_PAGE_TABLE_SYNC_MASK)
+               arch_sync_kernel_mappings(start, start + size);
+
        return err;
 }
 
@@ -2622,6 +2789,7 @@ static inline void wp_page_reuse(struct vm_fault *vmf)
        if (ptep_set_access_flags(vma, vmf->address, vmf->pte, entry, 1))
                update_mmu_cache(vma, vmf->address, vmf->pte);
        pte_unmap_unlock(vmf->pte, vmf->ptl);
+       count_vm_event(PGREUSE);
 }
 
 /*
@@ -2927,50 +3095,25 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf)
         * not dirty accountable.
         */
        if (PageAnon(vmf->page)) {
-               int total_map_swapcount;
-               if (PageKsm(vmf->page) && (PageSwapCache(vmf->page) ||
-                                          page_count(vmf->page) != 1))
+               struct page *page = vmf->page;
+
+               /* PageKsm() doesn't necessarily raise the page refcount */
+               if (PageKsm(page) || page_count(page) != 1)
+                       goto copy;
+               if (!trylock_page(page))
+                       goto copy;
+               if (PageKsm(page) || page_mapcount(page) != 1 || page_count(page) != 1) {
+                       unlock_page(page);
                        goto copy;
-               if (!trylock_page(vmf->page)) {
-                       get_page(vmf->page);
-                       pte_unmap_unlock(vmf->pte, vmf->ptl);
-                       lock_page(vmf->page);
-                       vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd,
-                                       vmf->address, &vmf->ptl);
-                       if (!pte_same(*vmf->pte, vmf->orig_pte)) {
-                               update_mmu_tlb(vma, vmf->address, vmf->pte);
-                               unlock_page(vmf->page);
-                               pte_unmap_unlock(vmf->pte, vmf->ptl);
-                               put_page(vmf->page);
-                               return 0;
-                       }
-                       put_page(vmf->page);
-               }
-               if (PageKsm(vmf->page)) {
-                       bool reused = reuse_ksm_page(vmf->page, vmf->vma,
-                                                    vmf->address);
-                       unlock_page(vmf->page);
-                       if (!reused)
-                               goto copy;
-                       wp_page_reuse(vmf);
-                       return VM_FAULT_WRITE;
-               }
-               if (reuse_swap_page(vmf->page, &total_map_swapcount)) {
-                       if (total_map_swapcount == 1) {
-                               /*
-                                * The page is all ours. Move it to
-                                * our anon_vma so the rmap code will
-                                * not search our parent or siblings.
-                                * Protected against the rmap code by
-                                * the page lock.
-                                */
-                               page_move_anon_rmap(vmf->page, vma);
-                       }
-                       unlock_page(vmf->page);
-                       wp_page_reuse(vmf);
-                       return VM_FAULT_WRITE;
                }
-               unlock_page(vmf->page);
+               /*
+                * Ok, we've got the only map reference, and the only
+                * page count reference, and the page is locked,
+                * it's dark out, and we're wearing sunglasses. Hit it.
+                */
+               unlock_page(page);
+               wp_page_reuse(vmf);
+               return VM_FAULT_WRITE;
        } else if (unlikely((vma->vm_flags & (VM_WRITE|VM_SHARED)) ==
                                        (VM_WRITE|VM_SHARED))) {
                return wp_page_shared(vmf);
index e9d5ab5..ce3e73e 100644 (file)
@@ -729,7 +729,7 @@ void __ref move_pfn_range_to_zone(struct zone *zone, unsigned long start_pfn,
         * are reserved so nobody should be touching them so we should be safe
         */
        memmap_init_zone(nr_pages, nid, zone_idx(zone), start_pfn,
-                       MEMMAP_HOTPLUG, altmap);
+                        MEMINIT_HOTPLUG, altmap);
 
        set_zone_contiguous(zone);
 }
@@ -1080,7 +1080,8 @@ int __ref add_memory_resource(int nid, struct resource *res)
        }
 
        /* link memory sections under this node.*/
-       ret = link_mem_sections(nid, PFN_DOWN(start), PFN_UP(start + size - 1));
+       ret = link_mem_sections(nid, PFN_DOWN(start), PFN_UP(start + size - 1),
+                               MEMINIT_HOTPLUG);
        BUG_ON(ret);
 
        /* create new memmap entry */
@@ -1575,6 +1576,20 @@ static int __ref __offline_pages(unsigned long start_pfn,
                /* check again */
                ret = walk_system_ram_range(start_pfn, end_pfn - start_pfn,
                                            NULL, check_pages_isolated_cb);
+               /*
+                * per-cpu pages are drained in start_isolate_page_range, but if
+                * there are still pages that are not free, make sure that we
+                * drain again, because when we isolated range we might
+                * have raced with another thread that was adding pages to pcp
+                * list.
+                *
+                * Forward progress should be still guaranteed because
+                * pages on the pcp list can only belong to MOVABLE_ZONE
+                * because has_unmovable_pages explicitly checks for
+                * PageBuddy on freed pages on other zones.
+                */
+               if (ret)
+                       drain_all_pages(zone);
        } while (ret);
 
        /* Ok, all of our target is isolated.
index 03e38b7..006dace 100644 (file)
@@ -216,7 +216,7 @@ void *memremap_pages(struct dev_pagemap *pgmap, int nid)
                        return ERR_PTR(-EINVAL);
                }
                break;
-       case MEMORY_DEVICE_DEVDAX:
+       case MEMORY_DEVICE_GENERIC:
                need_devmap_managed = false;
                break;
        case MEMORY_DEVICE_PCI_P2PDMA:
index 34a842a..04a98bb 100644 (file)
@@ -246,13 +246,13 @@ static bool remove_migration_pte(struct page *page, struct vm_area_struct *vma,
                else if (pte_swp_uffd_wp(*pvmw.pte))
                        pte = pte_mkuffd_wp(pte);
 
-               if (unlikely(is_zone_device_page(new))) {
-                       if (is_device_private_page(new)) {
-                               entry = make_device_private_entry(new, pte_write(pte));
-                               pte = swp_entry_to_pte(entry);
-                               if (pte_swp_uffd_wp(*pvmw.pte))
-                                       pte = pte_mkuffd_wp(pte);
-                       }
+               if (unlikely(is_device_private_page(new))) {
+                       entry = make_device_private_entry(new, pte_write(pte));
+                       pte = swp_entry_to_pte(entry);
+                       if (pte_swp_soft_dirty(*pvmw.pte))
+                               pte = pte_swp_mksoft_dirty(pte);
+                       if (pte_swp_uffd_wp(*pvmw.pte))
+                               pte = pte_swp_mkuffd_wp(pte);
                }
 
 #ifdef CONFIG_HUGETLB_PAGE
@@ -668,7 +668,8 @@ void migrate_page_states(struct page *newpage, struct page *page)
 
        copy_page_owner(page, newpage);
 
-       mem_cgroup_migrate(page, newpage);
+       if (!PageHuge(page))
+               mem_cgroup_migrate(page, newpage);
 }
 EXPORT_SYMBOL(migrate_page_states);
 
@@ -1445,7 +1446,7 @@ retry:
                         * Capture required information that might get lost
                         * during migration.
                         */
-                       is_thp = PageTransHuge(page);
+                       is_thp = PageTransHuge(page) && !PageHuge(page);
                        nr_subpages = thp_nr_pages(page);
                        cond_resched();
 
@@ -1471,7 +1472,7 @@ retry:
                                 * we encounter them after the rest of the list
                                 * is processed.
                                 */
-                               if (PageTransHuge(page) && !PageHuge(page)) {
+                               if (is_thp) {
                                        lock_page(page);
                                        rc = split_huge_page_to_list(page, from);
                                        unlock_page(page);
@@ -1480,8 +1481,7 @@ retry:
                                                nr_thp_split++;
                                                goto retry;
                                        }
-                               }
-                               if (is_thp) {
+
                                        nr_thp_failed++;
                                        nr_failed += nr_subpages;
                                        goto out;
@@ -2427,10 +2427,17 @@ again:
                        entry = make_migration_entry(page, mpfn &
                                                     MIGRATE_PFN_WRITE);
                        swp_pte = swp_entry_to_pte(entry);
-                       if (pte_soft_dirty(pte))
-                               swp_pte = pte_swp_mksoft_dirty(swp_pte);
-                       if (pte_uffd_wp(pte))
-                               swp_pte = pte_swp_mkuffd_wp(swp_pte);
+                       if (pte_present(pte)) {
+                               if (pte_soft_dirty(pte))
+                                       swp_pte = pte_swp_mksoft_dirty(swp_pte);
+                               if (pte_uffd_wp(pte))
+                                       swp_pte = pte_swp_mkuffd_wp(swp_pte);
+                       } else {
+                               if (pte_swp_soft_dirty(pte))
+                                       swp_pte = pte_swp_mksoft_dirty(swp_pte);
+                               if (pte_swp_uffd_wp(pte))
+                                       swp_pte = pte_swp_mkuffd_wp(swp_pte);
+                       }
                        set_pte_at(mm, addr, ptep, swp_pte);
 
                        /*
index 93ca2bf..884b121 100644 (file)
@@ -58,11 +58,14 @@ EXPORT_SYMBOL(can_do_mlock);
  */
 void clear_page_mlock(struct page *page)
 {
+       int nr_pages;
+
        if (!TestClearPageMlocked(page))
                return;
 
-       mod_zone_page_state(page_zone(page), NR_MLOCK, -thp_nr_pages(page));
-       count_vm_event(UNEVICTABLE_PGCLEARED);
+       nr_pages = thp_nr_pages(page);
+       mod_zone_page_state(page_zone(page), NR_MLOCK, -nr_pages);
+       count_vm_events(UNEVICTABLE_PGCLEARED, nr_pages);
        /*
         * The previous TestClearPageMlocked() corresponds to the smp_mb()
         * in __pagevec_lru_add_fn().
@@ -76,7 +79,7 @@ void clear_page_mlock(struct page *page)
                 * We lost the race. the page already moved to evictable list.
                 */
                if (PageUnevictable(page))
-                       count_vm_event(UNEVICTABLE_PGSTRANDED);
+                       count_vm_events(UNEVICTABLE_PGSTRANDED, nr_pages);
        }
 }
 
@@ -93,9 +96,10 @@ void mlock_vma_page(struct page *page)
        VM_BUG_ON_PAGE(PageCompound(page) && PageDoubleMap(page), page);
 
        if (!TestSetPageMlocked(page)) {
-               mod_zone_page_state(page_zone(page), NR_MLOCK,
-                                   thp_nr_pages(page));
-               count_vm_event(UNEVICTABLE_PGMLOCKED);
+               int nr_pages = thp_nr_pages(page);
+
+               mod_zone_page_state(page_zone(page), NR_MLOCK, nr_pages);
+               count_vm_events(UNEVICTABLE_PGMLOCKED, nr_pages);
                if (!isolate_lru_page(page))
                        putback_lru_page(page);
        }
@@ -138,7 +142,7 @@ static void __munlock_isolated_page(struct page *page)
 
        /* Did try_to_unlock() succeed or punt? */
        if (!PageMlocked(page))
-               count_vm_event(UNEVICTABLE_PGMUNLOCKED);
+               count_vm_events(UNEVICTABLE_PGMUNLOCKED, thp_nr_pages(page));
 
        putback_lru_page(page);
 }
@@ -154,10 +158,12 @@ static void __munlock_isolated_page(struct page *page)
  */
 static void __munlock_isolation_failed(struct page *page)
 {
+       int nr_pages = thp_nr_pages(page);
+
        if (PageUnevictable(page))
-               __count_vm_event(UNEVICTABLE_PGSTRANDED);
+               __count_vm_events(UNEVICTABLE_PGSTRANDED, nr_pages);
        else
-               __count_vm_event(UNEVICTABLE_PGMUNLOCKED);
+               __count_vm_events(UNEVICTABLE_PGMUNLOCKED, nr_pages);
 }
 
 /**
index 40248d8..f793eb7 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1781,7 +1781,11 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
                        merge = vma_merge(mm, prev, vma->vm_start, vma->vm_end, vma->vm_flags,
                                NULL, vma->vm_file, vma->vm_pgoff, NULL, NULL_VM_UFFD_CTX);
                        if (merge) {
-                               fput(file);
+                               /* ->mmap() can change vma->vm_file and fput the original file. So
+                                * fput the vma->vm_file here or we would add an extra fput for file
+                                * and cause general protection fault ultimately.
+                                */
+                               fput(vma->vm_file);
                                vm_area_free(vma);
                                vma = merge;
                                /* Update vm_flags and possible addr to pick up the change. We don't
@@ -1812,6 +1816,15 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
                vma_set_anonymous(vma);
        }
 
+       /* Allow architectures to sanity-check the vm_flags */
+       if (!arch_validate_flags(vma->vm_flags)) {
+               error = -EINVAL;
+               if (file)
+                       goto unmap_and_free_vma;
+               else
+                       goto free_vma;
+       }
+
        vma_link(mm, vma, prev, rb_link, rb_parent);
        /* Once vma denies write, undo our temporary denial count */
        if (file) {
index ce8b8a5..56c02be 100644 (file)
@@ -603,6 +603,12 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
                        goto out;
                }
 
+               /* Allow architectures to sanity-check the new flags */
+               if (!arch_validate_flags(newflags)) {
+                       error = -EINVAL;
+                       goto out;
+               }
+
                error = security_file_mprotect(vma, reqprot, prot);
                if (error)
                        goto out;
index 75a3271..0df7ca3 100644 (file)
@@ -5,7 +5,7 @@
  *  Replacement code for mm functions to support CPU's that don't
  *  have any form of memory management unit (thus no virtual memory).
  *
- *  See Documentation/mm/nommu-mmap.rst
+ *  See Documentation/admin-guide/mm/nommu-mmap.rst
  *
  *  Copyright (c) 2004-2008 David Howells <dhowells@redhat.com>
  *  Copyright (c) 2000-2003 David McCullough <davidm@snapgear.com>
index fab5e97..780c8f0 100644 (file)
@@ -69,6 +69,7 @@
 #include <linux/nmi.h>
 #include <linux/psi.h>
 #include <linux/padata.h>
+#include <linux/khugepaged.h>
 
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
@@ -3367,9 +3368,16 @@ struct page *rmqueue(struct zone *preferred_zone,
        struct page *page;
 
        if (likely(order == 0)) {
-               page = rmqueue_pcplist(preferred_zone, zone, gfp_flags,
+               /*
+                * MIGRATE_MOVABLE pcplist could have the pages on CMA area and
+                * we need to skip it when CMA area isn't allowed.
+                */
+               if (!IS_ENABLED(CONFIG_CMA) || alloc_flags & ALLOC_CMA ||
+                               migratetype != MIGRATE_MOVABLE) {
+                       page = rmqueue_pcplist(preferred_zone, zone, gfp_flags,
                                        migratetype, alloc_flags);
-               goto out;
+                       goto out;
+               }
        }
 
        /*
@@ -3381,7 +3389,13 @@ struct page *rmqueue(struct zone *preferred_zone,
 
        do {
                page = NULL;
-               if (alloc_flags & ALLOC_HARDER) {
+               /*
+                * order-0 request can reach here when the pcplist is skipped
+                * due to non-CMA allocation context. HIGHATOMIC area is
+                * reserved for high-order atomic allocation, so order-0
+                * request should skip it.
+                */
+               if (order > 0 && alloc_flags & ALLOC_HARDER) {
                        page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC);
                        if (page)
                                trace_mm_page_alloc_zone_locked(page, order, migratetype);
@@ -5975,7 +5989,7 @@ overlap_memmap_init(unsigned long zone, unsigned long *pfn)
  * done. Non-atomic initialization, single-pass.
  */
 void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
-               unsigned long start_pfn, enum memmap_context context,
+               unsigned long start_pfn, enum meminit_context context,
                struct vmem_altmap *altmap)
 {
        unsigned long pfn, end_pfn = start_pfn + size;
@@ -6007,7 +6021,7 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
                 * There can be holes in boot-time mem_map[]s handed to this
                 * function.  They do not exist on hotplugged memory.
                 */
-               if (context == MEMMAP_EARLY) {
+               if (context == MEMINIT_EARLY) {
                        if (overlap_memmap_init(zone, &pfn))
                                continue;
                        if (defer_init(nid, pfn, end_pfn))
@@ -6016,7 +6030,7 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
 
                page = pfn_to_page(pfn);
                __init_single_page(page, pfn, zone, nid);
-               if (context == MEMMAP_HOTPLUG)
+               if (context == MEMINIT_HOTPLUG)
                        __SetPageReserved(page);
 
                /*
@@ -6099,7 +6113,7 @@ void __ref memmap_init_zone_device(struct zone *zone,
                 * check here not to call set_pageblock_migratetype() against
                 * pfn out of zone.
                 *
-                * Please note that MEMMAP_HOTPLUG path doesn't clear memmap
+                * Please note that MEMINIT_HOTPLUG path doesn't clear memmap
                 * because this is done early in section_activate()
                 */
                if (!(pfn & (pageblock_nr_pages - 1))) {
@@ -6137,7 +6151,7 @@ void __meminit __weak memmap_init(unsigned long size, int nid,
                if (end_pfn > start_pfn) {
                        size = end_pfn - start_pfn;
                        memmap_init_zone(size, nid, zone, start_pfn,
-                                        MEMMAP_EARLY, NULL);
+                                        MEMINIT_EARLY, NULL);
                }
        }
 }
@@ -7891,6 +7905,8 @@ int __meminit init_per_zone_wmark_min(void)
        setup_min_slab_ratio();
 #endif
 
+       khugepaged_min_free_kbytes_update();
+
        return 0;
 }
 postcore_initcall(init_per_zone_wmark_min)
index e485a6e..4ca28aa 100644 (file)
@@ -252,6 +252,16 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
                unlock_page(page);
                goto out;
        }
+       /*
+        * Arch code may have to preserve more data than just the page
+        * contents, e.g. memory tags.
+        */
+       ret = arch_prepare_to_swap(page);
+       if (ret) {
+               set_page_dirty(page);
+               unlock_page(page);
+               goto out;
+       }
        if (frontswap_store(page) == 0) {
                set_page_writeback(page);
                unlock_page(page);
index 242c031..63a3db1 100644 (file)
@@ -170,6 +170,14 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages)
  * pageblocks we may have modified and return -EBUSY to caller. This
  * prevents two threads from simultaneously working on overlapping ranges.
  *
+ * Please note that there is no strong synchronization with the page allocator
+ * either. Pages might be freed while their page blocks are marked ISOLATED.
+ * In some cases pages might still end up on pcp lists and that would allow
+ * for their allocation even when they are in fact isolated already. Depending
+ * on how strong of a guarantee the caller needs drain_all_pages might be needed
+ * (e.g. __offline_pages will need to call it after check for isolated range for
+ * a next retry).
+ *
  * Return: the number of isolated pageblocks on success and -EBUSY if any part
  * of range cannot be isolated.
  */
index f470962..1ed1a34 100644 (file)
@@ -1316,7 +1316,7 @@ static struct pcpu_chunk * __init pcpu_alloc_first_chunk(unsigned long tmp_addr,
 
        /* allocate chunk */
        alloc_size = sizeof(struct pcpu_chunk) +
-               BITS_TO_LONGS(region_size >> PAGE_SHIFT);
+               BITS_TO_LONGS(region_size >> PAGE_SHIFT) * sizeof(unsigned long);
        chunk = memblock_alloc(alloc_size, SMP_CACHE_BYTES);
        if (!chunk)
                panic("%s: Failed to allocate %zu bytes\n", __func__,
index 29c0520..fd12da8 100644 (file)
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 
-#ifdef CONFIG_COMPAT
-#include <linux/compat.h>
-#endif
-
 /**
  * process_vm_rw_pages - read/write pages from task specified
  * @pages: array of pointers to pages we want to copy
@@ -276,20 +272,17 @@ static ssize_t process_vm_rw(pid_t pid,
        if (rc < 0)
                return rc;
        if (!iov_iter_count(&iter))
-               goto free_iovecs;
-
-       rc = rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt, UIO_FASTIOV,
-                                  iovstack_r, &iov_r);
-       if (rc <= 0)
-               goto free_iovecs;
-
+               goto free_iov_l;
+       iov_r = iovec_from_user(rvec, riovcnt, UIO_FASTIOV, iovstack_r, false);
+       if (IS_ERR(iov_r)) {
+               rc = PTR_ERR(iov_r);
+               goto free_iov_l;
+       }
        rc = process_vm_rw_core(pid, &iter, iov_r, riovcnt, flags, vm_write);
-
-free_iovecs:
        if (iov_r != iovstack_r)
                kfree(iov_r);
+free_iov_l:
        kfree(iov_l);
-
        return rc;
 }
 
@@ -307,68 +300,3 @@ SYSCALL_DEFINE6(process_vm_writev, pid_t, pid,
 {
        return process_vm_rw(pid, lvec, liovcnt, rvec, riovcnt, flags, 1);
 }
-
-#ifdef CONFIG_COMPAT
-
-static ssize_t
-compat_process_vm_rw(compat_pid_t pid,
-                    const struct compat_iovec __user *lvec,
-                    unsigned long liovcnt,
-                    const struct compat_iovec __user *rvec,
-                    unsigned long riovcnt,
-                    unsigned long flags, int vm_write)
-{
-       struct iovec iovstack_l[UIO_FASTIOV];
-       struct iovec iovstack_r[UIO_FASTIOV];
-       struct iovec *iov_l = iovstack_l;
-       struct iovec *iov_r = iovstack_r;
-       struct iov_iter iter;
-       ssize_t rc = -EFAULT;
-       int dir = vm_write ? WRITE : READ;
-
-       if (flags != 0)
-               return -EINVAL;
-
-       rc = compat_import_iovec(dir, lvec, liovcnt, UIO_FASTIOV, &iov_l, &iter);
-       if (rc < 0)
-               return rc;
-       if (!iov_iter_count(&iter))
-               goto free_iovecs;
-       rc = compat_rw_copy_check_uvector(CHECK_IOVEC_ONLY, rvec, riovcnt,
-                                         UIO_FASTIOV, iovstack_r,
-                                         &iov_r);
-       if (rc <= 0)
-               goto free_iovecs;
-
-       rc = process_vm_rw_core(pid, &iter, iov_r, riovcnt, flags, vm_write);
-
-free_iovecs:
-       if (iov_r != iovstack_r)
-               kfree(iov_r);
-       kfree(iov_l);
-       return rc;
-}
-
-COMPAT_SYSCALL_DEFINE6(process_vm_readv, compat_pid_t, pid,
-                      const struct compat_iovec __user *, lvec,
-                      compat_ulong_t, liovcnt,
-                      const struct compat_iovec __user *, rvec,
-                      compat_ulong_t, riovcnt,
-                      compat_ulong_t, flags)
-{
-       return compat_process_vm_rw(pid, lvec, liovcnt, rvec,
-                                   riovcnt, flags, 0);
-}
-
-COMPAT_SYSCALL_DEFINE6(process_vm_writev, compat_pid_t, pid,
-                      const struct compat_iovec __user *, lvec,
-                      compat_ulong_t, liovcnt,
-                      const struct compat_iovec __user *, rvec,
-                      compat_ulong_t, riovcnt,
-                      compat_ulong_t, flags)
-{
-       return compat_process_vm_rw(pid, lvec, liovcnt, rvec,
-                                   riovcnt, flags, 1);
-}
-
-#endif
index 83cc459..9425260 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1511,9 +1511,14 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
                         */
                        entry = make_migration_entry(page, 0);
                        swp_pte = swp_entry_to_pte(entry);
-                       if (pte_soft_dirty(pteval))
+
+                       /*
+                        * pteval maps a zone device page and is therefore
+                        * a swap pte.
+                        */
+                       if (pte_swp_soft_dirty(pteval))
                                swp_pte = pte_swp_mksoft_dirty(swp_pte);
-                       if (pte_uffd_wp(pteval))
+                       if (pte_swp_uffd_wp(pteval))
                                swp_pte = pte_swp_mkuffd_wp(swp_pte);
                        set_pte_at(mm, pvmw.address, pvmw.pte, swp_pte);
                        /*
index 271548c..d42c27e 100644 (file)
@@ -279,11 +279,13 @@ static int shmem_reserve_inode(struct super_block *sb, ino_t *inop)
 
        if (!(sb->s_flags & SB_KERNMOUNT)) {
                spin_lock(&sbinfo->stat_lock);
-               if (!sbinfo->free_inodes) {
-                       spin_unlock(&sbinfo->stat_lock);
-                       return -ENOSPC;
+               if (sbinfo->max_inodes) {
+                       if (!sbinfo->free_inodes) {
+                               spin_unlock(&sbinfo->stat_lock);
+                               return -ENOSPC;
+                       }
+                       sbinfo->free_inodes--;
                }
-               sbinfo->free_inodes--;
                if (inop) {
                        ino = sbinfo->next_ino++;
                        if (unlikely(is_zero_ino(ino)))
@@ -1734,6 +1736,12 @@ static int shmem_swapin_page(struct inode *inode, pgoff_t index,
        }
        wait_on_page_writeback(page);
 
+       /*
+        * Some architectures may have to restore extra metadata to the
+        * physical page after reading from swap.
+        */
+       arch_swap_restore(swap, page);
+
        if (shmem_should_replace_page(page, gfp)) {
                error = shmem_replace_page(&page, gfp, info, index);
                if (error)
@@ -2267,6 +2275,9 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
                        vma->vm_flags &= ~(VM_MAYWRITE);
        }
 
+       /* arm64 - allow memory tagging on RAM-based files */
+       vma->vm_flags |= VM_MTE_ALLOWED;
+
        file_accessed(file);
        vma->vm_ops = &shmem_vm_ops;
        if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
index 3160dff..f658e86 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1632,6 +1632,10 @@ static void slab_destroy(struct kmem_cache *cachep, struct page *page)
                kmem_cache_free(cachep->freelist_cache, freelist);
 }
 
+/*
+ * Update the size of the caches before calling slabs_destroy as it may
+ * recursively call kfree.
+ */
 static void slabs_destroy(struct kmem_cache *cachep, struct list_head *list)
 {
        struct page *page, *n;
@@ -2153,8 +2157,8 @@ static void do_drain(void *arg)
        spin_lock(&n->list_lock);
        free_block(cachep, ac->entry, ac->avail, node, &list);
        spin_unlock(&n->list_lock);
-       slabs_destroy(cachep, &list);
        ac->avail = 0;
+       slabs_destroy(cachep, &list);
 }
 
 static void drain_cpu_caches(struct kmem_cache *cachep)
@@ -3402,9 +3406,9 @@ free_done:
        }
 #endif
        spin_unlock(&n->list_lock);
-       slabs_destroy(cachep, &list);
        ac->avail -= batchcount;
        memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void *)*ac->avail);
+       slabs_destroy(cachep, &list);
 }
 
 /*
index 68c02b2..6d35740 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -672,12 +672,12 @@ static void slab_fix(struct kmem_cache *s, char *fmt, ...)
 }
 
 static bool freelist_corrupted(struct kmem_cache *s, struct page *page,
-                              void *freelist, void *nextfree)
+                              void **freelist, void *nextfree)
 {
        if ((s->flags & SLAB_CONSISTENCY_CHECKS) &&
-           !check_valid_pointer(s, page, nextfree)) {
-               object_err(s, page, freelist, "Freechain corrupt");
-               freelist = NULL;
+           !check_valid_pointer(s, page, nextfree) && freelist) {
+               object_err(s, page, *freelist, "Freechain corrupt");
+               *freelist = NULL;
                slab_fix(s, "Isolate corrupted freechain");
                return true;
        }
@@ -1413,10 +1413,6 @@ slab_flags_t kmem_cache_flags(unsigned int object_size,
        char *next_block;
        slab_flags_t block_flags;
 
-       /* If slub_debug = 0, it folds into the if conditional. */
-       if (!slub_debug_string)
-               return flags | slub_debug;
-
        len = strlen(name);
        next_block = slub_debug_string;
        /* Go through all blocks of debug options, see if any matches our slab's name */
@@ -1450,7 +1446,7 @@ slab_flags_t kmem_cache_flags(unsigned int object_size,
                }
        }
 
-       return slub_debug;
+       return flags | slub_debug;
 }
 #else /* !CONFIG_SLUB_DEBUG */
 static inline void setup_object_debug(struct kmem_cache *s,
@@ -1494,7 +1490,7 @@ static inline void dec_slabs_node(struct kmem_cache *s, int node,
                                                        int objects) {}
 
 static bool freelist_corrupted(struct kmem_cache *s, struct page *page,
-                              void *freelist, void *nextfree)
+                              void **freelist, void *nextfree)
 {
        return false;
 }
@@ -2184,7 +2180,7 @@ static void deactivate_slab(struct kmem_cache *s, struct page *page,
                 * 'freelist' is already corrupted.  So isolate all objects
                 * starting at 'freelist'.
                 */
-               if (freelist_corrupted(s, page, freelist, nextfree))
+               if (freelist_corrupted(s, page, &freelist, nextfree))
                        break;
 
                do {
index d16d65d..65ef7e3 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -494,14 +494,14 @@ void lru_cache_add_inactive_or_unevictable(struct page *page,
 
        unevictable = (vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) == VM_LOCKED;
        if (unlikely(unevictable) && !TestSetPageMlocked(page)) {
+               int nr_pages = thp_nr_pages(page);
                /*
                 * We use the irq-unsafe __mod_zone_page_stat because this
                 * counter is not modified from interrupt context, and the pte
                 * lock is held(spinlock), which implies preemption disabled.
                 */
-               __mod_zone_page_state(page_zone(page), NR_MLOCK,
-                                   thp_nr_pages(page));
-               count_vm_event(UNEVICTABLE_PGMLOCKED);
+               __mod_zone_page_state(page_zone(page), NR_MLOCK, nr_pages);
+               count_vm_events(UNEVICTABLE_PGMLOCKED, nr_pages);
        }
        lru_cache_add(page);
 }
@@ -763,10 +763,20 @@ static void lru_add_drain_per_cpu(struct work_struct *dummy)
  */
 void lru_add_drain_all(void)
 {
-       static seqcount_t seqcount = SEQCNT_ZERO(seqcount);
-       static DEFINE_MUTEX(lock);
+       /*
+        * lru_drain_gen - Global pages generation number
+        *
+        * (A) Definition: global lru_drain_gen = x implies that all generations
+        *     0 < n <= x are already *scheduled* for draining.
+        *
+        * This is an optimization for the highly-contended use case where a
+        * user space workload keeps constantly generating a flow of pages for
+        * each CPU.
+        */
+       static unsigned int lru_drain_gen;
        static struct cpumask has_work;
-       int cpu, seq;
+       static DEFINE_MUTEX(lock);
+       unsigned cpu, this_gen;
 
        /*
         * Make sure nobody triggers this path before mm_percpu_wq is fully
@@ -775,21 +785,54 @@ void lru_add_drain_all(void)
        if (WARN_ON(!mm_percpu_wq))
                return;
 
-       seq = raw_read_seqcount_latch(&seqcount);
+       /*
+        * Guarantee pagevec counter stores visible by this CPU are visible to
+        * other CPUs before loading the current drain generation.
+        */
+       smp_mb();
+
+       /*
+        * (B) Locally cache global LRU draining generation number
+        *
+        * The read barrier ensures that the counter is loaded before the mutex
+        * is taken. It pairs with smp_mb() inside the mutex critical section
+        * at (D).
+        */
+       this_gen = smp_load_acquire(&lru_drain_gen);
 
        mutex_lock(&lock);
 
        /*
-        * Piggyback on drain started and finished while we waited for lock:
-        * all pages pended at the time of our enter were drained from vectors.
+        * (C) Exit the draining operation if a newer generation, from another
+        * lru_add_drain_all(), was already scheduled for draining. Check (A).
         */
-       if (__read_seqcount_retry(&seqcount, seq))
+       if (unlikely(this_gen != lru_drain_gen))
                goto done;
 
-       raw_write_seqcount_latch(&seqcount);
+       /*
+        * (D) Increment global generation number
+        *
+        * Pairs with smp_load_acquire() at (B), outside of the critical
+        * section. Use a full memory barrier to guarantee that the new global
+        * drain generation number is stored before loading pagevec counters.
+        *
+        * This pairing must be done here, before the for_each_online_cpu loop
+        * below which drains the page vectors.
+        *
+        * Let x, y, and z represent some system CPU numbers, where x < y < z.
+        * Assume CPU #z is is in the middle of the for_each_online_cpu loop
+        * below and has already reached CPU #y's per-cpu data. CPU #x comes
+        * along, adds some pages to its per-cpu vectors, then calls
+        * lru_add_drain_all().
+        *
+        * If the paired barrier is done at any later step, e.g. after the
+        * loop, CPU #x will just exit at (C) and miss flushing out all of its
+        * added pages.
+        */
+       WRITE_ONCE(lru_drain_gen, lru_drain_gen + 1);
+       smp_mb();
 
        cpumask_clear(&has_work);
-
        for_each_online_cpu(cpu) {
                struct work_struct *work = &per_cpu(lru_add_drain_work, cpu);
 
@@ -801,7 +844,7 @@ void lru_add_drain_all(void)
                    need_activate_page_drain(cpu)) {
                        INIT_WORK(work, lru_add_drain_per_cpu);
                        queue_work_on(cpu, mm_percpu_wq, work);
-                       cpumask_set_cpu(cpu, &has_work);
+                       __cpumask_set_cpu(cpu, &has_work);
                }
        }
 
@@ -816,7 +859,7 @@ void lru_add_drain_all(void)
 {
        lru_add_drain();
 }
-#endif
+#endif /* CONFIG_SMP */
 
 /**
  * release_pages - batched put_page()
index 12f59e6..4951f53 100644 (file)
@@ -717,6 +717,7 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset,
        else
                swap_slot_free_notify = NULL;
        while (offset <= end) {
+               arch_swap_invalidate_page(si->type, offset);
                frontswap_invalidate_page(si->type, offset);
                if (swap_slot_free_notify)
                        swap_slot_free_notify(si->bdev, offset);
@@ -1078,7 +1079,7 @@ start_over:
                        goto nextsi;
                }
                if (size == SWAPFILE_CLUSTER) {
-                       if (!(si->flags & SWP_FS))
+                       if (si->flags & SWP_BLKDEV)
                                n_ret = swap_alloc_cluster(si, swp_entries);
                } else
                        n_ret = scan_swap_map_slots(si, SWAP_HAS_CACHE,
@@ -2682,6 +2683,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        frontswap_map = frontswap_map_get(p);
        spin_unlock(&p->lock);
        spin_unlock(&swap_lock);
+       arch_swap_invalidate_area(p->type);
        frontswap_invalidate_area(p->type);
        frontswap_map_set(p, NULL);
        mutex_unlock(&swapon_mutex);
index 5ef378a..4e21fe7 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -957,7 +957,7 @@ out:
        return res;
 }
 
-int memcmp_pages(struct page *page1, struct page *page2)
+int __weak memcmp_pages(struct page *page1, struct page *page2)
 {
        char *addr1, *addr2;
        int ret;
index 99e1796..466fc31 100644 (file)
@@ -2615,6 +2615,14 @@ static void shrink_node_memcgs(pg_data_t *pgdat, struct scan_control *sc)
                unsigned long reclaimed;
                unsigned long scanned;
 
+               /*
+                * This loop can become CPU-bound when target memcgs
+                * aren't eligible for reclaim - either because they
+                * don't have any reclaimable pages, or because their
+                * memory is explicitly protected. Avoid soft lockups.
+                */
+               cond_resched();
+
                mem_cgroup_calculate_protection(target_memcg, memcg);
 
                if (mem_cgroup_below_min(memcg)) {
@@ -4260,8 +4268,14 @@ void check_move_unevictable_pages(struct pagevec *pvec)
        for (i = 0; i < pvec->nr; i++) {
                struct page *page = pvec->pages[i];
                struct pglist_data *pagepgdat = page_pgdat(page);
+               int nr_pages;
+
+               if (PageTransTail(page))
+                       continue;
+
+               nr_pages = thp_nr_pages(page);
+               pgscanned += nr_pages;
 
-               pgscanned++;
                if (pagepgdat != pgdat) {
                        if (pgdat)
                                spin_unlock_irq(&pgdat->lru_lock);
@@ -4280,7 +4294,7 @@ void check_move_unevictable_pages(struct pagevec *pvec)
                        ClearPageUnevictable(page);
                        del_page_from_lru_list(page, lruvec, LRU_UNEVICTABLE);
                        add_page_to_lru_list(page, lruvec, lru);
-                       pgrescued++;
+                       pgrescued += nr_pages;
                }
        }
 
index e670f91..4f7b4ee 100644 (file)
@@ -1241,6 +1241,7 @@ const char * const vmstat_text[] = {
        "pglazyfreed",
 
        "pgrefill",
+       "pgreuse",
        "pgsteal_kswapd",
        "pgsteal_direct",
        "pgscan_kswapd",
index 3dd7c97..ec8408d 100644 (file)
@@ -367,7 +367,7 @@ static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCSHWTSTAMP:
                if (!net_eq(dev_net(dev), &init_net))
                        break;
-               /* fall through */
+               fallthrough;
        case SIOCGMIIPHY:
        case SIOCGMIIREG:
        case SIOCSMIIREG:
index 3debad9..bc8807d 100644 (file)
@@ -520,7 +520,7 @@ static void xen_9pfs_front_changed(struct xenbus_device *dev,
        case XenbusStateClosed:
                if (dev->state == XenbusStateClosed)
                        break;
-               /* fall through - Missed the backend's CLOSING state */
+               fallthrough;    /* Missed the backend's CLOSING state */
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;
index 84367b8..1cfa9bf 100644 (file)
@@ -297,7 +297,7 @@ static int adjust_tp(struct atm_trafprm *tp, unsigned char aal)
                break;
        default:
                pr_warn("AAL problems ... (%d)\n", aal);
-               /* fall through */
+               fallthrough;
        case ATM_AAL5:
                max_sdu = ATM_MAX_AAL5_PDU;
        }
@@ -417,7 +417,7 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
        case ATM_NO_AAL:
                /* ATM_AAL5 is also used in the "0 for default" case */
                vcc->qos.aal = ATM_AAL5;
-               /* fall through */
+               fallthrough;
        case ATM_AAL5:
                error = atm_init_aal5(vcc);
                vcc->stats = &dev->stats.aal5;
index 875fc0b..b570ef9 100644 (file)
@@ -380,7 +380,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
 
                if (mesg->content.normal.no_source_le_narp)
                        break;
-               /* FALL THROUGH */
+               fallthrough;
        case l_arp_update:
                lec_arp_update(priv, mesg->content.normal.mac_addr,
                               mesg->content.normal.atm_addr,
index 94bdc65..5323698 100644 (file)
@@ -266,7 +266,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
                                goto done;
                        }
        }
-       /* fall through */
+               fallthrough;
        case ATM_SETESIF:
        {
                unsigned char esi[ESI_LEN];
@@ -288,7 +288,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
                        error = -EPERM;
                        goto done;
                }
-               /* fall through */
+               fallthrough;
        case ATM_GETSTAT:
                size = sizeof(struct atm_dev_stats);
                error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
@@ -361,7 +361,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
                        error = -EINVAL;
                        goto done;
                }
-               /* fall through */
+               fallthrough;
        case ATM_SETCIRANGE:
        case SONET_GETSTATZ:
        case SONET_SETDIAG:
@@ -371,7 +371,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
                        error = -EPERM;
                        goto done;
                }
-               /* fall through */
+               fallthrough;
        default:
                if (IS_ENABLED(CONFIG_COMPAT) && compat) {
 #ifdef CONFIG_COMPAT
index 0f8495b..717fe65 100644 (file)
@@ -881,6 +881,12 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
                   ntohl(ogm_packet->seqno), ogm_throughput, ogm_packet->ttl,
                   ogm_packet->version, ntohs(ogm_packet->tvlv_len));
 
+       if (batadv_is_my_mac(bat_priv, ogm_packet->orig)) {
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Drop packet: originator packet from ourself\n");
+               return;
+       }
+
        /* If the throughput metric is 0, immediately drop the packet. No need
         * to create orig_node / neigh_node for an unusable route.
         */
@@ -1008,11 +1014,6 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb,
        if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
                goto free_skb;
 
-       ogm_packet = (struct batadv_ogm2_packet *)skb->data;
-
-       if (batadv_is_my_mac(bat_priv, ogm_packet->orig))
-               goto free_skb;
-
        batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
        batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
                           skb->len + ETH_HLEN);
index 91a04ca..c350ab6 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/lockdep.h>
 #include <linux/netdevice.h>
 #include <linux/netlink.h>
+#include <linux/preempt.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
 #include <linux/seq_file.h>
@@ -83,11 +84,12 @@ static inline u32 batadv_choose_claim(const void *data, u32 size)
  */
 static inline u32 batadv_choose_backbone_gw(const void *data, u32 size)
 {
-       const struct batadv_bla_claim *claim = (struct batadv_bla_claim *)data;
+       const struct batadv_bla_backbone_gw *gw;
        u32 hash = 0;
 
-       hash = jhash(&claim->addr, sizeof(claim->addr), hash);
-       hash = jhash(&claim->vid, sizeof(claim->vid), hash);
+       gw = (struct batadv_bla_backbone_gw *)data;
+       hash = jhash(&gw->orig, sizeof(gw->orig), hash);
+       hash = jhash(&gw->vid, sizeof(gw->vid), hash);
 
        return hash % size;
 }
@@ -437,7 +439,10 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac,
        batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
                           skb->len + ETH_HLEN);
 
-       netif_rx(skb);
+       if (in_interrupt())
+               netif_rx(skb);
+       else
+               netif_rx_ni(skb);
 out:
        if (primary_if)
                batadv_hardif_put(primary_if);
@@ -1576,13 +1581,16 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
 }
 
 /**
- * batadv_bla_check_bcast_duplist() - Check if a frame is in the broadcast dup.
+ * batadv_bla_check_duplist() - Check if a frame is in the broadcast dup.
  * @bat_priv: the bat priv with all the soft interface information
- * @skb: contains the bcast_packet to be checked
+ * @skb: contains the multicast packet to be checked
+ * @payload_ptr: pointer to position inside the head buffer of the skb
+ *  marking the start of the data to be CRC'ed
+ * @orig: originator mac address, NULL if unknown
  *
- * check if it is on our broadcast list. Another gateway might
- * have sent the same packet because it is connected to the same backbone,
- * so we have to remove this duplicate.
+ * Check if it is on our broadcast list. Another gateway might have sent the
+ * same packet because it is connected to the same backbone, so we have to
+ * remove this duplicate.
  *
  * This is performed by checking the CRC, which will tell us
  * with a good chance that it is the same packet. If it is furthermore
@@ -1591,19 +1599,17 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
  *
  * Return: true if a packet is in the duplicate list, false otherwise.
  */
-bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
-                                   struct sk_buff *skb)
+static bool batadv_bla_check_duplist(struct batadv_priv *bat_priv,
+                                    struct sk_buff *skb, u8 *payload_ptr,
+                                    const u8 *orig)
 {
-       int i, curr;
-       __be32 crc;
-       struct batadv_bcast_packet *bcast_packet;
        struct batadv_bcast_duplist_entry *entry;
        bool ret = false;
-
-       bcast_packet = (struct batadv_bcast_packet *)skb->data;
+       int i, curr;
+       __be32 crc;
 
        /* calculate the crc ... */
-       crc = batadv_skb_crc32(skb, (u8 *)(bcast_packet + 1));
+       crc = batadv_skb_crc32(skb, payload_ptr);
 
        spin_lock_bh(&bat_priv->bla.bcast_duplist_lock);
 
@@ -1622,8 +1628,21 @@ bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
                if (entry->crc != crc)
                        continue;
 
-               if (batadv_compare_eth(entry->orig, bcast_packet->orig))
-                       continue;
+               /* are the originators both known and not anonymous? */
+               if (orig && !is_zero_ether_addr(orig) &&
+                   !is_zero_ether_addr(entry->orig)) {
+                       /* If known, check if the new frame came from
+                        * the same originator:
+                        * We are safe to take identical frames from the
+                        * same orig, if known, as multiplications in
+                        * the mesh are detected via the (orig, seqno) pair.
+                        * So we can be a bit more liberal here and allow
+                        * identical frames from the same orig which the source
+                        * host might have sent multiple times on purpose.
+                        */
+                       if (batadv_compare_eth(entry->orig, orig))
+                               continue;
+               }
 
                /* this entry seems to match: same crc, not too old,
                 * and from another gw. therefore return true to forbid it.
@@ -1639,7 +1658,14 @@ bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
        entry = &bat_priv->bla.bcast_duplist[curr];
        entry->crc = crc;
        entry->entrytime = jiffies;
-       ether_addr_copy(entry->orig, bcast_packet->orig);
+
+       /* known originator */
+       if (orig)
+               ether_addr_copy(entry->orig, orig);
+       /* anonymous originator */
+       else
+               eth_zero_addr(entry->orig);
+
        bat_priv->bla.bcast_duplist_curr = curr;
 
 out:
@@ -1649,6 +1675,48 @@ out:
 }
 
 /**
+ * batadv_bla_check_ucast_duplist() - Check if a frame is in the broadcast dup.
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: contains the multicast packet to be checked, decapsulated from a
+ *  unicast_packet
+ *
+ * Check if it is on our broadcast list. Another gateway might have sent the
+ * same packet because it is connected to the same backbone, so we have to
+ * remove this duplicate.
+ *
+ * Return: true if a packet is in the duplicate list, false otherwise.
+ */
+static bool batadv_bla_check_ucast_duplist(struct batadv_priv *bat_priv,
+                                          struct sk_buff *skb)
+{
+       return batadv_bla_check_duplist(bat_priv, skb, (u8 *)skb->data, NULL);
+}
+
+/**
+ * batadv_bla_check_bcast_duplist() - Check if a frame is in the broadcast dup.
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: contains the bcast_packet to be checked
+ *
+ * Check if it is on our broadcast list. Another gateway might have sent the
+ * same packet because it is connected to the same backbone, so we have to
+ * remove this duplicate.
+ *
+ * Return: true if a packet is in the duplicate list, false otherwise.
+ */
+bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
+                                   struct sk_buff *skb)
+{
+       struct batadv_bcast_packet *bcast_packet;
+       u8 *payload_ptr;
+
+       bcast_packet = (struct batadv_bcast_packet *)skb->data;
+       payload_ptr = (u8 *)(bcast_packet + 1);
+
+       return batadv_bla_check_duplist(bat_priv, skb, payload_ptr,
+                                       bcast_packet->orig);
+}
+
+/**
  * batadv_bla_is_backbone_gw_orig() - Check if the originator is a gateway for
  *  the VLAN identified by vid.
  * @bat_priv: the bat priv with all the soft interface information
@@ -1809,7 +1877,7 @@ batadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb,
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the frame to be checked
  * @vid: the VLAN ID of the frame
- * @is_bcast: the packet came in a broadcast packet type.
+ * @packet_type: the batman packet type this frame came in
  *
  * batadv_bla_rx avoidance checks if:
  *  * we have to race for a claim
@@ -1821,7 +1889,7 @@ batadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb,
  * further process the skb.
  */
 bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
-                  unsigned short vid, bool is_bcast)
+                  unsigned short vid, int packet_type)
 {
        struct batadv_bla_backbone_gw *backbone_gw;
        struct ethhdr *ethhdr;
@@ -1843,9 +1911,32 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
                goto handled;
 
        if (unlikely(atomic_read(&bat_priv->bla.num_requests)))
-               /* don't allow broadcasts while requests are in flight */
-               if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast)
-                       goto handled;
+               /* don't allow multicast packets while requests are in flight */
+               if (is_multicast_ether_addr(ethhdr->h_dest))
+                       /* Both broadcast flooding or multicast-via-unicasts
+                        * delivery might send to multiple backbone gateways
+                        * sharing the same LAN and therefore need to coordinate
+                        * which backbone gateway forwards into the LAN,
+                        * by claiming the payload source address.
+                        *
+                        * Broadcast flooding and multicast-via-unicasts
+                        * delivery use the following two batman packet types.
+                        * Note: explicitly exclude BATADV_UNICAST_4ADDR,
+                        * as the DHCP gateway feature will send explicitly
+                        * to only one BLA gateway, so the claiming process
+                        * should be avoided there.
+                        */
+                       if (packet_type == BATADV_BCAST ||
+                           packet_type == BATADV_UNICAST)
+                               goto handled;
+
+       /* potential duplicates from foreign BLA backbone gateways via
+        * multicast-in-unicast packets
+        */
+       if (is_multicast_ether_addr(ethhdr->h_dest) &&
+           packet_type == BATADV_UNICAST &&
+           batadv_bla_check_ucast_duplist(bat_priv, skb))
+               goto handled;
 
        ether_addr_copy(search_claim.addr, ethhdr->h_source);
        search_claim.vid = vid;
@@ -1880,13 +1971,14 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
                goto allow;
        }
 
-       /* if it is a broadcast ... */
-       if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast) {
+       /* if it is a multicast ... */
+       if (is_multicast_ether_addr(ethhdr->h_dest) &&
+           (packet_type == BATADV_BCAST || packet_type == BATADV_UNICAST)) {
                /* ... drop it. the responsible gateway is in charge.
                 *
-                * We need to check is_bcast because with the gateway
+                * We need to check packet type because with the gateway
                 * feature, broadcasts (like DHCP requests) may be sent
-                * using a unicast packet type.
+                * using a unicast 4 address packet type. See comment above.
                 */
                goto handled;
        } else {
index 41edb2c..a81c41b 100644 (file)
@@ -35,7 +35,7 @@ static inline bool batadv_bla_is_loopdetect_mac(const uint8_t *mac)
 
 #ifdef CONFIG_BATMAN_ADV_BLA
 bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
-                  unsigned short vid, bool is_bcast);
+                  unsigned short vid, int packet_type);
 bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
                   unsigned short vid);
 bool batadv_bla_is_backbone_gw(struct sk_buff *skb,
@@ -66,7 +66,7 @@ bool batadv_bla_check_claim(struct batadv_priv *bat_priv, u8 *addr,
 
 static inline bool batadv_bla_rx(struct batadv_priv *bat_priv,
                                 struct sk_buff *skb, unsigned short vid,
-                                bool is_bcast)
+                                int packet_type)
 {
        return false;
 }
index a18dcc6..ef3f85b 100644 (file)
@@ -703,8 +703,10 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
 
        chaddr_offset = *header_len + BATADV_DHCP_CHADDR_OFFSET;
        /* store the client address if the message is going to a client */
-       if (ret == BATADV_DHCP_TO_CLIENT &&
-           pskb_may_pull(skb, chaddr_offset + ETH_ALEN)) {
+       if (ret == BATADV_DHCP_TO_CLIENT) {
+               if (!pskb_may_pull(skb, chaddr_offset + ETH_ALEN))
+                       return BATADV_DHCP_NO;
+
                /* check if the DHCP packet carries an Ethernet DHCP */
                p = skb->data + *header_len + BATADV_DHCP_HTYPE_OFFSET;
                if (*p != BATADV_DHCP_HTYPE_ETHERNET)
index bdc4a1f..ca24a2e 100644 (file)
@@ -51,6 +51,7 @@
 #include <uapi/linux/batadv_packet.h>
 #include <uapi/linux/batman_adv.h>
 
+#include "bridge_loop_avoidance.h"
 #include "hard-interface.h"
 #include "hash.h"
 #include "log.h"
@@ -1435,6 +1436,35 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
 }
 
 /**
+ * batadv_mcast_forw_send_orig() - send a multicast packet to an originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the multicast packet to send
+ * @vid: the vlan identifier
+ * @orig_node: the originator to send the packet to
+ *
+ * Return: NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
+ */
+int batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
+                               struct sk_buff *skb,
+                               unsigned short vid,
+                               struct batadv_orig_node *orig_node)
+{
+       /* Avoid sending multicast-in-unicast packets to other BLA
+        * gateways - they already got the frame from the LAN side
+        * we share with them.
+        * TODO: Refactor to take BLA into account earlier, to avoid
+        * reducing the mcast_fanout count.
+        */
+       if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) {
+               dev_kfree_skb(skb);
+               return NET_XMIT_SUCCESS;
+       }
+
+       return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST, 0,
+                                      orig_node, vid);
+}
+
+/**
  * batadv_mcast_forw_tt() - forwards a packet to multicast listeners
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the multicast packet to transmit
@@ -1471,8 +1501,8 @@ batadv_mcast_forw_tt(struct batadv_priv *bat_priv, struct sk_buff *skb,
                        break;
                }
 
-               batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0,
-                                       orig_entry->orig_node, vid);
+               batadv_mcast_forw_send_orig(bat_priv, newskb, vid,
+                                           orig_entry->orig_node);
        }
        rcu_read_unlock();
 
@@ -1513,8 +1543,7 @@ batadv_mcast_forw_want_all_ipv4(struct batadv_priv *bat_priv,
                        break;
                }
 
-               batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0,
-                                       orig_node, vid);
+               batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
        }
        rcu_read_unlock();
        return ret;
@@ -1551,8 +1580,7 @@ batadv_mcast_forw_want_all_ipv6(struct batadv_priv *bat_priv,
                        break;
                }
 
-               batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0,
-                                       orig_node, vid);
+               batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
        }
        rcu_read_unlock();
        return ret;
@@ -1618,8 +1646,7 @@ batadv_mcast_forw_want_all_rtr4(struct batadv_priv *bat_priv,
                        break;
                }
 
-               batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0,
-                                       orig_node, vid);
+               batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
        }
        rcu_read_unlock();
        return ret;
@@ -1656,8 +1683,7 @@ batadv_mcast_forw_want_all_rtr6(struct batadv_priv *bat_priv,
                        break;
                }
 
-               batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0,
-                                       orig_node, vid);
+               batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
        }
        rcu_read_unlock();
        return ret;
index ebf8259..3e114bc 100644 (file)
@@ -46,6 +46,11 @@ enum batadv_forw_mode
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
                       struct batadv_orig_node **mcast_single_orig);
 
+int batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
+                               struct sk_buff *skb,
+                               unsigned short vid,
+                               struct batadv_orig_node *orig_node);
+
 int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
                           unsigned short vid);
 
@@ -72,6 +77,16 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
 }
 
 static inline int
+batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
+                           struct sk_buff *skb,
+                           unsigned short vid,
+                           struct batadv_orig_node *orig_node)
+{
+       kfree_skb(skb);
+       return NET_XMIT_DROP;
+}
+
+static inline int
 batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
                       unsigned short vid)
 {
index 27cdf5e..9e5c71e 100644 (file)
@@ -826,6 +826,10 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
        vid = batadv_get_vid(skb, hdr_len);
        ethhdr = (struct ethhdr *)(skb->data + hdr_len);
 
+       /* do not reroute multicast frames in a unicast header */
+       if (is_multicast_ether_addr(ethhdr->h_dest))
+               return true;
+
        /* check if the destination client was served by this node and it is now
         * roaming. In this case, it means that the node has got a ROAM_ADV
         * message and that it knows the new destination in the mesh to re-route
index 23833a0..cdde943 100644 (file)
@@ -364,9 +364,8 @@ send:
                                goto dropped;
                        ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
                } else if (mcast_single_orig) {
-                       ret = batadv_send_skb_unicast(bat_priv, skb,
-                                                     BATADV_UNICAST, 0,
-                                                     mcast_single_orig, vid);
+                       ret = batadv_mcast_forw_send_orig(bat_priv, skb, vid,
+                                                         mcast_single_orig);
                } else if (forw_mode == BATADV_FORW_SOME) {
                        ret = batadv_mcast_forw_send(bat_priv, skb, vid);
                } else {
@@ -425,10 +424,10 @@ void batadv_interface_rx(struct net_device *soft_iface,
        struct vlan_ethhdr *vhdr;
        struct ethhdr *ethhdr;
        unsigned short vid;
-       bool is_bcast;
+       int packet_type;
 
        batadv_bcast_packet = (struct batadv_bcast_packet *)skb->data;
-       is_bcast = (batadv_bcast_packet->packet_type == BATADV_BCAST);
+       packet_type = batadv_bcast_packet->packet_type;
 
        skb_pull_rcsum(skb, hdr_size);
        skb_reset_mac_header(skb);
@@ -471,7 +470,7 @@ void batadv_interface_rx(struct net_device *soft_iface,
        /* Let the bridge loop avoidance check the packet. If will
         * not handle it, we can safely push it up.
         */
-       if (batadv_bla_rx(bat_priv, skb, vid, is_bcast))
+       if (batadv_bla_rx(bat_priv, skb, vid, packet_type))
                goto out;
 
        if (orig_node)
index 99eb8c6..a66f211 100644 (file)
@@ -425,7 +425,7 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
        case BPF_PROG_TYPE_SCHED_CLS:
        case BPF_PROG_TYPE_SCHED_ACT:
                is_l2 = true;
-               /* fall through */
+               fallthrough;
        case BPF_PROG_TYPE_LWT_IN:
        case BPF_PROG_TYPE_LWT_OUT:
        case BPF_PROG_TYPE_LWT_XMIT:
index b18cdf0..dfec65e 100644 (file)
@@ -88,9 +88,10 @@ static void br_arp_send(struct net_bridge *br, struct net_bridge_port *p,
        }
 }
 
-static int br_chk_addr_ip(struct net_device *dev, void *data)
+static int br_chk_addr_ip(struct net_device *dev,
+                         struct netdev_nested_priv *priv)
 {
-       __be32 ip = *(__be32 *)data;
+       __be32 ip = *(__be32 *)priv->data;
        struct in_device *in_dev;
        __be32 addr = 0;
 
@@ -107,11 +108,15 @@ static int br_chk_addr_ip(struct net_device *dev, void *data)
 
 static bool br_is_local_ip(struct net_device *dev, __be32 ip)
 {
-       if (br_chk_addr_ip(dev, &ip))
+       struct netdev_nested_priv priv = {
+               .data = (void *)&ip,
+       };
+
+       if (br_chk_addr_ip(dev, &priv))
                return true;
 
        /* check if ip is configured on upper dev */
-       if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip, &ip))
+       if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip, &priv))
                return true;
 
        return false;
@@ -361,9 +366,10 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
        }
 }
 
-static int br_chk_addr_ip6(struct net_device *dev, void *data)
+static int br_chk_addr_ip6(struct net_device *dev,
+                          struct netdev_nested_priv *priv)
 {
-       struct in6_addr *addr = (struct in6_addr *)data;
+       struct in6_addr *addr = (struct in6_addr *)priv->data;
 
        if (ipv6_chk_addr(dev_net(dev), addr, dev, 0))
                return 1;
@@ -374,11 +380,15 @@ static int br_chk_addr_ip6(struct net_device *dev, void *data)
 static bool br_is_local_ip6(struct net_device *dev, struct in6_addr *addr)
 
 {
-       if (br_chk_addr_ip6(dev, addr))
+       struct netdev_nested_priv priv = {
+               .data = (void *)addr,
+       };
+
+       if (br_chk_addr_ip6(dev, &priv))
                return true;
 
        /* check if ip is configured on upper dev */
-       if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip6, addr))
+       if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip6, &priv))
                return true;
 
        return false;
index 9db504b..32ac834 100644 (file)
@@ -413,6 +413,8 @@ void br_fdb_delete_by_port(struct net_bridge *br,
 
                if (!do_all)
                        if (test_bit(BR_FDB_STATIC, &f->flags) ||
+                           (test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &f->flags) &&
+                            !test_bit(BR_FDB_OFFLOADED, &f->flags)) ||
                            (vid && f->key.vlan_id != vid))
                                continue;
 
index 147d525..da310f0 100644 (file)
@@ -380,6 +380,7 @@ static int br_fill_ifinfo(struct sk_buff *skb,
                          u32 filter_mask, const struct net_device *dev)
 {
        u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
+       struct nlattr *af = NULL;
        struct net_bridge *br;
        struct ifinfomsg *hdr;
        struct nlmsghdr *nlh;
@@ -423,11 +424,18 @@ static int br_fill_ifinfo(struct sk_buff *skb,
                nla_nest_end(skb, nest);
        }
 
+       if (filter_mask & (RTEXT_FILTER_BRVLAN |
+                          RTEXT_FILTER_BRVLAN_COMPRESSED |
+                          RTEXT_FILTER_MRP)) {
+               af = nla_nest_start_noflag(skb, IFLA_AF_SPEC);
+               if (!af)
+                       goto nla_put_failure;
+       }
+
        /* Check if  the VID information is requested */
        if ((filter_mask & RTEXT_FILTER_BRVLAN) ||
            (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) {
                struct net_bridge_vlan_group *vg;
-               struct nlattr *af;
                int err;
 
                /* RCU needed because of the VLAN locking rules (rcu || rtnl) */
@@ -441,11 +449,6 @@ static int br_fill_ifinfo(struct sk_buff *skb,
                        rcu_read_unlock();
                        goto done;
                }
-               af = nla_nest_start_noflag(skb, IFLA_AF_SPEC);
-               if (!af) {
-                       rcu_read_unlock();
-                       goto nla_put_failure;
-               }
                if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)
                        err = br_fill_ifvlaninfo_compressed(skb, vg);
                else
@@ -456,32 +459,25 @@ static int br_fill_ifinfo(struct sk_buff *skb,
                rcu_read_unlock();
                if (err)
                        goto nla_put_failure;
-
-               nla_nest_end(skb, af);
        }
 
        if (filter_mask & RTEXT_FILTER_MRP) {
-               struct nlattr *af;
                int err;
 
                if (!br_mrp_enabled(br) || port)
                        goto done;
 
-               af = nla_nest_start_noflag(skb, IFLA_AF_SPEC);
-               if (!af)
-                       goto nla_put_failure;
-
                rcu_read_lock();
                err = br_mrp_fill_info(skb, br);
                rcu_read_unlock();
 
                if (err)
                        goto nla_put_failure;
-
-               nla_nest_end(skb, af);
        }
 
 done:
+       if (af)
+               nla_nest_end(skb, af);
        nlmsg_end(skb, nlh);
        return 0;
 
index f9092c7..ee87800 100644 (file)
@@ -1288,11 +1288,13 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v,
        }
 }
 
-static int __br_vlan_get_pvid(const struct net_device *dev,
-                             struct net_bridge_port *p, u16 *p_pvid)
+int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid)
 {
        struct net_bridge_vlan_group *vg;
+       struct net_bridge_port *p;
 
+       ASSERT_RTNL();
+       p = br_port_get_check_rtnl(dev);
        if (p)
                vg = nbp_vlan_group(p);
        else if (netif_is_bridge_master(dev))
@@ -1303,18 +1305,23 @@ static int __br_vlan_get_pvid(const struct net_device *dev,
        *p_pvid = br_get_pvid(vg);
        return 0;
 }
-
-int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid)
-{
-       ASSERT_RTNL();
-
-       return __br_vlan_get_pvid(dev, br_port_get_check_rtnl(dev), p_pvid);
-}
 EXPORT_SYMBOL_GPL(br_vlan_get_pvid);
 
 int br_vlan_get_pvid_rcu(const struct net_device *dev, u16 *p_pvid)
 {
-       return __br_vlan_get_pvid(dev, br_port_get_check_rcu(dev), p_pvid);
+       struct net_bridge_vlan_group *vg;
+       struct net_bridge_port *p;
+
+       p = br_port_get_check_rcu(dev);
+       if (p)
+               vg = nbp_vlan_group_rcu(p);
+       else if (netif_is_bridge_master(dev))
+               vg = br_vlan_group_rcu(netdev_priv(dev));
+       else
+               return -EINVAL;
+
+       *p_pvid = br_get_pvid(vg);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(br_vlan_get_pvid_rcu);
 
@@ -1353,7 +1360,7 @@ static int br_vlan_is_bind_vlan_dev(const struct net_device *dev)
 }
 
 static int br_vlan_is_bind_vlan_dev_fn(struct net_device *dev,
-                                      __always_unused void *data)
+                              __always_unused struct netdev_nested_priv *priv)
 {
        return br_vlan_is_bind_vlan_dev(dev);
 }
@@ -1376,9 +1383,9 @@ struct br_vlan_bind_walk_data {
 };
 
 static int br_vlan_match_bind_vlan_dev_fn(struct net_device *dev,
-                                         void *data_in)
+                                         struct netdev_nested_priv *priv)
 {
-       struct br_vlan_bind_walk_data *data = data_in;
+       struct br_vlan_bind_walk_data *data = priv->data;
        int found = 0;
 
        if (br_vlan_is_bind_vlan_dev(dev) &&
@@ -1396,10 +1403,13 @@ br_vlan_get_upper_bind_vlan_dev(struct net_device *dev, u16 vid)
        struct br_vlan_bind_walk_data data = {
                .vid = vid,
        };
+       struct netdev_nested_priv priv = {
+               .data = (void *)&data,
+       };
 
        rcu_read_lock();
        netdev_walk_all_upper_dev_rcu(dev, br_vlan_match_bind_vlan_dev_fn,
-                                     &data);
+                                     &priv);
        rcu_read_unlock();
 
        return data.result;
@@ -1480,9 +1490,9 @@ struct br_vlan_link_state_walk_data {
 };
 
 static int br_vlan_link_state_change_fn(struct net_device *vlan_dev,
-                                       void *data_in)
+                                       struct netdev_nested_priv *priv)
 {
-       struct br_vlan_link_state_walk_data *data = data_in;
+       struct br_vlan_link_state_walk_data *data = priv->data;
 
        if (br_vlan_is_bind_vlan_dev(vlan_dev))
                br_vlan_set_vlan_dev_state(data->br, vlan_dev);
@@ -1496,10 +1506,13 @@ static void br_vlan_link_state_change(struct net_device *dev,
        struct br_vlan_link_state_walk_data data = {
                .br = br
        };
+       struct netdev_nested_priv priv = {
+               .data = (void *)&data,
+       };
 
        rcu_read_lock();
        netdev_walk_all_upper_dev_rcu(dev, br_vlan_link_state_change_fn,
-                                     &data);
+                                     &priv);
        rcu_read_unlock();
 }
 
index ce2767e..7b0af33 100644 (file)
@@ -116,7 +116,7 @@ static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt)
        if (segmented) {
                if (rfml->incomplete_frm == NULL) {
                        /* Initial Segment */
-                       if (cfpkt_peek_head(pkt, rfml->seghead, 6) < 0)
+                       if (cfpkt_peek_head(pkt, rfml->seghead, 6) != 0)
                                goto out;
 
                        rfml->pdu_size = get_unaligned_le16(rfml->seghead+4);
@@ -233,7 +233,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
        if (cfpkt_getlen(pkt) > rfml->fragment_size + RFM_HEAD_SIZE)
                err = cfpkt_peek_head(pkt, head, 6);
 
-       if (err < 0)
+       if (err != 0)
                goto out;
 
        while (cfpkt_getlen(frontpkt) > rfml->fragment_size + RFM_HEAD_SIZE) {
index b93876c..1be4c89 100644 (file)
@@ -1086,7 +1086,7 @@ static int j1939_sk_send_loop(struct j1939_priv *priv,  struct sock *sk,
                break;
        case -ERESTARTSYS:
                ret = -EINTR;
-               /* fall through */
+               fallthrough;
        case -EAGAIN: /* OK */
                if (todo_size != size)
                        ret = size - todo_size;
index a8dd956..0cec415 100644 (file)
@@ -860,7 +860,7 @@ static int j1939_xtp_txnext_transmiter(struct j1939_session *session)
                                return ret;
                }
 
-               /* fall through */
+               fallthrough;
        case J1939_TP_CMD_CTS:
        case 0xff: /* did some data */
        case J1939_ETP_CMD_DPO:
@@ -1764,12 +1764,12 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
        case J1939_ETP_CMD_DPO:
                if (skcb->addr.type == J1939_ETP)
                        break;
-               /* fall through */
-       case J1939_TP_CMD_BAM: /* fall through */
+               fallthrough;
+       case J1939_TP_CMD_BAM:
        case J1939_TP_CMD_CTS: /* fall through */
                if (skcb->addr.type != J1939_ETP)
                        break;
-               /* fall through */
+               fallthrough;
        default:
                netdev_info(priv->ndev, "%s: 0x%p: last %02x\n", __func__,
                            session, session->last_cmd);
@@ -1965,8 +1965,8 @@ static void j1939_tp_cmd_recv(struct j1939_priv *priv, struct sk_buff *skb)
        switch (cmd) {
        case J1939_ETP_CMD_RTS:
                extd = J1939_ETP;
-               /* fall through */
-       case J1939_TP_CMD_BAM: /* fall through */
+               fallthrough;
+       case J1939_TP_CMD_BAM:
        case J1939_TP_CMD_RTS: /* fall through */
                if (skcb->addr.type != extd)
                        return;
@@ -1987,7 +1987,7 @@ static void j1939_tp_cmd_recv(struct j1939_priv *priv, struct sk_buff *skb)
 
        case J1939_ETP_CMD_CTS:
                extd = J1939_ETP;
-               /* fall through */
+               fallthrough;
        case J1939_TP_CMD_CTS:
                if (skcb->addr.type != extd)
                        return;
@@ -2014,7 +2014,7 @@ static void j1939_tp_cmd_recv(struct j1939_priv *priv, struct sk_buff *skb)
 
        case J1939_ETP_CMD_EOMA:
                extd = J1939_ETP;
-               /* fall through */
+               fallthrough;
        case J1939_TP_CMD_EOMA:
                if (skcb->addr.type != extd)
                        return;
@@ -2050,14 +2050,14 @@ int j1939_tp_recv(struct j1939_priv *priv, struct sk_buff *skb)
        switch (skcb->addr.pgn) {
        case J1939_ETP_PGN_DAT:
                skcb->addr.type = J1939_ETP;
-               /* fall through */
+               fallthrough;
        case J1939_TP_PGN_DAT:
                j1939_xtp_rx_dat(priv, skb);
                break;
 
        case J1939_ETP_PGN_CTL:
                skcb->addr.type = J1939_ETP;
-               /* fall through */
+               fallthrough;
        case J1939_TP_PGN_CTL:
                if (skb->len < 8)
                        return 0; /* Don't care. Nothing to extract here */
index 81e1e00..16a47c0 100644 (file)
@@ -50,35 +50,35 @@ unsigned int ceph_str_hash_rjenkins(const char *str, unsigned int length)
        switch (len) {
        case 11:
                c = c + ((__u32)k[10] << 24);
-               /* fall through */
+               fallthrough;
        case 10:
                c = c + ((__u32)k[9] << 16);
-               /* fall through */
+               fallthrough;
        case 9:
                c = c + ((__u32)k[8] << 8);
                /* the first byte of c is reserved for the length */
-               /* fall through */
+               fallthrough;
        case 8:
                b = b + ((__u32)k[7] << 24);
-               /* fall through */
+               fallthrough;
        case 7:
                b = b + ((__u32)k[6] << 16);
-               /* fall through */
+               fallthrough;
        case 6:
                b = b + ((__u32)k[5] << 8);
-               /* fall through */
+               fallthrough;
        case 5:
                b = b + k[4];
-               /* fall through */
+               fallthrough;
        case 4:
                a = a + ((__u32)k[3] << 24);
-               /* fall through */
+               fallthrough;
        case 3:
                a = a + ((__u32)k[2] << 16);
-               /* fall through */
+               fallthrough;
        case 2:
                a = a + ((__u32)k[1] << 8);
-               /* fall through */
+               fallthrough;
        case 1:
                a = a + k[0];
                /* case 0: nothing left to add */
index 07e5614..7057f8d 100644 (file)
@@ -987,7 +987,7 @@ int crush_do_rule(const struct crush_map *map,
                case CRUSH_RULE_CHOOSELEAF_FIRSTN:
                case CRUSH_RULE_CHOOSE_FIRSTN:
                        firstn = 1;
-                       /* fall through */
+                       fallthrough;
                case CRUSH_RULE_CHOOSELEAF_INDEP:
                case CRUSH_RULE_CHOOSE_INDEP:
                        if (wsize == 0)
index 27d6ab1..d4d7a0e 100644 (file)
@@ -412,7 +412,7 @@ static void ceph_sock_state_change(struct sock *sk)
        switch (sk->sk_state) {
        case TCP_CLOSE:
                dout("%s TCP_CLOSE\n", __func__);
-               /* fall through */
+               fallthrough;
        case TCP_CLOSE_WAIT:
                dout("%s TCP_CLOSE_WAIT\n", __func__);
                con_sock_state_closing(con);
@@ -575,7 +575,7 @@ static int ceph_tcp_sendpage(struct socket *sock, struct page *page,
         * coalescing neighboring slab objects into a single frag which
         * triggers one of hardened usercopy checks.
         */
-       if (page_count(page) >= 1 && !PageSlab(page))
+       if (sendpage_ok(page))
                sendpage = sock->ops->sendpage;
        else
                sendpage = sock_no_sendpage;
@@ -2751,7 +2751,7 @@ more:
                        switch (ret) {
                        case -EBADMSG:
                                con->error_msg = "bad crc/signature";
-                               /* fall through */
+                               fallthrough;
                        case -EBADE:
                                ret = -EIO;
                                break;
index 3d8c801..d633a0a 100644 (file)
@@ -1307,7 +1307,7 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
                 * request had a non-zero tid.  Work around this weirdness
                 * by allocating a new message.
                 */
-               /* fall through */
+               fallthrough;
        case CEPH_MSG_MON_MAP:
        case CEPH_MSG_MDS_MAP:
        case CEPH_MSG_OSD_MAP:
index e4fbcad..7901ab6 100644 (file)
@@ -3854,7 +3854,7 @@ static void scan_requests(struct ceph_osd *osd,
                        if (!force_resend && !force_resend_writes)
                                break;
 
-                       /* fall through */
+                       fallthrough;
                case CALC_TARGET_NEED_RESEND:
                        cancel_linger_map_check(lreq);
                        /*
@@ -3891,7 +3891,7 @@ static void scan_requests(struct ceph_osd *osd,
                             !force_resend_writes))
                                break;
 
-                       /* fall through */
+                       fallthrough;
                case CALC_TARGET_NEED_RESEND:
                        cancel_map_check(req);
                        unlink_request(osd, req);
index 95ce707..ddd15af 100644 (file)
@@ -98,8 +98,8 @@ int get_compat_msghdr(struct msghdr *kmsg,
        if (err)
                return err;
 
-       err = compat_import_iovec(save_addr ? READ : WRITE, compat_ptr(ptr),
-                                  len, UIO_FASTIOV, iov, &kmsg->msg_iter);
+       err = import_iovec(save_addr ? READ : WRITE, compat_ptr(ptr), len,
+                          UIO_FASTIOV, iov, &kmsg->msg_iter);
        return err < 0 ? err : 0;
 }
 
index d42c9ea..4906b44 100644 (file)
@@ -4690,10 +4690,10 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
                break;
        default:
                bpf_warn_invalid_xdp_action(act);
-               /* fall through */
+               fallthrough;
        case XDP_ABORTED:
                trace_xdp_exception(skb->dev, xdp_prog, act);
-               /* fall through */
+               fallthrough;
        case XDP_DROP:
        do_drop:
                kfree_skb(skb);
@@ -6612,12 +6612,13 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
                netdev_err_once(dev, "%s() called with weight %d\n", __func__,
                                weight);
        napi->weight = weight;
-       list_add(&napi->dev_list, &dev->napi_list);
        napi->dev = dev;
 #ifdef CONFIG_NETPOLL
        napi->poll_owner = -1;
 #endif
        set_bit(NAPI_STATE_SCHED, &napi->state);
+       set_bit(NAPI_STATE_NPSVC, &napi->state);
+       list_add_rcu(&napi->dev_list, &dev->napi_list);
        napi_hash_add(napi);
 }
 EXPORT_SYMBOL(netif_napi_add);
@@ -6811,9 +6812,10 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev,
        return NULL;
 }
 
-static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data)
+static int ____netdev_has_upper_dev(struct net_device *upper_dev,
+                                   struct netdev_nested_priv *priv)
 {
-       struct net_device *dev = data;
+       struct net_device *dev = (struct net_device *)priv->data;
 
        return upper_dev == dev;
 }
@@ -6830,10 +6832,14 @@ static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data)
 bool netdev_has_upper_dev(struct net_device *dev,
                          struct net_device *upper_dev)
 {
+       struct netdev_nested_priv priv = {
+               .data = (void *)upper_dev,
+       };
+
        ASSERT_RTNL();
 
        return netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,
-                                            upper_dev);
+                                            &priv);
 }
 EXPORT_SYMBOL(netdev_has_upper_dev);
 
@@ -6850,8 +6856,12 @@ EXPORT_SYMBOL(netdev_has_upper_dev);
 bool netdev_has_upper_dev_all_rcu(struct net_device *dev,
                                  struct net_device *upper_dev)
 {
+       struct netdev_nested_priv priv = {
+               .data = (void *)upper_dev,
+       };
+
        return !!netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,
-                                              upper_dev);
+                                              &priv);
 }
 EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu);
 
@@ -6996,8 +7006,8 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
 
 static int __netdev_walk_all_upper_dev(struct net_device *dev,
                                       int (*fn)(struct net_device *dev,
-                                                void *data),
-                                      void *data)
+                                        struct netdev_nested_priv *priv),
+                                      struct netdev_nested_priv *priv)
 {
        struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
        struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
@@ -7009,7 +7019,7 @@ static int __netdev_walk_all_upper_dev(struct net_device *dev,
 
        while (1) {
                if (now != dev) {
-                       ret = fn(now, data);
+                       ret = fn(now, priv);
                        if (ret)
                                return ret;
                }
@@ -7045,8 +7055,8 @@ static int __netdev_walk_all_upper_dev(struct net_device *dev,
 
 int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
                                  int (*fn)(struct net_device *dev,
-                                           void *data),
-                                 void *data)
+                                           struct netdev_nested_priv *priv),
+                                 struct netdev_nested_priv *priv)
 {
        struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
        struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
@@ -7057,7 +7067,7 @@ int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
 
        while (1) {
                if (now != dev) {
-                       ret = fn(now, data);
+                       ret = fn(now, priv);
                        if (ret)
                                return ret;
                }
@@ -7093,10 +7103,15 @@ EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu);
 static bool __netdev_has_upper_dev(struct net_device *dev,
                                   struct net_device *upper_dev)
 {
+       struct netdev_nested_priv priv = {
+               .flags = 0,
+               .data = (void *)upper_dev,
+       };
+
        ASSERT_RTNL();
 
        return __netdev_walk_all_upper_dev(dev, ____netdev_has_upper_dev,
-                                          upper_dev);
+                                          &priv);
 }
 
 /**
@@ -7214,8 +7229,8 @@ static struct net_device *__netdev_next_lower_dev(struct net_device *dev,
 
 int netdev_walk_all_lower_dev(struct net_device *dev,
                              int (*fn)(struct net_device *dev,
-                                       void *data),
-                             void *data)
+                                       struct netdev_nested_priv *priv),
+                             struct netdev_nested_priv *priv)
 {
        struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
        struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
@@ -7226,7 +7241,7 @@ int netdev_walk_all_lower_dev(struct net_device *dev,
 
        while (1) {
                if (now != dev) {
-                       ret = fn(now, data);
+                       ret = fn(now, priv);
                        if (ret)
                                return ret;
                }
@@ -7261,8 +7276,8 @@ EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev);
 
 static int __netdev_walk_all_lower_dev(struct net_device *dev,
                                       int (*fn)(struct net_device *dev,
-                                                void *data),
-                                      void *data)
+                                        struct netdev_nested_priv *priv),
+                                      struct netdev_nested_priv *priv)
 {
        struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
        struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
@@ -7274,7 +7289,7 @@ static int __netdev_walk_all_lower_dev(struct net_device *dev,
 
        while (1) {
                if (now != dev) {
-                       ret = fn(now, data);
+                       ret = fn(now, priv);
                        if (ret)
                                return ret;
                }
@@ -7363,22 +7378,34 @@ static u8 __netdev_lower_depth(struct net_device *dev)
        return max_depth;
 }
 
-static int __netdev_update_upper_level(struct net_device *dev, void *data)
+static int __netdev_update_upper_level(struct net_device *dev,
+                                      struct netdev_nested_priv *__unused)
 {
        dev->upper_level = __netdev_upper_depth(dev) + 1;
        return 0;
 }
 
-static int __netdev_update_lower_level(struct net_device *dev, void *data)
+static int __netdev_update_lower_level(struct net_device *dev,
+                                      struct netdev_nested_priv *priv)
 {
        dev->lower_level = __netdev_lower_depth(dev) + 1;
+
+#ifdef CONFIG_LOCKDEP
+       if (!priv)
+               return 0;
+
+       if (priv->flags & NESTED_SYNC_IMM)
+               dev->nested_level = dev->lower_level - 1;
+       if (priv->flags & NESTED_SYNC_TODO)
+               net_unlink_todo(dev);
+#endif
        return 0;
 }
 
 int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
                                  int (*fn)(struct net_device *dev,
-                                           void *data),
-                                 void *data)
+                                           struct netdev_nested_priv *priv),
+                                 struct netdev_nested_priv *priv)
 {
        struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
        struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
@@ -7389,7 +7416,7 @@ int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
 
        while (1) {
                if (now != dev) {
-                       ret = fn(now, data);
+                       ret = fn(now, priv);
                        if (ret)
                                return ret;
                }
@@ -7649,6 +7676,7 @@ static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
 static int __netdev_upper_dev_link(struct net_device *dev,
                                   struct net_device *upper_dev, bool master,
                                   void *upper_priv, void *upper_info,
+                                  struct netdev_nested_priv *priv,
                                   struct netlink_ext_ack *extack)
 {
        struct netdev_notifier_changeupper_info changeupper_info = {
@@ -7705,9 +7733,9 @@ static int __netdev_upper_dev_link(struct net_device *dev,
        __netdev_update_upper_level(dev, NULL);
        __netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
 
-       __netdev_update_lower_level(upper_dev, NULL);
+       __netdev_update_lower_level(upper_dev, priv);
        __netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level,
-                                   NULL);
+                                   priv);
 
        return 0;
 
@@ -7732,8 +7760,13 @@ int netdev_upper_dev_link(struct net_device *dev,
                          struct net_device *upper_dev,
                          struct netlink_ext_ack *extack)
 {
+       struct netdev_nested_priv priv = {
+               .flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO,
+               .data = NULL,
+       };
+
        return __netdev_upper_dev_link(dev, upper_dev, false,
-                                      NULL, NULL, extack);
+                                      NULL, NULL, &priv, extack);
 }
 EXPORT_SYMBOL(netdev_upper_dev_link);
 
@@ -7756,21 +7789,19 @@ int netdev_master_upper_dev_link(struct net_device *dev,
                                 void *upper_priv, void *upper_info,
                                 struct netlink_ext_ack *extack)
 {
+       struct netdev_nested_priv priv = {
+               .flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO,
+               .data = NULL,
+       };
+
        return __netdev_upper_dev_link(dev, upper_dev, true,
-                                      upper_priv, upper_info, extack);
+                                      upper_priv, upper_info, &priv, extack);
 }
 EXPORT_SYMBOL(netdev_master_upper_dev_link);
 
-/**
- * netdev_upper_dev_unlink - Removes a link to upper device
- * @dev: device
- * @upper_dev: new upper device
- *
- * Removes a link to device which is upper to this one. The caller must hold
- * the RTNL lock.
- */
-void netdev_upper_dev_unlink(struct net_device *dev,
-                            struct net_device *upper_dev)
+static void __netdev_upper_dev_unlink(struct net_device *dev,
+                                     struct net_device *upper_dev,
+                                     struct netdev_nested_priv *priv)
 {
        struct netdev_notifier_changeupper_info changeupper_info = {
                .info = {
@@ -7795,9 +7826,28 @@ void netdev_upper_dev_unlink(struct net_device *dev,
        __netdev_update_upper_level(dev, NULL);
        __netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
 
-       __netdev_update_lower_level(upper_dev, NULL);
+       __netdev_update_lower_level(upper_dev, priv);
        __netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level,
-                                   NULL);
+                                   priv);
+}
+
+/**
+ * netdev_upper_dev_unlink - Removes a link to upper device
+ * @dev: device
+ * @upper_dev: new upper device
+ *
+ * Removes a link to device which is upper to this one. The caller must hold
+ * the RTNL lock.
+ */
+void netdev_upper_dev_unlink(struct net_device *dev,
+                            struct net_device *upper_dev)
+{
+       struct netdev_nested_priv priv = {
+               .flags = NESTED_SYNC_TODO,
+               .data = NULL,
+       };
+
+       __netdev_upper_dev_unlink(dev, upper_dev, &priv);
 }
 EXPORT_SYMBOL(netdev_upper_dev_unlink);
 
@@ -7833,6 +7883,10 @@ int netdev_adjacent_change_prepare(struct net_device *old_dev,
                                   struct net_device *dev,
                                   struct netlink_ext_ack *extack)
 {
+       struct netdev_nested_priv priv = {
+               .flags = 0,
+               .data = NULL,
+       };
        int err;
 
        if (!new_dev)
@@ -7840,8 +7894,8 @@ int netdev_adjacent_change_prepare(struct net_device *old_dev,
 
        if (old_dev && new_dev != old_dev)
                netdev_adjacent_dev_disable(dev, old_dev);
-
-       err = netdev_upper_dev_link(new_dev, dev, extack);
+       err = __netdev_upper_dev_link(new_dev, dev, false, NULL, NULL, &priv,
+                                     extack);
        if (err) {
                if (old_dev && new_dev != old_dev)
                        netdev_adjacent_dev_enable(dev, old_dev);
@@ -7856,6 +7910,11 @@ void netdev_adjacent_change_commit(struct net_device *old_dev,
                                   struct net_device *new_dev,
                                   struct net_device *dev)
 {
+       struct netdev_nested_priv priv = {
+               .flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO,
+               .data = NULL,
+       };
+
        if (!new_dev || !old_dev)
                return;
 
@@ -7863,7 +7922,7 @@ void netdev_adjacent_change_commit(struct net_device *old_dev,
                return;
 
        netdev_adjacent_dev_enable(dev, old_dev);
-       netdev_upper_dev_unlink(old_dev, dev);
+       __netdev_upper_dev_unlink(old_dev, dev, &priv);
 }
 EXPORT_SYMBOL(netdev_adjacent_change_commit);
 
@@ -7871,13 +7930,18 @@ void netdev_adjacent_change_abort(struct net_device *old_dev,
                                  struct net_device *new_dev,
                                  struct net_device *dev)
 {
+       struct netdev_nested_priv priv = {
+               .flags = 0,
+               .data = NULL,
+       };
+
        if (!new_dev)
                return;
 
        if (old_dev && new_dev != old_dev)
                netdev_adjacent_dev_enable(dev, old_dev);
 
-       netdev_upper_dev_unlink(new_dev, dev);
+       __netdev_upper_dev_unlink(new_dev, dev, &priv);
 }
 EXPORT_SYMBOL(netdev_adjacent_change_abort);
 
@@ -8646,7 +8710,7 @@ int dev_get_port_parent_id(struct net_device *dev,
                if (!first.id_len)
                        first = *ppid;
                else if (memcmp(&first, ppid, sizeof(*ppid)))
-                       return -ENODATA;
+                       return -EOPNOTSUPP;
        }
 
        return err;
@@ -10061,6 +10125,19 @@ static void netdev_wait_allrefs(struct net_device *dev)
 void netdev_run_todo(void)
 {
        struct list_head list;
+#ifdef CONFIG_LOCKDEP
+       struct list_head unlink_list;
+
+       list_replace_init(&net_unlink_list, &unlink_list);
+
+       while (!list_empty(&unlink_list)) {
+               struct net_device *dev = list_first_entry(&unlink_list,
+                                                         struct net_device,
+                                                         unlink_list);
+               list_del(&dev->unlink_list);
+               dev->nested_level = dev->lower_level - 1;
+       }
+#endif
 
        /* Snapshot list, allow later requests */
        list_replace_init(&net_todo_list, &list);
@@ -10273,6 +10350,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
        dev->gso_max_segs = GSO_MAX_SEGS;
        dev->upper_level = 1;
        dev->lower_level = 1;
+#ifdef CONFIG_LOCKDEP
+       dev->nested_level = 0;
+       INIT_LIST_HEAD(&dev->unlink_list);
+#endif
 
        INIT_LIST_HEAD(&dev->napi_list);
        INIT_LIST_HEAD(&dev->unreg_list);
index 54cd568..fa1c37e 100644 (file)
@@ -637,7 +637,7 @@ int dev_uc_sync(struct net_device *to, struct net_device *from)
        if (to->addr_len != from->addr_len)
                return -EINVAL;
 
-       netif_addr_lock_nested(to);
+       netif_addr_lock(to);
        err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
        if (!err)
                __dev_set_rx_mode(to);
@@ -667,7 +667,7 @@ int dev_uc_sync_multiple(struct net_device *to, struct net_device *from)
        if (to->addr_len != from->addr_len)
                return -EINVAL;
 
-       netif_addr_lock_nested(to);
+       netif_addr_lock(to);
        err = __hw_addr_sync_multiple(&to->uc, &from->uc, to->addr_len);
        if (!err)
                __dev_set_rx_mode(to);
@@ -700,7 +700,7 @@ void dev_uc_unsync(struct net_device *to, struct net_device *from)
         * larger.
         */
        netif_addr_lock_bh(from);
-       netif_addr_lock_nested(to);
+       netif_addr_lock(to);
        __hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
        __dev_set_rx_mode(to);
        netif_addr_unlock(to);
@@ -867,7 +867,7 @@ int dev_mc_sync(struct net_device *to, struct net_device *from)
        if (to->addr_len != from->addr_len)
                return -EINVAL;
 
-       netif_addr_lock_nested(to);
+       netif_addr_lock(to);
        err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len);
        if (!err)
                __dev_set_rx_mode(to);
@@ -897,7 +897,7 @@ int dev_mc_sync_multiple(struct net_device *to, struct net_device *from)
        if (to->addr_len != from->addr_len)
                return -EINVAL;
 
-       netif_addr_lock_nested(to);
+       netif_addr_lock(to);
        err = __hw_addr_sync_multiple(&to->mc, &from->mc, to->addr_len);
        if (!err)
                __dev_set_rx_mode(to);
@@ -922,7 +922,7 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from)
 
        /* See the above comments inside dev_uc_unsync(). */
        netif_addr_lock_bh(from);
-       netif_addr_lock_nested(to);
+       netif_addr_lock(to);
        __hw_addr_unsync(&to->mc, &from->mc, to->addr_len);
        __dev_set_rx_mode(to);
        netif_addr_unlock(to);
index b2cf9b7..205e92e 100644 (file)
@@ -322,7 +322,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                err = net_hwtstamp_validate(ifr);
                if (err)
                        return err;
-               /* fall through */
+               fallthrough;
 
        /*
         *      Unknown or private ioctl
@@ -478,7 +478,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_c
        case SIOCSIFTXQLEN:
                if (!capable(CAP_NET_ADMIN))
                        return -EPERM;
-               /* fall through */
+               fallthrough;
        /*
         *      These ioctl calls:
         *      - require local superuser power.
@@ -503,7 +503,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_c
        case SIOCSHWTSTAMP:
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        return -EPERM;
-               /* fall through */
+               fallthrough;
        case SIOCBONDSLAVEINFOQUERY:
        case SIOCBONDINFOQUERY:
                dev_load(net, ifr->ifr_name);
index e5feb87..80ec1cd 100644 (file)
@@ -6196,8 +6196,8 @@ devlink_trap_action_get_from_info(struct genl_info *info,
 
        val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
        switch (val) {
-       case DEVLINK_TRAP_ACTION_DROP: /* fall-through */
-       case DEVLINK_TRAP_ACTION_TRAP: /* fall-through */
+       case DEVLINK_TRAP_ACTION_DROP:
+       case DEVLINK_TRAP_ACTION_TRAP:
        case DEVLINK_TRAP_ACTION_MIRROR:
                *p_trap_action = val;
                break;
index b09bebe..9704522 100644 (file)
@@ -1189,7 +1189,7 @@ static int net_dm_alert_mode_get_from_info(struct genl_info *info,
        val = nla_get_u8(info->attrs[NET_DM_ATTR_ALERT_MODE]);
 
        switch (val) {
-       case NET_DM_ALERT_MODE_SUMMARY: /* fall-through */
+       case NET_DM_ALERT_MODE_SUMMARY:
        case NET_DM_ALERT_MODE_PACKET:
                *p_alert_mode = val;
                break;
index d6b6ced..0c01bd8 100644 (file)
@@ -144,7 +144,7 @@ static void dst_destroy_rcu(struct rcu_head *head)
 
 /* Operations to mark dst as DEAD and clean up the net device referenced
  * by dst:
- * 1. put the dst under loopback interface and discard all tx/rx packets
+ * 1. put the dst under blackhole interface and discard all tx/rx packets
  *    on this route.
  * 2. release the net_device
  * This function should be called when removing routes from the fib tree
index 51678a5..7bcfb16 100644 (file)
@@ -16,7 +16,7 @@
 #include <net/ip_tunnels.h>
 #include <linux/indirect_call_wrapper.h>
 
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+#if defined(CONFIG_IPV6) && defined(CONFIG_IPV6_MULTIPLE_TABLES)
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 #define INDIRECT_CALL_MT(f, f2, f1, ...) \
        INDIRECT_CALL_INET(f, f2, f1, __VA_ARGS__)
index b2df520..b5f3faa 100644 (file)
@@ -4838,6 +4838,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
        fl4.saddr = params->ipv4_src;
        fl4.fl4_sport = params->sport;
        fl4.fl4_dport = params->dport;
+       fl4.flowi4_multipath_hash = 0;
 
        if (flags & BPF_FIB_LOOKUP_DIRECT) {
                u32 tbid = l3mdev_fib_table_rcu(dev) ? : RT_TABLE_MAIN;
@@ -7065,8 +7066,6 @@ static int bpf_gen_ld_abs(const struct bpf_insn *orig,
        bool indirect = BPF_MODE(orig->code) == BPF_IND;
        struct bpf_insn *insn = insn_buf;
 
-       /* We're guaranteed here that CTX is in R6. */
-       *insn++ = BPF_MOV64_REG(BPF_REG_1, BPF_REG_CTX);
        if (!indirect) {
                *insn++ = BPF_MOV64_IMM(BPF_REG_2, orig->imm);
        } else {
@@ -7074,6 +7073,8 @@ static int bpf_gen_ld_abs(const struct bpf_insn *orig,
                if (orig->imm)
                        *insn++ = BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, orig->imm);
        }
+       /* We're guaranteed here that CTX is in R6. */
+       *insn++ = BPF_MOV64_REG(BPF_REG_1, BPF_REG_CTX);
 
        switch (BPF_SIZE(orig->code)) {
        case BPF_B:
@@ -9223,7 +9224,7 @@ sk_reuseport_is_valid_access(int off, int size,
        case bpf_ctx_range(struct sk_reuseport_md, eth_protocol):
                if (size < sizeof_field(struct sk_buff, protocol))
                        return false;
-               /* fall through */
+               fallthrough;
        case bpf_ctx_range(struct sk_reuseport_md, ip_protocol):
        case bpf_ctx_range(struct sk_reuseport_md, bind_inany):
        case bpf_ctx_range(struct sk_reuseport_md, len):
@@ -9522,7 +9523,7 @@ BPF_CALL_1(bpf_skc_to_tcp6_sock, struct sock *, sk)
         * trigger an explicit type generation here.
         */
        BTF_TYPE_EMIT(struct tcp6_sock);
-       if (sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP &&
+       if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP &&
            sk->sk_family == AF_INET6)
                return (unsigned long)sk;
 
@@ -9540,7 +9541,7 @@ const struct bpf_func_proto bpf_skc_to_tcp6_sock_proto = {
 
 BPF_CALL_1(bpf_skc_to_tcp_sock, struct sock *, sk)
 {
-       if (sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP)
+       if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP)
                return (unsigned long)sk;
 
        return (unsigned long)NULL;
@@ -9557,13 +9558,19 @@ const struct bpf_func_proto bpf_skc_to_tcp_sock_proto = {
 
 BPF_CALL_1(bpf_skc_to_tcp_timewait_sock, struct sock *, sk)
 {
+       /* BTF types for tcp_timewait_sock and inet_timewait_sock are not
+        * generated if CONFIG_INET=n. Trigger an explicit generation here.
+        */
+       BTF_TYPE_EMIT(struct inet_timewait_sock);
+       BTF_TYPE_EMIT(struct tcp_timewait_sock);
+
 #ifdef CONFIG_INET
-       if (sk->sk_prot == &tcp_prot && sk->sk_state == TCP_TIME_WAIT)
+       if (sk && sk->sk_prot == &tcp_prot && sk->sk_state == TCP_TIME_WAIT)
                return (unsigned long)sk;
 #endif
 
 #if IS_BUILTIN(CONFIG_IPV6)
-       if (sk->sk_prot == &tcpv6_prot && sk->sk_state == TCP_TIME_WAIT)
+       if (sk && sk->sk_prot == &tcpv6_prot && sk->sk_state == TCP_TIME_WAIT)
                return (unsigned long)sk;
 #endif
 
@@ -9582,12 +9589,12 @@ const struct bpf_func_proto bpf_skc_to_tcp_timewait_sock_proto = {
 BPF_CALL_1(bpf_skc_to_tcp_request_sock, struct sock *, sk)
 {
 #ifdef CONFIG_INET
-       if (sk->sk_prot == &tcp_prot  && sk->sk_state == TCP_NEW_SYN_RECV)
+       if (sk && sk->sk_prot == &tcp_prot && sk->sk_state == TCP_NEW_SYN_RECV)
                return (unsigned long)sk;
 #endif
 
 #if IS_BUILTIN(CONFIG_IPV6)
-       if (sk->sk_prot == &tcpv6_prot && sk->sk_state == TCP_NEW_SYN_RECV)
+       if (sk && sk->sk_prot == &tcpv6_prot && sk->sk_state == TCP_NEW_SYN_RECV)
                return (unsigned long)sk;
 #endif
 
@@ -9609,7 +9616,7 @@ BPF_CALL_1(bpf_skc_to_udp6_sock, struct sock *, sk)
         * trigger an explicit type generation here.
         */
        BTF_TYPE_EMIT(struct udp6_sock);
-       if (sk_fullsock(sk) && sk->sk_protocol == IPPROTO_UDP &&
+       if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_UDP &&
            sk->sk_type == SOCK_DGRAM && sk->sk_family == AF_INET6)
                return (unsigned long)sk;
 
index dcd61ac..944ab21 100644 (file)
@@ -251,10 +251,10 @@ int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp)
        if (refcount_read(&net->count) == 0)
                return NETNSA_NSID_NOT_ASSIGNED;
 
-       spin_lock(&net->nsid_lock);
+       spin_lock_bh(&net->nsid_lock);
        id = __peernet2id(net, peer);
        if (id >= 0) {
-               spin_unlock(&net->nsid_lock);
+               spin_unlock_bh(&net->nsid_lock);
                return id;
        }
 
@@ -264,12 +264,12 @@ int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp)
         * just been idr_remove()'d from there in cleanup_net().
         */
        if (!maybe_get_net(peer)) {
-               spin_unlock(&net->nsid_lock);
+               spin_unlock_bh(&net->nsid_lock);
                return NETNSA_NSID_NOT_ASSIGNED;
        }
 
        id = alloc_netid(net, peer, -1);
-       spin_unlock(&net->nsid_lock);
+       spin_unlock_bh(&net->nsid_lock);
 
        put_net(peer);
        if (id < 0)
@@ -534,20 +534,20 @@ static void unhash_nsid(struct net *net, struct net *last)
        for_each_net(tmp) {
                int id;
 
-               spin_lock(&tmp->nsid_lock);
+               spin_lock_bh(&tmp->nsid_lock);
                id = __peernet2id(tmp, net);
                if (id >= 0)
                        idr_remove(&tmp->netns_ids, id);
-               spin_unlock(&tmp->nsid_lock);
+               spin_unlock_bh(&tmp->nsid_lock);
                if (id >= 0)
                        rtnl_net_notifyid(tmp, RTM_DELNSID, id, 0, NULL,
                                          GFP_KERNEL);
                if (tmp == last)
                        break;
        }
-       spin_lock(&net->nsid_lock);
+       spin_lock_bh(&net->nsid_lock);
        idr_destroy(&net->netns_ids);
-       spin_unlock(&net->nsid_lock);
+       spin_unlock_bh(&net->nsid_lock);
 }
 
 static LLIST_HEAD(cleanup_list);
@@ -760,9 +760,9 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
                return PTR_ERR(peer);
        }
 
-       spin_lock(&net->nsid_lock);
+       spin_lock_bh(&net->nsid_lock);
        if (__peernet2id(net, peer) >= 0) {
-               spin_unlock(&net->nsid_lock);
+               spin_unlock_bh(&net->nsid_lock);
                err = -EEXIST;
                NL_SET_BAD_ATTR(extack, nla);
                NL_SET_ERR_MSG(extack,
@@ -771,7 +771,7 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
        }
 
        err = alloc_netid(net, peer, nsid);
-       spin_unlock(&net->nsid_lock);
+       spin_unlock_bh(&net->nsid_lock);
        if (err >= 0) {
                rtnl_net_notifyid(net, RTM_NEWNSID, err, NETLINK_CB(skb).portid,
                                  nlh, GFP_KERNEL);
index 093e90e..2338753 100644 (file)
@@ -162,7 +162,7 @@ static void poll_napi(struct net_device *dev)
        struct napi_struct *napi;
        int cpu = smp_processor_id();
 
-       list_for_each_entry(napi, &dev->napi_list, dev_list) {
+       list_for_each_entry_rcu(napi, &dev->napi_list, dev_list) {
                if (cmpxchg(&napi->poll_owner, -1, cpu) == -1) {
                        poll_one_napi(napi);
                        smp_store_release(&napi->poll_owner, -1);
index b53b6d3..44fdbb9 100644 (file)
@@ -3430,7 +3430,7 @@ xmit_more:
                net_info_ratelimited("%s xmit error: %d\n",
                                     pkt_dev->odevname, ret);
                pkt_dev->errors++;
-               /* fall through */
+               fallthrough;
        case NETDEV_TX_BUSY:
                /* Retry it next time */
                refcount_dec(&(pkt_dev->skb->users));
@@ -3699,7 +3699,7 @@ static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn)
                                   cpu_to_node(cpu),
                                   "kpktgend_%d", cpu);
        if (IS_ERR(p)) {
-               pr_err("kernel_thread() failed for cpu %d\n", t->cpu);
+               pr_err("kthread_create_on_node() failed for cpu %d\n", t->cpu);
                list_del(&t->th_list);
                kfree(t);
                return PTR_ERR(p);
index e18184f..5cd6d48 100644 (file)
@@ -820,6 +820,7 @@ void skb_tx_error(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(skb_tx_error);
 
+#ifdef CONFIG_TRACEPOINTS
 /**
  *     consume_skb - free an skbuff
  *     @skb: buffer to free
@@ -837,6 +838,7 @@ void consume_skb(struct sk_buff *skb)
        __kfree_skb(skb);
 }
 EXPORT_SYMBOL(consume_skb);
+#endif
 
 /**
  *     consume_stateless_skb - free an skbuff, assuming it is stateless
@@ -2723,19 +2725,20 @@ EXPORT_SYMBOL(skb_checksum);
 /* Both of above in one bottle. */
 
 __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
-                                   u8 *to, int len, __wsum csum)
+                                   u8 *to, int len)
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
        struct sk_buff *frag_iter;
        int pos = 0;
+       __wsum csum = 0;
 
        /* Copy header. */
        if (copy > 0) {
                if (copy > len)
                        copy = len;
                csum = csum_partial_copy_nocheck(skb->data + offset, to,
-                                                copy, csum);
+                                                copy);
                if ((len -= copy) == 0)
                        return csum;
                offset += copy;
@@ -2765,7 +2768,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
                                vaddr = kmap_atomic(p);
                                csum2 = csum_partial_copy_nocheck(vaddr + p_off,
                                                                  to + copied,
-                                                                 p_len, 0);
+                                                                 p_len);
                                kunmap_atomic(vaddr);
                                csum = csum_block_add(csum, csum2, pos);
                                pos += p_len;
@@ -2791,7 +2794,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
                                copy = len;
                        csum2 = skb_copy_and_csum_bits(frag_iter,
                                                       offset - start,
-                                                      to, copy, 0);
+                                                      to, copy);
                        csum = csum_block_add(csum, csum2, pos);
                        if ((len -= copy) == 0)
                                return csum;
@@ -3011,7 +3014,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
        csum = 0;
        if (csstart != skb->len)
                csum = skb_copy_and_csum_bits(skb, csstart, to + csstart,
-                                             skb->len - csstart, 0);
+                                             skb->len - csstart);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                long csstuff = csstart + skb->csum_offset;
@@ -3932,7 +3935,7 @@ normal:
                                        skb_copy_and_csum_bits(head_skb, offset,
                                                               skb_put(nskb,
                                                                       len),
-                                                              len, 0);
+                                                              len);
                                SKB_GSO_CB(nskb)->csum_start =
                                        skb_headroom(nskb) + doffset;
                        } else {
@@ -5620,7 +5623,7 @@ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto,
        lse->label_stack_entry = mpls_lse;
        skb_postpush_rcsum(skb, lse, MPLS_HLEN);
 
-       if (ethernet)
+       if (ethernet && mac_len >= ETH_HLEN)
                skb_mod_eth_type(skb, eth_hdr(skb), mpls_proto);
        skb->protocol = mpls_proto;
 
@@ -5660,7 +5663,7 @@ int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len,
        skb_reset_mac_header(skb);
        skb_set_network_header(skb, mac_len);
 
-       if (ethernet) {
+       if (ethernet && mac_len >= ETH_HLEN) {
                struct ethhdr *hdr;
 
                /* use mpls_hdr() to get ethertype to account for VLANs. */
index 6a32a1f..6495831 100644 (file)
@@ -772,7 +772,6 @@ static void sk_psock_verdict_apply(struct sk_psock *psock,
                sk_psock_skb_redirect(skb);
                break;
        case __SK_DROP:
-               /* fall-through */
        default:
 out_free:
                kfree_skb(skb);
index e4f40b1..6c5c6b1 100644 (file)
@@ -1008,7 +1008,7 @@ set_sndbuf:
                break;
        case SO_TIMESTAMPING_NEW:
                sock_set_flag(sk, SOCK_TSTAMP_NEW);
-               /* fall through */
+               fallthrough;
        case SO_TIMESTAMPING_OLD:
                if (val & ~SOF_TIMESTAMPING_MASK) {
                        ret = -EINVAL;
@@ -3254,7 +3254,7 @@ void sk_common_release(struct sock *sk)
                sk->sk_prot->destroy(sk);
 
        /*
-        * Observation: when sock_common_release is called, processes have
+        * Observation: when sk_common_release is called, processes have
         * no access to socket. But net still has.
         * Step one, detach it from networking:
         *
index 84dde5a..16014ad 100644 (file)
@@ -1426,6 +1426,7 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh,
 {
        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
        struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
+       int prio;
        int err;
 
        if (!ops)
@@ -1475,6 +1476,13 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh,
                struct dcbnl_buffer *buffer =
                        nla_data(ieee[DCB_ATTR_DCB_BUFFER]);
 
+               for (prio = 0; prio < ARRAY_SIZE(buffer->prio2buffer); prio++) {
+                       if (buffer->prio2buffer[prio] >= DCBX_MAX_BUFFERS) {
+                               err = -EINVAL;
+                               goto err;
+                       }
+               }
+
                err = ops->dcbnl_setbuffer(netdev, buffer);
                if (err)
                        goto err;
index aef72f6..b9ee1a4 100644 (file)
@@ -608,7 +608,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
                 */
                if (hc->rx_x_recv > 0)
                        break;
-               /* fall through */
+               fallthrough;
        case CCID3_FBACK_PERIODIC:
                delta = ktime_us_delta(now, hc->rx_tstamp_last_feedback);
                if (delta <= 0)
index afc071e..788dd62 100644 (file)
@@ -1407,7 +1407,8 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
         *      Negotiation during connection setup
         */
        case DCCP_LISTEN:
-               server = true;                  /* fall through */
+               server = true;
+               fallthrough;
        case DCCP_REQUESTING:
                switch (opt) {
                case DCCPO_CHANGE_L:
index bd9cfdb..2cbb757 100644 (file)
@@ -64,7 +64,7 @@ static int dccp_rcv_close(struct sock *sk, struct sk_buff *skb)
                 */
                if (dccp_sk(sk)->dccps_role != DCCP_ROLE_CLIENT)
                        break;
-               /* fall through */
+               fallthrough;
        case DCCP_REQUESTING:
        case DCCP_ACTIVE_CLOSEREQ:
                dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
@@ -76,7 +76,7 @@ static int dccp_rcv_close(struct sock *sk, struct sk_buff *skb)
                queued = 1;
                dccp_fin(sk, skb);
                dccp_set_state(sk, DCCP_PASSIVE_CLOSE);
-               /* fall through */
+               fallthrough;
        case DCCP_PASSIVE_CLOSE:
                /*
                 * Retransmitted Close: we have already enqueued the first one.
@@ -113,7 +113,7 @@ static int dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
                queued = 1;
                dccp_fin(sk, skb);
                dccp_set_state(sk, DCCP_PASSIVE_CLOSEREQ);
-               /* fall through */
+               fallthrough;
        case DCCP_PASSIVE_CLOSEREQ:
                sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP);
        }
@@ -530,7 +530,7 @@ static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
        case DCCP_PKT_DATA:
                if (sk->sk_state == DCCP_RESPOND)
                        break;
-               /* fall through */
+               fallthrough;
        case DCCP_PKT_DATAACK:
        case DCCP_PKT_ACK:
                /*
@@ -684,7 +684,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                /* Step 8: if using Ack Vectors, mark packet acknowledgeable */
                dccp_handle_ackvec_processing(sk, skb);
                dccp_deliver_input_to_ccids(sk, skb);
-               /* fall through */
+               fallthrough;
        case DCCP_RESPOND:
                queued = dccp_rcv_respond_partopen_state_process(sk, skb,
                                                                 dh, len);
index 51aaba7..d24cad0 100644 (file)
@@ -225,7 +225,7 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                         * interested. The RX CCID need not parse Ack Vectors,
                         * since it is only interested in clearing old state.
                         */
-                       /* fall through */
+                       fallthrough;
                case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC:
                        if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk,
                                                     pkt_type, opt, value, len))
index 6433187..50e6d56 100644 (file)
@@ -62,7 +62,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                switch (dcb->dccpd_type) {
                case DCCP_PKT_DATA:
                        set_ack = 0;
-                       /* fall through */
+                       fallthrough;
                case DCCP_PKT_DATAACK:
                case DCCP_PKT_RESET:
                        break;
@@ -72,12 +72,12 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                        /* Use ISS on the first (non-retransmitted) Request. */
                        if (icsk->icsk_retransmits == 0)
                                dcb->dccpd_seq = dp->dccps_iss;
-                       /* fall through */
+                       fallthrough;
 
                case DCCP_PKT_SYNC:
                case DCCP_PKT_SYNCACK:
                        ackno = dcb->dccpd_ack_seq;
-                       /* fall through */
+                       fallthrough;
                default:
                        /*
                         * Set owner/destructor: some skbs are allocated via
@@ -481,7 +481,7 @@ struct sk_buff *dccp_ctl_make_reset(struct sock *sk, struct sk_buff *rcv_skb)
        case DCCP_RESET_CODE_PACKET_ERROR:
                dhr->dccph_reset_data[0] = rxdh->dccph_type;
                break;
-       case DCCP_RESET_CODE_OPTION_ERROR:      /* fall through */
+       case DCCP_RESET_CODE_OPTION_ERROR:
        case DCCP_RESET_CODE_MANDATORY_ERROR:
                memcpy(dhr->dccph_reset_data, dcb->dccpd_reset_data, 3);
                break;
index d148ab1..6d705d9 100644 (file)
@@ -101,7 +101,7 @@ void dccp_set_state(struct sock *sk, const int state)
                if (inet_csk(sk)->icsk_bind_hash != NULL &&
                    !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
                        inet_put_port(sk);
-               /* fall through */
+               fallthrough;
        default:
                if (oldstate == DCCP_OPEN)
                        DCCP_DEC_STATS(DCCP_MIB_CURRESTAB);
@@ -834,7 +834,7 @@ int dccp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
                case DCCP_PKT_CLOSEREQ:
                        if (!(flags & MSG_PEEK))
                                dccp_finish_passive_close(sk);
-                       /* fall through */
+                       fallthrough;
                case DCCP_PKT_RESET:
                        dccp_pr_debug("found fin (%s) ok!\n",
                                      dccp_packet_name(dh->dccph_type));
@@ -960,7 +960,7 @@ static void dccp_terminate_connection(struct sock *sk)
        case DCCP_PARTOPEN:
                dccp_pr_debug("Stop PARTOPEN timer (%p)\n", sk);
                inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
-               /* fall through */
+               fallthrough;
        case DCCP_OPEN:
                dccp_send_close(sk, 1);
 
@@ -969,7 +969,7 @@ static void dccp_terminate_connection(struct sock *sk)
                        next_state = DCCP_ACTIVE_CLOSEREQ;
                else
                        next_state = DCCP_CLOSING;
-               /* fall through */
+               fallthrough;
        default:
                dccp_set_state(sk, next_state);
        }
index 3b53d76..5dbd45d 100644 (file)
@@ -623,12 +623,12 @@ static void dn_destroy_sock(struct sock *sk)
                goto disc_reject;
        case DN_RUN:
                scp->state = DN_DI;
-               /* fall through */
+               fallthrough;
        case DN_DI:
        case DN_DR:
 disc_reject:
                dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->sk_allocation);
-               /* fall through */
+               fallthrough;
        case DN_NC:
        case DN_NR:
        case DN_RJ:
@@ -642,7 +642,7 @@ disc_reject:
                break;
        default:
                printk(KERN_DEBUG "DECnet: dn_destroy_sock passed socket in invalid state\n");
-               /* fall through */
+               fallthrough;
        case DN_O:
                dn_stop_slow_timer(sk);
 
index c68503a..c97bdca 100644 (file)
@@ -483,7 +483,7 @@ static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb)
                break;
        case DN_RUN:
                sk->sk_shutdown |= SHUTDOWN_MASK;
-               /* fall through */
+               fallthrough;
        case DN_CC:
                scp->state = DN_CN;
        }
index 33fefb0..4086f9c 100644 (file)
@@ -156,7 +156,7 @@ static void dn_rehash_zone(struct dn_zone *dz)
        default:
                printk(KERN_DEBUG "DECnet: dn_rehash_zone: BUG! %d\n",
                       old_divisor);
-               /* fall through */
+               fallthrough;
        case 256:
                new_divisor = 1024;
                new_hashmask = 0x3FF;
index deae519..67b5ab2 100644 (file)
@@ -75,7 +75,7 @@ static void strip_it(char *str)
                case '\r':
                case ':':
                        *str = 0;
-                       /* Fallthrough */
+                       fallthrough;
                case 0:
                        return;
                }
index 41d60ee..16e5f98 100644 (file)
@@ -1799,15 +1799,27 @@ int dsa_slave_create(struct dsa_port *port)
 
        dsa_slave_notify(slave_dev, DSA_PORT_REGISTER);
 
-       ret = register_netdev(slave_dev);
+       rtnl_lock();
+
+       ret = register_netdevice(slave_dev);
        if (ret) {
                netdev_err(master, "error %d registering interface %s\n",
                           ret, slave_dev->name);
+               rtnl_unlock();
                goto out_phy;
        }
 
+       ret = netdev_upper_dev_link(master, slave_dev, NULL);
+
+       rtnl_unlock();
+
+       if (ret)
+               goto out_unregister;
+
        return 0;
 
+out_unregister:
+       unregister_netdev(slave_dev);
 out_phy:
        rtnl_lock();
        phylink_disconnect_phy(p->dp->pl);
@@ -1824,16 +1836,18 @@ out_free:
 
 void dsa_slave_destroy(struct net_device *slave_dev)
 {
+       struct net_device *master = dsa_slave_to_master(slave_dev);
        struct dsa_port *dp = dsa_slave_to_port(slave_dev);
        struct dsa_slave_priv *p = netdev_priv(slave_dev);
 
        netif_carrier_off(slave_dev);
        rtnl_lock();
+       netdev_upper_dev_unlink(master, slave_dev);
+       unregister_netdevice(slave_dev);
        phylink_disconnect_phy(dp->pl);
        rtnl_unlock();
 
        dsa_slave_notify(slave_dev, DSA_PORT_UNREGISTER);
-       unregister_netdev(slave_dev);
        phylink_destroy(dp->pl);
        gro_cells_destroy(&p->gcells);
        free_percpu(p->stats64);
@@ -2009,7 +2023,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
        switchdev_work->event = event;
 
        switch (event) {
-       case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */
+       case SWITCHDEV_FDB_ADD_TO_DEVICE:
        case SWITCHDEV_FDB_DEL_TO_DEVICE:
                if (dsa_slave_switchdev_fdb_work_init(switchdev_work, ptr))
                        goto err_fdb_work_init;
index 42f327c..b4fc05c 100644 (file)
@@ -160,11 +160,14 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
        packing(injection, &qos_class, 19,  17, OCELOT_TAG_LEN, PACK, 0);
 
        if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+               struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
+
                rew_op = ocelot_port->ptp_cmd;
-               if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
-                       rew_op |= (ocelot_port->ts_id  % 4) << 3;
-                       ocelot_port->ts_id++;
-               }
+               /* Retrieve timestamp ID populated inside skb->cb[0] of the
+                * clone by ocelot_port_add_txtstamp_skb
+                */
+               if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
+                       rew_op |= clone->cb[0] << 3;
 
                packing(injection, &rew_op, 125, 117, OCELOT_TAG_LEN, PACK, 0);
        }
index 5c20727..0c3f54b 100644 (file)
@@ -866,7 +866,7 @@ static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
        [ETHNL_MCGRP_MONITOR] = { .name = ETHTOOL_MCGRP_MONITOR_NAME },
 };
 
-static struct genl_family ethtool_genl_family = {
+static struct genl_family ethtool_genl_family __ro_after_init = {
        .name           = ETHTOOL_GENL_NAME,
        .version        = ETHTOOL_GENL_VERSION,
        .netnsok        = true,
index 84f2328..d93bf2d 100644 (file)
@@ -200,7 +200,7 @@ int ethnl_tunnel_info_doit(struct sk_buff *skb, struct genl_info *info)
        reply_len = ret + ethnl_reply_header_size();
 
        rskb = ethnl_reply_init(reply_len, req_info.dev,
-                               ETHTOOL_MSG_TUNNEL_INFO_GET,
+                               ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY,
                                ETHTOOL_A_TUNNEL_INFO_HEADER,
                                info, &reply_payload);
        if (!rskb) {
@@ -273,7 +273,7 @@ int ethnl_tunnel_info_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
                                goto cont;
 
                        ehdr = ethnl_dump_put(skb, cb,
-                                             ETHTOOL_MSG_TUNNEL_INFO_GET);
+                                             ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY);
                        if (!ehdr) {
                                ret = -EMSGSIZE;
                                goto out;
index 06c3cd9..0e4681c 100644 (file)
@@ -76,7 +76,7 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
                proto = nla_get_u8(data[IFLA_HSR_PROTOCOL]);
 
        if (proto >= HSR_PROTOCOL_MAX) {
-               NL_SET_ERR_MSG_MOD(extack, "Unsupported protocol\n");
+               NL_SET_ERR_MSG_MOD(extack, "Unsupported protocol");
                return -EINVAL;
        }
 
@@ -84,14 +84,14 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
                proto_version = HSR_V0;
        } else {
                if (proto == HSR_PROTOCOL_PRP) {
-                       NL_SET_ERR_MSG_MOD(extack, "PRP version unsupported\n");
+                       NL_SET_ERR_MSG_MOD(extack, "PRP version unsupported");
                        return -EINVAL;
                }
 
                proto_version = nla_get_u8(data[IFLA_HSR_VERSION]);
                if (proto_version > HSR_V1) {
                        NL_SET_ERR_MSG_MOD(extack,
-                                          "Only HSR version 0/1 supported\n");
+                                          "Only HSR version 0/1 supported");
                        return -EINVAL;
                }
        }
index bbe9b3b..be6f06a 100644 (file)
@@ -195,7 +195,7 @@ static int lowpan_frag_rx_handlers_result(struct sk_buff *skb,
                net_warn_ratelimited("%s: received unknown dispatch\n",
                                     __func__);
 
-               /* fall-through */
+               fallthrough;
        default:
                /* all others failure */
                return NET_RX_DROP;
index b34d050..517e649 100644 (file)
@@ -35,11 +35,11 @@ static int lowpan_rx_handlers_result(struct sk_buff *skb, lowpan_rx_result res)
                net_warn_ratelimited("%s: received unknown dispatch\n",
                                     __func__);
 
-               /* fall-through */
+               fallthrough;
        case RX_DROP_UNUSABLE:
                kfree_skb(skb);
 
-               /* fall-through */
+               fallthrough;
        case RX_DROP:
                return NET_RX_DROP;
        case RX_QUEUED:
index 4107949..86a23e4 100644 (file)
@@ -362,6 +362,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
        fl4.flowi4_tun_key.tun_id = 0;
        fl4.flowi4_flags = 0;
        fl4.flowi4_uid = sock_net_uid(net, NULL);
+       fl4.flowi4_multipath_hash = 0;
 
        no_addr = idev->ifa_list == NULL;
 
index c89b46f..ffc5332 100644 (file)
@@ -2121,7 +2121,8 @@ void fib_info_notify_update(struct net *net, struct nl_info *info)
                struct hlist_head *head = &net->ipv4.fib_table_hash[h];
                struct fib_table *tb;
 
-               hlist_for_each_entry_rcu(tb, head, tb_hlist)
+               hlist_for_each_entry_rcu(tb, head, tb_hlist,
+                                        lockdep_rtnl_is_held())
                        __fib_info_notify_update(net, tb, info);
        }
 }
index cf36f95..bdaaee5 100644 (file)
@@ -352,7 +352,7 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
 
        csum = skb_copy_and_csum_bits(icmp_param->skb,
                                      icmp_param->offset + offset,
-                                     to, len, 0);
+                                     to, len);
 
        skb->csum = csum_block_add(skb->csum, csum, odd);
        if (icmp_pointers[icmp_param->data.icmph.type].error)
@@ -376,15 +376,15 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
                ip_flush_pending_frames(sk);
        } else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
                struct icmphdr *icmph = icmp_hdr(skb);
-               __wsum csum = 0;
+               __wsum csum;
                struct sk_buff *skb1;
 
+               csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
+                                                (char *)icmph,
+                                                icmp_param->head_len);
                skb_queue_walk(&sk->sk_write_queue, skb1) {
                        csum = csum_add(csum, skb1->csum);
                }
-               csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
-                                                (char *)icmph,
-                                                icmp_param->head_len, csum);
                icmph->checksum = csum_fold(csum);
                skb->ip_summed = CHECKSUM_NONE;
                ip_push_pending_frames(sk, fl4);
index 4a98dd7..f1bd95f 100644 (file)
@@ -186,8 +186,8 @@ errout:
 }
 EXPORT_SYMBOL_GPL(inet_diag_msg_attrs_fill);
 
-static void inet_diag_parse_attrs(const struct nlmsghdr *nlh, int hdrlen,
-                                 struct nlattr **req_nlas)
+static int inet_diag_parse_attrs(const struct nlmsghdr *nlh, int hdrlen,
+                                struct nlattr **req_nlas)
 {
        struct nlattr *nla;
        int remaining;
@@ -195,9 +195,13 @@ static void inet_diag_parse_attrs(const struct nlmsghdr *nlh, int hdrlen,
        nlmsg_for_each_attr(nla, nlh, hdrlen, remaining) {
                int type = nla_type(nla);
 
+               if (type == INET_DIAG_REQ_PROTOCOL && nla_len(nla) != sizeof(u32))
+                       return -EINVAL;
+
                if (type < __INET_DIAG_REQ_MAX)
                        req_nlas[type] = nla;
        }
+       return 0;
 }
 
 static int inet_diag_get_protocol(const struct inet_diag_req_v2 *req,
@@ -574,7 +578,10 @@ static int inet_diag_cmd_exact(int cmd, struct sk_buff *in_skb,
        int err, protocol;
 
        memset(&dump_data, 0, sizeof(dump_data));
-       inet_diag_parse_attrs(nlh, hdrlen, dump_data.req_nlas);
+       err = inet_diag_parse_attrs(nlh, hdrlen, dump_data.req_nlas);
+       if (err)
+               return err;
+
        protocol = inet_diag_get_protocol(req, &dump_data);
 
        handler = inet_diag_lock_handler(protocol);
@@ -1180,8 +1187,11 @@ static int __inet_diag_dump_start(struct netlink_callback *cb, int hdrlen)
        if (!cb_data)
                return -ENOMEM;
 
-       inet_diag_parse_attrs(nlh, hdrlen, cb_data->req_nlas);
-
+       err = inet_diag_parse_attrs(nlh, hdrlen, cb_data->req_nlas);
+       if (err) {
+               kfree(cb_data);
+               return err;
+       }
        nla = cb_data->inet_diag_nla_bc;
        if (nla) {
                err = inet_diag_bc_audit(nla, skb);
index 61f802d..5131cf7 100644 (file)
@@ -74,6 +74,7 @@
 #include <net/icmp.h>
 #include <net/checksum.h>
 #include <net/inetpeer.h>
+#include <net/inet_ecn.h>
 #include <net/lwtunnel.h>
 #include <linux/bpf-cgroup.h>
 #include <linux/igmp.h>
@@ -1126,7 +1127,7 @@ alloc_new_skb:
                        if (fraggap) {
                                skb->csum = skb_copy_and_csum_bits(
                                        skb_prev, maxfraglen,
-                                       data + transhdrlen, fraggap, 0);
+                                       data + transhdrlen, fraggap);
                                skb_prev->csum = csum_sub(skb_prev->csum,
                                                          skb->csum);
                                data += fraggap;
@@ -1411,7 +1412,7 @@ ssize_t   ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
                                skb->csum = skb_copy_and_csum_bits(skb_prev,
                                                                   maxfraglen,
                                                    skb_transport_header(skb),
-                                                                  fraggap, 0);
+                                                                  fraggap);
                                skb_prev->csum = csum_sub(skb_prev->csum,
                                                          skb->csum);
                                pskb_trim_unique(skb_prev, maxfraglen);
@@ -1648,7 +1649,7 @@ static int ip_reply_glue_bits(void *dptr, char *to, int offset,
 {
        __wsum csum;
 
-       csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0);
+       csum = csum_partial_copy_nocheck(dptr+offset, to, len);
        skb->csum = csum_block_add(skb->csum, csum, odd);
        return 0;
 }
@@ -1703,7 +1704,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
        if (IS_ERR(rt))
                return;
 
-       inet_sk(sk)->tos = arg->tos;
+       inet_sk(sk)->tos = arg->tos & ~INET_ECN_MASK;
 
        sk->sk_protocol = ip_hdr(skb)->protocol;
        sk->sk_bound_dev_if = arg->bound_dev_if;
index 75c6013..b2ea1a8 100644 (file)
@@ -554,6 +554,7 @@ static int ip_tun_parse_opts_vxlan(struct nlattr *attr,
 
                attr = tb[LWTUNNEL_IP_OPT_VXLAN_GBP];
                md->gbp = nla_get_u32(attr);
+               md->gbp &= VXLAN_GBP_MASK;
                info->key.tun_flags |= TUNNEL_VXLAN_OPT;
        }
 
index 49daaed..f687abb 100644 (file)
@@ -490,6 +490,7 @@ static struct xfrm_tunnel vti_ipip_handler __read_mostly = {
        .priority       =       0,
 };
 
+#if IS_ENABLED(CONFIG_IPV6)
 static struct xfrm_tunnel vti_ipip6_handler __read_mostly = {
        .handler        =       vti_rcv_tunnel,
        .cb_handler     =       vti_rcv_cb,
@@ -497,6 +498,7 @@ static struct xfrm_tunnel vti_ipip6_handler __read_mostly = {
        .priority       =       0,
 };
 #endif
+#endif
 
 static int __net_init vti_init_net(struct net *net)
 {
index 7afde88..3f248a1 100644 (file)
@@ -3,7 +3,7 @@
  * nf_nat_pptp.c
  *
  * NAT support for PPTP (Point to Point Tunneling Protocol).
- * PPTP is a protocol for creating virtual private networks.
+ * PPTP is a protocol for creating virtual private networks.
  * It is a specification defined by Microsoft and some vendors
  * working with Microsoft.  PPTP is built on top of a modified
  * version of the Internet Generic Routing Encapsulation Protocol.
index 1074df7..8d5e169 100644 (file)
@@ -293,6 +293,7 @@ static const struct snmp_mib snmp4_net_list[] = {
        SNMP_MIB_ITEM("TcpTimeoutRehash", LINUX_MIB_TCPTIMEOUTREHASH),
        SNMP_MIB_ITEM("TcpDuplicateDataRehash", LINUX_MIB_TCPDUPLICATEDATAREHASH),
        SNMP_MIB_ITEM("TCPDSACKRecvSegs", LINUX_MIB_TCPDSACKRECVSEGS),
+       SNMP_MIB_ITEM("TCPDSACKIgnoredDubious", LINUX_MIB_TCPDSACKIGNOREDDUBIOUS),
        SNMP_MIB_SENTINEL
 };
 
index 6fd4330..355f3ca 100644 (file)
@@ -478,7 +478,7 @@ static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
                        skb->csum = csum_block_add(
                                skb->csum,
                                csum_partial_copy_nocheck(rfv->hdr.c + offset,
-                                                         to, copy, 0),
+                                                         to, copy),
                                odd);
 
                odd = 0;
@@ -610,7 +610,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        } else if (!ipc.oif) {
                ipc.oif = inet->uc_index;
        } else if (ipv4_is_lbcast(daddr) && inet->uc_index) {
-               /* oif is set, packet is to local broadcast and
+               /* oif is set, packet is to local broadcast
                 * and uc_index is set. oif is most likely set
                 * by sk_bound_dev_if. If uc_index != oif check if the
                 * oif is an L3 master and uc_index is an L3 slave.
index 8ca6bca..58642b2 100644 (file)
@@ -786,8 +786,10 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
                        neigh_event_send(n, NULL);
                } else {
                        if (fib_lookup(net, fl4, &res, 0) == 0) {
-                               struct fib_nh_common *nhc = FIB_RES_NHC(res);
+                               struct fib_nh_common *nhc;
 
+                               fib_select_path(net, &res, fl4, skb);
+                               nhc = FIB_RES_NHC(res);
                                update_or_create_fnhe(nhc, fl4->daddr, new_gw,
                                                0, false,
                                                jiffies + ip_rt_gc_timeout);
@@ -1013,6 +1015,7 @@ out:      kfree_skb(skb);
 static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
 {
        struct dst_entry *dst = &rt->dst;
+       struct net *net = dev_net(dst->dev);
        u32 old_mtu = ipv4_mtu(dst);
        struct fib_result res;
        bool lock = false;
@@ -1033,9 +1036,11 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
                return;
 
        rcu_read_lock();
-       if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) {
-               struct fib_nh_common *nhc = FIB_RES_NHC(res);
+       if (fib_lookup(net, fl4, &res, 0) == 0) {
+               struct fib_nh_common *nhc;
 
+               fib_select_path(net, &res, fl4, NULL);
+               nhc = FIB_RES_NHC(res);
                update_or_create_fnhe(nhc, fl4->daddr, 0, mtu, lock,
                                      jiffies + ip_rt_mtu_expires);
        }
@@ -2147,6 +2152,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        fl4.daddr = daddr;
        fl4.saddr = saddr;
        fl4.flowi4_uid = sock_net_uid(net, NULL);
+       fl4.flowi4_multipath_hash = 0;
 
        if (fib4_rules_early_flow_dissect(net, skb, &fl4, &_flkeys)) {
                flkeys = &_flkeys;
@@ -2667,8 +2673,6 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
        fib_select_path(net, res, fl4, skb);
 
        dev_out = FIB_RES_DEV(*res);
-       fl4->flowi4_oif = dev_out->ifindex;
-
 
 make_route:
        rth = __mkroute_output(res, fl4, orig_oif, dev_out, flags);
index f0794f0..e037566 100644 (file)
@@ -214,7 +214,7 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb,
                sock_rps_save_rxhash(child, skb);
 
                if (rsk_drop_req(req)) {
-                       refcount_set(&req->rsk_refcnt, 2);
+                       reqsk_put(req);
                        return child;
                }
 
index 31f3b85..2135ee7 100644 (file)
@@ -970,7 +970,8 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
        long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
 
        if (IS_ENABLED(CONFIG_DEBUG_VM) &&
-           WARN_ONCE(PageSlab(page), "page must not be a Slab one"))
+           WARN_ONCE(!sendpage_ok(page),
+                     "page must not be a Slab one and have page_count > 0"))
                return -EINVAL;
 
        /* Wait for a connection to finish. One exception is TCP Fast Open
index 184ea55..b1ce205 100644 (file)
@@ -885,21 +885,34 @@ struct tcp_sacktag_state {
        struct rate_sample *rate;
 };
 
-/* Take a notice that peer is sending D-SACKs */
+/* Take a notice that peer is sending D-SACKs. Skip update of data delivery
+ * and spurious retransmission information if this DSACK is unlikely caused by
+ * sender's action:
+ * - DSACKed sequence range is larger than maximum receiver's window.
+ * - Total no. of DSACKed segments exceed the total no. of retransmitted segs.
+ */
 static u32 tcp_dsack_seen(struct tcp_sock *tp, u32 start_seq,
                          u32 end_seq, struct tcp_sacktag_state *state)
 {
        u32 seq_len, dup_segs = 1;
 
-       if (before(start_seq, end_seq)) {
-               seq_len = end_seq - start_seq;
-               if (seq_len > tp->mss_cache)
-                       dup_segs = DIV_ROUND_UP(seq_len, tp->mss_cache);
-       }
+       if (!before(start_seq, end_seq))
+               return 0;
+
+       seq_len = end_seq - start_seq;
+       /* Dubious DSACK: DSACKed range greater than maximum advertised rwnd */
+       if (seq_len > tp->max_window)
+               return 0;
+       if (seq_len > tp->mss_cache)
+               dup_segs = DIV_ROUND_UP(seq_len, tp->mss_cache);
+
+       tp->dsack_dups += dup_segs;
+       /* Skip the DSACK if dup segs weren't retransmitted by sender */
+       if (tp->dsack_dups > tp->total_retrans)
+               return 0;
 
        tp->rx_opt.sack_ok |= TCP_DSACK_SEEN;
        tp->rack.dsack_seen = 1;
-       tp->dsack_dups += dup_segs;
 
        state->flag |= FLAG_DSACKING_ACK;
        /* A spurious retransmission is delivered */
@@ -1153,6 +1166,11 @@ static bool tcp_check_dsack(struct sock *sk, const struct sk_buff *ack_skb,
        }
 
        dup_segs = tcp_dsack_seen(tp, start_seq_0, end_seq_0, state);
+       if (!dup_segs) {        /* Skip dubious DSACK */
+               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPDSACKIGNOREDDUBIOUS);
+               return false;
+       }
+
        NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPDSACKRECVSEGS, dup_segs);
 
        /* D-SACK for already forgotten data... Do dumb counting. */
index 5084333..592c739 100644 (file)
@@ -1788,12 +1788,12 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
 
        __skb_pull(skb, hdrlen);
        if (skb_try_coalesce(tail, skb, &fragstolen, &delta)) {
-               thtail->window = th->window;
-
                TCP_SKB_CB(tail)->end_seq = TCP_SKB_CB(skb)->end_seq;
 
-               if (after(TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(tail)->ack_seq))
+               if (likely(!before(TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(tail)->ack_seq))) {
                        TCP_SKB_CB(tail)->ack_seq = TCP_SKB_CB(skb)->ack_seq;
+                       thtail->window = th->window;
+               }
 
                /* We have to update both TCP_SKB_CB(tail)->tcp_flags and
                 * thtail->fin, so that the fast path in tcp_rcv_established()
index 76bff79..747f56e 100644 (file)
@@ -303,6 +303,7 @@ config IPV6_SEG6_LWTUNNEL
 config IPV6_SEG6_HMAC
        bool "IPv6: Segment Routing HMAC support"
        depends on IPV6
+       select CRYPTO
        select CRYPTO_HMAC
        select CRYPTO_SHA1
        select CRYPTO_SHA256
index a4e4912..83b2511 100644 (file)
@@ -314,10 +314,10 @@ static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, st
 {
        struct icmpv6_msg *msg = (struct icmpv6_msg *) from;
        struct sk_buff *org_skb = msg->skb;
-       __wsum csum = 0;
+       __wsum csum;
 
        csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset,
-                                     to, len, csum);
+                                     to, len);
        skb->csum = csum_block_add(skb->csum, csum, odd);
        if (!(msg->type & ICMPV6_INFOMSG_MASK))
                nf_ct_attach(skb, org_skb);
index 25a90f3..4a664ad 100644 (file)
@@ -1993,14 +1993,19 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
 /* Need to own table->tb6_lock */
 int fib6_del(struct fib6_info *rt, struct nl_info *info)
 {
-       struct fib6_node *fn = rcu_dereference_protected(rt->fib6_node,
-                                   lockdep_is_held(&rt->fib6_table->tb6_lock));
-       struct fib6_table *table = rt->fib6_table;
        struct net *net = info->nl_net;
        struct fib6_info __rcu **rtp;
        struct fib6_info __rcu **rtp_next;
+       struct fib6_table *table;
+       struct fib6_node *fn;
+
+       if (rt == net->ipv6.fib6_null_entry)
+               return -ENOENT;
 
-       if (!fn || rt == net->ipv6.fib6_null_entry)
+       table = rt->fib6_table;
+       fn = rcu_dereference_protected(rt->fib6_node,
+                                      lockdep_is_held(&table->tb6_lock));
+       if (!fn)
                return -ENOENT;
 
        WARN_ON(!(fn->fn_flags & RTN_RTINFO));
index c78e67d..2689498 100644 (file)
@@ -1615,7 +1615,7 @@ alloc_new_skb:
                        if (fraggap) {
                                skb->csum = skb_copy_and_csum_bits(
                                        skb_prev, maxfraglen,
-                                       data + transhdrlen, fraggap, 0);
+                                       data + transhdrlen, fraggap);
                                skb_prev->csum = csum_sub(skb_prev->csum,
                                                          skb->csum);
                                data += fraggap;
index 874f01c..6e4ab80 100644 (file)
@@ -746,7 +746,7 @@ static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
                        skb->csum = csum_block_add(
                                skb->csum,
                                csum_partial_copy_nocheck(rfv->c + offset,
-                                                         to, copy, 0),
+                                                         to, copy),
                                odd);
 
                odd = 0;
index 5e7e25e..fb075d9 100644 (file)
@@ -4202,7 +4202,7 @@ static struct fib6_info *rt6_add_route_info(struct net *net,
                .fc_nlinfo.nl_net = net,
        };
 
-       cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
+       cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
        cfg.fc_dst = *prefix;
        cfg.fc_gateway = *gwaddr;
 
index fac2135..5b60a4b 100644 (file)
@@ -21,6 +21,7 @@
 #include <net/calipso.h>
 #endif
 
+static int two = 2;
 static int flowlabel_reflect_max = 0x7;
 static int auto_flowlabels_min;
 static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
@@ -150,7 +151,7 @@ static struct ctl_table ipv6_table_template[] = {
                .mode           = 0644,
                .proc_handler   = proc_rt6_multipath_hash_policy,
                .extra1         = SYSCTL_ZERO,
-               .extra2         = SYSCTL_ONE,
+               .extra2         = &two,
        },
        {
                .procname       = "seg6_flowlabel",
index 6ee9851..a95af62 100644 (file)
@@ -418,7 +418,7 @@ static void iucv_sock_close(struct sock *sk)
                        sk->sk_state = IUCV_DISCONN;
                        sk->sk_state_change(sk);
                }
-               /* fall through */
+               fallthrough;
 
        case IUCV_DISCONN:
                sk->sk_state = IUCV_CLOSING;
@@ -433,7 +433,7 @@ static void iucv_sock_close(struct sock *sk)
                                        iucv_sock_in_state(sk, IUCV_CLOSED, 0),
                                        timeo);
                }
-               /* fall through */
+               fallthrough;
 
        case IUCV_CLOSING:
                sk->sk_state = IUCV_CLOSED;
@@ -444,7 +444,7 @@ static void iucv_sock_close(struct sock *sk)
 
                skb_queue_purge(&iucv->send_skb_q);
                skb_queue_purge(&iucv->backlog_skb_q);
-               /* fall through */
+               fallthrough;
 
        default:
                iucv_sever_path(sk, 1);
@@ -2111,10 +2111,10 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
                        kfree_skb(skb);
                        break;
                }
-               /* fall through - and receive non-zero length data */
+               fallthrough;    /* and receive non-zero length data */
        case (AF_IUCV_FLAG_SHT):
                /* shutdown request */
-               /* fall through - and receive zero length data */
+               fallthrough;    /* and receive zero length data */
        case 0:
                /* plain data frame */
                IUCV_SKB_CB(skb)->class = trans_hdr->iucv_hdr.class;
index e71ca5a..864326f 100644 (file)
@@ -154,7 +154,7 @@ int l3mdev_master_upper_ifindex_by_index_rcu(struct net *net, int ifindex)
 EXPORT_SYMBOL_GPL(l3mdev_master_upper_ifindex_by_index_rcu);
 
 /**
- *     l3mdev_fib_table - get FIB table id associated with an L3
+ *     l3mdev_fib_table_rcu - get FIB table id associated with an L3
  *                             master interface
  *     @dev: targeted interface
  */
index 366f76c..26d2f8b 100644 (file)
@@ -405,18 +405,14 @@ ieee80211_calc_legacy_rate_duration(u16 bitrate, bool short_pre,
        return duration;
 }
 
-u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
-                             struct ieee80211_rx_status *status,
-                             int len)
+static u32 ieee80211_get_rate_duration(struct ieee80211_hw *hw,
+                                      struct ieee80211_rx_status *status,
+                                      u32 *overhead)
 {
-       struct ieee80211_supported_band *sband;
-       const struct ieee80211_rate *rate;
        bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI;
-       bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE;
        int bw, streams;
        int group, idx;
        u32 duration;
-       bool cck;
 
        switch (status->bw) {
        case RATE_INFO_BW_20:
@@ -437,20 +433,6 @@ u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
        }
 
        switch (status->encoding) {
-       case RX_ENC_LEGACY:
-               if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ))
-                       return 0;
-
-               sband = hw->wiphy->bands[status->band];
-               if (!sband || status->rate_idx >= sband->n_bitrates)
-                       return 0;
-
-               rate = &sband->bitrates[status->rate_idx];
-               cck = rate->flags & IEEE80211_RATE_MANDATORY_B;
-
-               return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp,
-                                                          cck, len);
-
        case RX_ENC_VHT:
                streams = status->nss;
                idx = status->rate_idx;
@@ -477,51 +459,146 @@ u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
 
        duration = airtime_mcs_groups[group].duration[idx];
        duration <<= airtime_mcs_groups[group].shift;
+       *overhead = 36 + (streams << 2);
+
+       return duration;
+}
+
+
+u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
+                             struct ieee80211_rx_status *status,
+                             int len)
+{
+       struct ieee80211_supported_band *sband;
+       u32 duration, overhead = 0;
+
+       if (status->encoding == RX_ENC_LEGACY) {
+               const struct ieee80211_rate *rate;
+               bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE;
+               bool cck;
+
+               if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ))
+                       return 0;
+
+               sband = hw->wiphy->bands[status->band];
+               if (!sband || status->rate_idx >= sband->n_bitrates)
+                       return 0;
+
+               rate = &sband->bitrates[status->rate_idx];
+               cck = rate->flags & IEEE80211_RATE_MANDATORY_B;
+
+               return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp,
+                                                          cck, len);
+       }
+
+       duration = ieee80211_get_rate_duration(hw, status, &overhead);
+       if (!duration)
+               return 0;
+
        duration *= len;
        duration /= AVG_PKT_SIZE;
        duration /= 1024;
 
-       duration += 36 + (streams << 2);
-
-       return duration;
+       return duration + overhead;
 }
 EXPORT_SYMBOL_GPL(ieee80211_calc_rx_airtime);
 
-static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw,
-                                         struct ieee80211_tx_rate *rate,
-                                         u8 band, int len)
+static bool ieee80211_fill_rate_info(struct ieee80211_hw *hw,
+                                    struct ieee80211_rx_status *stat, u8 band,
+                                    struct rate_info *ri)
 {
-       struct ieee80211_rx_status stat = {
-               .band = band,
-       };
+       struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
+       int i;
 
-       if (rate->idx < 0 || !rate->count)
+       if (!ri || !sband)
+           return false;
+
+       stat->bw = ri->bw;
+       stat->nss = ri->nss;
+       stat->rate_idx = ri->mcs;
+
+       if (ri->flags & RATE_INFO_FLAGS_HE_MCS)
+               stat->encoding = RX_ENC_HE;
+       else if (ri->flags & RATE_INFO_FLAGS_VHT_MCS)
+               stat->encoding = RX_ENC_VHT;
+       else if (ri->flags & RATE_INFO_FLAGS_MCS)
+               stat->encoding = RX_ENC_HT;
+       else
+               stat->encoding = RX_ENC_LEGACY;
+
+       if (ri->flags & RATE_INFO_FLAGS_SHORT_GI)
+               stat->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+       stat->he_gi = ri->he_gi;
+
+       if (stat->encoding != RX_ENC_LEGACY)
+               return true;
+
+       stat->rate_idx = 0;
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if (ri->legacy != sband->bitrates[i].bitrate)
+                       continue;
+
+               stat->rate_idx = i;
+               return true;
+       }
+
+       return false;
+}
+
+static int ieee80211_fill_rx_status(struct ieee80211_rx_status *stat,
+                                   struct ieee80211_hw *hw,
+                                   struct ieee80211_tx_rate *rate,
+                                   struct rate_info *ri, u8 band, int len)
+{
+       memset(stat, 0, sizeof(*stat));
+       stat->band = band;
+
+       if (ieee80211_fill_rate_info(hw, stat, band, ri))
                return 0;
 
-       if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
-               stat.bw = RATE_INFO_BW_80;
+       if (rate->idx < 0 || !rate->count)
+               return -1;
+
+       if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
+               stat->bw = RATE_INFO_BW_160;
+       else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+               stat->bw = RATE_INFO_BW_80;
        else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
-               stat.bw = RATE_INFO_BW_40;
+               stat->bw = RATE_INFO_BW_40;
        else
-               stat.bw = RATE_INFO_BW_20;
+               stat->bw = RATE_INFO_BW_20;
 
-       stat.enc_flags = 0;
+       stat->enc_flags = 0;
        if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
-               stat.enc_flags |= RX_ENC_FLAG_SHORTPRE;
+               stat->enc_flags |= RX_ENC_FLAG_SHORTPRE;
        if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
-               stat.enc_flags |= RX_ENC_FLAG_SHORT_GI;
+               stat->enc_flags |= RX_ENC_FLAG_SHORT_GI;
 
-       stat.rate_idx = rate->idx;
+       stat->rate_idx = rate->idx;
        if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
-               stat.encoding = RX_ENC_VHT;
-               stat.rate_idx = ieee80211_rate_get_vht_mcs(rate);
-               stat.nss = ieee80211_rate_get_vht_nss(rate);
+               stat->encoding = RX_ENC_VHT;
+               stat->rate_idx = ieee80211_rate_get_vht_mcs(rate);
+               stat->nss = ieee80211_rate_get_vht_nss(rate);
        } else if (rate->flags & IEEE80211_TX_RC_MCS) {
-               stat.encoding = RX_ENC_HT;
+               stat->encoding = RX_ENC_HT;
        } else {
-               stat.encoding = RX_ENC_LEGACY;
+               stat->encoding = RX_ENC_LEGACY;
        }
 
+       return 0;
+}
+
+static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw,
+                                         struct ieee80211_tx_rate *rate,
+                                         struct rate_info *ri,
+                                         u8 band, int len)
+{
+       struct ieee80211_rx_status stat;
+
+       if (ieee80211_fill_rx_status(&stat, hw, rate, ri, band, len))
+               return 0;
+
        return ieee80211_calc_rx_airtime(hw, &stat, len);
 }
 
@@ -536,7 +613,7 @@ u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
                struct ieee80211_tx_rate *rate = &info->status.rates[i];
                u32 cur_duration;
 
-               cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate,
+               cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate, NULL,
                                                              info->band, len);
                if (!cur_duration)
                        break;
@@ -572,26 +649,47 @@ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
        if (pubsta) {
                struct sta_info *sta = container_of(pubsta, struct sta_info,
                                                    sta);
+               struct ieee80211_rx_status stat;
                struct ieee80211_tx_rate *rate = &sta->tx_stats.last_rate;
-               u32 airtime;
+               struct rate_info *ri = &sta->tx_stats.last_rate_info;
+               u32 duration, overhead;
+               u8 agg_shift;
 
-               if (!(rate->flags & (IEEE80211_TX_RC_VHT_MCS |
-                                    IEEE80211_TX_RC_MCS)))
-                       ampdu = false;
+               if (ieee80211_fill_rx_status(&stat, hw, rate, ri, band, len))
+                       return 0;
 
+               if (stat.encoding == RX_ENC_LEGACY || !ampdu)
+                       return ieee80211_calc_rx_airtime(hw, &stat, len);
+
+               duration = ieee80211_get_rate_duration(hw, &stat, &overhead);
                /*
                 * Assume that HT/VHT transmission on any AC except VO will
                 * use aggregation. Since we don't have reliable reporting
-                * of aggregation length, assume an average of 16.
+                * of aggregation length, assume an average size based on the
+                * tx rate.
                 * This will not be very accurate, but much better than simply
-                * assuming un-aggregated tx.
+                * assuming un-aggregated tx in all cases.
                 */
-               airtime = ieee80211_calc_tx_airtime_rate(hw, rate, band,
-                                                        ampdu ? len * 16 : len);
-               if (ampdu)
-                       airtime /= 16;
-
-               return airtime;
+               if (duration > 400 * 1024) /* <= VHT20 MCS2 1S */
+                       agg_shift = 1;
+               else if (duration > 250 * 1024) /* <= VHT20 MCS3 1S or MCS1 2S */
+                       agg_shift = 2;
+               else if (duration > 150 * 1024) /* <= VHT20 MCS5 1S or MCS2 2S */
+                       agg_shift = 3;
+               else if (duration > 70 * 1024) /* <= VHT20 MCS5 2S */
+                       agg_shift = 4;
+               else if (stat.encoding != RX_ENC_HE ||
+                        duration > 20 * 1024) /* <= HE40 MCS6 2S */
+                       agg_shift = 5;
+               else
+                       agg_shift = 6;
+
+               duration *= len;
+               duration /= AVG_PKT_SIZE;
+               duration /= 1024;
+               duration += (overhead >> agg_shift);
+
+               return max_t(u32, duration, 4);
        }
 
        if (!conf)
index ac87030..2e400b0 100644 (file)
@@ -4861,6 +4861,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_supported_band *sband;
        struct cfg80211_chan_def chandef;
        bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
+       bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ;
        struct ieee80211_bss *bss = (void *)cbss->priv;
        int ret;
        u32 i;
@@ -4879,7 +4880,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
        }
 
-       if (!sband->vht_cap.vht_supported && !is_6ghz) {
+       if (!sband->vht_cap.vht_supported && is_5ghz) {
                ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
                ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
        }
index 836cde5..a959ebf 100644 (file)
@@ -451,7 +451,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        else if (status->bw == RATE_INFO_BW_5)
                channel_flags |= IEEE80211_CHAN_QUARTER;
 
-       if (status->band == NL80211_BAND_5GHZ)
+       if (status->band == NL80211_BAND_5GHZ ||
+           status->band == NL80211_BAND_6GHZ)
                channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ;
        else if (status->encoding != RX_ENC_LEGACY)
                channel_flags |= IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
index 9d398c9..d501011 100644 (file)
@@ -524,7 +524,7 @@ struct ieee80211_sta_rx_stats {
  * @status_stats.retry_failed: # of frames that failed after retry
  * @status_stats.retry_count: # of retries attempted
  * @status_stats.lost_packets: # of lost packets
- * @status_stats.last_tdls_pkt_time: timestamp of last TDLS packet
+ * @status_stats.last_pkt_time: timestamp of last ACKed packet
  * @status_stats.msdu_retries: # of MSDU retries
  * @status_stats.msdu_failed: # of failed MSDUs
  * @status_stats.last_ack: last ack timestamp (jiffies)
@@ -597,7 +597,7 @@ struct sta_info {
                unsigned long filtered;
                unsigned long retry_failed, retry_count;
                unsigned int lost_packets;
-               unsigned long last_tdls_pkt_time;
+               unsigned long last_pkt_time;
                u64 msdu_retries[IEEE80211_NUM_TIDS + 1];
                u64 msdu_failed[IEEE80211_NUM_TIDS + 1];
                unsigned long last_ack;
@@ -611,6 +611,7 @@ struct sta_info {
                u64 packets[IEEE80211_NUM_ACS];
                u64 bytes[IEEE80211_NUM_ACS];
                struct ieee80211_tx_rate last_rate;
+               struct rate_info last_rate_info;
                u64 msdu[IEEE80211_NUM_TIDS + 1];
        } tx_stats;
        u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
index adb1d30..0794396 100644 (file)
@@ -755,12 +755,16 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
  *  - current throughput (higher value for higher tpt)?
  */
 #define STA_LOST_PKT_THRESHOLD 50
+#define STA_LOST_PKT_TIME      HZ              /* 1 sec since last ACK */
 #define STA_LOST_TDLS_PKT_THRESHOLD    10
 #define STA_LOST_TDLS_PKT_TIME         (10*HZ) /* 10secs since last ACK */
 
 static void ieee80211_lost_packet(struct sta_info *sta,
                                  struct ieee80211_tx_info *info)
 {
+       unsigned long pkt_time = STA_LOST_PKT_TIME;
+       unsigned int pkt_thr = STA_LOST_PKT_THRESHOLD;
+
        /* If driver relies on its own algorithm for station kickout, skip
         * mac80211 packet loss mechanism.
         */
@@ -773,21 +777,20 @@ static void ieee80211_lost_packet(struct sta_info *sta,
                return;
 
        sta->status_stats.lost_packets++;
-       if (!sta->sta.tdls &&
-           sta->status_stats.lost_packets < STA_LOST_PKT_THRESHOLD)
-               return;
+       if (sta->sta.tdls) {
+               pkt_time = STA_LOST_TDLS_PKT_TIME;
+               pkt_thr = STA_LOST_PKT_THRESHOLD;
+       }
 
        /*
         * If we're in TDLS mode, make sure that all STA_LOST_TDLS_PKT_THRESHOLD
         * of the last packets were lost, and that no ACK was received in the
         * last STA_LOST_TDLS_PKT_TIME ms, before triggering the CQM packet-loss
         * mechanism.
+        * For non-TDLS, use STA_LOST_PKT_THRESHOLD and STA_LOST_PKT_TIME
         */
-       if (sta->sta.tdls &&
-           (sta->status_stats.lost_packets < STA_LOST_TDLS_PKT_THRESHOLD ||
-            time_before(jiffies,
-                        sta->status_stats.last_tdls_pkt_time +
-                        STA_LOST_TDLS_PKT_TIME)))
+       if (sta->status_stats.lost_packets < pkt_thr ||
+           !time_after(jiffies, sta->status_stats.last_pkt_time + pkt_time))
                return;
 
        cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
@@ -1033,9 +1036,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
                                        sta->status_stats.lost_packets = 0;
 
                                /* Track when last TDLS packet was ACKed */
-                               if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
-                                       sta->status_stats.last_tdls_pkt_time =
-                                               jiffies;
+                               sta->status_stats.last_pkt_time = jiffies;
                        } else if (noack_success) {
                                /* nothing to do here, do not account as lost */
                        } else {
@@ -1137,9 +1138,17 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
        struct ieee80211_tx_info *info = status->info;
        struct ieee80211_sta *pubsta = status->sta;
        struct ieee80211_supported_band *sband;
+       struct sta_info *sta;
        int retry_count;
        bool acked, noack_success;
 
+       if (pubsta) {
+               sta = container_of(pubsta, struct sta_info, sta);
+
+               if (status->rate)
+                       sta->tx_stats.last_rate_info = *status->rate;
+       }
+
        if (status->skb)
                return __ieee80211_tx_status(hw, status);
 
@@ -1154,10 +1163,6 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
        noack_success = !!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED);
 
        if (pubsta) {
-               struct sta_info *sta;
-
-               sta = container_of(pubsta, struct sta_info, sta);
-
                if (!acked && !noack_success)
                        sta->status_stats.retry_failed++;
                sta->status_stats.retry_count += retry_count;
@@ -1168,9 +1173,8 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
                        if (sta->status_stats.lost_packets)
                                sta->status_stats.lost_packets = 0;
 
-                       /* Track when last TDLS packet was ACKed */
-                       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
-                               sta->status_stats.last_tdls_pkt_time = jiffies;
+                       /* Track when last packet was ACKed */
+                       sta->status_stats.last_pkt_time = jiffies;
                } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
                        return;
                } else if (noack_success) {
@@ -1259,8 +1263,7 @@ void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
                        if (sta->status_stats.lost_packets)
                                sta->status_stats.lost_packets = 0;
 
-                       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
-                               sta->status_stats.last_tdls_pkt_time = jiffies;
+                       sta->status_stats.last_pkt_time = jiffies;
                } else {
                        ieee80211_lost_packet(sta, info);
                }
index c8504ff..8d3bfc0 100644 (file)
@@ -3353,9 +3353,10 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
                he_chandef.center_freq1 =
                        ieee80211_channel_to_frequency(he_6ghz_oper->ccfs0,
                                                       NL80211_BAND_6GHZ);
-               he_chandef.center_freq2 =
-                       ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1,
-                                                      NL80211_BAND_6GHZ);
+               if (support_80_80 || support_160)
+                       he_chandef.center_freq2 =
+                               ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1,
+                                                              NL80211_BAND_6GHZ);
        }
 
        if (!cfg80211_chandef_valid(&he_chandef)) {
index 9c6045f..d1b64d0 100644 (file)
@@ -168,10 +168,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
        /* take some capabilities as-is */
        cap_info = le32_to_cpu(vht_cap_ie->vht_cap_info);
        vht_cap->cap = cap_info;
-       vht_cap->cap &= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
-                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
-                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
-                       IEEE80211_VHT_CAP_RXLDPC |
+       vht_cap->cap &= IEEE80211_VHT_CAP_RXLDPC |
                        IEEE80211_VHT_CAP_VHT_TXOP_PS |
                        IEEE80211_VHT_CAP_HTC_VHT |
                        IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
@@ -180,6 +177,9 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                        IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
                        IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
 
+       vht_cap->cap |= min_t(u32, cap_info & IEEE80211_VHT_CAP_MAX_MPDU_MASK,
+                             own_cap.cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK);
+
        /* and some based on our own capabilities */
        switch (own_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
        case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
index ab52811..c829e4a 100644 (file)
@@ -34,11 +34,11 @@ void ieee802154_xmit_worker(struct work_struct *work)
        if (res)
                goto err_tx;
 
-       ieee802154_xmit_complete(&local->hw, skb, false);
-
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
 
+       ieee802154_xmit_complete(&local->hw, skb, false);
+
        return;
 
 err_tx:
@@ -78,6 +78,8 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
 
        /* async is priority, otherwise sync is fallback */
        if (local->ops->xmit_async) {
+               unsigned int len = skb->len;
+
                ret = drv_xmit_async(local, skb);
                if (ret) {
                        ieee802154_wake_queue(&local->hw);
@@ -85,7 +87,7 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
                }
 
                dev->stats.tx_packets++;
-               dev->stats.tx_bytes += skb->len;
+               dev->stats.tx_bytes += len;
        } else {
                local->tx_skb = skb;
                queue_work(local->workqueue, &local->tx_work);
index 6fdd0c9..f2868a8 100644 (file)
@@ -1516,7 +1516,7 @@ static void mpls_ifdown(struct net_device *dev, int event)
                        case NETDEV_DOWN:
                        case NETDEV_UNREGISTER:
                                nh_flags |= RTNH_F_DEAD;
-                               /* fall through */
+                               fallthrough;
                        case NETDEV_CHANGE:
                                nh_flags |= RTNH_F_LINKDOWN;
                                break;
index 7fa822b..888bbbb 100644 (file)
@@ -451,7 +451,10 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,
 static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
                                 struct sk_buff *skb, struct mptcp_ext *ext)
 {
-       u64 data_fin_tx_seq = READ_ONCE(mptcp_sk(subflow->conn)->write_seq);
+       /* The write_seq value has already been incremented, so the actual
+        * sequence number for the DATA_FIN is one less.
+        */
+       u64 data_fin_tx_seq = READ_ONCE(mptcp_sk(subflow->conn)->write_seq) - 1;
 
        if (!ext->use_map || !skb->len) {
                /* RFC6824 requires a DSS mapping with specific values
@@ -460,10 +463,7 @@ static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
                ext->data_fin = 1;
                ext->use_map = 1;
                ext->dsn64 = 1;
-               /* The write_seq value has already been incremented, so
-                * the actual sequence number for the DATA_FIN is one less.
-                */
-               ext->data_seq = data_fin_tx_seq - 1;
+               ext->data_seq = data_fin_tx_seq;
                ext->subflow_seq = 0;
                ext->data_len = 1;
        } else if (ext->data_seq + ext->data_len == data_fin_tx_seq) {
@@ -518,11 +518,11 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
 
        if (subflow->use_64bit_ack) {
                ack_size = TCPOLEN_MPTCP_DSS_ACK64;
-               opts->ext_copy.data_ack = msk->ack_seq;
+               opts->ext_copy.data_ack = READ_ONCE(msk->ack_seq);
                opts->ext_copy.ack64 = 1;
        } else {
                ack_size = TCPOLEN_MPTCP_DSS_ACK32;
-               opts->ext_copy.data_ack32 = (uint32_t)(msk->ack_seq);
+               opts->ext_copy.data_ack32 = (uint32_t)READ_ONCE(msk->ack_seq);
                opts->ext_copy.ack64 = 0;
        }
        opts->ext_copy.use_ack = 1;
@@ -782,7 +782,7 @@ static void update_una(struct mptcp_sock *msk,
        }
 }
 
-bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq)
+bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq, bool use_64bit)
 {
        /* Skip if DATA_FIN was already received.
         * If updating simultaneously with the recvmsg loop, values
@@ -792,7 +792,8 @@ bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq)
        if (READ_ONCE(msk->rcv_data_fin) || !READ_ONCE(msk->first))
                return false;
 
-       WRITE_ONCE(msk->rcv_data_fin_seq, data_fin_seq);
+       WRITE_ONCE(msk->rcv_data_fin_seq,
+                  expand_ack(READ_ONCE(msk->ack_seq), data_fin_seq, use_64bit));
        WRITE_ONCE(msk->rcv_data_fin, 1);
 
        return true;
@@ -875,7 +876,7 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
         */
        if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) {
                if (mp_opt.data_fin && mp_opt.data_len == 1 &&
-                   mptcp_update_rcv_data_fin(msk, mp_opt.data_seq) &&
+                   mptcp_update_rcv_data_fin(msk, mp_opt.data_seq, mp_opt.dsn64) &&
                    schedule_work(&msk->work))
                        sock_hold(subflow->conn);
 
index c8820c4..770da36 100644 (file)
@@ -66,6 +66,16 @@ static bool addresses_equal(const struct mptcp_addr_info *a,
        return a->port == b->port;
 }
 
+static bool address_zero(const struct mptcp_addr_info *addr)
+{
+       struct mptcp_addr_info zero;
+
+       memset(&zero, 0, sizeof(zero));
+       zero.family = addr->family;
+
+       return addresses_equal(addr, &zero, false);
+}
+
 static void local_address(const struct sock_common *skc,
                          struct mptcp_addr_info *addr)
 {
@@ -171,9 +181,9 @@ static void check_work_pending(struct mptcp_sock *msk)
 
 static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
 {
+       struct mptcp_addr_info remote = { 0 };
        struct sock *sk = (struct sock *)msk;
        struct mptcp_pm_addr_entry *local;
-       struct mptcp_addr_info remote;
        struct pm_nl_pernet *pernet;
 
        pernet = net_generic(sock_net((struct sock *)msk), pm_nl_pernet_id);
@@ -323,10 +333,13 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
         * addr
         */
        local_address((struct sock_common *)msk, &msk_local);
-       local_address((struct sock_common *)msk, &skc_local);
+       local_address((struct sock_common *)skc, &skc_local);
        if (addresses_equal(&msk_local, &skc_local, false))
                return 0;
 
+       if (address_zero(&skc_local))
+               return 0;
+
        pernet = net_generic(sock_net((struct sock *)msk), pm_nl_pernet_id);
 
        rcu_read_lock();
@@ -341,7 +354,7 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
                return ret;
 
        /* address not found, add to local list */
-       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
        if (!entry)
                return -ENOMEM;
 
index 1aad411..5d747c6 100644 (file)
@@ -123,7 +123,7 @@ static void __mptcp_move_skb(struct mptcp_sock *msk, struct sock *ssk,
 
        skb_ext_reset(skb);
        skb_orphan(skb);
-       msk->ack_seq += copy_len;
+       WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len);
 
        tail = skb_peek_tail(&sk->sk_receive_queue);
        if (offset == 0 && tail) {
@@ -193,7 +193,6 @@ static void mptcp_check_data_fin_ack(struct sock *sk)
                        sk->sk_state_change(sk);
                        break;
                case TCP_CLOSING:
-                       fallthrough;
                case TCP_LAST_ACK:
                        inet_sk_state_store(sk, TCP_CLOSE);
                        sk->sk_state_change(sk);
@@ -262,7 +261,7 @@ static void mptcp_check_data_fin(struct sock *sk)
        if (mptcp_pending_data_fin(sk, &rcv_data_fin_seq)) {
                struct mptcp_subflow_context *subflow;
 
-               msk->ack_seq++;
+               WRITE_ONCE(msk->ack_seq, msk->ack_seq + 1);
                WRITE_ONCE(msk->rcv_data_fin, 0);
 
                sk->sk_shutdown |= RCV_SHUTDOWN;
@@ -892,7 +891,6 @@ restart:
                goto out;
        }
 
-wait_for_sndbuf:
        __mptcp_flush_join_list(msk);
        ssk = mptcp_subflow_get_send(msk);
        while (!sk_stream_memory_free(sk) ||
@@ -982,7 +980,7 @@ wait_for_sndbuf:
                                 */
                                mptcp_set_timeout(sk, ssk);
                                release_sock(ssk);
-                               goto wait_for_sndbuf;
+                               goto restart;
                        }
                }
        }
@@ -1541,7 +1539,7 @@ static void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how)
        case TCP_LISTEN:
                if (!(how & RCV_SHUTDOWN))
                        break;
-               /* fall through */
+               fallthrough;
        case TCP_SYN_SENT:
                tcp_disconnect(ssk, O_NONBLOCK);
                break;
@@ -1722,7 +1720,7 @@ struct sock *mptcp_sk_clone(const struct sock *sk,
                msk->remote_key = mp_opt->sndr_key;
                mptcp_crypto_key_sha(msk->remote_key, NULL, &ack_seq);
                ack_seq++;
-               msk->ack_seq = ack_seq;
+               WRITE_ONCE(msk->ack_seq, ack_seq);
        }
 
        sock_reset_flag(nsk, SOCK_RCU_FREE);
@@ -2074,7 +2072,7 @@ bool mptcp_finish_join(struct sock *sk)
        parent_sock = READ_ONCE(parent->sk_socket);
        if (parent_sock && !sk->sk_socket)
                mptcp_sock_graft(sk, parent_sock);
-       subflow->map_seq = msk->ack_seq;
+       subflow->map_seq = READ_ONCE(msk->ack_seq);
        return true;
 }
 
index 60b27d4..20f04ac 100644 (file)
@@ -387,7 +387,7 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk);
 bool mptcp_finish_join(struct sock *sk);
 void mptcp_data_acked(struct sock *sk);
 void mptcp_subflow_eof(struct sock *sk);
-bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq);
+bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq, bool use_64bit);
 
 void __init mptcp_token_init(void);
 static inline void mptcp_token_init_request(struct request_sock *req)
index e8cac26..6f035af 100644 (file)
@@ -731,7 +731,8 @@ static enum mapping_status get_mapping_status(struct sock *ssk,
 
        if (mpext->data_fin == 1) {
                if (data_len == 1) {
-                       mptcp_update_rcv_data_fin(msk, mpext->data_seq);
+                       bool updated = mptcp_update_rcv_data_fin(msk, mpext->data_seq,
+                                                                mpext->dsn64);
                        pr_debug("DATA_FIN with no payload seq=%llu", mpext->data_seq);
                        if (subflow->map_valid) {
                                /* A DATA_FIN might arrive in a DSS
@@ -742,11 +743,23 @@ static enum mapping_status get_mapping_status(struct sock *ssk,
                                skb_ext_del(skb, SKB_EXT_MPTCP);
                                return MAPPING_OK;
                        } else {
+                               if (updated && schedule_work(&msk->work))
+                                       sock_hold((struct sock *)msk);
+
                                return MAPPING_DATA_FIN;
                        }
                } else {
-                       mptcp_update_rcv_data_fin(msk, mpext->data_seq + data_len);
-                       pr_debug("DATA_FIN with mapping seq=%llu", mpext->data_seq + data_len);
+                       u64 data_fin_seq = mpext->data_seq + data_len - 1;
+
+                       /* If mpext->data_seq is a 32-bit value, data_fin_seq
+                        * must also be limited to 32 bits.
+                        */
+                       if (!mpext->dsn64)
+                               data_fin_seq &= GENMASK_ULL(31, 0);
+
+                       mptcp_update_rcv_data_fin(msk, data_fin_seq, mpext->dsn64);
+                       pr_debug("DATA_FIN with mapping seq=%llu dsn64=%d",
+                                data_fin_seq, mpext->dsn64);
                }
 
                /* Adjust for DATA_FIN using 1 byte of sequence space */
@@ -1063,6 +1076,7 @@ int __mptcp_subflow_connect(struct sock *sk, int ifindex,
        struct mptcp_sock *msk = mptcp_sk(sk);
        struct mptcp_subflow_context *subflow;
        struct sockaddr_storage addr;
+       int remote_id = remote->id;
        int local_id = loc->id;
        struct socket *sf;
        struct sock *ssk;
@@ -1107,10 +1121,11 @@ int __mptcp_subflow_connect(struct sock *sk, int ifindex,
                goto failed;
 
        mptcp_crypto_key_sha(subflow->remote_key, &remote_token, NULL);
-       pr_debug("msk=%p remote_token=%u local_id=%d", msk, remote_token,
-                local_id);
+       pr_debug("msk=%p remote_token=%u local_id=%d remote_id=%d", msk,
+                remote_token, local_id, remote_id);
        subflow->remote_token = remote_token;
        subflow->local_id = local_id;
+       subflow->remote_id = remote_id;
        subflow->request_join = 1;
        subflow->request_bkup = 1;
        mptcp_info2sockaddr(remote, &addr);
@@ -1347,6 +1362,7 @@ static void subflow_ulp_clone(const struct request_sock *req,
                new_ctx->fully_established = 1;
                new_ctx->backup = subflow_req->backup;
                new_ctx->local_id = subflow_req->local_id;
+               new_ctx->remote_id = subflow_req->remote_id;
                new_ctx->token = subflow_req->token;
                new_ctx->thmac = subflow_req->thmac;
        }
index 1f387be..f1be3e3 100644 (file)
@@ -474,7 +474,7 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
        switch (nd->state) {
        case ncsi_dev_state_suspend:
                nd->state = ncsi_dev_state_suspend_select;
-               /* Fall through */
+               fallthrough;
        case ncsi_dev_state_suspend_select:
                ndp->pending_req_num = 1;
 
@@ -1302,7 +1302,7 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
        switch (nd->state) {
        case ncsi_dev_state_probe:
                nd->state = ncsi_dev_state_probe_deselect;
-               /* Fall through */
+               fallthrough;
        case ncsi_dev_state_probe_deselect:
                ndp->pending_req_num = 8;
 
index 32b0288..dc2e7da 100644 (file)
@@ -315,7 +315,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
        switch (skb->ip_summed) {
        case CHECKSUM_NONE:
                skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
-               /* fall through */
+               fallthrough;
        case CHECKSUM_COMPLETE:
 #ifdef CONFIG_IP_VS_IPV6
                if (af == AF_INET6) {
index 153d896..68260d9 100644 (file)
@@ -318,7 +318,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
                case CHECKSUM_NONE:
                        skb->csum = skb_checksum(skb, udphoff,
                                                 skb->len - udphoff, 0);
-                       /* fall through */
+                       fallthrough;
                case CHECKSUM_COMPLETE:
 #ifdef CONFIG_IP_VS_IPV6
                        if (af == AF_INET6) {
index 832eabe..c3a4214 100644 (file)
@@ -851,7 +851,6 @@ static int ctnetlink_done(struct netlink_callback *cb)
 }
 
 struct ctnetlink_filter {
-       u_int32_t cta_flags;
        u8 family;
 
        u_int32_t orig_flags;
@@ -906,10 +905,6 @@ static int ctnetlink_parse_tuple_filter(const struct nlattr * const cda[],
                                         struct nf_conntrack_zone *zone,
                                         u_int32_t flags);
 
-/* applied on filters */
-#define CTA_FILTER_F_CTA_MARK                  (1 << 0)
-#define CTA_FILTER_F_CTA_MARK_MASK             (1 << 1)
-
 static struct ctnetlink_filter *
 ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
 {
@@ -930,14 +925,10 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
 #ifdef CONFIG_NF_CONNTRACK_MARK
        if (cda[CTA_MARK]) {
                filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
-               filter->cta_flags |= CTA_FILTER_FLAG(CTA_MARK);
-
-               if (cda[CTA_MARK_MASK]) {
+               if (cda[CTA_MARK_MASK])
                        filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
-                       filter->cta_flags |= CTA_FILTER_FLAG(CTA_MARK_MASK);
-               } else {
+               else
                        filter->mark.mask = 0xffffffff;
-               }
        } else if (cda[CTA_MARK_MASK]) {
                err = -EINVAL;
                goto err_filter;
@@ -1117,11 +1108,7 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
        }
 
 #ifdef CONFIG_NF_CONNTRACK_MARK
-       if ((filter->cta_flags & CTA_FILTER_FLAG(CTA_MARK_MASK)) &&
-           (ct->mark & filter->mark.mask) != filter->mark.val)
-               goto ignore_entry;
-       else if ((filter->cta_flags & CTA_FILTER_FLAG(CTA_MARK)) &&
-                ct->mark != filter->mark.val)
+       if ((ct->mark & filter->mark.mask) != filter->mark.val)
                goto ignore_entry;
 #endif
 
@@ -1404,7 +1391,8 @@ ctnetlink_parse_tuple_filter(const struct nlattr * const cda[],
        if (err < 0)
                return err;
 
-
+       if (l3num != NFPROTO_IPV4 && l3num != NFPROTO_IPV6)
+               return -EOPNOTSUPP;
        tuple->src.l3num = l3num;
 
        if (flags & CTA_FILTER_FLAG(CTA_IP_DST) ||
index 1f44d52..5105d42 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
- * PPTP is a protocol for creating virtual private networks.
+ * PPTP is a protocol for creating virtual private networks.
  * It is a specification defined by Microsoft and some vendors
  * working with Microsoft.  PPTP is built on top of a modified
  * version of the Internet Generic Routing Encapsulation Protocol.
index 95f7998..47e9319 100644 (file)
@@ -565,6 +565,7 @@ static int nf_ct_netns_inet_get(struct net *net)
        int err;
 
        err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
+#if IS_ENABLED(CONFIG_IPV6)
        if (err < 0)
                goto err1;
        err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
@@ -575,6 +576,7 @@ static int nf_ct_netns_inet_get(struct net *net)
 err2:
        nf_ct_netns_put(net, NFPROTO_IPV4);
 err1:
+#endif
        return err;
 }
 
index 4f897b1..810cca2 100644 (file)
@@ -62,6 +62,8 @@ static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = {
        [SCTP_CONNTRACK_HEARTBEAT_ACKED]        = 210 SECS,
 };
 
+#define        SCTP_FLAG_HEARTBEAT_VTAG_FAILED 1
+
 #define sNO SCTP_CONNTRACK_NONE
 #define        sCL SCTP_CONNTRACK_CLOSED
 #define        sCW SCTP_CONNTRACK_COOKIE_WAIT
@@ -369,6 +371,7 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
        u_int32_t offset, count;
        unsigned int *timeouts;
        unsigned long map[256 / sizeof(unsigned long)] = { 0 };
+       bool ignore = false;
 
        if (sctp_error(skb, dataoff, state))
                return -NF_ACCEPT;
@@ -427,15 +430,39 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
                        /* Sec 8.5.1 (D) */
                        if (sh->vtag != ct->proto.sctp.vtag[dir])
                                goto out_unlock;
-               } else if (sch->type == SCTP_CID_HEARTBEAT ||
-                          sch->type == SCTP_CID_HEARTBEAT_ACK) {
+               } else if (sch->type == SCTP_CID_HEARTBEAT) {
+                       if (ct->proto.sctp.vtag[dir] == 0) {
+                               pr_debug("Setting %d vtag %x for dir %d\n", sch->type, sh->vtag, dir);
+                               ct->proto.sctp.vtag[dir] = sh->vtag;
+                       } else if (sh->vtag != ct->proto.sctp.vtag[dir]) {
+                               if (test_bit(SCTP_CID_DATA, map) || ignore)
+                                       goto out_unlock;
+
+                               ct->proto.sctp.flags |= SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
+                               ct->proto.sctp.last_dir = dir;
+                               ignore = true;
+                               continue;
+                       } else if (ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) {
+                               ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
+                       }
+               } else if (sch->type == SCTP_CID_HEARTBEAT_ACK) {
                        if (ct->proto.sctp.vtag[dir] == 0) {
                                pr_debug("Setting vtag %x for dir %d\n",
                                         sh->vtag, dir);
                                ct->proto.sctp.vtag[dir] = sh->vtag;
                        } else if (sh->vtag != ct->proto.sctp.vtag[dir]) {
-                               pr_debug("Verification tag check failed\n");
-                               goto out_unlock;
+                               if (test_bit(SCTP_CID_DATA, map) || ignore)
+                                       goto out_unlock;
+
+                               if ((ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) == 0 ||
+                                   ct->proto.sctp.last_dir == dir)
+                                       goto out_unlock;
+
+                               ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
+                               ct->proto.sctp.vtag[dir] = sh->vtag;
+                               ct->proto.sctp.vtag[!dir] = 0;
+                       } else if (ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) {
+                               ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
                        }
                }
 
@@ -470,6 +497,10 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
        }
        spin_unlock_bh(&ct->lock);
 
+       /* allow but do not refresh timeout */
+       if (ignore)
+               return NF_ACCEPT;
+
        timeouts = nf_ct_timeout_lookup(ct);
        if (!timeouts)
                timeouts = nf_sctp_pernet(nf_ct_net(ct))->timeouts;
index 6892e49..e8c86ee 100644 (file)
@@ -1152,7 +1152,7 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct,
                   && (old_state == TCP_CONNTRACK_SYN_RECV
                       || old_state == TCP_CONNTRACK_ESTABLISHED)
                   && new_state == TCP_CONNTRACK_ESTABLISHED) {
-               /* Set ASSURED if we see see valid ack in ESTABLISHED
+               /* Set ASSURED if we see valid ack in ESTABLISHED
                   after SYN_RECV or a valid answer for a picked up
                   connection. */
                set_bit(IPS_ASSURED_BIT, &ct->status);
index 760ca24..af402f4 100644 (file)
@@ -81,18 +81,6 @@ static bool udp_error(struct sk_buff *skb,
        return false;
 }
 
-static void nf_conntrack_udp_refresh_unreplied(struct nf_conn *ct,
-                                              struct sk_buff *skb,
-                                              enum ip_conntrack_info ctinfo,
-                                              u32 extra_jiffies)
-{
-       if (unlikely(ctinfo == IP_CT_ESTABLISHED_REPLY &&
-                    ct->status & IPS_NAT_CLASH))
-               nf_ct_kill(ct);
-       else
-               nf_ct_refresh_acct(ct, ctinfo, skb, extra_jiffies);
-}
-
 /* Returns verdict for packet, and may modify conntracktype */
 int nf_conntrack_udp_packet(struct nf_conn *ct,
                            struct sk_buff *skb,
@@ -124,12 +112,15 @@ int nf_conntrack_udp_packet(struct nf_conn *ct,
 
                nf_ct_refresh_acct(ct, ctinfo, skb, extra);
 
+               /* never set ASSURED for IPS_NAT_CLASH, they time out soon */
+               if (unlikely((ct->status & IPS_NAT_CLASH)))
+                       return NF_ACCEPT;
+
                /* Also, more likely to be important, and not a probe */
                if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
                        nf_conntrack_event_cache(IPCT_ASSURED, ct);
        } else {
-               nf_conntrack_udp_refresh_unreplied(ct, skb, ctinfo,
-                                                  timeouts[UDP_CT_UNREPLIED]);
+               nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[UDP_CT_UNREPLIED]);
        }
        return NF_ACCEPT;
 }
@@ -206,12 +197,15 @@ int nf_conntrack_udplite_packet(struct nf_conn *ct,
        if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
                nf_ct_refresh_acct(ct, ctinfo, skb,
                                   timeouts[UDP_CT_REPLIED]);
+
+               if (unlikely((ct->status & IPS_NAT_CLASH)))
+                       return NF_ACCEPT;
+
                /* Also, more likely to be important, and not a probe */
                if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
                        nf_conntrack_event_cache(IPCT_ASSURED, ct);
        } else {
-               nf_conntrack_udp_refresh_unreplied(ct, skb, ctinfo,
-                                                  timeouts[UDP_CT_UNREPLIED]);
+               nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[UDP_CT_UNREPLIED]);
        }
        return NF_ACCEPT;
 }
index fd814e5..4603b66 100644 (file)
@@ -684,6 +684,18 @@ nla_put_failure:
        return -1;
 }
 
+struct nftnl_skb_parms {
+       bool report;
+};
+#define NFT_CB(skb)    (*(struct nftnl_skb_parms*)&((skb)->cb))
+
+static void nft_notify_enqueue(struct sk_buff *skb, bool report,
+                              struct list_head *notify_list)
+{
+       NFT_CB(skb).report = report;
+       list_add_tail(&skb->list, notify_list);
+}
+
 static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
 {
        struct sk_buff *skb;
@@ -715,8 +727,7 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
                goto err;
        }
 
-       nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
-                      ctx->report, GFP_KERNEL);
+       nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
        return;
 err:
        nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -815,11 +826,11 @@ static int nf_tables_gettable(struct net *net, struct sock *nlsk,
                                        nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
                                        family, table);
        if (err < 0)
-               goto err;
+               goto err_fill_table_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
 
-err:
+err_fill_table_info:
        kfree_skb(skb2);
        return err;
 }
@@ -1468,8 +1479,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
                goto err;
        }
 
-       nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
-                      ctx->report, GFP_KERNEL);
+       nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
        return;
 err:
        nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -1563,11 +1573,11 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk,
                                        nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
                                        family, table, chain);
        if (err < 0)
-               goto err;
+               goto err_fill_chain_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
 
-err:
+err_fill_chain_info:
        kfree_skb(skb2);
        return err;
 }
@@ -2807,8 +2817,7 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
                goto err;
        }
 
-       nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
-                      ctx->report, GFP_KERNEL);
+       nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
        return;
 err:
        nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -3008,11 +3017,11 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
                                       nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
                                       family, table, chain, rule, NULL);
        if (err < 0)
-               goto err;
+               goto err_fill_rule_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
 
-err:
+err_fill_rule_info:
        kfree_skb(skb2);
        return err;
 }
@@ -3770,7 +3779,8 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
                        goto nla_put_failure;
        }
 
-       if (nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata))
+       if (set->udata &&
+           nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata))
                goto nla_put_failure;
 
        nest = nla_nest_start_noflag(skb, NFTA_SET_DESC);
@@ -3836,8 +3846,7 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx,
                goto err;
        }
 
-       nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, ctx->report,
-                      gfp_flags);
+       nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
        return;
 err:
        nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -3967,11 +3976,11 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
 
        err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
        if (err < 0)
-               goto err;
+               goto err_fill_set_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
 
-err:
+err_fill_set_info:
        kfree_skb(skb2);
        return err;
 }
@@ -4859,24 +4868,18 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        err = -ENOMEM;
        skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
        if (skb == NULL)
-               goto err1;
+               return err;
 
        err = nf_tables_fill_setelem_info(skb, ctx, ctx->seq, ctx->portid,
                                          NFT_MSG_NEWSETELEM, 0, set, &elem);
        if (err < 0)
-               goto err2;
+               goto err_fill_setelem;
 
-       err = nfnetlink_unicast(skb, ctx->net, ctx->portid, MSG_DONTWAIT);
-       /* This avoids a loop in nfnetlink. */
-       if (err < 0)
-               goto err1;
+       return nfnetlink_unicast(skb, ctx->net, ctx->portid);
 
-       return 0;
-err2:
+err_fill_setelem:
        kfree_skb(skb);
-err1:
-       /* this avoids a loop in nfnetlink. */
-       return err == -EAGAIN ? -ENOBUFS : err;
+       return err;
 }
 
 /* called with rcu_read_lock held */
@@ -4964,8 +4967,7 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
                goto err;
        }
 
-       nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, ctx->report,
-                      GFP_KERNEL);
+       nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
        return;
 err:
        nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -6181,10 +6183,11 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
                                      nlh->nlmsg_seq, NFT_MSG_NEWOBJ, 0,
                                      family, table, obj, reset);
        if (err < 0)
-               goto err;
+               goto err_fill_obj_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
-err:
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
+
+err_fill_obj_info:
        kfree_skb(skb2);
        return err;
 }
@@ -6279,7 +6282,7 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,
                goto err;
        }
 
-       nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report, gfp);
+       nft_notify_enqueue(skb, report, &net->nft.notify_list);
        return;
 err:
        nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -7044,10 +7047,11 @@ static int nf_tables_getflowtable(struct net *net, struct sock *nlsk,
                                            NFT_MSG_NEWFLOWTABLE, 0, family,
                                            flowtable, &flowtable->hook_list);
        if (err < 0)
-               goto err;
+               goto err_fill_flowtable_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
-err:
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
+
+err_fill_flowtable_info:
        kfree_skb(skb2);
        return err;
 }
@@ -7088,8 +7092,7 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
                goto err;
        }
 
-       nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
-                      ctx->report, GFP_KERNEL);
+       nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
        return;
 err:
        nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -7233,10 +7236,11 @@ static int nf_tables_getgen(struct net *net, struct sock *nlsk,
        err = nf_tables_fill_gen_info(skb2, net, NETLINK_CB(skb).portid,
                                      nlh->nlmsg_seq);
        if (err < 0)
-               goto err;
+               goto err_fill_gen_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
-err:
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
+
+err_fill_gen_info:
        kfree_skb(skb2);
        return err;
 }
@@ -7697,6 +7701,41 @@ static void nf_tables_commit_release(struct net *net)
        mutex_unlock(&net->nft.commit_mutex);
 }
 
+static void nft_commit_notify(struct net *net, u32 portid)
+{
+       struct sk_buff *batch_skb = NULL, *nskb, *skb;
+       unsigned char *data;
+       int len;
+
+       list_for_each_entry_safe(skb, nskb, &net->nft.notify_list, list) {
+               if (!batch_skb) {
+new_batch:
+                       batch_skb = skb;
+                       len = NLMSG_GOODSIZE - skb->len;
+                       list_del(&skb->list);
+                       continue;
+               }
+               len -= skb->len;
+               if (len > 0 && NFT_CB(skb).report == NFT_CB(batch_skb).report) {
+                       data = skb_put(batch_skb, skb->len);
+                       memcpy(data, skb->data, skb->len);
+                       list_del(&skb->list);
+                       kfree_skb(skb);
+                       continue;
+               }
+               nfnetlink_send(batch_skb, net, portid, NFNLGRP_NFTABLES,
+                              NFT_CB(batch_skb).report, GFP_KERNEL);
+               goto new_batch;
+       }
+
+       if (batch_skb) {
+               nfnetlink_send(batch_skb, net, portid, NFNLGRP_NFTABLES,
+                              NFT_CB(batch_skb).report, GFP_KERNEL);
+       }
+
+       WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
+}
+
 static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 {
        struct nft_trans *trans, *next;
@@ -7899,6 +7938,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                }
        }
 
+       nft_commit_notify(net, NETLINK_CB(skb).portid);
        nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
        nf_tables_commit_release(net);
 
@@ -8723,6 +8763,7 @@ static int __net_init nf_tables_init_net(struct net *net)
        INIT_LIST_HEAD(&net->nft.tables);
        INIT_LIST_HEAD(&net->nft.commit_list);
        INIT_LIST_HEAD(&net->nft.module_list);
+       INIT_LIST_HEAD(&net->nft.notify_list);
        mutex_init(&net->nft.commit_mutex);
        net->nft.base_seq = 1;
        net->nft.validate_state = NFT_VALIDATE_SKIP;
@@ -8739,6 +8780,7 @@ static void __net_exit nf_tables_exit_net(struct net *net)
        mutex_unlock(&net->nft.commit_mutex);
        WARN_ON_ONCE(!list_empty(&net->nft.tables));
        WARN_ON_ONCE(!list_empty(&net->nft.module_list));
+       WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
 }
 
 static struct pernet_operations nf_tables_net_ops = {
index 5f24edf..3a2e64e 100644 (file)
@@ -149,10 +149,15 @@ int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error)
 }
 EXPORT_SYMBOL_GPL(nfnetlink_set_err);
 
-int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
-                     int flags)
+int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid)
 {
-       return netlink_unicast(net->nfnl, skb, portid, flags);
+       int err;
+
+       err = nlmsg_unicast(net->nfnl, skb, portid);
+       if (err == -EAGAIN)
+               err = -ENOBUFS;
+
+       return err;
 }
 EXPORT_SYMBOL_GPL(nfnetlink_unicast);
 
index f029924..b35e8d9 100644 (file)
@@ -356,8 +356,7 @@ __nfulnl_send(struct nfulnl_instance *inst)
                        goto out;
                }
        }
-       nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid,
-                         MSG_DONTWAIT);
+       nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid);
 out:
        inst->qlen = 0;
        inst->skb = NULL;
index dadfc06..d1d8bca 100644 (file)
@@ -681,7 +681,7 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue,
        *packet_id_ptr = htonl(entry->id);
 
        /* nfnetlink_unicast will either free the nskb or add it to a socket */
-       err = nfnetlink_unicast(nskb, net, queue->peer_portid, MSG_DONTWAIT);
+       err = nfnetlink_unicast(nskb, net, queue->peer_portid);
        if (err < 0) {
                if (queue->flags & NFQA_CFG_F_FAIL_OPEN) {
                        failopen = 1;
index 3b9b97a..3a6c84f 100644 (file)
@@ -102,7 +102,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
        }
 
        if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
-           ct->status & IPS_SEQ_ADJUST)
+           ct->status & (IPS_SEQ_ADJUST | IPS_NAT_CLASH))
                goto out;
 
        if (!nf_ct_is_confirmed(ct))
index 7bc6537..b37bd02 100644 (file)
@@ -147,11 +147,11 @@ nft_meta_get_eval_skugid(enum nft_meta_keys key,
 
        switch (key) {
        case NFT_META_SKUID:
-               *dest = from_kuid_munged(&init_user_ns,
+               *dest = from_kuid_munged(sock_net(sk)->user_ns,
                                         sock->file->f_cred->fsuid);
                break;
        case NFT_META_SKGID:
-               *dest = from_kgid_munged(&init_user_ns,
+               *dest = from_kgid_munged(sock_net(sk)->user_ns,
                                         sock->file->f_cred->fsgid);
                break;
        default:
index ed7cb9f..7a2e596 100644 (file)
@@ -87,7 +87,9 @@ void nft_payload_eval(const struct nft_expr *expr,
        u32 *dest = &regs->data[priv->dreg];
        int offset;
 
-       dest[priv->len / NFT_REG32_SIZE] = 0;
+       if (priv->len % NFT_REG32_SIZE)
+               dest[priv->len / NFT_REG32_SIZE] = 0;
+
        switch (priv->base) {
        case NFT_PAYLOAD_LL_HEADER:
                if (!skb_mac_header_was_set(skb))
index 4b2834f..217ab36 100644 (file)
@@ -218,11 +218,11 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                               struct nft_rbtree_elem *new,
                               struct nft_set_ext **ext)
 {
+       bool overlap = false, dup_end_left = false, dup_end_right = false;
        struct nft_rbtree *priv = nft_set_priv(set);
        u8 genmask = nft_genmask_next(net);
        struct nft_rbtree_elem *rbe;
        struct rb_node *parent, **p;
-       bool overlap = false;
        int d;
 
        /* Detect overlaps as we descend the tree. Set the flag in these cases:
@@ -238,24 +238,44 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
         *
         * b1. _ _ __>|  !_ _ __|  (insert end before existing start)
         * b2. _ _ ___|  !_ _ _>|  (insert end after existing start)
-        * b3. _ _ ___! >|_ _ __|  (insert start after existing end)
+        * b3. _ _ ___! >|_ _ __|  (insert start after existing end, as a leaf)
+        *            '--' no nodes falling in this range
+        * b4.          >|_ _   !  (insert start before existing start)
         *
         * Case a3. resolves to b3.:
         * - if the inserted start element is the leftmost, because the '0'
         *   element in the tree serves as end element
-        * - otherwise, if an existing end is found. Note that end elements are
-        *   always inserted after corresponding start elements.
+        * - otherwise, if an existing end is found immediately to the left. If
+        *   there are existing nodes in between, we need to further descend the
+        *   tree before we can conclude the new start isn't causing an overlap
+        *
+        * or to b4., which, preceded by a3., means we already traversed one or
+        * more existing intervals entirely, from the right.
         *
         * For a new, rightmost pair of elements, we'll hit cases b3. and b2.,
         * in that order.
         *
         * The flag is also cleared in two special cases:
         *
-        * b4. |__ _ _!|<_ _ _   (insert start right before existing end)
-        * b5. |__ _ >|!__ _ _   (insert end right after existing start)
+        * b5. |__ _ _!|<_ _ _   (insert start right before existing end)
+        * b6. |__ _ >|!__ _ _   (insert end right after existing start)
         *
         * which always happen as last step and imply that no further
         * overlapping is possible.
+        *
+        * Another special case comes from the fact that start elements matching
+        * an already existing start element are allowed: insertion is not
+        * performed but we return -EEXIST in that case, and the error will be
+        * cleared by the caller if NLM_F_EXCL is not present in the request.
+        * This way, request for insertion of an exact overlap isn't reported as
+        * error to userspace if not desired.
+        *
+        * However, if the existing start matches a pre-existing start, but the
+        * end element doesn't match the corresponding pre-existing end element,
+        * we need to report a partial overlap. This is a local condition that
+        * can be noticed without need for a tracking flag, by checking for a
+        * local duplicated end for a corresponding start, from left and right,
+        * separately.
         */
 
        parent = NULL;
@@ -272,26 +292,41 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                        if (nft_rbtree_interval_start(new)) {
                                if (nft_rbtree_interval_end(rbe) &&
                                    nft_set_elem_active(&rbe->ext, genmask) &&
-                                   !nft_set_elem_expired(&rbe->ext))
+                                   !nft_set_elem_expired(&rbe->ext) && !*p)
                                        overlap = false;
                        } else {
+                               if (dup_end_left && !*p)
+                                       return -ENOTEMPTY;
+
                                overlap = nft_rbtree_interval_end(rbe) &&
                                          nft_set_elem_active(&rbe->ext,
                                                              genmask) &&
                                          !nft_set_elem_expired(&rbe->ext);
+
+                               if (overlap) {
+                                       dup_end_right = true;
+                                       continue;
+                               }
                        }
                } else if (d > 0) {
                        p = &parent->rb_right;
 
                        if (nft_rbtree_interval_end(new)) {
+                               if (dup_end_right && !*p)
+                                       return -ENOTEMPTY;
+
                                overlap = nft_rbtree_interval_end(rbe) &&
                                          nft_set_elem_active(&rbe->ext,
                                                              genmask) &&
                                          !nft_set_elem_expired(&rbe->ext);
-                       } else if (nft_rbtree_interval_end(rbe) &&
-                                  nft_set_elem_active(&rbe->ext, genmask) &&
+
+                               if (overlap) {
+                                       dup_end_left = true;
+                                       continue;
+                               }
+                       } else if (nft_set_elem_active(&rbe->ext, genmask) &&
                                   !nft_set_elem_expired(&rbe->ext)) {
-                               overlap = true;
+                               overlap = nft_rbtree_interval_end(rbe);
                        }
                } else {
                        if (nft_rbtree_interval_end(rbe) &&
@@ -316,6 +351,8 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                                p = &parent->rb_left;
                        }
                }
+
+               dup_end_left = dup_end_right = false;
        }
 
        if (overlap)
index 19bef17..6064118 100644 (file)
@@ -640,7 +640,7 @@ static void __net_exit recent_proc_net_exit(struct net *net)
        struct recent_table *t;
 
        /* recent_net_exit() is called before recent_mt_destroy(). Make sure
-        * that the parent xt_recent proc entry is is empty before trying to
+        * that the parent xt_recent proc entry is empty before trying to
         * remove it.
         */
        spin_lock_bh(&recent_lock);
index d07de2c..f73a838 100644 (file)
@@ -85,6 +85,7 @@ static void netlbl_domhsh_free_entry(struct rcu_head *entry)
                        kfree(netlbl_domhsh_addr6_entry(iter6));
                }
 #endif /* IPv6 */
+               kfree(ptr->def.addrsel);
        }
        kfree(ptr->domain);
        kfree(ptr);
@@ -537,6 +538,8 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                                goto add_return;
                }
 #endif /* IPv6 */
+               /* cleanup the new entry since we've moved everything over */
+               netlbl_domhsh_free_entry(&entry->rcu);
        } else
                ret_val = -EINVAL;
 
@@ -580,6 +583,12 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
 {
        int ret_val = 0;
        struct audit_buffer *audit_buf;
+       struct netlbl_af4list *iter4;
+       struct netlbl_domaddr4_map *map4;
+#if IS_ENABLED(CONFIG_IPV6)
+       struct netlbl_af6list *iter6;
+       struct netlbl_domaddr6_map *map6;
+#endif /* IPv6 */
 
        if (entry == NULL)
                return -ENOENT;
@@ -597,6 +606,9 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
                ret_val = -ENOENT;
        spin_unlock(&netlbl_domhsh_lock);
 
+       if (ret_val)
+               return ret_val;
+
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
        if (audit_buf != NULL) {
                audit_log_format(audit_buf,
@@ -606,40 +618,29 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
                audit_log_end(audit_buf);
        }
 
-       if (ret_val == 0) {
-               struct netlbl_af4list *iter4;
-               struct netlbl_domaddr4_map *map4;
-#if IS_ENABLED(CONFIG_IPV6)
-               struct netlbl_af6list *iter6;
-               struct netlbl_domaddr6_map *map6;
-#endif /* IPv6 */
-
-               switch (entry->def.type) {
-               case NETLBL_NLTYPE_ADDRSELECT:
-                       netlbl_af4list_foreach_rcu(iter4,
-                                            &entry->def.addrsel->list4) {
-                               map4 = netlbl_domhsh_addr4_entry(iter4);
-                               cipso_v4_doi_putdef(map4->def.cipso);
-                       }
+       switch (entry->def.type) {
+       case NETLBL_NLTYPE_ADDRSELECT:
+               netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
+                       map4 = netlbl_domhsh_addr4_entry(iter4);
+                       cipso_v4_doi_putdef(map4->def.cipso);
+               }
 #if IS_ENABLED(CONFIG_IPV6)
-                       netlbl_af6list_foreach_rcu(iter6,
-                                            &entry->def.addrsel->list6) {
-                               map6 = netlbl_domhsh_addr6_entry(iter6);
-                               calipso_doi_putdef(map6->def.calipso);
-                       }
+               netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
+                       map6 = netlbl_domhsh_addr6_entry(iter6);
+                       calipso_doi_putdef(map6->def.calipso);
+               }
 #endif /* IPv6 */
-                       break;
-               case NETLBL_NLTYPE_CIPSOV4:
-                       cipso_v4_doi_putdef(entry->def.cipso);
-                       break;
+               break;
+       case NETLBL_NLTYPE_CIPSOV4:
+               cipso_v4_doi_putdef(entry->def.cipso);
+               break;
 #if IS_ENABLED(CONFIG_IPV6)
-               case NETLBL_NLTYPE_CALIPSO:
-                       calipso_doi_putdef(entry->def.calipso);
-                       break;
+       case NETLBL_NLTYPE_CALIPSO:
+               calipso_doi_putdef(entry->def.calipso);
+               break;
 #endif /* IPv6 */
-               }
-               call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
        }
+       call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
 
        return ret_val;
 }
index b5f30d7..d2d1448 100644 (file)
@@ -353,7 +353,7 @@ static void netlink_rcv_wake(struct sock *sk)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
 
-       if (skb_queue_empty(&sk->sk_receive_queue))
+       if (skb_queue_empty_lockless(&sk->sk_receive_queue))
                clear_bit(NETLINK_S_CONGESTED, &nlk->state);
        if (!test_bit(NETLINK_S_CONGESTED, &nlk->state))
                wake_up_interruptible(&nlk->wait);
index 1eb65a7..c4b4d33 100644 (file)
@@ -1079,7 +1079,7 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
        if (err)
                return err;
 
-       while (netlink_policy_dump_loop(&cb->args[1])) {
+       while (netlink_policy_dump_loop(cb->args[1])) {
                void *hdr;
                struct nlattr *nest;
 
@@ -1113,6 +1113,12 @@ nla_put_failure:
        return skb->len;
 }
 
+static int ctrl_dumppolicy_done(struct netlink_callback *cb)
+{
+       netlink_policy_dump_free(cb->args[1]);
+       return 0;
+}
+
 static const struct genl_ops genl_ctrl_ops[] = {
        {
                .cmd            = CTRL_CMD_GETFAMILY,
@@ -1123,6 +1129,7 @@ static const struct genl_ops genl_ctrl_ops[] = {
        {
                .cmd            = CTRL_CMD_GETPOLICY,
                .dumpit         = ctrl_dumppolicy,
+               .done           = ctrl_dumppolicy_done,
        },
 };
 
index 2b3e26f..0176b59 100644 (file)
@@ -84,7 +84,6 @@ int netlink_policy_dump_start(const struct nla_policy *policy,
        unsigned int policy_idx;
        int err;
 
-       /* also returns 0 if "*_state" is our ERR_PTR() end marker */
        if (*_state)
                return 0;
 
@@ -140,21 +139,11 @@ static bool netlink_policy_dump_finished(struct nl_policy_dump *state)
               !state->policies[state->policy_idx].policy;
 }
 
-bool netlink_policy_dump_loop(unsigned long *_state)
+bool netlink_policy_dump_loop(unsigned long _state)
 {
-       struct nl_policy_dump *state = (void *)*_state;
-
-       if (IS_ERR(state))
-               return false;
-
-       if (netlink_policy_dump_finished(state)) {
-               kfree(state);
-               /* store end marker instead of freed state */
-               *_state = (unsigned long)ERR_PTR(-ENOENT);
-               return false;
-       }
+       struct nl_policy_dump *state = (void *)_state;
 
-       return true;
+       return !netlink_policy_dump_finished(state);
 }
 
 int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state)
@@ -188,7 +177,7 @@ send_attribute:
                goto next;
        case NLA_NESTED:
                type = NL_ATTR_TYPE_NESTED;
-               /* fall through */
+               fallthrough;
        case NLA_NESTED_ARRAY:
                if (pt->type == NLA_NESTED_ARRAY)
                        type = NL_ATTR_TYPE_NESTED_ARRAY;
@@ -309,3 +298,10 @@ nla_put_failure:
        nla_nest_cancel(skb, policy);
        return -ENOBUFS;
 }
+
+void netlink_policy_dump_free(unsigned long _state)
+{
+       struct nl_policy_dump *state = (void *)_state;
+
+       kfree(state);
+}
index 2bef377..69e5890 100644 (file)
@@ -122,7 +122,7 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
 
        case NR_DISCREQ:
                nr_write_internal(sk, NR_DISCACK);
-               /* fall through */
+               fallthrough;
        case NR_DISCACK:
                nr_disconnect(sk, 0);
                break;
index 0891ee0..78da5ea 100644 (file)
@@ -263,7 +263,7 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
        case 3:
                re_sort_routes(nr_node, 0, 1);
                re_sort_routes(nr_node, 1, 2);
-               /* fall through */
+               fallthrough;
        case 2:
                re_sort_routes(nr_node, 0, 1);
        case 1:
@@ -356,7 +356,7 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
                                switch (i) {
                                case 0:
                                        nr_node->routes[0] = nr_node->routes[1];
-                                       /* fall through */
+                                       fallthrough;
                                case 1:
                                        nr_node->routes[1] = nr_node->routes[2];
                                case 2:
@@ -479,7 +479,7 @@ static int nr_dec_obs(void)
                                switch (i) {
                                case 0:
                                        s->routes[0] = s->routes[1];
-                                       /* Fallthrough */
+                                       fallthrough;
                                case 1:
                                        s->routes[1] = s->routes[2];
                                case 2:
@@ -526,7 +526,7 @@ void nr_rt_device_down(struct net_device *dev)
                                                switch (i) {
                                                case 0:
                                                        t->routes[0] = t->routes[1];
-                                                       /* fall through */
+                                                       fallthrough;
                                                case 1:
                                                        t->routes[1] = t->routes[2];
                                                case 2:
index 98d393e..12d42ab 100644 (file)
@@ -778,7 +778,7 @@ static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct,
                        }
                }
                /* Non-ICMP, fall thru to initialize if needed. */
-               /* fall through */
+               fallthrough;
        case IP_CT_NEW:
                /* Seen it before?  This can happen for loopback, retrans,
                 * or local packets.
@@ -905,15 +905,19 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
        }
        err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype);
 
-       if (err == NF_ACCEPT &&
-           ct->status & IPS_SRC_NAT && ct->status & IPS_DST_NAT) {
-               if (maniptype == NF_NAT_MANIP_SRC)
-                       maniptype = NF_NAT_MANIP_DST;
-               else
-                       maniptype = NF_NAT_MANIP_SRC;
-
-               err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range,
-                                        maniptype);
+       if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) {
+               if (ct->status & IPS_SRC_NAT) {
+                       if (maniptype == NF_NAT_MANIP_SRC)
+                               maniptype = NF_NAT_MANIP_DST;
+                       else
+                               maniptype = NF_NAT_MANIP_SRC;
+
+                       err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range,
+                                                maniptype);
+               } else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
+                       err = ovs_ct_nat_execute(skb, ct, ctinfo, NULL,
+                                                NF_NAT_MANIP_SRC);
+               }
        }
 
        /* Mark NAT done if successful and update the flow key. */
@@ -1540,7 +1544,7 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
                switch (type) {
                case OVS_CT_ATTR_FORCE_COMMIT:
                        info->force = true;
-                       /* fall through. */
+                       fallthrough;
                case OVS_CT_ATTR_COMMIT:
                        info->commit = true;
                        break;
index 03942c3..b03d142 100644 (file)
@@ -675,7 +675,7 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
                        case -EINVAL:
                                memset(&key->ip, 0, sizeof(key->ip));
                                memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr));
-                               /* fall-through */
+                               fallthrough;
                        case -EPROTO:
                                skb->transport_header = skb->network_header;
                                error = 0;
index 479c257..2b33e97 100644 (file)
@@ -2170,7 +2170,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
        int skb_len = skb->len;
        unsigned int snaplen, res;
        unsigned long status = TP_STATUS_USER;
-       unsigned short macoff, netoff, hdrlen;
+       unsigned short macoff, hdrlen;
+       unsigned int netoff;
        struct sk_buff *copy_skb = NULL;
        struct timespec64 ts;
        __u32 ts_status;
@@ -2239,6 +2240,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                }
                macoff = netoff - maclen;
        }
+       if (netoff > USHRT_MAX) {
+               atomic_inc(&po->tp_drops);
+               goto drop_n_restore;
+       }
        if (po->tp_version <= TPACKET_V2) {
                if (macoff + snaplen > po->rx_ring.frame_size) {
                        if (po->copy_thresh &&
@@ -4061,7 +4066,7 @@ static int packet_notifier(struct notifier_block *this,
                case NETDEV_UNREGISTER:
                        if (po->mclist)
                                packet_dev_mclist_delete(dev, &po->mclist);
-                       /* fallthrough */
+                       fallthrough;
 
                case NETDEV_DOWN:
                        if (dev->ifindex == po->ifindex) {
index e47d09a..a152591 100644 (file)
@@ -368,7 +368,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
                        err = -EINVAL;
                        goto out;
                }
-               /* fall through */
+               fallthrough;
        case PNS_PEP_DISABLE_REQ:
                atomic_set(&pn->tx_credits, 0);
                pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
@@ -385,7 +385,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
 
        case PNS_PIPE_ALIGNED_DATA:
                __skb_pull(skb, 1);
-               /* fall through */
+               fallthrough;
        case PNS_PIPE_DATA:
                __skb_pull(skb, 3); /* Pipe data header */
                if (!pn_flow_safe(pn->rx_fc)) {
@@ -417,11 +417,11 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
                err = pipe_rcv_created(sk, skb);
                if (err)
                        break;
-               /* fall through */
+               fallthrough;
        case PNS_PIPE_RESET_IND:
                if (!pn->init_enable)
                        break;
-               /* fall through */
+               fallthrough;
        case PNS_PIPE_ENABLED_IND:
                if (!pn_flow_safe(pn->tx_fc)) {
                        atomic_set(&pn->tx_credits, 1);
@@ -555,7 +555,7 @@ static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb)
        switch (hdr->message_id) {
        case PNS_PIPE_ALIGNED_DATA:
                __skb_pull(skb, 1);
-               /* fall through */
+               fallthrough;
        case PNS_PIPE_DATA:
                __skb_pull(skb, 3); /* Pipe data header */
                if (!pn_flow_safe(pn->rx_fc)) {
index d8252fd..b8559c8 100644 (file)
@@ -199,17 +199,30 @@ static int announce_servers(struct sockaddr_qrtr *sq)
        if (!node)
                return 0;
 
+       rcu_read_lock();
        /* Announce the list of servers registered in this node */
        radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
                srv = radix_tree_deref_slot(slot);
+               if (!srv)
+                       continue;
+               if (radix_tree_deref_retry(srv)) {
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+               slot = radix_tree_iter_resume(slot, &iter);
+               rcu_read_unlock();
 
                ret = service_announce_new(sq, srv);
                if (ret < 0) {
                        pr_err("failed to announce new service\n");
                        return ret;
                }
+
+               rcu_read_lock();
        }
 
+       rcu_read_unlock();
+
        return 0;
 }
 
@@ -344,11 +357,22 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
        if (!node)
                return 0;
 
+       rcu_read_lock();
        /* Advertise removal of this client to all servers of remote node */
        radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
                srv = radix_tree_deref_slot(slot);
+               if (!srv)
+                       continue;
+               if (radix_tree_deref_retry(srv)) {
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+               slot = radix_tree_iter_resume(slot, &iter);
+               rcu_read_unlock();
                server_del(node, srv->port);
+               rcu_read_lock();
        }
+       rcu_read_unlock();
 
        /* Advertise the removal of this client to all local servers */
        local_node = node_get(qrtr_ns.local_node);
@@ -359,8 +383,17 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
        pkt.cmd = cpu_to_le32(QRTR_TYPE_BYE);
        pkt.client.node = cpu_to_le32(from->sq_node);
 
+       rcu_read_lock();
        radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
                srv = radix_tree_deref_slot(slot);
+               if (!srv)
+                       continue;
+               if (radix_tree_deref_retry(srv)) {
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+               slot = radix_tree_iter_resume(slot, &iter);
+               rcu_read_unlock();
 
                sq.sq_family = AF_QIPCRTR;
                sq.sq_node = srv->node;
@@ -374,8 +407,11 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
                        pr_err("failed to send bye cmd\n");
                        return ret;
                }
+               rcu_read_lock();
        }
 
+       rcu_read_unlock();
+
        return 0;
 }
 
@@ -434,8 +470,17 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
        pkt.client.node = cpu_to_le32(node_id);
        pkt.client.port = cpu_to_le32(port);
 
+       rcu_read_lock();
        radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
                srv = radix_tree_deref_slot(slot);
+               if (!srv)
+                       continue;
+               if (radix_tree_deref_retry(srv)) {
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+               slot = radix_tree_iter_resume(slot, &iter);
+               rcu_read_unlock();
 
                sq.sq_family = AF_QIPCRTR;
                sq.sq_node = srv->node;
@@ -449,8 +494,11 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
                        pr_err("failed to send del client cmd\n");
                        return ret;
                }
+               rcu_read_lock();
        }
 
+       rcu_read_unlock();
+
        return 0;
 }
 
@@ -554,20 +602,40 @@ static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
        filter.service = service;
        filter.instance = instance;
 
+       rcu_read_lock();
        radix_tree_for_each_slot(node_slot, &nodes, &node_iter, 0) {
                node = radix_tree_deref_slot(node_slot);
+               if (!node)
+                       continue;
+               if (radix_tree_deref_retry(node)) {
+                       node_slot = radix_tree_iter_retry(&node_iter);
+                       continue;
+               }
+               node_slot = radix_tree_iter_resume(node_slot, &node_iter);
 
                radix_tree_for_each_slot(srv_slot, &node->servers,
                                         &srv_iter, 0) {
                        struct qrtr_server *srv;
 
                        srv = radix_tree_deref_slot(srv_slot);
+                       if (!srv)
+                               continue;
+                       if (radix_tree_deref_retry(srv)) {
+                               srv_slot = radix_tree_iter_retry(&srv_iter);
+                               continue;
+                       }
+
                        if (!server_match(srv, &filter))
                                continue;
 
+                       srv_slot = radix_tree_iter_resume(srv_slot, &srv_iter);
+
+                       rcu_read_unlock();
                        lookup_notify(from, srv, true);
+                       rcu_read_lock();
                }
        }
+       rcu_read_unlock();
 
        /* Empty notification, to indicate end of listing */
        lookup_notify(from, NULL, true);
index 90c558f..957aa92 100644 (file)
@@ -332,8 +332,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb,
 {
        struct qrtr_hdr_v1 *hdr;
        size_t len = skb->len;
-       int rc = -ENODEV;
-       int confirm_rx;
+       int rc, confirm_rx;
 
        confirm_rx = qrtr_tx_wait(node, to->sq_node, to->sq_port, type);
        if (confirm_rx < 0) {
@@ -357,15 +356,17 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb,
        hdr->size = cpu_to_le32(len);
        hdr->confirm_rx = !!confirm_rx;
 
-       skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr));
-
-       mutex_lock(&node->ep_lock);
-       if (node->ep)
-               rc = node->ep->xmit(node->ep, skb);
-       else
-               kfree_skb(skb);
-       mutex_unlock(&node->ep_lock);
+       rc = skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr));
 
+       if (!rc) {
+               mutex_lock(&node->ep_lock);
+               rc = -ENODEV;
+               if (node->ep)
+                       rc = node->ep->xmit(node->ep, skb);
+               else
+                       kfree_skb(skb);
+               mutex_unlock(&node->ep_lock);
+       }
        /* Need to ensure that a subsequent message carries the otherwise lost
         * confirm_rx flag if we dropped this one */
        if (rc && confirm_rx)
index 9a529a0..985d0b7 100644 (file)
@@ -934,7 +934,7 @@ static int rds_rm_size(struct msghdr *msg, int num_sgs,
 
                case RDS_CMSG_ZCOPY_COOKIE:
                        zcopy_cookie = true;
-                       /* fall through */
+                       fallthrough;
 
                case RDS_CMSG_RDMA_DEST:
                case RDS_CMSG_RDMA_MAP:
index 0d4fab2..6af786d 100644 (file)
@@ -216,7 +216,7 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
        switch (frametype) {
        case ROSE_RESET_REQUEST:
                rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
-               /* fall through */
+               fallthrough;
        case ROSE_RESET_CONFIRMATION:
                rose_stop_timer(sk);
                rose_start_idletimer(sk);
index 5277631..6e35703 100644 (file)
@@ -343,7 +343,7 @@ static int rose_del_node(struct rose_route_struct *rose_route,
                                case 0:
                                        rose_node->neighbour[0] =
                                                rose_node->neighbour[1];
-                                       /* fall through */
+                                       fallthrough;
                                case 1:
                                        rose_node->neighbour[1] =
                                                rose_node->neighbour[2];
@@ -505,7 +505,7 @@ void rose_rt_device_down(struct net_device *dev)
                                switch (i) {
                                case 0:
                                        t->neighbour[0] = t->neighbour[1];
-                                       /* fall through */
+                                       fallthrough;
                                case 1:
                                        t->neighbour[1] = t->neighbour[2];
                                case 2:
index e6725a6..186c8a8 100644 (file)
@@ -246,7 +246,7 @@ static int rxrpc_listen(struct socket *sock, int backlog)
                        ret = 0;
                        break;
                }
-               /* Fall through */
+               fallthrough;
        default:
                ret = -EBUSY;
                break;
@@ -545,7 +545,7 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
 
                rx->local = local;
                rx->sk.sk_state = RXRPC_CLIENT_BOUND;
-               /* Fall through */
+               fallthrough;
 
        case RXRPC_CLIENT_BOUND:
                if (!m->msg_name &&
@@ -553,7 +553,7 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
                        m->msg_name = &rx->connect_srx;
                        m->msg_namelen = sizeof(rx->connect_srx);
                }
-               /* Fall through */
+               fallthrough;
        case RXRPC_SERVER_BOUND:
        case RXRPC_SERVER_LISTENING:
                ret = rxrpc_do_sendmsg(rx, m, len);
index 6d29a36..97aebb5 100644 (file)
@@ -488,7 +488,6 @@ enum rxrpc_call_flag {
        RXRPC_CALL_RX_LAST,             /* Received the last packet (at rxtx_top) */
        RXRPC_CALL_TX_LAST,             /* Last packet in Tx buffer (at rxtx_top) */
        RXRPC_CALL_SEND_PING,           /* A ping will need to be sent */
-       RXRPC_CALL_PINGING,             /* Ping in process */
        RXRPC_CALL_RETRANS_TIMEOUT,     /* Retransmission due to timeout occurred */
        RXRPC_CALL_BEGAN_RX_TIMER,      /* We began the expect_rx_by timer */
        RXRPC_CALL_RX_HEARD,            /* The peer responded at least once to this call */
@@ -519,7 +518,6 @@ enum rxrpc_call_state {
        RXRPC_CALL_CLIENT_RECV_REPLY,   /* - client receiving reply phase */
        RXRPC_CALL_SERVER_PREALLOC,     /* - service preallocation */
        RXRPC_CALL_SERVER_SECURING,     /* - server securing request connection */
-       RXRPC_CALL_SERVER_ACCEPTING,    /* - server accepting request */
        RXRPC_CALL_SERVER_RECV_REQUEST, /* - server receiving request */
        RXRPC_CALL_SERVER_ACK_REQUEST,  /* - server pending ACK of request */
        RXRPC_CALL_SERVER_SEND_REPLY,   /* - server sending reply */
@@ -673,9 +671,13 @@ struct rxrpc_call {
        rxrpc_seq_t             ackr_consumed;  /* Highest packet shown consumed */
        rxrpc_seq_t             ackr_seen;      /* Highest packet shown seen */
 
-       /* ping management */
-       rxrpc_serial_t          ping_serial;    /* Last ping sent */
-       ktime_t                 ping_time;      /* Time last ping sent */
+       /* RTT management */
+       rxrpc_serial_t          rtt_serial[4];  /* Serial number of DATA or PING sent */
+       ktime_t                 rtt_sent_at[4]; /* Time packet sent */
+       unsigned long           rtt_avail;      /* Mask of available slots in bits 0-3,
+                                                * Mask of pending samples in 8-11 */
+#define RXRPC_CALL_RTT_AVAIL_MASK      0xf
+#define RXRPC_CALL_RTT_PEND_SHIFT      8
 
        /* transmission-phase ACK management */
        ktime_t                 acks_latest_ts; /* Timestamp of latest ACK received */
@@ -711,8 +713,8 @@ struct rxrpc_ack_summary {
 enum rxrpc_command {
        RXRPC_CMD_SEND_DATA,            /* send data message */
        RXRPC_CMD_SEND_ABORT,           /* request abort generation */
-       RXRPC_CMD_ACCEPT,               /* [server] accept incoming call */
        RXRPC_CMD_REJECT_BUSY,          /* [server] reject a call as busy */
+       RXRPC_CMD_CHARGE_ACCEPT,        /* [server] charge accept preallocation */
 };
 
 struct rxrpc_call_params {
@@ -752,9 +754,7 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *,
                                           struct rxrpc_sock *,
                                           struct sk_buff *);
 void rxrpc_accept_incoming_calls(struct rxrpc_local *);
-struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *, unsigned long,
-                                    rxrpc_notify_rx_t);
-int rxrpc_reject_call(struct rxrpc_sock *);
+int rxrpc_user_charge_accept(struct rxrpc_sock *, unsigned long);
 
 /*
  * call_event.c
@@ -1037,7 +1037,7 @@ static inline bool __rxrpc_abort_eproto(struct rxrpc_call *call,
 /*
  * rtt.c
  */
-void rxrpc_peer_add_rtt(struct rxrpc_call *, enum rxrpc_rtt_rx_trace,
+void rxrpc_peer_add_rtt(struct rxrpc_call *, enum rxrpc_rtt_rx_trace, int,
                        rxrpc_serial_t, rxrpc_serial_t, ktime_t, ktime_t);
 unsigned long rxrpc_get_rto_backoff(struct rxrpc_peer *, bool);
 void rxrpc_peer_init_rtt(struct rxrpc_peer *);
index 032ed76..8df1964 100644 (file)
@@ -39,8 +39,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
                                      unsigned int debug_id)
 {
        const void *here = __builtin_return_address(0);
-       struct rxrpc_call *call;
+       struct rxrpc_call *call, *xcall;
        struct rxrpc_net *rxnet = rxrpc_net(sock_net(&rx->sk));
+       struct rb_node *parent, **pp;
        int max, tmp;
        unsigned int size = RXRPC_BACKLOG_MAX;
        unsigned int head, tail, call_head, call_tail;
@@ -94,7 +95,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
        }
 
        /* Now it gets complicated, because calls get registered with the
-        * socket here, particularly if a user ID is preassigned by the user.
+        * socket here, with a user ID preassigned by the user.
         */
        call = rxrpc_alloc_call(rx, gfp, debug_id);
        if (!call)
@@ -107,34 +108,33 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
                         here, (const void *)user_call_ID);
 
        write_lock(&rx->call_lock);
-       if (user_attach_call) {
-               struct rxrpc_call *xcall;
-               struct rb_node *parent, **pp;
-
-               /* Check the user ID isn't already in use */
-               pp = &rx->calls.rb_node;
-               parent = NULL;
-               while (*pp) {
-                       parent = *pp;
-                       xcall = rb_entry(parent, struct rxrpc_call, sock_node);
-                       if (user_call_ID < xcall->user_call_ID)
-                               pp = &(*pp)->rb_left;
-                       else if (user_call_ID > xcall->user_call_ID)
-                               pp = &(*pp)->rb_right;
-                       else
-                               goto id_in_use;
-               }
 
-               call->user_call_ID = user_call_ID;
-               call->notify_rx = notify_rx;
+       /* Check the user ID isn't already in use */
+       pp = &rx->calls.rb_node;
+       parent = NULL;
+       while (*pp) {
+               parent = *pp;
+               xcall = rb_entry(parent, struct rxrpc_call, sock_node);
+               if (user_call_ID < xcall->user_call_ID)
+                       pp = &(*pp)->rb_left;
+               else if (user_call_ID > xcall->user_call_ID)
+                       pp = &(*pp)->rb_right;
+               else
+                       goto id_in_use;
+       }
+
+       call->user_call_ID = user_call_ID;
+       call->notify_rx = notify_rx;
+       if (user_attach_call) {
                rxrpc_get_call(call, rxrpc_call_got_kernel);
                user_attach_call(call, user_call_ID);
-               rxrpc_get_call(call, rxrpc_call_got_userid);
-               rb_link_node(&call->sock_node, parent, pp);
-               rb_insert_color(&call->sock_node, &rx->calls);
-               set_bit(RXRPC_CALL_HAS_USERID, &call->flags);
        }
 
+       rxrpc_get_call(call, rxrpc_call_got_userid);
+       rb_link_node(&call->sock_node, parent, pp);
+       rb_insert_color(&call->sock_node, &rx->calls);
+       set_bit(RXRPC_CALL_HAS_USERID, &call->flags);
+
        list_add(&call->sock_link, &rx->sock_calls);
 
        write_unlock(&rx->call_lock);
@@ -157,11 +157,8 @@ id_in_use:
 }
 
 /*
- * Preallocate sufficient service connections, calls and peers to cover the
- * entire backlog of a socket.  When a new call comes in, if we don't have
- * sufficient of each available, the call gets rejected as busy or ignored.
- *
- * The backlog is replenished when a connection is accepted or rejected.
+ * Allocate the preallocation buffers for incoming service calls.  These must
+ * be charged manually.
  */
 int rxrpc_service_prealloc(struct rxrpc_sock *rx, gfp_t gfp)
 {
@@ -174,13 +171,6 @@ int rxrpc_service_prealloc(struct rxrpc_sock *rx, gfp_t gfp)
                rx->backlog = b;
        }
 
-       if (rx->discard_new_call)
-               return 0;
-
-       while (rxrpc_service_prealloc_one(rx, b, NULL, NULL, 0, gfp,
-                                         atomic_inc_return(&rxrpc_debug_id)) == 0)
-               ;
-
        return 0;
 }
 
@@ -333,6 +323,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
        rxrpc_see_call(call);
        call->conn = conn;
        call->security = conn->security;
+       call->security_ix = conn->security_ix;
        call->peer = rxrpc_get_peer(conn->params.peer);
        call->cong_cwnd = call->peer->cong_cwnd;
        return call;
@@ -402,8 +393,6 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
 
        if (rx->notify_new_call)
                rx->notify_new_call(&rx->sk, call, call->user_call_ID);
-       else
-               sk_acceptq_added(&rx->sk);
 
        spin_lock(&conn->state_lock);
        switch (conn->state) {
@@ -415,12 +404,8 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
 
        case RXRPC_CONN_SERVICE:
                write_lock(&call->state_lock);
-               if (call->state < RXRPC_CALL_COMPLETE) {
-                       if (rx->discard_new_call)
-                               call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
-                       else
-                               call->state = RXRPC_CALL_SERVER_ACCEPTING;
-               }
+               if (call->state < RXRPC_CALL_COMPLETE)
+                       call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
                write_unlock(&call->state_lock);
                break;
 
@@ -440,9 +425,6 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
 
        rxrpc_send_ping(call, skb);
 
-       if (call->state == RXRPC_CALL_SERVER_ACCEPTING)
-               rxrpc_notify_socket(call);
-
        /* We have to discard the prealloc queue's ref here and rely on a
         * combination of the RCU read lock and refs held either by the socket
         * (recvmsg queue, to-be-accepted queue or user ID tree) or the kernel
@@ -460,187 +442,18 @@ no_call:
 }
 
 /*
- * handle acceptance of a call by userspace
- * - assign the user call ID to the call at the front of the queue
- * - called with the socket locked.
+ * Charge up socket with preallocated calls, attaching user call IDs.
  */
-struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *rx,
-                                    unsigned long user_call_ID,
-                                    rxrpc_notify_rx_t notify_rx)
-       __releases(&rx->sk.sk_lock.slock)
-       __acquires(call->user_mutex)
+int rxrpc_user_charge_accept(struct rxrpc_sock *rx, unsigned long user_call_ID)
 {
-       struct rxrpc_call *call;
-       struct rb_node *parent, **pp;
-       int ret;
-
-       _enter(",%lx", user_call_ID);
-
-       ASSERT(!irqs_disabled());
-
-       write_lock(&rx->call_lock);
-
-       if (list_empty(&rx->to_be_accepted)) {
-               write_unlock(&rx->call_lock);
-               release_sock(&rx->sk);
-               kleave(" = -ENODATA [empty]");
-               return ERR_PTR(-ENODATA);
-       }
-
-       /* check the user ID isn't already in use */
-       pp = &rx->calls.rb_node;
-       parent = NULL;
-       while (*pp) {
-               parent = *pp;
-               call = rb_entry(parent, struct rxrpc_call, sock_node);
-
-               if (user_call_ID < call->user_call_ID)
-                       pp = &(*pp)->rb_left;
-               else if (user_call_ID > call->user_call_ID)
-                       pp = &(*pp)->rb_right;
-               else
-                       goto id_in_use;
-       }
-
-       /* Dequeue the first call and check it's still valid.  We gain
-        * responsibility for the queue's reference.
-        */
-       call = list_entry(rx->to_be_accepted.next,
-                         struct rxrpc_call, accept_link);
-       write_unlock(&rx->call_lock);
-
-       /* We need to gain the mutex from the interrupt handler without
-        * upsetting lockdep, so we have to release it there and take it here.
-        * We are, however, still holding the socket lock, so other accepts
-        * must wait for us and no one can add the user ID behind our backs.
-        */
-       if (mutex_lock_interruptible(&call->user_mutex) < 0) {
-               release_sock(&rx->sk);
-               kleave(" = -ERESTARTSYS");
-               return ERR_PTR(-ERESTARTSYS);
-       }
-
-       write_lock(&rx->call_lock);
-       list_del_init(&call->accept_link);
-       sk_acceptq_removed(&rx->sk);
-       rxrpc_see_call(call);
-
-       /* Find the user ID insertion point. */
-       pp = &rx->calls.rb_node;
-       parent = NULL;
-       while (*pp) {
-               parent = *pp;
-               call = rb_entry(parent, struct rxrpc_call, sock_node);
-
-               if (user_call_ID < call->user_call_ID)
-                       pp = &(*pp)->rb_left;
-               else if (user_call_ID > call->user_call_ID)
-                       pp = &(*pp)->rb_right;
-               else
-                       BUG();
-       }
-
-       write_lock_bh(&call->state_lock);
-       switch (call->state) {
-       case RXRPC_CALL_SERVER_ACCEPTING:
-               call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
-               break;
-       case RXRPC_CALL_COMPLETE:
-               ret = call->error;
-               goto out_release;
-       default:
-               BUG();
-       }
-
-       /* formalise the acceptance */
-       call->notify_rx = notify_rx;
-       call->user_call_ID = user_call_ID;
-       rxrpc_get_call(call, rxrpc_call_got_userid);
-       rb_link_node(&call->sock_node, parent, pp);
-       rb_insert_color(&call->sock_node, &rx->calls);
-       if (test_and_set_bit(RXRPC_CALL_HAS_USERID, &call->flags))
-               BUG();
-
-       write_unlock_bh(&call->state_lock);
-       write_unlock(&rx->call_lock);
-       rxrpc_notify_socket(call);
-       rxrpc_service_prealloc(rx, GFP_KERNEL);
-       release_sock(&rx->sk);
-       _leave(" = %p{%d}", call, call->debug_id);
-       return call;
-
-out_release:
-       _debug("release %p", call);
-       write_unlock_bh(&call->state_lock);
-       write_unlock(&rx->call_lock);
-       rxrpc_release_call(rx, call);
-       rxrpc_put_call(call, rxrpc_call_put);
-       goto out;
-
-id_in_use:
-       ret = -EBADSLT;
-       write_unlock(&rx->call_lock);
-out:
-       rxrpc_service_prealloc(rx, GFP_KERNEL);
-       release_sock(&rx->sk);
-       _leave(" = %d", ret);
-       return ERR_PTR(ret);
-}
-
-/*
- * Handle rejection of a call by userspace
- * - reject the call at the front of the queue
- */
-int rxrpc_reject_call(struct rxrpc_sock *rx)
-{
-       struct rxrpc_call *call;
-       bool abort = false;
-       int ret;
-
-       _enter("");
-
-       ASSERT(!irqs_disabled());
-
-       write_lock(&rx->call_lock);
-
-       if (list_empty(&rx->to_be_accepted)) {
-               write_unlock(&rx->call_lock);
-               return -ENODATA;
-       }
-
-       /* Dequeue the first call and check it's still valid.  We gain
-        * responsibility for the queue's reference.
-        */
-       call = list_entry(rx->to_be_accepted.next,
-                         struct rxrpc_call, accept_link);
-       list_del_init(&call->accept_link);
-       sk_acceptq_removed(&rx->sk);
-       rxrpc_see_call(call);
+       struct rxrpc_backlog *b = rx->backlog;
 
-       write_lock_bh(&call->state_lock);
-       switch (call->state) {
-       case RXRPC_CALL_SERVER_ACCEPTING:
-               __rxrpc_abort_call("REJ", call, 1, RX_USER_ABORT, -ECONNABORTED);
-               abort = true;
-               /* fall through */
-       case RXRPC_CALL_COMPLETE:
-               ret = call->error;
-               goto out_discard;
-       default:
-               BUG();
-       }
+       if (rx->sk.sk_state == RXRPC_CLOSE)
+               return -ESHUTDOWN;
 
-out_discard:
-       write_unlock_bh(&call->state_lock);
-       write_unlock(&rx->call_lock);
-       if (abort) {
-               rxrpc_send_abort_packet(call);
-               rxrpc_release_call(rx, call);
-               rxrpc_put_call(call, rxrpc_call_put);
-       }
-       rxrpc_service_prealloc(rx, GFP_KERNEL);
-       _leave(" = %d", ret);
-       return ret;
+       return rxrpc_service_prealloc_one(rx, b, NULL, NULL, user_call_ID,
+                                         GFP_KERNEL,
+                                         atomic_inc_return(&rxrpc_debug_id));
 }
 
 /*
index 38a4616..ed49769 100644 (file)
@@ -23,7 +23,6 @@ const char *const rxrpc_call_states[NR__RXRPC_CALL_STATES] = {
        [RXRPC_CALL_CLIENT_RECV_REPLY]          = "ClRcvRpl",
        [RXRPC_CALL_SERVER_PREALLOC]            = "SvPrealc",
        [RXRPC_CALL_SERVER_SECURING]            = "SvSecure",
-       [RXRPC_CALL_SERVER_ACCEPTING]           = "SvAccept",
        [RXRPC_CALL_SERVER_RECV_REQUEST]        = "SvRcvReq",
        [RXRPC_CALL_SERVER_ACK_REQUEST]         = "SvAckReq",
        [RXRPC_CALL_SERVER_SEND_REPLY]          = "SvSndRpl",
@@ -153,6 +152,7 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,
        call->cong_ssthresh = RXRPC_RXTX_BUFF_SIZE - 1;
 
        call->rxnet = rxnet;
+       call->rtt_avail = RXRPC_CALL_RTT_AVAIL_MASK;
        atomic_inc(&rxnet->nr_calls);
        return call;
 
@@ -351,9 +351,7 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx,
        call->call_id           = sp->hdr.callNumber;
        call->service_id        = sp->hdr.serviceId;
        call->cid               = sp->hdr.cid;
-       call->state             = RXRPC_CALL_SERVER_ACCEPTING;
-       if (sp->hdr.securityIndex > 0)
-               call->state     = RXRPC_CALL_SERVER_SECURING;
+       call->state             = RXRPC_CALL_SERVER_SECURING;
        call->cong_tstamp       = skb->tstamp;
 
        /* Set the channel for this call.  We don't get channel_lock as we're
index f2a1a5d..159e3ed 100644 (file)
@@ -881,7 +881,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
                        conn->cache_state = RXRPC_CONN_CLIENT_ACTIVE;
                        rxrpc_activate_channels_locked(conn);
                }
-               /* fall through */
+               fallthrough;
        case RXRPC_CONN_CLIENT_ACTIVE:
                if (list_empty(&conn->waiting_calls)) {
                        rxrpc_deactivate_one_channel(conn, channel);
index 447f55c..64ace29 100644 (file)
@@ -269,7 +269,7 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
        if (call) {
                write_lock_bh(&call->state_lock);
                if (call->state == RXRPC_CALL_SERVER_SECURING) {
-                       call->state = RXRPC_CALL_SERVER_ACCEPTING;
+                       call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
                        rxrpc_notify_socket(call);
                }
                write_unlock_bh(&call->state_lock);
@@ -340,18 +340,18 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
                        return ret;
 
                spin_lock(&conn->channel_lock);
-               spin_lock(&conn->state_lock);
+               spin_lock_bh(&conn->state_lock);
 
                if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
                        conn->state = RXRPC_CONN_SERVICE;
-                       spin_unlock(&conn->state_lock);
+                       spin_unlock_bh(&conn->state_lock);
                        for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
                                rxrpc_call_is_secure(
                                        rcu_dereference_protected(
                                                conn->channels[loop].call,
                                                lockdep_is_held(&conn->channel_lock)));
                } else {
-                       spin_unlock(&conn->state_lock);
+                       spin_unlock_bh(&conn->state_lock);
                }
 
                spin_unlock(&conn->channel_lock);
index 7675793..667c44a 100644 (file)
@@ -608,36 +608,57 @@ unlock:
 }
 
 /*
- * Process a requested ACK.
+ * See if there's a cached RTT probe to complete.
  */
-static void rxrpc_input_requested_ack(struct rxrpc_call *call,
-                                     ktime_t resp_time,
-                                     rxrpc_serial_t orig_serial,
-                                     rxrpc_serial_t ack_serial)
+static void rxrpc_complete_rtt_probe(struct rxrpc_call *call,
+                                    ktime_t resp_time,
+                                    rxrpc_serial_t acked_serial,
+                                    rxrpc_serial_t ack_serial,
+                                    enum rxrpc_rtt_rx_trace type)
 {
-       struct rxrpc_skb_priv *sp;
-       struct sk_buff *skb;
+       rxrpc_serial_t orig_serial;
+       unsigned long avail;
        ktime_t sent_at;
-       int ix;
+       bool matched = false;
+       int i;
 
-       for (ix = 0; ix < RXRPC_RXTX_BUFF_SIZE; ix++) {
-               skb = call->rxtx_buffer[ix];
-               if (!skb)
-                       continue;
+       avail = READ_ONCE(call->rtt_avail);
+       smp_rmb(); /* Read avail bits before accessing data. */
 
-               sent_at = skb->tstamp;
-               smp_rmb(); /* Read timestamp before serial. */
-               sp = rxrpc_skb(skb);
-               if (sp->hdr.serial != orig_serial)
+       for (i = 0; i < ARRAY_SIZE(call->rtt_serial); i++) {
+               if (!test_bit(i + RXRPC_CALL_RTT_PEND_SHIFT, &avail))
                        continue;
-               goto found;
-       }
 
-       return;
+               sent_at = call->rtt_sent_at[i];
+               orig_serial = call->rtt_serial[i];
+
+               if (orig_serial == acked_serial) {
+                       clear_bit(i + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail);
+                       smp_mb(); /* Read data before setting avail bit */
+                       set_bit(i, &call->rtt_avail);
+                       if (type != rxrpc_rtt_rx_cancel)
+                               rxrpc_peer_add_rtt(call, type, i, acked_serial, ack_serial,
+                                                  sent_at, resp_time);
+                       else
+                               trace_rxrpc_rtt_rx(call, rxrpc_rtt_rx_cancel, i,
+                                                  orig_serial, acked_serial, 0, 0);
+                       matched = true;
+               }
+
+               /* If a later serial is being acked, then mark this slot as
+                * being available.
+                */
+               if (after(acked_serial, orig_serial)) {
+                       trace_rxrpc_rtt_rx(call, rxrpc_rtt_rx_obsolete, i,
+                                          orig_serial, acked_serial, 0, 0);
+                       clear_bit(i + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail);
+                       smp_wmb();
+                       set_bit(i, &call->rtt_avail);
+               }
+       }
 
-found:
-       rxrpc_peer_add_rtt(call, rxrpc_rtt_rx_requested_ack,
-                          orig_serial, ack_serial, sent_at, resp_time);
+       if (!matched)
+               trace_rxrpc_rtt_rx(call, rxrpc_rtt_rx_lost, 9, 0, acked_serial, 0, 0);
 }
 
 /*
@@ -682,27 +703,11 @@ static void rxrpc_input_check_for_lost_ack(struct rxrpc_call *call)
  */
 static void rxrpc_input_ping_response(struct rxrpc_call *call,
                                      ktime_t resp_time,
-                                     rxrpc_serial_t orig_serial,
+                                     rxrpc_serial_t acked_serial,
                                      rxrpc_serial_t ack_serial)
 {
-       rxrpc_serial_t ping_serial;
-       ktime_t ping_time;
-
-       ping_time = call->ping_time;
-       smp_rmb();
-       ping_serial = READ_ONCE(call->ping_serial);
-
-       if (orig_serial == call->acks_lost_ping)
+       if (acked_serial == call->acks_lost_ping)
                rxrpc_input_check_for_lost_ack(call);
-
-       if (before(orig_serial, ping_serial) ||
-           !test_and_clear_bit(RXRPC_CALL_PINGING, &call->flags))
-               return;
-       if (after(orig_serial, ping_serial))
-               return;
-
-       rxrpc_peer_add_rtt(call, rxrpc_rtt_rx_ping_response,
-                          orig_serial, ack_serial, ping_time, resp_time);
 }
 
 /*
@@ -843,7 +848,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
                struct rxrpc_ackinfo info;
                u8 acks[RXRPC_MAXACKS];
        } buf;
-       rxrpc_serial_t acked_serial;
+       rxrpc_serial_t ack_serial, acked_serial;
        rxrpc_seq_t first_soft_ack, hard_ack, prev_pkt;
        int nr_acks, offset, ioffset;
 
@@ -856,6 +861,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
        }
        offset += sizeof(buf.ack);
 
+       ack_serial = sp->hdr.serial;
        acked_serial = ntohl(buf.ack.serial);
        first_soft_ack = ntohl(buf.ack.firstPacket);
        prev_pkt = ntohl(buf.ack.previousPacket);
@@ -864,31 +870,42 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
        summary.ack_reason = (buf.ack.reason < RXRPC_ACK__INVALID ?
                              buf.ack.reason : RXRPC_ACK__INVALID);
 
-       trace_rxrpc_rx_ack(call, sp->hdr.serial, acked_serial,
+       trace_rxrpc_rx_ack(call, ack_serial, acked_serial,
                           first_soft_ack, prev_pkt,
                           summary.ack_reason, nr_acks);
 
-       if (buf.ack.reason == RXRPC_ACK_PING_RESPONSE)
+       switch (buf.ack.reason) {
+       case RXRPC_ACK_PING_RESPONSE:
                rxrpc_input_ping_response(call, skb->tstamp, acked_serial,
-                                         sp->hdr.serial);
-       if (buf.ack.reason == RXRPC_ACK_REQUESTED)
-               rxrpc_input_requested_ack(call, skb->tstamp, acked_serial,
-                                         sp->hdr.serial);
+                                         ack_serial);
+               rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial,
+                                        rxrpc_rtt_rx_ping_response);
+               break;
+       case RXRPC_ACK_REQUESTED:
+               rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial,
+                                        rxrpc_rtt_rx_requested_ack);
+               break;
+       default:
+               if (acked_serial != 0)
+                       rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial,
+                                                rxrpc_rtt_rx_cancel);
+               break;
+       }
 
        if (buf.ack.reason == RXRPC_ACK_PING) {
-               _proto("Rx ACK %%%u PING Request", sp->hdr.serial);
+               _proto("Rx ACK %%%u PING Request", ack_serial);
                rxrpc_propose_ACK(call, RXRPC_ACK_PING_RESPONSE,
-                                 sp->hdr.serial, true, true,
+                                 ack_serial, true, true,
                                  rxrpc_propose_ack_respond_to_ping);
        } else if (sp->hdr.flags & RXRPC_REQUEST_ACK) {
                rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED,
-                                 sp->hdr.serial, true, true,
+                                 ack_serial, true, true,
                                  rxrpc_propose_ack_respond_to_ack);
        }
 
        /* Discard any out-of-order or duplicate ACKs (outside lock). */
        if (!rxrpc_is_ack_valid(call, first_soft_ack, prev_pkt)) {
-               trace_rxrpc_rx_discard_ack(call->debug_id, sp->hdr.serial,
+               trace_rxrpc_rx_discard_ack(call->debug_id, ack_serial,
                                           first_soft_ack, call->ackr_first_seq,
                                           prev_pkt, call->ackr_prev_seq);
                return;
@@ -904,7 +921,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
 
        /* Discard any out-of-order or duplicate ACKs (inside lock). */
        if (!rxrpc_is_ack_valid(call, first_soft_ack, prev_pkt)) {
-               trace_rxrpc_rx_discard_ack(call->debug_id, sp->hdr.serial,
+               trace_rxrpc_rx_discard_ack(call->debug_id, ack_serial,
                                           first_soft_ack, call->ackr_first_seq,
                                           prev_pkt, call->ackr_prev_seq);
                goto out;
@@ -964,7 +981,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
            RXRPC_TX_ANNO_LAST &&
            summary.nr_acks == call->tx_top - hard_ack &&
            rxrpc_is_client_call(call))
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, sp->hdr.serial,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, ack_serial,
                                  false, true,
                                  rxrpc_propose_ack_ping_for_lost_reply);
 
@@ -1084,7 +1101,7 @@ static void rxrpc_input_implicit_end_call(struct rxrpc_sock *rx,
        switch (READ_ONCE(call->state)) {
        case RXRPC_CALL_SERVER_AWAIT_ACK:
                rxrpc_call_completed(call);
-               /* Fall through */
+               fallthrough;
        case RXRPC_CALL_COMPLETE:
                break;
        default:
@@ -1243,12 +1260,12 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
        case RXRPC_PACKET_TYPE_BUSY:
                if (rxrpc_to_server(sp))
                        goto discard;
-               /* Fall through */
+               fallthrough;
        case RXRPC_PACKET_TYPE_ACK:
        case RXRPC_PACKET_TYPE_ACKALL:
                if (sp->hdr.callNumber == 0)
                        goto bad_message;
-               /* Fall through */
+               fallthrough;
        case RXRPC_PACKET_TYPE_ABORT:
                break;
 
index 94c3df3..2e8bd3b 100644 (file)
@@ -903,7 +903,7 @@ int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
 
        _enter("");
 
-       if (optlen <= 0 || optlen > PAGE_SIZE - 1)
+       if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->securities)
                return -EINVAL;
 
        description = memdup_sockptr_nul(optval, optlen);
@@ -940,7 +940,7 @@ int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
        if (IS_ERR(description))
                return PTR_ERR(description);
 
-       key = request_key_net(&key_type_keyring, description, sock_net(&rx->sk), NULL);
+       key = request_key(&key_type_keyring, description, NULL);
        if (IS_ERR(key)) {
                kfree(description);
                _leave(" = %ld", PTR_ERR(key));
@@ -1072,7 +1072,7 @@ static long rxrpc_read(const struct key *key,
 
                switch (token->security_index) {
                case RXRPC_SECURITY_RXKAD:
-                       toksize += 9 * 4;       /* viceid, kvno, key*2 + len, begin,
+                       toksize += 8 * 4;       /* viceid, kvno, key*2, begin,
                                                 * end, primary, tktlen */
                        toksize += RND(token->kad->ticket_len);
                        break;
@@ -1107,7 +1107,8 @@ static long rxrpc_read(const struct key *key,
                        break;
 
                default: /* we have a ticket we can't encode */
-                       BUG();
+                       pr_err("Unsupported key token type (%u)\n",
+                              token->security_index);
                        continue;
                }
 
@@ -1138,6 +1139,14 @@ static long rxrpc_read(const struct key *key,
                        memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3));    \
                xdr += (_l + 3) >> 2;                                   \
        } while(0)
+#define ENCODE_BYTES(l, s)                                             \
+       do {                                                            \
+               u32 _l = (l);                                           \
+               memcpy(xdr, (s), _l);                                   \
+               if (_l & 3)                                             \
+                       memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3));    \
+               xdr += (_l + 3) >> 2;                                   \
+       } while(0)
 #define ENCODE64(x)                                    \
        do {                                            \
                __be64 y = cpu_to_be64(x);              \
@@ -1165,7 +1174,7 @@ static long rxrpc_read(const struct key *key,
                case RXRPC_SECURITY_RXKAD:
                        ENCODE(token->kad->vice_id);
                        ENCODE(token->kad->kvno);
-                       ENCODE_DATA(8, token->kad->session_key);
+                       ENCODE_BYTES(8, token->kad->session_key);
                        ENCODE(token->kad->start);
                        ENCODE(token->kad->expiry);
                        ENCODE(token->kad->primary_flag);
@@ -1215,7 +1224,6 @@ static long rxrpc_read(const struct key *key,
                        break;
 
                default:
-                       BUG();
                        break;
                }
 
index c8b2097..ede058f 100644 (file)
@@ -162,7 +162,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
                /* Fall through and set IPv4 options too otherwise we don't get
                 * errors from IPv4 packets sent through the IPv6 socket.
                 */
-               /* Fall through */
+               fallthrough;
        case AF_INET:
                /* we want to receive ICMP errors */
                ip_sock_set_recverr(local->socket->sk);
index 1ba43c3..3cfff79 100644 (file)
@@ -124,6 +124,49 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
 }
 
 /*
+ * Record the beginning of an RTT probe.
+ */
+static int rxrpc_begin_rtt_probe(struct rxrpc_call *call, rxrpc_serial_t serial,
+                                enum rxrpc_rtt_tx_trace why)
+{
+       unsigned long avail = call->rtt_avail;
+       int rtt_slot = 9;
+
+       if (!(avail & RXRPC_CALL_RTT_AVAIL_MASK))
+               goto no_slot;
+
+       rtt_slot = __ffs(avail & RXRPC_CALL_RTT_AVAIL_MASK);
+       if (!test_and_clear_bit(rtt_slot, &call->rtt_avail))
+               goto no_slot;
+
+       call->rtt_serial[rtt_slot] = serial;
+       call->rtt_sent_at[rtt_slot] = ktime_get_real();
+       smp_wmb(); /* Write data before avail bit */
+       set_bit(rtt_slot + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail);
+
+       trace_rxrpc_rtt_tx(call, why, rtt_slot, serial);
+       return rtt_slot;
+
+no_slot:
+       trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_no_slot, rtt_slot, serial);
+       return -1;
+}
+
+/*
+ * Cancel an RTT probe.
+ */
+static void rxrpc_cancel_rtt_probe(struct rxrpc_call *call,
+                                  rxrpc_serial_t serial, int rtt_slot)
+{
+       if (rtt_slot != -1) {
+               clear_bit(rtt_slot + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail);
+               smp_wmb(); /* Clear pending bit before setting slot */
+               set_bit(rtt_slot, &call->rtt_avail);
+               trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_cancel, rtt_slot, serial);
+       }
+}
+
+/*
  * Send an ACK call packet.
  */
 int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
@@ -136,7 +179,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
        rxrpc_serial_t serial;
        rxrpc_seq_t hard_ack, top;
        size_t len, n;
-       int ret;
+       int ret, rtt_slot = -1;
        u8 reason;
 
        if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
@@ -196,18 +239,8 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
        if (_serial)
                *_serial = serial;
 
-       if (ping) {
-               call->ping_serial = serial;
-               smp_wmb();
-               /* We need to stick a time in before we send the packet in case
-                * the reply gets back before kernel_sendmsg() completes - but
-                * asking UDP to send the packet can take a relatively long
-                * time.
-                */
-               call->ping_time = ktime_get_real();
-               set_bit(RXRPC_CALL_PINGING, &call->flags);
-               trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_ping, serial);
-       }
+       if (ping)
+               rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_ping);
 
        ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
        conn->params.peer->last_tx_at = ktime_get_seconds();
@@ -221,8 +254,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
 
        if (call->state < RXRPC_CALL_COMPLETE) {
                if (ret < 0) {
-                       if (ping)
-                               clear_bit(RXRPC_CALL_PINGING, &call->flags);
+                       rxrpc_cancel_rtt_probe(call, serial, rtt_slot);
                        rxrpc_propose_ACK(call, pkt->ack.reason,
                                          ntohl(pkt->ack.serial),
                                          false, true,
@@ -321,7 +353,7 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
        struct kvec iov[2];
        rxrpc_serial_t serial;
        size_t len;
-       int ret;
+       int ret, rtt_slot = -1;
 
        _enter(",{%d}", skb->len);
 
@@ -397,6 +429,8 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
        sp->hdr.serial = serial;
        smp_wmb(); /* Set serial before timestamp */
        skb->tstamp = ktime_get_real();
+       if (whdr.flags & RXRPC_REQUEST_ACK)
+               rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_data);
 
        /* send the packet by UDP
         * - returns -EMSGSIZE if UDP would have to fragment the packet
@@ -408,12 +442,15 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
        conn->params.peer->last_tx_at = ktime_get_seconds();
 
        up_read(&conn->params.local->defrag_sem);
-       if (ret < 0)
+       if (ret < 0) {
+               rxrpc_cancel_rtt_probe(call, serial, rtt_slot);
                trace_rxrpc_tx_fail(call->debug_id, serial, ret,
                                    rxrpc_tx_point_call_data_nofrag);
-       else
+       } else {
                trace_rxrpc_tx_packet(call->debug_id, &whdr,
                                      rxrpc_tx_point_call_data_nofrag);
+       }
+
        rxrpc_tx_backoff(call, ret);
        if (ret == -EMSGSIZE)
                goto send_fragmentable;
@@ -422,7 +459,6 @@ done:
        if (ret >= 0) {
                if (whdr.flags & RXRPC_REQUEST_ACK) {
                        call->peer->rtt_last_req = skb->tstamp;
-                       trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_data, serial);
                        if (call->peer->rtt_count > 1) {
                                unsigned long nowj = jiffies, ack_lost_at;
 
@@ -469,6 +505,8 @@ send_fragmentable:
        sp->hdr.serial = serial;
        smp_wmb(); /* Set serial before timestamp */
        skb->tstamp = ktime_get_real();
+       if (whdr.flags & RXRPC_REQUEST_ACK)
+               rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_data);
 
        switch (conn->params.local->srx.transport.family) {
        case AF_INET6:
@@ -487,12 +525,14 @@ send_fragmentable:
                BUG();
        }
 
-       if (ret < 0)
+       if (ret < 0) {
+               rxrpc_cancel_rtt_probe(call, serial, rtt_slot);
                trace_rxrpc_tx_fail(call->debug_id, serial, ret,
                                    rxrpc_tx_point_call_data_frag);
-       else
+       } else {
                trace_rxrpc_tx_packet(call->debug_id, &whdr,
                                      rxrpc_tx_point_call_data_frag);
+       }
        rxrpc_tx_backoff(call, ret);
 
        up_write(&conn->params.local->defrag_sem);
index a852f46..be03285 100644 (file)
@@ -273,7 +273,7 @@ static void rxrpc_store_error(struct rxrpc_peer *peer,
        case SO_EE_ORIGIN_ICMP6:
                if (err == EACCES)
                        err = EHOSTUNREACH;
-               /* Fall through */
+               fallthrough;
        default:
                _proto("Rx Received error report { orig=%u }", ee->ee_origin);
                break;
index ca29976..68396d0 100644 (file)
@@ -502,11 +502,21 @@ EXPORT_SYMBOL(rxrpc_kernel_get_peer);
  * rxrpc_kernel_get_srtt - Get a call's peer smoothed RTT
  * @sock: The socket on which the call is in progress.
  * @call: The call to query
+ * @_srtt: Where to store the SRTT value.
  *
- * Get the call's peer smoothed RTT.
+ * Get the call's peer smoothed RTT in uS.
  */
-u32 rxrpc_kernel_get_srtt(struct socket *sock, struct rxrpc_call *call)
+bool rxrpc_kernel_get_srtt(struct socket *sock, struct rxrpc_call *call,
+                          u32 *_srtt)
 {
-       return call->peer->srtt_us >> 3;
+       struct rxrpc_peer *peer = call->peer;
+
+       if (peer->rtt_count == 0) {
+               *_srtt = 1000000; /* 1S */
+               return false;
+       }
+
+       *_srtt = call->peer->srtt_us >> 3;
+       return true;
 }
 EXPORT_SYMBOL(rxrpc_kernel_get_srtt);
index efecc5a..2c84285 100644 (file)
@@ -179,37 +179,6 @@ static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg)
 }
 
 /*
- * Pass back notification of a new call.  The call is added to the
- * to-be-accepted list.  This means that the next call to be accepted might not
- * be the last call seen awaiting acceptance, but unless we leave this on the
- * front of the queue and block all other messages until someone gives us a
- * user_ID for it, there's not a lot we can do.
- */
-static int rxrpc_recvmsg_new_call(struct rxrpc_sock *rx,
-                                 struct rxrpc_call *call,
-                                 struct msghdr *msg, int flags)
-{
-       int tmp = 0, ret;
-
-       ret = put_cmsg(msg, SOL_RXRPC, RXRPC_NEW_CALL, 0, &tmp);
-
-       if (ret == 0 && !(flags & MSG_PEEK)) {
-               _debug("to be accepted");
-               write_lock_bh(&rx->recvmsg_lock);
-               list_del_init(&call->recvmsg_link);
-               write_unlock_bh(&rx->recvmsg_lock);
-
-               rxrpc_get_call(call, rxrpc_call_got);
-               write_lock(&rx->call_lock);
-               list_add_tail(&call->accept_link, &rx->to_be_accepted);
-               write_unlock(&rx->call_lock);
-       }
-
-       trace_rxrpc_recvmsg(call, rxrpc_recvmsg_to_be_accepted, 1, 0, 0, ret);
-       return ret;
-}
-
-/*
  * End the packet reception phase.
  */
 static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
@@ -630,9 +599,6 @@ try_again:
        }
 
        switch (READ_ONCE(call->state)) {
-       case RXRPC_CALL_SERVER_ACCEPTING:
-               ret = rxrpc_recvmsg_new_call(rx, call, msg, flags);
-               break;
        case RXRPC_CALL_CLIENT_RECV_REPLY:
        case RXRPC_CALL_SERVER_RECV_REQUEST:
        case RXRPC_CALL_SERVER_ACK_REQUEST:
@@ -728,7 +694,7 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
               call->debug_id, rxrpc_call_states[call->state],
               iov_iter_count(iter), want_more);
 
-       ASSERTCMP(call->state, !=, RXRPC_CALL_SERVER_ACCEPTING);
+       ASSERTCMP(call->state, !=, RXRPC_CALL_SERVER_SECURING);
 
        mutex_lock(&call->user_mutex);
 
@@ -776,7 +742,7 @@ out:
        case RXRPC_ACK_DELAY:
                if (ret != -EAGAIN)
                        break;
-               /* Fall through */
+               fallthrough;
        default:
                rxrpc_send_ack_packet(call, false, NULL);
        }
index 928d8b3..1221b06 100644 (file)
@@ -146,6 +146,7 @@ static void rxrpc_ack_update_rtt(struct rxrpc_peer *peer, long rtt_us)
  * exclusive access to the peer RTT data.
  */
 void rxrpc_peer_add_rtt(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why,
+                       int rtt_slot,
                        rxrpc_serial_t send_serial, rxrpc_serial_t resp_serial,
                        ktime_t send_time, ktime_t resp_time)
 {
@@ -162,7 +163,7 @@ void rxrpc_peer_add_rtt(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why,
                peer->rtt_count++;
        spin_unlock(&peer->rtt_input_lock);
 
-       trace_rxrpc_rtt_rx(call, why, send_serial, resp_serial,
+       trace_rxrpc_rtt_rx(call, why, rtt_slot, send_serial, resp_serial,
                           peer->srtt_us >> 3, peer->rto_j);
 }
 
index 52a24d4..e08130e 100644 (file)
@@ -1137,7 +1137,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
        ret = -ENOMEM;
        ticket = kmalloc(ticket_len, GFP_NOFS);
        if (!ticket)
-               goto temporary_error;
+               goto temporary_error_free_resp;
 
        eproto = tracepoint_string("rxkad_tkt_short");
        abort_code = RXKADPACKETSHORT;
@@ -1230,6 +1230,7 @@ protocol_error:
 
 temporary_error_free_ticket:
        kfree(ticket);
+temporary_error_free_resp:
        kfree(response);
 temporary_error:
        /* Ignore the response packet if we got a temporary error such as
index f3f6da6..d27140c 100644 (file)
@@ -241,7 +241,7 @@ static int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
                        trace_rxrpc_timer(call, rxrpc_timer_init_for_send_reply, now);
                        if (!last)
                                break;
-                       /* Fall through */
+                       fallthrough;
                case RXRPC_CALL_SERVER_SEND_REPLY:
                        call->state = RXRPC_CALL_SERVER_AWAIT_ACK;
                        rxrpc_notify_end_tx(rx, call, notify_end_tx);
@@ -530,10 +530,10 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p)
                                return -EINVAL;
                        break;
 
-               case RXRPC_ACCEPT:
+               case RXRPC_CHARGE_ACCEPT:
                        if (p->command != RXRPC_CMD_SEND_DATA)
                                return -EINVAL;
-                       p->command = RXRPC_CMD_ACCEPT;
+                       p->command = RXRPC_CMD_CHARGE_ACCEPT;
                        if (len != 0)
                                return -EINVAL;
                        break;
@@ -659,16 +659,12 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
        if (ret < 0)
                goto error_release_sock;
 
-       if (p.command == RXRPC_CMD_ACCEPT) {
+       if (p.command == RXRPC_CMD_CHARGE_ACCEPT) {
                ret = -EINVAL;
                if (rx->sk.sk_state != RXRPC_SERVER_LISTENING)
                        goto error_release_sock;
-               call = rxrpc_accept_call(rx, p.call.user_call_ID, NULL);
-               /* The socket is now unlocked. */
-               if (IS_ERR(call))
-                       return PTR_ERR(call);
-               ret = 0;
-               goto out_put_unlock;
+               ret = rxrpc_user_charge_accept(rx, p.call.user_call_ID);
+               goto error_release_sock;
        }
 
        call = rxrpc_find_call_by_user_ID(rx, p.call.user_call_ID);
@@ -690,7 +686,6 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
                case RXRPC_CALL_CLIENT_AWAIT_CONN:
                case RXRPC_CALL_SERVER_PREALLOC:
                case RXRPC_CALL_SERVER_SECURING:
-               case RXRPC_CALL_SERVER_ACCEPTING:
                        rxrpc_put_call(call, rxrpc_call_put);
                        ret = -EBUSY;
                        goto error_release_sock;
@@ -721,13 +716,13 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
                if (p.call.timeouts.normal > 0 && j == 0)
                        j = 1;
                WRITE_ONCE(call->next_rx_timo, j);
-               /* Fall through */
+               fallthrough;
        case 2:
                j = msecs_to_jiffies(p.call.timeouts.idle);
                if (p.call.timeouts.idle > 0 && j == 0)
                        j = 1;
                WRITE_ONCE(call->next_req_timo, j);
-               /* Fall through */
+               fallthrough;
        case 1:
                if (p.call.timeouts.hard > 0) {
                        j = msecs_to_jiffies(p.call.timeouts.hard);
index 063d8aa..798430e 100644 (file)
@@ -235,6 +235,8 @@ static int tcf_dump_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
                index++;
                if (index < s_i)
                        continue;
+               if (IS_ERR(p))
+                       continue;
 
                if (jiffy_since &&
                    time_after(jiffy_since,
@@ -307,6 +309,8 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
 
        mutex_lock(&idrinfo->lock);
        idr_for_each_entry_ul(idr, p, tmp, id) {
+               if (IS_ERR(p))
+                       continue;
                ret = tcf_idr_release_unsafe(p);
                if (ret == ACT_P_DELETED) {
                        module_put(ops->owner);
@@ -467,17 +471,6 @@ int tcf_idr_create_from_flags(struct tc_action_net *tn, u32 index,
 }
 EXPORT_SYMBOL(tcf_idr_create_from_flags);
 
-void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a)
-{
-       struct tcf_idrinfo *idrinfo = tn->idrinfo;
-
-       mutex_lock(&idrinfo->lock);
-       /* Replace ERR_PTR(-EBUSY) allocated by tcf_idr_check_alloc */
-       WARN_ON(!IS_ERR(idr_replace(&idrinfo->action_idr, a, a->tcfa_index)));
-       mutex_unlock(&idrinfo->lock);
-}
-EXPORT_SYMBOL(tcf_idr_insert);
-
 /* Cleanup idr index that was allocated but not initialized. */
 
 void tcf_idr_cleanup(struct tc_action_net *tn, u32 index)
@@ -731,13 +724,6 @@ int tcf_action_destroy(struct tc_action *actions[], int bind)
        return ret;
 }
 
-static int tcf_action_destroy_1(struct tc_action *a, int bind)
-{
-       struct tc_action *actions[] = { a, NULL };
-
-       return tcf_action_destroy(actions, bind);
-}
-
 static int tcf_action_put(struct tc_action *p)
 {
        return __tcf_action_put(p, false);
@@ -902,6 +888,26 @@ static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
        [TCA_ACT_HW_STATS]      = NLA_POLICY_BITFIELD32(TCA_ACT_HW_STATS_ANY),
 };
 
+static void tcf_idr_insert_many(struct tc_action *actions[])
+{
+       int i;
+
+       for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
+               struct tc_action *a = actions[i];
+               struct tcf_idrinfo *idrinfo;
+
+               if (!a)
+                       continue;
+               idrinfo = a->idrinfo;
+               mutex_lock(&idrinfo->lock);
+               /* Replace ERR_PTR(-EBUSY) allocated by tcf_idr_check_alloc if
+                * it is just created, otherwise this is just a nop.
+                */
+               idr_replace(&idrinfo->action_idr, a, a->tcfa_index);
+               mutex_unlock(&idrinfo->lock);
+       }
+}
+
 struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
                                    struct nlattr *nla, struct nlattr *est,
                                    char *name, int ovr, int bind,
@@ -1002,13 +1008,6 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
        if (err != ACT_P_CREATED)
                module_put(a_o->owner);
 
-       if (TC_ACT_EXT_CMP(a->tcfa_action, TC_ACT_GOTO_CHAIN) &&
-           !rcu_access_pointer(a->goto_chain)) {
-               tcf_action_destroy_1(a, bind);
-               NL_SET_ERR_MSG(extack, "can't use goto chain with NULL chain");
-               return ERR_PTR(-EINVAL);
-       }
-
        return a;
 
 err_mod:
@@ -1051,6 +1050,11 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
                actions[i - 1] = act;
        }
 
+       /* We have to commit them all together, because if any error happened in
+        * between, we could not handle the failure gracefully.
+        */
+       tcf_idr_insert_many(actions);
+
        *attr_size = tcf_action_full_attrs_size(sz);
        return i - 1;
 
index 54d5652..a4c7ba3 100644 (file)
@@ -365,9 +365,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
 
-       if (res == ACT_P_CREATED) {
-               tcf_idr_insert(tn, *act);
-       } else {
+       if (res != ACT_P_CREATED) {
                /* make sure the program being replaced is no longer executing */
                synchronize_rcu();
                tcf_bpf_cfg_cleanup(&old);
index f901421..e19885d 100644 (file)
@@ -139,7 +139,6 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
                ci->net = net;
                ci->zone = parm->zone;
 
-               tcf_idr_insert(tn, *a);
                ret = ACT_P_CREATED;
        } else if (ret > 0) {
                ci = to_connmark(*a);
index f5826e4..4fa4fcb 100644 (file)
@@ -110,9 +110,6 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
        if (params_new)
                kfree_rcu(params_new, rcu);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
-
        return ret;
 put_chain:
        if (goto_ch)
index 2c36191..a780afd 100644 (file)
@@ -1297,8 +1297,6 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
                tcf_chain_put_by_act(goto_ch);
        if (params)
                call_rcu(&params->rcu, tcf_ct_params_free);
-       if (res == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
 
        return res;
 
index b5042f3..6084300 100644 (file)
@@ -269,9 +269,6 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
        if (cp_new)
                kfree_rcu(cp_new, rcu);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
-
        return ret;
 
 put_chain:
index 410e3bb..73c3926 100644 (file)
@@ -140,8 +140,6 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
        return ret;
 release_idr:
        tcf_idr_release(*a, bind);
index 1fb8d42..7c0771d 100644 (file)
@@ -437,9 +437,6 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
-
        return ret;
 
 chain_put:
index c1fcd85..a2ddea0 100644 (file)
@@ -436,6 +436,25 @@ static void tcf_ife_cleanup(struct tc_action *a)
                kfree_rcu(p, rcu);
 }
 
+static int load_metalist(struct nlattr **tb, bool rtnl_held)
+{
+       int i;
+
+       for (i = 1; i < max_metacnt; i++) {
+               if (tb[i]) {
+                       void *val = nla_data(tb[i]);
+                       int len = nla_len(tb[i]);
+                       int rc;
+
+                       rc = load_metaops_and_vet(i, val, len, rtnl_held);
+                       if (rc != 0)
+                               return rc;
+               }
+       }
+
+       return 0;
+}
+
 static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
                             bool exists, bool rtnl_held)
 {
@@ -449,10 +468,6 @@ static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
                        val = nla_data(tb[i]);
                        len = nla_len(tb[i]);
 
-                       rc = load_metaops_and_vet(i, val, len, rtnl_held);
-                       if (rc != 0)
-                               return rc;
-
                        rc = add_metainfo(ife, i, val, len, exists);
                        if (rc)
                                return rc;
@@ -509,6 +524,21 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
        if (!p)
                return -ENOMEM;
 
+       if (tb[TCA_IFE_METALST]) {
+               err = nla_parse_nested_deprecated(tb2, IFE_META_MAX,
+                                                 tb[TCA_IFE_METALST], NULL,
+                                                 NULL);
+               if (err) {
+                       kfree(p);
+                       return err;
+               }
+               err = load_metalist(tb2, rtnl_held);
+               if (err) {
+                       kfree(p);
+                       return err;
+               }
+       }
+
        index = parm->index;
        err = tcf_idr_check_alloc(tn, &index, a, bind);
        if (err < 0) {
@@ -570,15 +600,9 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
        }
 
        if (tb[TCA_IFE_METALST]) {
-               err = nla_parse_nested_deprecated(tb2, IFE_META_MAX,
-                                                 tb[TCA_IFE_METALST], NULL,
-                                                 NULL);
-               if (err)
-                       goto metadata_parse_err;
                err = populate_metalist(ife, tb2, exists, rtnl_held);
                if (err)
                        goto metadata_parse_err;
-
        } else {
                /* if no passed metadata allow list or passed allow-all
                 * then here we process by adding as many supported metadatum
@@ -603,9 +627,6 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
        if (p)
                kfree_rcu(p, rcu);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
-
        return ret;
 metadata_parse_err:
        if (goto_ch)
index 400a2cf..8dc3bec 100644 (file)
@@ -189,8 +189,6 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
        ipt->tcfi_t     = t;
        ipt->tcfi_hook  = hook;
        spin_unlock_bh(&ipt->tcf_lock);
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
        return ret;
 
 err3:
index b270531..e24b7e2 100644 (file)
@@ -194,8 +194,6 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                spin_lock(&mirred_list_lock);
                list_add(&m->tcfm_list, &mirred_list);
                spin_unlock(&mirred_list_lock);
-
-               tcf_idr_insert(tn, *a);
        }
 
        return ret;
index 8118e26..e298ec3 100644 (file)
@@ -273,8 +273,6 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
        if (p)
                kfree_rcu(p, rcu);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
        return ret;
 put_chain:
        if (goto_ch)
index 855a6fa..1ebd2a8 100644 (file)
@@ -93,9 +93,6 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
-
        return ret;
 release_idr:
        tcf_idr_release(*a, bind);
index c158bfe..b453044 100644 (file)
@@ -238,8 +238,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
        spin_unlock_bh(&p->tcf_lock);
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
        return ret;
 
 put_chain:
index 0b431d4..8d8452b 100644 (file)
@@ -201,8 +201,6 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
        if (new)
                kfree_rcu(new, rcu);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
        return ret;
 
 failure:
index 5e2df59..3ebf9ed 100644 (file)
@@ -116,8 +116,6 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
        return ret;
 put_chain:
        if (goto_ch)
index 9813ca4..a4f3d0f 100644 (file)
@@ -157,8 +157,6 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
                        goto release_idr;
        }
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
        return ret;
 put_chain:
        if (goto_ch)
index d065238..e5f3fb8 100644 (file)
@@ -225,8 +225,6 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
        return ret;
 put_chain:
        if (goto_ch)
index 39e6d94..81a1c67 100644 (file)
@@ -190,8 +190,6 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
        return ret;
 put_chain:
        if (goto_ch)
index 536c4bc..a229751 100644 (file)
@@ -156,6 +156,7 @@ tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len,
                struct vxlan_metadata *md = dst;
 
                md->gbp = nla_get_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]);
+               md->gbp &= VXLAN_GBP_MASK;
        }
 
        return sizeof(struct vxlan_metadata);
@@ -536,9 +537,6 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
-
        return ret;
 
 put_chain:
index a5ff9f6..163b038 100644 (file)
@@ -229,8 +229,6 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
        if (p)
                kfree_rcu(p, rcu);
 
-       if (ret == ACT_P_CREATED)
-               tcf_idr_insert(tn, *a);
        return ret;
 put_chain:
        if (goto_ch)
index a4f7ef1..fed18fd 100644 (file)
@@ -1175,8 +1175,10 @@ static int fl_set_vxlan_opt(const struct nlattr *nla, struct fl_flow_key *key,
                return -EINVAL;
        }
 
-       if (tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP])
+       if (tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]) {
                md->gbp = nla_get_u32(tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]);
+               md->gbp &= VXLAN_GBP_MASK;
+       }
 
        return sizeof(*md);
 }
@@ -1221,6 +1223,7 @@ static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key,
                }
                if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) {
                        nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX];
+                       memset(&md->u, 0x00, sizeof(md->u));
                        md->u.index = nla_get_be32(nla);
                }
        } else if (md->version == 2) {
index 0618b63..7d37638 100644 (file)
@@ -1670,7 +1670,7 @@ static u32 cake_classify(struct Qdisc *sch, struct cake_tin_data **t,
                case TC_ACT_QUEUED:
                case TC_ACT_TRAP:
                        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
-                       /* fall through */
+                       fallthrough;
                case TC_ACT_SHOT:
                        return 0;
                }
index 265a61d..54c4172 100644 (file)
@@ -1131,24 +1131,10 @@ EXPORT_SYMBOL(dev_activate);
 
 static void qdisc_deactivate(struct Qdisc *qdisc)
 {
-       bool nolock = qdisc->flags & TCQ_F_NOLOCK;
-
        if (qdisc->flags & TCQ_F_BUILTIN)
                return;
-       if (test_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state))
-               return;
-
-       if (nolock)
-               spin_lock_bh(&qdisc->seqlock);
-       spin_lock_bh(qdisc_lock(qdisc));
 
        set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state);
-
-       qdisc_reset(qdisc);
-
-       spin_unlock_bh(qdisc_lock(qdisc));
-       if (nolock)
-               spin_unlock_bh(&qdisc->seqlock);
 }
 
 static void dev_deactivate_queue(struct net_device *dev,
@@ -1165,6 +1151,30 @@ static void dev_deactivate_queue(struct net_device *dev,
        }
 }
 
+static void dev_reset_queue(struct net_device *dev,
+                           struct netdev_queue *dev_queue,
+                           void *_unused)
+{
+       struct Qdisc *qdisc;
+       bool nolock;
+
+       qdisc = dev_queue->qdisc_sleeping;
+       if (!qdisc)
+               return;
+
+       nolock = qdisc->flags & TCQ_F_NOLOCK;
+
+       if (nolock)
+               spin_lock_bh(&qdisc->seqlock);
+       spin_lock_bh(qdisc_lock(qdisc));
+
+       qdisc_reset(qdisc);
+
+       spin_unlock_bh(qdisc_lock(qdisc));
+       if (nolock)
+               spin_unlock_bh(&qdisc->seqlock);
+}
+
 static bool some_qdisc_is_busy(struct net_device *dev)
 {
        unsigned int i;
@@ -1213,12 +1223,20 @@ void dev_deactivate_many(struct list_head *head)
                dev_watchdog_down(dev);
        }
 
-       /* Wait for outstanding qdisc-less dev_queue_xmit calls.
+       /* Wait for outstanding qdisc-less dev_queue_xmit calls or
+        * outstanding qdisc enqueuing calls.
         * This is avoided if all devices are in dismantle phase :
         * Caller will call synchronize_net() for us
         */
        synchronize_net();
 
+       list_for_each_entry(dev, head, close_list) {
+               netdev_for_each_tx_queue(dev, dev_reset_queue, NULL);
+
+               if (dev_ingress_queue(dev))
+                       dev_reset_queue(dev, dev_ingress_queue(dev), NULL);
+       }
+
        /* Wait for outstanding qdisc_run calls. */
        list_for_each_entry(dev, head, close_list) {
                while (some_qdisc_is_busy(dev)) {
index deac82f..e89fab6 100644 (file)
@@ -353,23 +353,11 @@ static int red_init(struct Qdisc *sch, struct nlattr *opt,
                              FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP,
                              tb[TCA_RED_EARLY_DROP_BLOCK], extack);
        if (err)
-               goto err_early_drop_init;
-
-       err = tcf_qevent_init(&q->qe_mark, sch,
-                             FLOW_BLOCK_BINDER_TYPE_RED_MARK,
-                             tb[TCA_RED_MARK_BLOCK], extack);
-       if (err)
-               goto err_mark_init;
-
-       return 0;
+               return err;
 
-err_mark_init:
-       tcf_qevent_destroy(&q->qe_early_drop, sch);
-err_early_drop_init:
-       del_timer_sync(&q->adapt_timer);
-       red_offload(sch, false);
-       qdisc_put(q->qdisc);
-       return err;
+       return tcf_qevent_init(&q->qe_mark, sch,
+                              FLOW_BLOCK_BINDER_TYPE_RED_MARK,
+                              tb[TCA_RED_MARK_BLOCK], extack);
 }
 
 static int red_change(struct Qdisc *sch, struct nlattr *opt,
index e981992..b0ad768 100644 (file)
@@ -777,9 +777,11 @@ static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = {
        [TCA_TAPRIO_ATTR_TXTIME_DELAY]               = { .type = NLA_U32 },
 };
 
-static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry,
+static int fill_sched_entry(struct taprio_sched *q, struct nlattr **tb,
+                           struct sched_entry *entry,
                            struct netlink_ext_ack *extack)
 {
+       int min_duration = length_to_duration(q, ETH_ZLEN);
        u32 interval = 0;
 
        if (tb[TCA_TAPRIO_SCHED_ENTRY_CMD])
@@ -794,7 +796,10 @@ static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry,
                interval = nla_get_u32(
                        tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]);
 
-       if (interval == 0) {
+       /* The interval should allow at least the minimum ethernet
+        * frame to go out.
+        */
+       if (interval < min_duration) {
                NL_SET_ERR_MSG(extack, "Invalid interval for schedule entry");
                return -EINVAL;
        }
@@ -804,8 +809,9 @@ static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry,
        return 0;
 }
 
-static int parse_sched_entry(struct nlattr *n, struct sched_entry *entry,
-                            int index, struct netlink_ext_ack *extack)
+static int parse_sched_entry(struct taprio_sched *q, struct nlattr *n,
+                            struct sched_entry *entry, int index,
+                            struct netlink_ext_ack *extack)
 {
        struct nlattr *tb[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { };
        int err;
@@ -819,10 +825,10 @@ static int parse_sched_entry(struct nlattr *n, struct sched_entry *entry,
 
        entry->index = index;
 
-       return fill_sched_entry(tb, entry, extack);
+       return fill_sched_entry(q, tb, entry, extack);
 }
 
-static int parse_sched_list(struct nlattr *list,
+static int parse_sched_list(struct taprio_sched *q, struct nlattr *list,
                            struct sched_gate_list *sched,
                            struct netlink_ext_ack *extack)
 {
@@ -847,7 +853,7 @@ static int parse_sched_list(struct nlattr *list,
                        return -ENOMEM;
                }
 
-               err = parse_sched_entry(n, entry, i, extack);
+               err = parse_sched_entry(q, n, entry, i, extack);
                if (err < 0) {
                        kfree(entry);
                        return err;
@@ -862,7 +868,7 @@ static int parse_sched_list(struct nlattr *list,
        return i;
 }
 
-static int parse_taprio_schedule(struct nlattr **tb,
+static int parse_taprio_schedule(struct taprio_sched *q, struct nlattr **tb,
                                 struct sched_gate_list *new,
                                 struct netlink_ext_ack *extack)
 {
@@ -883,8 +889,8 @@ static int parse_taprio_schedule(struct nlattr **tb,
                new->cycle_time = nla_get_s64(tb[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME]);
 
        if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST])
-               err = parse_sched_list(
-                       tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST], new, extack);
+               err = parse_sched_list(q, tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST],
+                                      new, extack);
        if (err < 0)
                return err;
 
@@ -1176,9 +1182,27 @@ static void taprio_offload_config_changed(struct taprio_sched *q)
        spin_unlock(&q->current_entry_lock);
 }
 
-static void taprio_sched_to_offload(struct taprio_sched *q,
+static u32 tc_map_to_queue_mask(struct net_device *dev, u32 tc_mask)
+{
+       u32 i, queue_mask = 0;
+
+       for (i = 0; i < dev->num_tc; i++) {
+               u32 offset, count;
+
+               if (!(tc_mask & BIT(i)))
+                       continue;
+
+               offset = dev->tc_to_txq[i].offset;
+               count = dev->tc_to_txq[i].count;
+
+               queue_mask |= GENMASK(offset + count - 1, offset);
+       }
+
+       return queue_mask;
+}
+
+static void taprio_sched_to_offload(struct net_device *dev,
                                    struct sched_gate_list *sched,
-                                   const struct tc_mqprio_qopt *mqprio,
                                    struct tc_taprio_qopt_offload *offload)
 {
        struct sched_entry *entry;
@@ -1193,7 +1217,8 @@ static void taprio_sched_to_offload(struct taprio_sched *q,
 
                e->command = entry->command;
                e->interval = entry->interval;
-               e->gate_mask = entry->gate_mask;
+               e->gate_mask = tc_map_to_queue_mask(dev, entry->gate_mask);
+
                i++;
        }
 
@@ -1201,7 +1226,6 @@ static void taprio_sched_to_offload(struct taprio_sched *q,
 }
 
 static int taprio_enable_offload(struct net_device *dev,
-                                struct tc_mqprio_qopt *mqprio,
                                 struct taprio_sched *q,
                                 struct sched_gate_list *sched,
                                 struct netlink_ext_ack *extack)
@@ -1223,7 +1247,7 @@ static int taprio_enable_offload(struct net_device *dev,
                return -ENOMEM;
        }
        offload->enable = 1;
-       taprio_sched_to_offload(q, sched, mqprio, offload);
+       taprio_sched_to_offload(dev, sched, offload);
 
        err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TAPRIO, offload);
        if (err < 0) {
@@ -1455,7 +1479,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
                goto free_sched;
        }
 
-       err = parse_taprio_schedule(tb, new_admin, extack);
+       err = parse_taprio_schedule(q, tb, new_admin, extack);
        if (err < 0)
                goto free_sched;
 
@@ -1485,7 +1509,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
        }
 
        if (FULL_OFFLOAD_IS_ENABLED(q->flags))
-               err = taprio_enable_offload(dev, mqprio, q, new_admin, extack);
+               err = taprio_enable_offload(dev, q, new_admin, extack);
        else
                err = taprio_disable_offload(dev, q, extack);
        if (err)
index 9e289c7..7e59d8a 100644 (file)
@@ -494,6 +494,7 @@ int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
 out_err:
        /* Clean up any successful allocations */
        sctp_auth_destroy_hmacs(ep->auth_hmacs);
+       ep->auth_hmacs = NULL;
        return -ENOMEM;
 }
 
index aea2a98..8a58f42 100644 (file)
@@ -875,7 +875,7 @@ static int sctp_inet6_af_supported(sa_family_t family, struct sctp_sock *sp)
        case AF_INET:
                if (!__ipv6_only_sock(sctp_opt2sk(sp)))
                        return 1;
-               /* fallthru */
+               fallthrough;
        default:
                return 0;
        }
index 577e3bc..3fd06a2 100644 (file)
@@ -912,7 +912,7 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
                case SCTP_CID_ABORT:
                        if (sctp_test_T_bit(chunk))
                                ctx->packet->vtag = ctx->asoc->c.my_vtag;
-                       /* fallthru */
+                       fallthrough;
 
                /* The following chunks are "response" chunks, i.e.
                 * they are generated in response to something we
@@ -927,7 +927,7 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
                case SCTP_CID_ECN_CWR:
                case SCTP_CID_ASCONF_ACK:
                        one_packet = 1;
-                       /* Fall through */
+                       fallthrough;
 
                case SCTP_CID_SACK:
                case SCTP_CID_HEARTBEAT:
@@ -1030,7 +1030,7 @@ static void sctp_outq_flush_data(struct sctp_flush_ctx *ctx,
                if (!ctx->packet || !ctx->packet->has_cookie_echo)
                        return;
 
-               /* fall through */
+               fallthrough;
        case SCTP_STATE_ESTABLISHED:
        case SCTP_STATE_SHUTDOWN_PENDING:
        case SCTP_STATE_SHUTDOWN_RECEIVED:
index 4791047..c11c245 100644 (file)
@@ -2077,7 +2077,7 @@ static enum sctp_ierror sctp_process_unk_param(
                break;
        case SCTP_PARAM_ACTION_DISCARD_ERR:
                retval =  SCTP_IERROR_ERROR;
-               /* Fall through */
+               fallthrough;
        case SCTP_PARAM_ACTION_SKIP_ERR:
                /* Make an ERROR chunk, preparing enough room for
                 * returning multiple unknown parameters.
index 9f36fe9..aa821e7 100644 (file)
@@ -1516,7 +1516,7 @@ static int sctp_cmd_interpreter(enum sctp_event_type event_type,
 
                        if (timer_pending(timer))
                                break;
-                       /* fall through */
+                       fallthrough;
 
                case SCTP_CMD_TIMER_START:
                        timer = &asoc->timers[cmd->obj.to];
index e86620f..c669f8b 100644 (file)
@@ -4315,7 +4315,7 @@ enum sctp_disposition sctp_sf_eat_auth(struct net *net,
                        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
                                        SCTP_CHUNK(err_chunk));
                }
-               /* Fall Through */
+               fallthrough;
        case SCTP_IERROR_AUTH_BAD_KEYID:
        case SCTP_IERROR_BAD_SIG:
                return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
index ec1fba1..53d0a41 100644 (file)
@@ -8060,8 +8060,6 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 
        pr_debug("%s: begins, snum:%d\n", __func__, snum);
 
-       local_bh_disable();
-
        if (snum == 0) {
                /* Search for an available port. */
                int low, high, remaining, index;
@@ -8079,20 +8077,21 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                                continue;
                        index = sctp_phashfn(net, rover);
                        head = &sctp_port_hashtable[index];
-                       spin_lock(&head->lock);
+                       spin_lock_bh(&head->lock);
                        sctp_for_each_hentry(pp, &head->chain)
                                if ((pp->port == rover) &&
                                    net_eq(net, pp->net))
                                        goto next;
                        break;
                next:
-                       spin_unlock(&head->lock);
+                       spin_unlock_bh(&head->lock);
+                       cond_resched();
                } while (--remaining > 0);
 
                /* Exhausted local port range during search? */
                ret = 1;
                if (remaining <= 0)
-                       goto fail;
+                       return ret;
 
                /* OK, here is the one we will use.  HEAD (the port
                 * hash table list entry) is non-NULL and we hold it's
@@ -8107,7 +8106,7 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                 * port iterator, pp being NULL.
                 */
                head = &sctp_port_hashtable[sctp_phashfn(net, snum)];
-               spin_lock(&head->lock);
+               spin_lock_bh(&head->lock);
                sctp_for_each_hentry(pp, &head->chain) {
                        if ((pp->port == snum) && net_eq(pp->net, net))
                                goto pp_found;
@@ -8207,10 +8206,7 @@ success:
        ret = 0;
 
 fail_unlock:
-       spin_unlock(&head->lock);
-
-fail:
-       local_bh_enable();
+       spin_unlock_bh(&head->lock);
        return ret;
 }
 
@@ -9224,13 +9220,10 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
 static inline void sctp_copy_descendant(struct sock *sk_to,
                                        const struct sock *sk_from)
 {
-       int ancestor_size = sizeof(struct inet_sock) +
-                           sizeof(struct sctp_sock) -
-                           offsetof(struct sctp_sock, pd_lobby);
-
-       if (sk_from->sk_family == PF_INET6)
-               ancestor_size += sizeof(struct ipv6_pinfo);
+       size_t ancestor_size = sizeof(struct inet_sock);
 
+       ancestor_size += sk_from->sk_prot->obj_size;
+       ancestor_size -= offsetof(struct sctp_sock, pd_lobby);
        __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size);
 }
 
index 290270c..0e7409e 100644 (file)
@@ -116,7 +116,6 @@ static void smc_close_cancel_work(struct smc_sock *smc)
        cancel_work_sync(&smc->conn.close_work);
        cancel_delayed_work_sync(&smc->conn.tx_work);
        lock_sock(sk);
-       sk->sk_state = SMC_CLOSED;
 }
 
 /* terminate smc socket abnormally - active abort
@@ -134,22 +133,22 @@ void smc_close_active_abort(struct smc_sock *smc)
        }
        switch (sk->sk_state) {
        case SMC_ACTIVE:
-               sk->sk_state = SMC_PEERABORTWAIT;
-               smc_close_cancel_work(smc);
-               sk->sk_state = SMC_CLOSED;
-               sock_put(sk); /* passive closing */
-               break;
        case SMC_APPCLOSEWAIT1:
        case SMC_APPCLOSEWAIT2:
+               sk->sk_state = SMC_PEERABORTWAIT;
                smc_close_cancel_work(smc);
+               if (sk->sk_state != SMC_PEERABORTWAIT)
+                       break;
                sk->sk_state = SMC_CLOSED;
-               sock_put(sk); /* postponed passive closing */
+               sock_put(sk); /* (postponed) passive closing */
                break;
        case SMC_PEERCLOSEWAIT1:
        case SMC_PEERCLOSEWAIT2:
        case SMC_PEERFINCLOSEWAIT:
                sk->sk_state = SMC_PEERABORTWAIT;
                smc_close_cancel_work(smc);
+               if (sk->sk_state != SMC_PEERABORTWAIT)
+                       break;
                sk->sk_state = SMC_CLOSED;
                smc_conn_free(&smc->conn);
                release_clcsock = true;
@@ -159,6 +158,8 @@ void smc_close_active_abort(struct smc_sock *smc)
        case SMC_APPFINCLOSEWAIT:
                sk->sk_state = SMC_PEERABORTWAIT;
                smc_close_cancel_work(smc);
+               if (sk->sk_state != SMC_PEERABORTWAIT)
+                       break;
                sk->sk_state = SMC_CLOSED;
                smc_conn_free(&smc->conn);
                release_clcsock = true;
@@ -372,7 +373,7 @@ static void smc_close_passive_work(struct work_struct *work)
        case SMC_PEERCLOSEWAIT1:
                if (rxflags->peer_done_writing)
                        sk->sk_state = SMC_PEERCLOSEWAIT2;
-               /* fall through */
+               fallthrough;
                /* to check for closing */
        case SMC_PEERCLOSEWAIT2:
                if (!smc_cdc_rxed_any_close(conn))
index b42fa3b..a406627 100644 (file)
@@ -1356,6 +1356,8 @@ create:
        if (ini->is_smcd) {
                conn->rx_off = sizeof(struct smcd_cdc_msg);
                smcd_cdc_rx_init(conn); /* init tasklet for this conn */
+       } else {
+               conn->rx_off = 0;
        }
 #ifndef KERNEL_HAS_ATOMIC64
        spin_lock_init(&conn->acurs_lock);
@@ -1777,6 +1779,7 @@ int smc_buf_create(struct smc_sock *smc, bool is_smcd)
                list_del(&smc->conn.sndbuf_desc->list);
                mutex_unlock(&smc->conn.lgr->sndbufs_lock);
                smc_buf_free(smc->conn.lgr, false, smc->conn.sndbuf_desc);
+               smc->conn.sndbuf_desc = NULL;
        }
        return rc;
 }
index df5b0a6..3ea3346 100644 (file)
@@ -841,6 +841,9 @@ int smc_llc_cli_add_link(struct smc_link *link, struct smc_llc_qentry *qentry)
        struct smc_init_info ini;
        int lnk_idx, rc = 0;
 
+       if (!llc->qp_mtu)
+               goto out_reject;
+
        ini.vlan_id = lgr->vlan_id;
        smc_pnet_find_alt_roce(lgr, &ini, link->smcibdev);
        if (!memcmp(llc->sender_gid, link->peer_gid, SMC_GID_SIZE) &&
@@ -917,10 +920,20 @@ out:
        kfree(qentry);
 }
 
+static bool smc_llc_is_empty_llc_message(union smc_llc_msg *llc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(llc->raw.data); i++)
+               if (llc->raw.data[i])
+                       return false;
+       return true;
+}
+
 static bool smc_llc_is_local_add_link(union smc_llc_msg *llc)
 {
        if (llc->raw.hdr.common.type == SMC_LLC_ADD_LINK &&
-           !llc->add_link.qp_mtu && !llc->add_link.link_num)
+           smc_llc_is_empty_llc_message(llc))
                return true;
        return false;
 }
index dbbe8ea..58cac2d 100644 (file)
@@ -3610,7 +3610,7 @@ int kernel_getsockname(struct socket *sock, struct sockaddr *addr)
 EXPORT_SYMBOL(kernel_getsockname);
 
 /**
- *     kernel_peername - get the address which the socket is connected (kernel space)
+ *     kernel_getpeername - get the address which the socket is connected (kernel space)
  *     @sock: socket
  *     @addr: address holder
  *
@@ -3638,9 +3638,11 @@ EXPORT_SYMBOL(kernel_getpeername);
 int kernel_sendpage(struct socket *sock, struct page *page, int offset,
                    size_t size, int flags)
 {
-       if (sock->ops->sendpage)
+       if (sock->ops->sendpage) {
+               /* Warn in case the improper page to zero-copy send */
+               WARN_ONCE(!sendpage_ok(page), "improper page for zero-copy send");
                return sock->ops->sendpage(sock, page, offset, size, flags);
-
+       }
        return sock_no_sendpage(sock, page, offset, size, flags);
 }
 EXPORT_SYMBOL(kernel_sendpage);
@@ -3671,7 +3673,7 @@ int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset,
 EXPORT_SYMBOL(kernel_sendpage_locked);
 
 /**
- *     kernel_shutdown - shut down part of a full-duplex connection (kernel space)
+ *     kernel_sock_shutdown - shut down part of a full-duplex connection (kernel space)
  *     @sock: socket
  *     @how: connection part
  *
index 3bcf985..bbbb5af 100644 (file)
@@ -21,7 +21,6 @@ config RPCSEC_GSS_KRB5
        depends on SUNRPC && CRYPTO
        depends on CRYPTO_MD5 && CRYPTO_DES && CRYPTO_CBC && CRYPTO_CTS
        depends on CRYPTO_ECB && CRYPTO_HMAC && CRYPTO_SHA1 && CRYPTO_AES
-       depends on CRYPTO_ARC4
        default y
        select SUNRPC_GSS
        help
index 794fb30..634b6c6 100644 (file)
@@ -138,135 +138,6 @@ checksummer(struct scatterlist *sg, void *data)
        return crypto_ahash_update(req);
 }
 
-static int
-arcfour_hmac_md5_usage_to_salt(unsigned int usage, u8 salt[4])
-{
-       unsigned int ms_usage;
-
-       switch (usage) {
-       case KG_USAGE_SIGN:
-               ms_usage = 15;
-               break;
-       case KG_USAGE_SEAL:
-               ms_usage = 13;
-               break;
-       default:
-               return -EINVAL;
-       }
-       salt[0] = (ms_usage >> 0) & 0xff;
-       salt[1] = (ms_usage >> 8) & 0xff;
-       salt[2] = (ms_usage >> 16) & 0xff;
-       salt[3] = (ms_usage >> 24) & 0xff;
-
-       return 0;
-}
-
-static u32
-make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen,
-                      struct xdr_buf *body, int body_offset, u8 *cksumkey,
-                      unsigned int usage, struct xdr_netobj *cksumout)
-{
-       struct scatterlist              sg[1];
-       int err = -1;
-       u8 *checksumdata;
-       u8 *rc4salt;
-       struct crypto_ahash *md5;
-       struct crypto_ahash *hmac_md5;
-       struct ahash_request *req;
-
-       if (cksumkey == NULL)
-               return GSS_S_FAILURE;
-
-       if (cksumout->len < kctx->gk5e->cksumlength) {
-               dprintk("%s: checksum buffer length, %u, too small for %s\n",
-                       __func__, cksumout->len, kctx->gk5e->name);
-               return GSS_S_FAILURE;
-       }
-
-       rc4salt = kmalloc_array(4, sizeof(*rc4salt), GFP_NOFS);
-       if (!rc4salt)
-               return GSS_S_FAILURE;
-
-       if (arcfour_hmac_md5_usage_to_salt(usage, rc4salt)) {
-               dprintk("%s: invalid usage value %u\n", __func__, usage);
-               goto out_free_rc4salt;
-       }
-
-       checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS);
-       if (!checksumdata)
-               goto out_free_rc4salt;
-
-       md5 = crypto_alloc_ahash("md5", 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(md5))
-               goto out_free_cksum;
-
-       hmac_md5 = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0,
-                                     CRYPTO_ALG_ASYNC);
-       if (IS_ERR(hmac_md5))
-               goto out_free_md5;
-
-       req = ahash_request_alloc(md5, GFP_NOFS);
-       if (!req)
-               goto out_free_hmac_md5;
-
-       ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
-
-       err = crypto_ahash_init(req);
-       if (err)
-               goto out;
-       sg_init_one(sg, rc4salt, 4);
-       ahash_request_set_crypt(req, sg, NULL, 4);
-       err = crypto_ahash_update(req);
-       if (err)
-               goto out;
-
-       sg_init_one(sg, header, hdrlen);
-       ahash_request_set_crypt(req, sg, NULL, hdrlen);
-       err = crypto_ahash_update(req);
-       if (err)
-               goto out;
-       err = xdr_process_buf(body, body_offset, body->len - body_offset,
-                             checksummer, req);
-       if (err)
-               goto out;
-       ahash_request_set_crypt(req, NULL, checksumdata, 0);
-       err = crypto_ahash_final(req);
-       if (err)
-               goto out;
-
-       ahash_request_free(req);
-       req = ahash_request_alloc(hmac_md5, GFP_NOFS);
-       if (!req)
-               goto out_free_hmac_md5;
-
-       ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
-
-       err = crypto_ahash_setkey(hmac_md5, cksumkey, kctx->gk5e->keylength);
-       if (err)
-               goto out;
-
-       sg_init_one(sg, checksumdata, crypto_ahash_digestsize(md5));
-       ahash_request_set_crypt(req, sg, checksumdata,
-                               crypto_ahash_digestsize(md5));
-       err = crypto_ahash_digest(req);
-       if (err)
-               goto out;
-
-       memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength);
-       cksumout->len = kctx->gk5e->cksumlength;
-out:
-       ahash_request_free(req);
-out_free_hmac_md5:
-       crypto_free_ahash(hmac_md5);
-out_free_md5:
-       crypto_free_ahash(md5);
-out_free_cksum:
-       kfree(checksumdata);
-out_free_rc4salt:
-       kfree(rc4salt);
-       return err ? GSS_S_FAILURE : 0;
-}
-
 /*
  * checksum the plaintext data and hdrlen bytes of the token header
  * The checksum is performed over the first 8 bytes of the
@@ -284,11 +155,6 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
        u8 *checksumdata;
        unsigned int checksumlen;
 
-       if (kctx->gk5e->ctype == CKSUMTYPE_HMAC_MD5_ARCFOUR)
-               return make_checksum_hmac_md5(kctx, header, hdrlen,
-                                             body, body_offset,
-                                             cksumkey, usage, cksumout);
-
        if (cksumout->len < kctx->gk5e->cksumlength) {
                dprintk("%s: checksum buffer length, %u, too small for %s\n",
                        __func__, cksumout->len, kctx->gk5e->name);
@@ -942,145 +808,3 @@ out_err:
                ret = GSS_S_FAILURE;
        return ret;
 }
-
-/*
- * Compute Kseq given the initial session key and the checksum.
- * Set the key of the given cipher.
- */
-int
-krb5_rc4_setup_seq_key(struct krb5_ctx *kctx,
-                      struct crypto_sync_skcipher *cipher,
-                      unsigned char *cksum)
-{
-       struct crypto_shash *hmac;
-       struct shash_desc *desc;
-       u8 Kseq[GSS_KRB5_MAX_KEYLEN];
-       u32 zeroconstant = 0;
-       int err;
-
-       dprintk("%s: entered\n", __func__);
-
-       hmac = crypto_alloc_shash(kctx->gk5e->cksum_name, 0, 0);
-       if (IS_ERR(hmac)) {
-               dprintk("%s: error %ld, allocating hash '%s'\n",
-                       __func__, PTR_ERR(hmac), kctx->gk5e->cksum_name);
-               return PTR_ERR(hmac);
-       }
-
-       desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac),
-                      GFP_NOFS);
-       if (!desc) {
-               dprintk("%s: failed to allocate shash descriptor for '%s'\n",
-                       __func__, kctx->gk5e->cksum_name);
-               crypto_free_shash(hmac);
-               return -ENOMEM;
-       }
-
-       desc->tfm = hmac;
-
-       /* Compute intermediate Kseq from session key */
-       err = crypto_shash_setkey(hmac, kctx->Ksess, kctx->gk5e->keylength);
-       if (err)
-               goto out_err;
-
-       err = crypto_shash_digest(desc, (u8 *)&zeroconstant, 4, Kseq);
-       if (err)
-               goto out_err;
-
-       /* Compute final Kseq from the checksum and intermediate Kseq */
-       err = crypto_shash_setkey(hmac, Kseq, kctx->gk5e->keylength);
-       if (err)
-               goto out_err;
-
-       err = crypto_shash_digest(desc, cksum, 8, Kseq);
-       if (err)
-               goto out_err;
-
-       err = crypto_sync_skcipher_setkey(cipher, Kseq, kctx->gk5e->keylength);
-       if (err)
-               goto out_err;
-
-       err = 0;
-
-out_err:
-       kfree_sensitive(desc);
-       crypto_free_shash(hmac);
-       dprintk("%s: returning %d\n", __func__, err);
-       return err;
-}
-
-/*
- * Compute Kcrypt given the initial session key and the plaintext seqnum.
- * Set the key of cipher kctx->enc.
- */
-int
-krb5_rc4_setup_enc_key(struct krb5_ctx *kctx,
-                      struct crypto_sync_skcipher *cipher,
-                      s32 seqnum)
-{
-       struct crypto_shash *hmac;
-       struct shash_desc *desc;
-       u8 Kcrypt[GSS_KRB5_MAX_KEYLEN];
-       u8 zeroconstant[4] = {0};
-       u8 seqnumarray[4];
-       int err, i;
-
-       dprintk("%s: entered, seqnum %u\n", __func__, seqnum);
-
-       hmac = crypto_alloc_shash(kctx->gk5e->cksum_name, 0, 0);
-       if (IS_ERR(hmac)) {
-               dprintk("%s: error %ld, allocating hash '%s'\n",
-                       __func__, PTR_ERR(hmac), kctx->gk5e->cksum_name);
-               return PTR_ERR(hmac);
-       }
-
-       desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac),
-                      GFP_NOFS);
-       if (!desc) {
-               dprintk("%s: failed to allocate shash descriptor for '%s'\n",
-                       __func__, kctx->gk5e->cksum_name);
-               crypto_free_shash(hmac);
-               return -ENOMEM;
-       }
-
-       desc->tfm = hmac;
-
-       /* Compute intermediate Kcrypt from session key */
-       for (i = 0; i < kctx->gk5e->keylength; i++)
-               Kcrypt[i] = kctx->Ksess[i] ^ 0xf0;
-
-       err = crypto_shash_setkey(hmac, Kcrypt, kctx->gk5e->keylength);
-       if (err)
-               goto out_err;
-
-       err = crypto_shash_digest(desc, zeroconstant, 4, Kcrypt);
-       if (err)
-               goto out_err;
-
-       /* Compute final Kcrypt from the seqnum and intermediate Kcrypt */
-       err = crypto_shash_setkey(hmac, Kcrypt, kctx->gk5e->keylength);
-       if (err)
-               goto out_err;
-
-       seqnumarray[0] = (unsigned char) ((seqnum >> 24) & 0xff);
-       seqnumarray[1] = (unsigned char) ((seqnum >> 16) & 0xff);
-       seqnumarray[2] = (unsigned char) ((seqnum >> 8) & 0xff);
-       seqnumarray[3] = (unsigned char) ((seqnum >> 0) & 0xff);
-
-       err = crypto_shash_digest(desc, seqnumarray, 4, Kcrypt);
-       if (err)
-               goto out_err;
-
-       err = crypto_sync_skcipher_setkey(cipher, Kcrypt,
-                                         kctx->gk5e->keylength);
-       if (err)
-               goto out_err;
-
-       err = 0;
-
-out_err:
-       kfree_sensitive(desc);
-       crypto_free_shash(hmac);
-       dprintk("%s: returning %d\n", __func__, err);
-       return err;
-}
index a84a5b2..ae9acf3 100644 (file)
@@ -52,27 +52,6 @@ static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
        },
 #endif /* CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES */
        /*
-        * RC4-HMAC
-        */
-       {
-         .etype = ENCTYPE_ARCFOUR_HMAC,
-         .ctype = CKSUMTYPE_HMAC_MD5_ARCFOUR,
-         .name = "rc4-hmac",
-         .encrypt_name = "ecb(arc4)",
-         .cksum_name = "hmac(md5)",
-         .encrypt = krb5_encrypt,
-         .decrypt = krb5_decrypt,
-         .mk_key = NULL,
-         .signalg = SGN_ALG_HMAC_MD5,
-         .sealalg = SEAL_ALG_MICROSOFT_RC4,
-         .keybytes = 16,
-         .keylength = 16,
-         .blocksize = 1,
-         .conflen = 8,
-         .cksumlength = 8,
-         .keyed_cksum = 1,
-       },
-       /*
         * 3DES
         */
        {
@@ -401,78 +380,6 @@ out_err:
        return -EINVAL;
 }
 
-/*
- * Note that RC4 depends on deriving keys using the sequence
- * number or the checksum of a token.  Therefore, the final keys
- * cannot be calculated until the token is being constructed!
- */
-static int
-context_derive_keys_rc4(struct krb5_ctx *ctx)
-{
-       struct crypto_shash *hmac;
-       char sigkeyconstant[] = "signaturekey";
-       int slen = strlen(sigkeyconstant) + 1;  /* include null terminator */
-       struct shash_desc *desc;
-       int err;
-
-       dprintk("RPC:       %s: entered\n", __func__);
-       /*
-        * derive cksum (aka Ksign) key
-        */
-       hmac = crypto_alloc_shash(ctx->gk5e->cksum_name, 0, 0);
-       if (IS_ERR(hmac)) {
-               dprintk("%s: error %ld allocating hash '%s'\n",
-                       __func__, PTR_ERR(hmac), ctx->gk5e->cksum_name);
-               err = PTR_ERR(hmac);
-               goto out_err;
-       }
-
-       err = crypto_shash_setkey(hmac, ctx->Ksess, ctx->gk5e->keylength);
-       if (err)
-               goto out_err_free_hmac;
-
-
-       desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac), GFP_NOFS);
-       if (!desc) {
-               dprintk("%s: failed to allocate hash descriptor for '%s'\n",
-                       __func__, ctx->gk5e->cksum_name);
-               err = -ENOMEM;
-               goto out_err_free_hmac;
-       }
-
-       desc->tfm = hmac;
-
-       err = crypto_shash_digest(desc, sigkeyconstant, slen, ctx->cksum);
-       kfree_sensitive(desc);
-       if (err)
-               goto out_err_free_hmac;
-       /*
-        * allocate hash, and skciphers for data and seqnum encryption
-        */
-       ctx->enc = crypto_alloc_sync_skcipher(ctx->gk5e->encrypt_name, 0, 0);
-       if (IS_ERR(ctx->enc)) {
-               err = PTR_ERR(ctx->enc);
-               goto out_err_free_hmac;
-       }
-
-       ctx->seq = crypto_alloc_sync_skcipher(ctx->gk5e->encrypt_name, 0, 0);
-       if (IS_ERR(ctx->seq)) {
-               crypto_free_sync_skcipher(ctx->enc);
-               err = PTR_ERR(ctx->seq);
-               goto out_err_free_hmac;
-       }
-
-       dprintk("RPC:       %s: returning success\n", __func__);
-
-       err = 0;
-
-out_err_free_hmac:
-       crypto_free_shash(hmac);
-out_err:
-       dprintk("RPC:       %s: returning %d\n", __func__, err);
-       return err;
-}
-
 static int
 context_derive_keys_new(struct krb5_ctx *ctx, gfp_t gfp_mask)
 {
@@ -649,8 +556,6 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx,
        switch (ctx->enctype) {
        case ENCTYPE_DES3_CBC_RAW:
                return context_derive_keys_des3(ctx, gfp_mask);
-       case ENCTYPE_ARCFOUR_HMAC:
-               return context_derive_keys_rc4(ctx);
        case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
        case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
                return context_derive_keys_new(ctx, gfp_mask);
index f1d280a..3306141 100644 (file)
@@ -214,7 +214,6 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
                BUG();
        case ENCTYPE_DES_CBC_RAW:
        case ENCTYPE_DES3_CBC_RAW:
-       case ENCTYPE_ARCFOUR_HMAC:
                return gss_get_mic_v1(ctx, text, token);
        case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
        case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
index 5071051..fb11781 100644 (file)
 # define RPCDBG_FACILITY        RPCDBG_AUTH
 #endif
 
-static s32
-krb5_make_rc4_seq_num(struct krb5_ctx *kctx, int direction, s32 seqnum,
-                     unsigned char *cksum, unsigned char *buf)
-{
-       struct crypto_sync_skcipher *cipher;
-       unsigned char *plain;
-       s32 code;
-
-       dprintk("RPC:       %s:\n", __func__);
-       cipher = crypto_alloc_sync_skcipher(kctx->gk5e->encrypt_name, 0, 0);
-       if (IS_ERR(cipher))
-               return PTR_ERR(cipher);
-
-       plain = kmalloc(8, GFP_NOFS);
-       if (!plain)
-               return -ENOMEM;
-
-       plain[0] = (unsigned char) ((seqnum >> 24) & 0xff);
-       plain[1] = (unsigned char) ((seqnum >> 16) & 0xff);
-       plain[2] = (unsigned char) ((seqnum >> 8) & 0xff);
-       plain[3] = (unsigned char) ((seqnum >> 0) & 0xff);
-       plain[4] = direction;
-       plain[5] = direction;
-       plain[6] = direction;
-       plain[7] = direction;
-
-       code = krb5_rc4_setup_seq_key(kctx, cipher, cksum);
-       if (code)
-               goto out;
-
-       code = krb5_encrypt(cipher, cksum, plain, buf, 8);
-out:
-       kfree(plain);
-       crypto_free_sync_skcipher(cipher);
-       return code;
-}
 s32
 krb5_make_seq_num(struct krb5_ctx *kctx,
                struct crypto_sync_skcipher *key,
@@ -85,10 +49,6 @@ krb5_make_seq_num(struct krb5_ctx *kctx,
        unsigned char *plain;
        s32 code;
 
-       if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC)
-               return krb5_make_rc4_seq_num(kctx, direction, seqnum,
-                                            cksum, buf);
-
        plain = kmalloc(8, GFP_NOFS);
        if (!plain)
                return -ENOMEM;
@@ -108,50 +68,6 @@ krb5_make_seq_num(struct krb5_ctx *kctx,
        return code;
 }
 
-static s32
-krb5_get_rc4_seq_num(struct krb5_ctx *kctx, unsigned char *cksum,
-                    unsigned char *buf, int *direction, s32 *seqnum)
-{
-       struct crypto_sync_skcipher *cipher;
-       unsigned char *plain;
-       s32 code;
-
-       dprintk("RPC:       %s:\n", __func__);
-       cipher = crypto_alloc_sync_skcipher(kctx->gk5e->encrypt_name, 0, 0);
-       if (IS_ERR(cipher))
-               return PTR_ERR(cipher);
-
-       code = krb5_rc4_setup_seq_key(kctx, cipher, cksum);
-       if (code)
-               goto out;
-
-       plain = kmalloc(8, GFP_NOFS);
-       if (!plain) {
-               code = -ENOMEM;
-               goto out;
-       }
-
-       code = krb5_decrypt(cipher, cksum, buf, plain, 8);
-       if (code)
-               goto out_plain;
-
-       if ((plain[4] != plain[5]) || (plain[4] != plain[6])
-                                  || (plain[4] != plain[7])) {
-               code = (s32)KG_BAD_SEQ;
-               goto out_plain;
-       }
-
-       *direction = plain[4];
-
-       *seqnum = ((plain[0] << 24) | (plain[1] << 16) |
-                                       (plain[2] << 8) | (plain[3]));
-out_plain:
-       kfree(plain);
-out:
-       crypto_free_sync_skcipher(cipher);
-       return code;
-}
-
 s32
 krb5_get_seq_num(struct krb5_ctx *kctx,
               unsigned char *cksum,
@@ -164,9 +80,6 @@ krb5_get_seq_num(struct krb5_ctx *kctx,
 
        dprintk("RPC:       krb5_get_seq_num:\n");
 
-       if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC)
-               return krb5_get_rc4_seq_num(kctx, cksum, buf,
-                                           direction, seqnum);
        plain = kmalloc(8, GFP_NOFS);
        if (!plain)
                return -ENOMEM;
index aaab91c..ba04e3e 100644 (file)
@@ -218,7 +218,6 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
                BUG();
        case ENCTYPE_DES_CBC_RAW:
        case ENCTYPE_DES3_CBC_RAW:
-       case ENCTYPE_ARCFOUR_HMAC:
                return gss_verify_mic_v1(ctx, message_buffer, read_token);
        case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
        case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
index 90b8329..e95c009 100644 (file)
@@ -137,7 +137,7 @@ gss_krb5_make_confounder(char *p, u32 conflen)
        switch (conflen) {
        case 16:
                *q++ = i++;
-               /* fall through */
+               fallthrough;
        case 8:
                *q++ = i++;
                break;
@@ -236,26 +236,9 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
                               seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8)))
                return GSS_S_FAILURE;
 
-       if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) {
-               struct crypto_sync_skcipher *cipher;
-               int err;
-               cipher = crypto_alloc_sync_skcipher(kctx->gk5e->encrypt_name,
-                                                   0, 0);
-               if (IS_ERR(cipher))
-                       return GSS_S_FAILURE;
-
-               krb5_rc4_setup_enc_key(kctx, cipher, seq_send);
-
-               err = gss_encrypt_xdr_buf(cipher, buf,
-                                         offset + headlen - conflen, pages);
-               crypto_free_sync_skcipher(cipher);
-               if (err)
-                       return GSS_S_FAILURE;
-       } else {
-               if (gss_encrypt_xdr_buf(kctx->enc, buf,
-                                       offset + headlen - conflen, pages))
-                       return GSS_S_FAILURE;
-       }
+       if (gss_encrypt_xdr_buf(kctx->enc, buf,
+                               offset + headlen - conflen, pages))
+               return GSS_S_FAILURE;
 
        return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
 }
@@ -316,37 +299,9 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, int len,
        crypt_offset = ptr + (GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength) -
                                        (unsigned char *)buf->head[0].iov_base;
 
-       /*
-        * Need plaintext seqnum to derive encryption key for arcfour-hmac
-        */
-       if (krb5_get_seq_num(kctx, ptr + GSS_KRB5_TOK_HDR_LEN,
-                            ptr + 8, &direction, &seqnum))
-               return GSS_S_BAD_SIG;
-
-       if ((kctx->initiate && direction != 0xff) ||
-           (!kctx->initiate && direction != 0))
-               return GSS_S_BAD_SIG;
-
        buf->len = len;
-       if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) {
-               struct crypto_sync_skcipher *cipher;
-               int err;
-
-               cipher = crypto_alloc_sync_skcipher(kctx->gk5e->encrypt_name,
-                                                   0, 0);
-               if (IS_ERR(cipher))
-                       return GSS_S_FAILURE;
-
-               krb5_rc4_setup_enc_key(kctx, cipher, seqnum);
-
-               err = gss_decrypt_xdr_buf(cipher, buf, crypt_offset);
-               crypto_free_sync_skcipher(cipher);
-               if (err)
-                       return GSS_S_DEFECTIVE_TOKEN;
-       } else {
-               if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset))
-                       return GSS_S_DEFECTIVE_TOKEN;
-       }
+       if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset))
+               return GSS_S_DEFECTIVE_TOKEN;
 
        if (kctx->gk5e->keyed_cksum)
                cksumkey = kctx->cksum;
@@ -370,6 +325,14 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, int len,
 
        /* do sequencing checks */
 
+       if (krb5_get_seq_num(kctx, ptr + GSS_KRB5_TOK_HDR_LEN,
+                            ptr + 8, &direction, &seqnum))
+               return GSS_S_BAD_SIG;
+
+       if ((kctx->initiate && direction != 0xff) ||
+           (!kctx->initiate && direction != 0))
+               return GSS_S_BAD_SIG;
+
        /* Copy the data back to the right position.  XXX: Would probably be
         * better to copy and encrypt at the same time. */
 
@@ -605,7 +568,6 @@ gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
                BUG();
        case ENCTYPE_DES_CBC_RAW:
        case ENCTYPE_DES3_CBC_RAW:
-       case ENCTYPE_ARCFOUR_HMAC:
                return gss_wrap_kerberos_v1(kctx, offset, buf, pages);
        case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
        case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
@@ -624,7 +586,6 @@ gss_unwrap_kerberos(struct gss_ctx *gctx, int offset,
                BUG();
        case ENCTYPE_DES_CBC_RAW:
        case ENCTYPE_DES3_CBC_RAW:
-       case ENCTYPE_ARCFOUR_HMAC:
                return gss_unwrap_kerberos_v1(kctx, offset, len, buf,
                                              &gctx->slack, &gctx->align);
        case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
index d26036a..76685ab 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/sunrpc/svc_xprt.h>
 #include <linux/sunrpc/auth_gss.h>
 #include <linux/sunrpc/gss_err.h>
-#include <linux/sunrpc/auth_gss.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/rpcgss.h>
index a91d1cd..62e0b6c 100644 (file)
@@ -1702,7 +1702,7 @@ call_reserveresult(struct rpc_task *task)
        switch (status) {
        case -ENOMEM:
                rpc_delay(task, HZ >> 2);
-               /* fall through */
+               fallthrough;
        case -EAGAIN:   /* woken up; retry */
                task->tk_action = call_retry_reserve;
                return;
@@ -1759,13 +1759,13 @@ call_refreshresult(struct rpc_task *task)
                /* Use rate-limiting and a max number of retries if refresh
                 * had status 0 but failed to update the cred.
                 */
-               /* fall through */
+               fallthrough;
        case -ETIMEDOUT:
                rpc_delay(task, 3*HZ);
-               /* fall through */
+               fallthrough;
        case -EAGAIN:
                status = -EACCES;
-               /* fall through */
+               fallthrough;
        case -EKEYEXPIRED:
                if (!task->tk_cred_retry)
                        break;
@@ -2132,7 +2132,7 @@ call_connect_status(struct rpc_task *task)
                        rpc_force_rebind(clnt);
                        goto out_retry;
                }
-               /* fall through */
+               fallthrough;
        case -ECONNRESET:
        case -ECONNABORTED:
        case -ENETDOWN:
@@ -2146,7 +2146,7 @@ call_connect_status(struct rpc_task *task)
                        break;
                /* retry with existing socket, after a delay */
                rpc_delay(task, 3*HZ);
-               /* fall through */
+               fallthrough;
        case -EADDRINUSE:
        case -ENOTCONN:
        case -EAGAIN:
@@ -2228,7 +2228,7 @@ call_transmit_status(struct rpc_task *task)
                 */
        case -ENOBUFS:
                rpc_delay(task, HZ>>2);
-               /* fall through */
+               fallthrough;
        case -EBADSLT:
        case -EAGAIN:
                task->tk_action = call_transmit;
@@ -2247,7 +2247,7 @@ call_transmit_status(struct rpc_task *task)
                        rpc_call_rpcerror(task, task->tk_status);
                        return;
                }
-               /* fall through */
+               fallthrough;
        case -ECONNRESET:
        case -ECONNABORTED:
        case -EADDRINUSE:
@@ -2313,7 +2313,7 @@ call_bc_transmit_status(struct rpc_task *task)
                break;
        case -ENOBUFS:
                rpc_delay(task, HZ>>2);
-               /* fall through */
+               fallthrough;
        case -EBADSLT:
        case -EAGAIN:
                task->tk_status = 0;
@@ -2380,7 +2380,7 @@ call_status(struct rpc_task *task)
                 * were a timeout.
                 */
                rpc_delay(task, 3*HZ);
-               /* fall through */
+               fallthrough;
        case -ETIMEDOUT:
                break;
        case -ECONNREFUSED:
@@ -2391,7 +2391,7 @@ call_status(struct rpc_task *task)
                break;
        case -EADDRINUSE:
                rpc_delay(task, 3*HZ);
-               /* fall through */
+               fallthrough;
        case -EPIPE:
        case -EAGAIN:
                break;
index c27123e..4a67685 100644 (file)
@@ -982,8 +982,8 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
        p = xdr_inline_decode(xdr, len);
        if (unlikely(p == NULL))
                goto out_fail;
-       dprintk("RPC: %5u RPCB_%s reply: %s\n", req->rq_task->tk_pid,
-                       req->rq_task->tk_msg.rpc_proc->p_name, (char *)p);
+       dprintk("RPC: %5u RPCB_%s reply: %*pE\n", req->rq_task->tk_pid,
+                       req->rq_task->tk_msg.rpc_proc->p_name, len, (char *)p);
 
        if (rpc_uaddr2sockaddr(req->rq_xprt->xprt_net, (char *)p, len,
                                sap, sizeof(address)) == 0)
index 3fc8af8..d52313a 100644 (file)
@@ -70,7 +70,7 @@ static size_t xdr_skb_read_and_csum_bits(struct xdr_skb_reader *desc, void *to,
        if (len > desc->count)
                len = desc->count;
        pos = desc->offset;
-       csum2 = skb_copy_and_csum_bits(desc->skb, pos, to, len, 0);
+       csum2 = skb_copy_and_csum_bits(desc->skb, pos, to, len);
        desc->csum = csum_block_add(desc->csum, csum2, pos);
        desc->count -= len;
        desc->offset += len;
index d5805fa..c2752e2 100644 (file)
@@ -228,7 +228,7 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
 static void svc_flush_bvec(const struct bio_vec *bvec, size_t size, size_t seek)
 {
        struct bvec_iter bi = {
-               .bi_size        = size,
+               .bi_size        = size + seek,
        };
        struct bio_vec bv;
 
index 6ba9d58..5a8e47b 100644 (file)
@@ -1623,7 +1623,7 @@ void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
        case -EAGAIN:
                xprt_add_backlog(xprt, task);
                dprintk("RPC:       waiting for request slot\n");
-               /* fall through */
+               fallthrough;
        default:
                task->tk_status = -EAGAIN;
        }
index 75c6467..ad6e2e4 100644 (file)
@@ -268,7 +268,7 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
        case RDMA_CM_EVENT_DEVICE_REMOVAL:
                pr_info("rpcrdma: removing device %s for %pISpc\n",
                        ep->re_id->device->name, sap);
-               /* fall through */
+               fallthrough;
        case RDMA_CM_EVENT_ADDR_CHANGE:
                ep->re_connect_status = -ENODEV;
                goto disconnected;
@@ -933,6 +933,8 @@ static void rpcrdma_req_reset(struct rpcrdma_req *req)
 
        rpcrdma_regbuf_dma_unmap(req->rl_sendbuf);
        rpcrdma_regbuf_dma_unmap(req->rl_recvbuf);
+
+       frwr_reset(req);
 }
 
 /* ASSUMPTION: the rb_allreqs list is stable for the duration,
index c57aef8..554e1bb 100644 (file)
@@ -885,7 +885,7 @@ static int xs_local_send_request(struct rpc_rqst *req)
        default:
                dprintk("RPC:       sendmsg returned unrecognized error %d\n",
                        -status);
-               /* fall through */
+               fallthrough;
        case -EPIPE:
                xs_close(xprt);
                status = -ENOTCONN;
@@ -1436,7 +1436,7 @@ static void xs_tcp_state_change(struct sock *sk)
                xprt->connect_cookie++;
                clear_bit(XPRT_CONNECTED, &xprt->state);
                xs_run_error_worker(transport, XPRT_SOCK_WAKE_DISCONNECT);
-               /* fall through */
+               fallthrough;
        case TCP_CLOSING:
                /*
                 * If the server closed down the connection, make sure that
@@ -2202,7 +2202,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
        switch (ret) {
        case 0:
                xs_set_srcport(transport, sock);
-               /* fall through */
+               fallthrough;
        case -EINPROGRESS:
                /* SYN_SENT! */
                if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO)
@@ -2255,7 +2255,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
        default:
                printk("%s: connect returned unhandled error %d\n",
                        __func__, status);
-               /* fall through */
+               fallthrough;
        case -EADDRNOTAVAIL:
                /* We're probably in TIME_WAIT. Get rid of existing socket,
                 * and retry
index 865f3e0..23d8685 100644 (file)
@@ -404,7 +404,7 @@ EXPORT_SYMBOL_GPL(unregister_switchdev_notifier);
  *     @val: value passed unmodified to notifier function
  *     @dev: port device
  *     @info: notifier information data
- *
+ *     @extack: netlink extended ack
  *     Call all network notifier blocks.
  */
 int call_switchdev_notifiers(unsigned long val, struct net_device *dev,
index 808b147..6504141 100644 (file)
@@ -652,7 +652,7 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
                        test_and_set_bit_lock(0, &b->up);
                        break;
                }
-               /* fall through */
+               fallthrough;
        case NETDEV_GOING_DOWN:
                clear_bit_unlock(0, &b->up);
                tipc_reset_bearer(net, b);
index c38baba..7c523dc 100644 (file)
@@ -326,7 +326,8 @@ static void tipc_aead_free(struct rcu_head *rp)
        if (aead->cloned) {
                tipc_aead_put(aead->cloned);
        } else {
-               head = *this_cpu_ptr(aead->tfm_entry);
+               head = *get_cpu_ptr(aead->tfm_entry);
+               put_cpu_ptr(aead->tfm_entry);
                list_for_each_entry_safe(tfm_entry, tmp, &head->list, list) {
                        crypto_free_aead(tfm_entry->tfm);
                        list_del(&tfm_entry->list);
@@ -399,10 +400,15 @@ static void tipc_aead_users_set(struct tipc_aead __rcu *aead, int val)
  */
 static struct crypto_aead *tipc_aead_tfm_next(struct tipc_aead *aead)
 {
-       struct tipc_tfm **tfm_entry = this_cpu_ptr(aead->tfm_entry);
+       struct tipc_tfm **tfm_entry;
+       struct crypto_aead *tfm;
 
+       tfm_entry = get_cpu_ptr(aead->tfm_entry);
        *tfm_entry = list_next_entry(*tfm_entry, list);
-       return (*tfm_entry)->tfm;
+       tfm = (*tfm_entry)->tfm;
+       put_cpu_ptr(tfm_entry);
+
+       return tfm;
 }
 
 /**
index 89257e2..b1fcd2a 100644 (file)
@@ -273,8 +273,8 @@ static struct tipc_member *tipc_group_find_node(struct tipc_group *grp,
        return NULL;
 }
 
-static void tipc_group_add_to_tree(struct tipc_group *grp,
-                                  struct tipc_member *m)
+static int tipc_group_add_to_tree(struct tipc_group *grp,
+                                 struct tipc_member *m)
 {
        u64 nkey, key = (u64)m->node << 32 | m->port;
        struct rb_node **n, *parent = NULL;
@@ -291,10 +291,11 @@ static void tipc_group_add_to_tree(struct tipc_group *grp,
                else if (key > nkey)
                        n = &(*n)->rb_right;
                else
-                       return;
+                       return -EEXIST;
        }
        rb_link_node(&m->tree_node, parent, n);
        rb_insert_color(&m->tree_node, &grp->members);
+       return 0;
 }
 
 static struct tipc_member *tipc_group_create_member(struct tipc_group *grp,
@@ -302,6 +303,7 @@ static struct tipc_member *tipc_group_create_member(struct tipc_group *grp,
                                                    u32 instance, int state)
 {
        struct tipc_member *m;
+       int ret;
 
        m = kzalloc(sizeof(*m), GFP_ATOMIC);
        if (!m)
@@ -314,8 +316,12 @@ static struct tipc_member *tipc_group_create_member(struct tipc_group *grp,
        m->port = port;
        m->instance = instance;
        m->bc_acked = grp->bc_snd_nxt - 1;
+       ret = tipc_group_add_to_tree(grp, m);
+       if (ret < 0) {
+               kfree(m);
+               return NULL;
+       }
        grp->member_cnt++;
-       tipc_group_add_to_tree(grp, m);
        tipc_nlist_add(&grp->dests, m->node);
        m->state = state;
        return m;
@@ -536,7 +542,7 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
                                update = true;
                                deliver = false;
                        }
-                       /* Fall thru */
+                       fallthrough;
                case TIPC_GRP_BCAST_MSG:
                        m->bc_rcv_nxt++;
                        ack = msg_grp_bc_ack_req(hdr);
index 1075781..cef38a9 100644 (file)
@@ -532,7 +532,8 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
  * tipc_link_bc_create - create new link to be used for broadcast
  * @net: pointer to associated network namespace
  * @mtu: mtu to be used initially if no peers
- * @window: send window to be used
+ * @min_win: minimal send window to be used by link
+ * @max_win: maximal send window to be used by link
  * @inputq: queue to put messages ready for delivery
  * @namedq: queue to put binding table update messages ready for delivery
  * @link: return value, pointer to put the created link
@@ -1239,7 +1240,7 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb,
                        skb_queue_tail(mc_inputq, skb);
                        return true;
                }
-               /* fall through */
+               fallthrough;
        case CONN_MANAGER:
                skb_queue_tail(inputq, skb);
                return true;
index 848fae6..52e93ba 100644 (file)
@@ -150,7 +150,8 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
        if (fragid == FIRST_FRAGMENT) {
                if (unlikely(head))
                        goto err;
-               if (unlikely(skb_unclone(frag, GFP_ATOMIC)))
+               frag = skb_unshare(frag, GFP_ATOMIC);
+               if (unlikely(!frag))
                        goto err;
                head = *headbuf = frag;
                *buf = NULL;
index 07419f3..11b27dd 100644 (file)
@@ -783,7 +783,7 @@ static __poll_t tipc_poll(struct file *file, struct socket *sock,
        case TIPC_ESTABLISHED:
                if (!tsk->cong_link_cnt && !tsk_conn_cong(tsk))
                        revents |= EPOLLOUT;
-               /* fall through */
+               fallthrough;
        case TIPC_LISTEN:
        case TIPC_CONNECTING:
                if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
@@ -2597,7 +2597,7 @@ static int tipc_connect(struct socket *sock, struct sockaddr *dest,
                 * case is EINPROGRESS, rather than EALREADY.
                 */
                res = -EINPROGRESS;
-               /* fall through */
+               fallthrough;
        case TIPC_CONNECTING:
                if (!timeout) {
                        if (previous == TIPC_CONNECTING)
@@ -2771,18 +2771,18 @@ static int tipc_shutdown(struct socket *sock, int how)
 
        trace_tipc_sk_shutdown(sk, NULL, TIPC_DUMP_ALL, " ");
        __tipc_shutdown(sock, TIPC_CONN_SHUTDOWN);
-       sk->sk_shutdown = SEND_SHUTDOWN;
+       sk->sk_shutdown = SHUTDOWN_MASK;
 
        if (sk->sk_state == TIPC_DISCONNECTING) {
                /* Discard any unreceived messages */
                __skb_queue_purge(&sk->sk_receive_queue);
 
-               /* Wake up anyone sleeping in poll */
-               sk->sk_state_change(sk);
                res = 0;
        } else {
                res = -ENOTCONN;
        }
+       /* Wake up anyone sleeping in poll. */
+       sk->sk_state_change(sk);
 
        release_sock(sk);
        return res;
index 9a3d9fe..95ab554 100644 (file)
@@ -2143,10 +2143,15 @@ void tls_sw_release_resources_tx(struct sock *sk)
        struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
        struct tls_rec *rec, *tmp;
+       int pending;
 
        /* Wait for any pending async encryptions to complete */
-       smp_store_mb(ctx->async_notify, true);
-       if (atomic_read(&ctx->encrypt_pending))
+       spin_lock_bh(&ctx->encrypt_compl_lock);
+       ctx->async_notify = true;
+       pending = atomic_read(&ctx->encrypt_pending);
+       spin_unlock_bh(&ctx->encrypt_compl_lock);
+
+       if (pending)
                crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
 
        tls_tx_records(sk, -1);
index 181ea6f..92784e5 100644 (file)
@@ -837,7 +837,7 @@ static int unix_create(struct net *net, struct socket *sock, int protocol,
                 */
        case SOCK_RAW:
                sock->type = SOCK_DGRAM;
-               /* fall through */
+               fallthrough;
        case SOCK_DGRAM:
                sock->ops = &unix_dgram_ops;
                break;
index faf7485..27026f5 100644 (file)
@@ -217,6 +217,7 @@ config LIB80211_CRYPT_WEP
 
 config LIB80211_CRYPT_CCMP
        tristate
+       select CRYPTO
        select CRYPTO_AES
        select CRYPTO_CCM
 
index 90f0f82..6a6f2f2 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/export.h>
+#include <linux/bitfield.h>
 #include <net/cfg80211.h>
 #include "core.h"
 #include "rdev-ops.h"
@@ -912,6 +913,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
        struct ieee80211_sta_vht_cap *vht_cap;
        struct ieee80211_edmg *edmg_cap;
        u32 width, control_freq, cap;
+       bool support_80_80 = false;
 
        if (WARN_ON(!cfg80211_chandef_valid(chandef)))
                return false;
@@ -957,7 +959,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
                if (!ht_cap->ht_supported &&
                    chandef->chan->band != NL80211_BAND_6GHZ)
                        return false;
-               /* fall through */
+               fallthrough;
        case NL80211_CHAN_WIDTH_20_NOHT:
                prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
                width = 20;
@@ -979,11 +981,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
                        return false;
                break;
        case NL80211_CHAN_WIDTH_80P80:
-               cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
-               if (chandef->chan->band != NL80211_BAND_6GHZ &&
-                   cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
+               cap = vht_cap->cap;
+               support_80_80 =
+                       (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) ||
+                       (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
+                        cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) ||
+                       u32_get_bits(cap, IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) > 1;
+               if (chandef->chan->band != NL80211_BAND_6GHZ && !support_80_80)
                        return false;
-               /* fall through */
+               fallthrough;
        case NL80211_CHAN_WIDTH_80:
                prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
                width = 80;
@@ -1001,7 +1007,8 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
                        return false;
                cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
                if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
-                   cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
+                   cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ &&
+                   !(vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK))
                        return false;
                break;
        default:
index a6c61a2..db7333e 100644 (file)
@@ -941,7 +941,7 @@ void cfg80211_cac_event(struct net_device *netdev,
                       sizeof(struct cfg80211_chan_def));
                queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
                cfg80211_sched_dfs_chan_update(rdev);
-               /* fall through */
+               fallthrough;
        case NL80211_RADAR_CAC_ABORTED:
                wdev->cac_started = false;
                break;
index c04fc6c..7fd45f6 100644 (file)
@@ -2107,7 +2107,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
-               /* fall through */
+               fallthrough;
        case 1:
                if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
                            sizeof(u32) * rdev->wiphy.n_cipher_suites,
@@ -2154,7 +2154,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
-               /* fall through */
+               fallthrough;
        case 2:
                if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
                                        rdev->wiphy.interface_modes))
@@ -2162,7 +2162,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
-               /* fall through */
+               fallthrough;
        case 3:
                nl_bands = nla_nest_start_noflag(msg,
                                                 NL80211_ATTR_WIPHY_BANDS);
@@ -2189,7 +2189,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                                state->chan_start++;
                                if (state->split)
                                        break;
-                               /* fall through */
+                               fallthrough;
                        default:
                                /* add frequencies */
                                nl_freqs = nla_nest_start_noflag(msg,
@@ -2244,7 +2244,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                        state->split_start++;
                if (state->split)
                        break;
-               /* fall through */
+               fallthrough;
        case 4:
                nl_cmds = nla_nest_start_noflag(msg,
                                                NL80211_ATTR_SUPPORTED_COMMANDS);
@@ -2273,7 +2273,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
-               /* fall through */
+               fallthrough;
        case 5:
                if (rdev->ops->remain_on_channel &&
                    (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
@@ -2291,7 +2291,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
-               /* fall through */
+               fallthrough;
        case 6:
 #ifdef CONFIG_PM
                if (nl80211_send_wowlan(msg, rdev, state->split))
@@ -2302,7 +2302,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
 #else
                state->split_start++;
 #endif
-               /* fall through */
+               fallthrough;
        case 7:
                if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
                                        rdev->wiphy.software_iftypes))
@@ -2315,7 +2315,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
-               /* fall through */
+               fallthrough;
        case 8:
                if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
                    nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
@@ -4172,6 +4172,9 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
        if (err)
                return err;
 
+       if (key.idx < 0)
+               return -EINVAL;
+
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
@@ -5207,7 +5210,7 @@ bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
                break;
        default:
                WARN_ON(1);
-               /* fall through */
+               fallthrough;
        case RATE_INFO_BW_20:
                rate_flg = 0;
                break;
@@ -6011,7 +6014,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 
        if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
                params.he_6ghz_capa =
-                       nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+                       nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
 
        if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
                params.airtime_weight =
index 35b8847..d8a90d3 100644 (file)
@@ -2946,6 +2946,9 @@ int regulatory_hint_user(const char *alpha2,
        if (WARN_ON(!alpha2))
                return -EINVAL;
 
+       if (!is_world_regdom(alpha2) && !is_an_alpha2(alpha2))
+               return -EINVAL;
+
        request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
        if (!request)
                return -ENOMEM;
index e67a744..04f2d19 100644 (file)
@@ -1433,7 +1433,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
        switch (ftype) {
        case CFG80211_BSS_FTYPE_BEACON:
                ies->from_beacon = true;
-               /* fall through */
+               fallthrough;
        case CFG80211_BSS_FTYPE_UNKNOWN:
                rcu_assign_pointer(tmp.pub.beacon_ies, ies);
                break;
index 985f3c2..079ce32 100644 (file)
@@ -205,7 +205,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev,
                return err;
        case CFG80211_CONN_ASSOC_FAILED_TIMEOUT:
                *treason = NL80211_TIMEOUT_ASSOC;
-               /* fall through */
+               fallthrough;
        case CFG80211_CONN_ASSOC_FAILED:
                cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                     NULL, 0,
@@ -215,7 +215,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev,
                cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                     NULL, 0,
                                     WLAN_REASON_DEAUTH_LEAVING, false);
-               /* fall through */
+               fallthrough;
        case CFG80211_CONN_ABANDON:
                /* free directly, disconnected event already sent */
                cfg80211_sme_free(wdev);
index dfad1c0..6fa99df 100644 (file)
@@ -95,7 +95,7 @@ u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
                /* see 802.11ax D6.1 27.3.23.2 */
                if (chan == 2)
                        return MHZ_TO_KHZ(5935);
-               if (chan <= 253)
+               if (chan <= 233)
                        return MHZ_TO_KHZ(5950 + chan * 5);
                break;
        case NL80211_BAND_60GHZ:
@@ -123,11 +123,13 @@ int ieee80211_freq_khz_to_channel(u32 freq)
                return (freq - 2407) / 5;
        else if (freq >= 4910 && freq <= 4980)
                return (freq - 4000) / 5;
-       else if (freq < 5945)
+       else if (freq < 5925)
                return (freq - 5000) / 5;
+       else if (freq == 5935)
+               return 2;
        else if (freq <= 45000) /* DMG band lower limit */
-               /* see 802.11ax D4.1 27.3.22.2 */
-               return (freq - 5940) / 5;
+               /* see 802.11ax D6.1 27.3.22.2 */
+               return (freq - 5950) / 5;
        else if (freq >= 58320 && freq <= 70200)
                return (freq - 56160) / 2160;
        else
@@ -198,7 +200,7 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
                                sband->bitrates[i].flags |=
                                        IEEE80211_RATE_MANDATORY_G;
                                want--;
-                               /* fall through */
+                               fallthrough;
                        default:
                                sband->bitrates[i].flags |=
                                        IEEE80211_RATE_ERP_G;
@@ -1008,7 +1010,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                case NL80211_IFTYPE_STATION:
                        if (dev->ieee80211_ptr->use_4addr)
                                break;
-                       /* fall through */
+                       fallthrough;
                case NL80211_IFTYPE_OCB:
                case NL80211_IFTYPE_P2P_CLIENT:
                case NL80211_IFTYPE_ADHOC:
index aa918d7..4d2160c 100644 (file)
@@ -1334,7 +1334,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
                        wstats.qual.qual = sig + 110;
                        break;
                }
-               /* fall through */
+               fallthrough;
        case CFG80211_SIGNAL_TYPE_UNSPEC:
                if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_SIGNAL)) {
                        wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
@@ -1343,7 +1343,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
                        wstats.qual.qual = sinfo.signal;
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                wstats.qual.updated |= IW_QUAL_LEVEL_INVALID;
                wstats.qual.updated |= IW_QUAL_QUAL_INVALID;
index 7fb3276..8e1a49b 100644 (file)
@@ -98,7 +98,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                                        *vc_fac_mask |= X25_MASK_REVERSE;
                                        break;
                                }
-                               /*fall through */
+                               fallthrough;
                        case X25_FAC_THROUGHPUT:
                                facilities->throughput = p[1];
                                *vc_fac_mask |= X25_MASK_THROUGHPUT;
index 4d3bb46..e1c4197 100644 (file)
@@ -349,7 +349,7 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
 
                case X25_RESET_REQUEST:
                        x25_write_internal(sk, X25_RESET_CONFIRMATION);
-                       /* fall through */
+                       fallthrough;
                case X25_RESET_CONFIRMATION: {
                        x25_stop_timer(sk);
                        x25->condition = 0x00;
index e97db37..b010bfd 100644 (file)
@@ -303,10 +303,10 @@ static int xdp_umem_account_pages(struct xdp_umem *umem)
 
 static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
 {
+       u32 npgs_rem, chunk_size = mr->chunk_size, headroom = mr->headroom;
        bool unaligned_chunks = mr->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG;
-       u32 chunk_size = mr->chunk_size, headroom = mr->headroom;
        u64 npgs, addr = mr->addr, size = mr->len;
-       unsigned int chunks, chunks_per_page;
+       unsigned int chunks, chunks_rem;
        int err;
 
        if (chunk_size < XDP_UMEM_MIN_CHUNK_SIZE || chunk_size > PAGE_SIZE) {
@@ -336,19 +336,18 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
        if ((addr + size) < addr)
                return -EINVAL;
 
-       npgs = size >> PAGE_SHIFT;
+       npgs = div_u64_rem(size, PAGE_SIZE, &npgs_rem);
+       if (npgs_rem)
+               npgs++;
        if (npgs > U32_MAX)
                return -EINVAL;
 
-       chunks = (unsigned int)div_u64(size, chunk_size);
+       chunks = (unsigned int)div_u64_rem(size, chunk_size, &chunks_rem);
        if (chunks == 0)
                return -EINVAL;
 
-       if (!unaligned_chunks) {
-               chunks_per_page = PAGE_SIZE / chunk_size;
-               if (chunks < chunks_per_page || chunks % chunks_per_page)
-                       return -EINVAL;
-       }
+       if (!unaligned_chunks && chunks_rem)
+               return -EINVAL;
 
        if (headroom >= chunk_size - XDP_PACKET_HEADROOM)
                return -EINVAL;
index c323162..6c5e09e 100644 (file)
@@ -377,15 +377,30 @@ static int xsk_generic_xmit(struct sock *sk)
                skb_shinfo(skb)->destructor_arg = (void *)(long)desc.addr;
                skb->destructor = xsk_destruct_skb;
 
+               /* Hinder dev_direct_xmit from freeing the packet and
+                * therefore completing it in the destructor
+                */
+               refcount_inc(&skb->users);
                err = dev_direct_xmit(skb, xs->queue_id);
+               if  (err == NETDEV_TX_BUSY) {
+                       /* Tell user-space to retry the send */
+                       skb->destructor = sock_wfree;
+                       /* Free skb without triggering the perf drop trace */
+                       consume_skb(skb);
+                       err = -EAGAIN;
+                       goto out;
+               }
+
                xskq_cons_release(xs->tx);
                /* Ignore NET_XMIT_CN as packet might have been sent */
-               if (err == NET_XMIT_DROP || err == NETDEV_TX_BUSY) {
+               if (err == NET_XMIT_DROP) {
                        /* SKB completed but not sent */
+                       kfree_skb(skb);
                        err = -EBUSY;
                        goto out;
                }
 
+               consume_skb(skb);
                sent_frame = true;
        }
 
index 827ccdf..1f08ebf 100644 (file)
@@ -29,8 +29,12 @@ static void handle_nonesp(struct espintcp_ctx *ctx, struct sk_buff *skb,
 
 static void handle_esp(struct sk_buff *skb, struct sock *sk)
 {
+       struct tcp_skb_cb *tcp_cb = (struct tcp_skb_cb *)skb->cb;
+
        skb_reset_transport_header(skb);
-       memset(skb->cb, 0, sizeof(skb->cb));
+
+       /* restore IP CB, we need at least IP6CB->nhoff */
+       memmove(skb->cb, &tcp_cb->header, sizeof(tcp_cb->header));
 
        rcu_read_lock();
        skb->dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif);
index eb81819..a8f6611 100644 (file)
@@ -303,7 +303,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
        }
 
        mtu = dst_mtu(dst);
-       if (!skb->ignore_df && skb->len > mtu) {
+       if (skb->len > mtu) {
                skb_dst_update_pmtu_no_confirm(skb, mtu);
 
                if (skb->protocol == htons(ETH_P_IPV6)) {
index d5280fd..d622c25 100644 (file)
@@ -3410,7 +3410,7 @@ decode_session6(struct sk_buff *skb, struct flowi *fl, bool reverse)
                switch (nexthdr) {
                case NEXTHDR_FRAGMENT:
                        onlyproto = 1;
-                       /* fall through */
+                       fallthrough;
                case NEXTHDR_ROUTING:
                case NEXTHDR_HOP:
                case NEXTHDR_DEST:
index 69520ad..efc89a9 100644 (file)
@@ -1019,7 +1019,8 @@ static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
         */
        if (x->km.state == XFRM_STATE_VALID) {
                if ((x->sel.family &&
-                    !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
+                    (x->sel.family != family ||
+                     !xfrm_selector_match(&x->sel, fl, family))) ||
                    !security_xfrm_state_pol_flow_match(x, pol, fl))
                        return;
 
@@ -1032,7 +1033,9 @@ static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
                *acq_in_progress = 1;
        } else if (x->km.state == XFRM_STATE_ERROR ||
                   x->km.state == XFRM_STATE_EXPIRED) {
-               if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
+               if ((!x->sel.family ||
+                    (x->sel.family == family &&
+                     xfrm_selector_match(&x->sel, fl, family))) &&
                    security_xfrm_state_pol_flow_match(x, pol, fl))
                        *error = -ESRCH;
        }
@@ -1072,7 +1075,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
                    tmpl->mode == x->props.mode &&
                    tmpl->id.proto == x->id.proto &&
                    (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
-                       xfrm_state_look_at(pol, x, fl, encap_family,
+                       xfrm_state_look_at(pol, x, fl, family,
                                           &best, &acquire_in_progress, &error);
        }
        if (best || acquire_in_progress)
@@ -1089,7 +1092,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
                    tmpl->mode == x->props.mode &&
                    tmpl->id.proto == x->id.proto &&
                    (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
-                       xfrm_state_look_at(pol, x, fl, encap_family,
+                       xfrm_state_look_at(pol, x, fl, family,
                                           &best, &acquire_in_progress, &error);
        }
 
@@ -1441,6 +1444,30 @@ out:
 EXPORT_SYMBOL(xfrm_state_add);
 
 #ifdef CONFIG_XFRM_MIGRATE
+static inline int clone_security(struct xfrm_state *x, struct xfrm_sec_ctx *security)
+{
+       struct xfrm_user_sec_ctx *uctx;
+       int size = sizeof(*uctx) + security->ctx_len;
+       int err;
+
+       uctx = kmalloc(size, GFP_KERNEL);
+       if (!uctx)
+               return -ENOMEM;
+
+       uctx->exttype = XFRMA_SEC_CTX;
+       uctx->len = size;
+       uctx->ctx_doi = security->ctx_doi;
+       uctx->ctx_alg = security->ctx_alg;
+       uctx->ctx_len = security->ctx_len;
+       memcpy(uctx + 1, security->ctx_str, security->ctx_len);
+       err = security_xfrm_state_alloc(x, uctx);
+       kfree(uctx);
+       if (err)
+               return err;
+
+       return 0;
+}
+
 static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
                                           struct xfrm_encap_tmpl *encap)
 {
@@ -1497,6 +1524,10 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
                        goto error;
        }
 
+       if (orig->security)
+               if (clone_security(x, orig->security))
+                       goto error;
+
        if (orig->coaddr) {
                x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
                                    GFP_KERNEL);
@@ -1510,6 +1541,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
        }
 
        memcpy(&x->mark, &orig->mark, sizeof(x->mark));
+       memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark));
 
        if (xfrm_init_state(x) < 0)
                goto error;
@@ -1521,7 +1553,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
        x->tfcpad = orig->tfcpad;
        x->replay_maxdiff = orig->replay_maxdiff;
        x->replay_maxage = orig->replay_maxage;
-       x->curlft.add_time = orig->curlft.add_time;
+       memcpy(&x->curlft, &orig->curlft, sizeof(x->curlft));
        x->km.state = orig->km.state;
        x->km.seq = orig->km.seq;
        x->replay = orig->replay;
index 7d71537..4b22ace 100644 (file)
@@ -483,7 +483,7 @@ int main(int argc, char **argv)
                                        "Option -%c requires an argument.\n\n",
                                        optopt);
                case 'h':
-                       // fallthrough
+                       fallthrough;
                default:
                        Usage();
                        return 0;
index 240f243..8b71894 100644 (file)
@@ -5,7 +5,7 @@
  * stack trace and selected registers when _do_fork() is called.
  *
  * For more information on theory of operation of kprobes, see
- * Documentation/staging/kprobes.rst
+ * Documentation/trace/kprobes.rst
  *
  * You will see the trace data in /var/log/messages and on the console
  * whenever _do_fork() is invoked to create a new process.
index 78a2da6..69fd123 100644 (file)
@@ -11,7 +11,7 @@
  * If no func_name is specified, _do_fork is instrumented
  *
  * For more information on theory of operation of kretprobes, see
- * Documentation/staging/kprobes.rst
+ * Documentation/trace/kprobes.rst
  *
  * Build and insert the kernel module as done in the kprobe example.
  * You will see the trace data in /var/log/messages and on the console
index c50f27b..c37f951 100644 (file)
@@ -11,5 +11,5 @@ endif
 # of some options does not break KCSAN nor causes false positive reports.
 CFLAGS_KCSAN := -fsanitize=thread \
        $(call cc-option,$(call cc-param,tsan-instrument-func-entry-exit=0) -fno-optimize-sibling-calls) \
-       $(call cc-option,$(call cc-param,tsan-instrument-read-before-write=1)) \
+       $(call cc-option,$(call cc-param,tsan-compound-read-before-write=1),$(call cc-option,$(call cc-param,tsan-instrument-read-before-write=1))) \
        $(call cc-param,tsan-distinguish-volatile=1)
index 8378c63..82748d4 100755 (executable)
@@ -16,6 +16,7 @@ fi
 cat <<EOF |
 asm-generic/atomic-instrumented.h
 asm-generic/atomic-long.h
+linux/atomic-arch-fallback.h
 linux/atomic-fallback.h
 EOF
 while read header; do
index 6afadf7..2b7fec7 100755 (executable)
@@ -5,9 +5,10 @@ ATOMICDIR=$(dirname $0)
 
 . ${ATOMICDIR}/atomic-tbl.sh
 
-#gen_param_check(arg)
+#gen_param_check(meta, arg)
 gen_param_check()
 {
+       local meta="$1"; shift
        local arg="$1"; shift
        local type="${arg%%:*}"
        local name="$(gen_param_name "${arg}")"
@@ -17,17 +18,25 @@ gen_param_check()
        i) return;;
        esac
 
-       # We don't write to constant parameters
-       [ ${type#c} != ${type} ] && rw="read"
+       if [ ${type#c} != ${type} ]; then
+               # We don't write to constant parameters.
+               rw="read"
+       elif [ "${meta}" != "s" ]; then
+               # An atomic RMW: if this parameter is not a constant, and this atomic is
+               # not just a 's'tore, this parameter is both read from and written to.
+               rw="read_write"
+       fi
 
        printf "\tinstrument_atomic_${rw}(${name}, sizeof(*${name}));\n"
 }
 
-#gen_param_check(arg...)
+#gen_params_checks(meta, arg...)
 gen_params_checks()
 {
+       local meta="$1"; shift
+
        while [ "$#" -gt 0 ]; do
-               gen_param_check "$1"
+               gen_param_check "$meta" "$1"
                shift;
        done
 }
@@ -77,7 +86,7 @@ gen_proto_order_variant()
 
        local ret="$(gen_ret_type "${meta}" "${int}")"
        local params="$(gen_params "${int}" "${atomic}" "$@")"
-       local checks="$(gen_params_checks "$@")"
+       local checks="$(gen_params_checks "${meta}" "$@")"
        local args="$(gen_args "$@")"
        local retstmt="$(gen_ret_stmt "${meta}")"
 
index 60d4a79..504d2e4 100755 (executable)
@@ -2639,8 +2639,8 @@ sub process {
 
 # Check if the commit log has what seems like a diff which can confuse patch
                if ($in_commit_log && !$commit_log_has_diff &&
-                   (($line =~ m@^\s+diff\b.*a/[\w/]+@ &&
-                     $line =~ m@^\s+diff\b.*a/([\w/]+)\s+b/$1\b@) ||
+                   (($line =~ m@^\s+diff\b.*a/([\w/]+)@ &&
+                     $line =~ m@^\s+diff\b.*a/[\w/]+\s+b/$1\b@) ||
                     $line =~ m@^\s*(?:\-\-\-\s+a/|\+\+\+\s+b/)@ ||
                     $line =~ m/^\s*\@\@ \-\d+,\d+ \+\d+,\d+ \@\@/)) {
                        ERROR("DIFF_IN_COMMIT_MSG",
index d8ec4bb..a28dc06 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 ///
-/// From Documentation/filesystems/sysfs.txt:
+/// From Documentation/filesystems/sysfs.rst:
 ///  show() must not use snprintf() when formatting the value to be
 ///  returned to user space. If you can guarantee that an overflow
 ///  will never happen you can use sprintf() otherwise you must use
index a698ece..4852bf4 100644 (file)
@@ -9,7 +9,7 @@ dtc-objs        := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
 dtc-objs       += dtc-lexer.lex.o dtc-parser.tab.o
 
 # Source files need to get at the userspace version of libfdt_env.h to compile
-HOST_EXTRACFLAGS := -I $(srctree)/$(src)/libfdt
+HOST_EXTRACFLAGS += -I $(srctree)/$(src)/libfdt
 
 ifeq ($(shell pkg-config --exists yaml-0.1 2>/dev/null && echo yes),)
 ifneq ($(CHECK_DT_BINDING)$(CHECK_DTBS),)
index 0096cd9..7ecd2cc 100644 (file)
@@ -82,6 +82,7 @@ static char *sym_name(const struct sym_entry *s)
 
 static bool is_ignored_symbol(const char *name, char type)
 {
+       /* Symbol names that exactly match to the following are ignored.*/
        static const char * const ignored_symbols[] = {
                /*
                 * Symbols which vary between passes. Passes 1 and 2 must have
@@ -104,6 +105,7 @@ static bool is_ignored_symbol(const char *name, char type)
                NULL
        };
 
+       /* Symbol names that begin with the following are ignored.*/
        static const char * const ignored_prefixes[] = {
                "$",                    /* local symbols for ARM, MIPS, etc. */
                ".LASANPC",             /* s390 kasan local symbols */
@@ -113,6 +115,7 @@ static bool is_ignored_symbol(const char *name, char type)
                NULL
        };
 
+       /* Symbol names that end with the following are ignored.*/
        static const char * const ignored_suffixes[] = {
                "_from_arm",            /* arm */
                "_from_thumb",          /* arm */
@@ -120,9 +123,15 @@ static bool is_ignored_symbol(const char *name, char type)
                NULL
        };
 
+       /* Symbol names that contain the following are ignored.*/
+       static const char * const ignored_matches[] = {
+               ".long_branch.",        /* ppc stub */
+               ".plt_branch.",         /* ppc stub */
+               NULL
+       };
+
        const char * const *p;
 
-       /* Exclude symbols which vary between passes. */
        for (p = ignored_symbols; *p; p++)
                if (!strcmp(name, *p))
                        return true;
@@ -138,6 +147,11 @@ static bool is_ignored_symbol(const char *name, char type)
                        return true;
        }
 
+       for (p = ignored_matches; *p; p++) {
+               if (strstr(name, *p))
+                       return true;
+       }
+
        if (type == 'U' || type == 'u')
                return true;
        /* exclude debugging symbols */
index d4ca829..8454649 100644 (file)
@@ -66,23 +66,6 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
                fprintf(stderr, "Error in writing or end of file.\n");
 }
 
-/* menu.c */
-void _menu_init(void);
-void menu_warn(struct menu *menu, const char *fmt, ...);
-struct menu *menu_add_menu(void);
-void menu_end_menu(void);
-void menu_add_entry(struct symbol *sym);
-void menu_add_dep(struct expr *dep);
-void menu_add_visibility(struct expr *dep);
-struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
-void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
-void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
-void menu_add_option_modules(void);
-void menu_add_option_defconfig_list(void);
-void menu_add_option_allnoconfig_y(void);
-void menu_finalize(struct menu *parent);
-void menu_set_type(int type);
-
 /* util.c */
 struct file *file_lookup(const char *name);
 void *xmalloc(size_t size);
@@ -109,6 +92,36 @@ void str_append(struct gstr *gs, const char *s);
 void str_printf(struct gstr *gs, const char *fmt, ...);
 const char *str_get(struct gstr *gs);
 
+/* menu.c */
+void _menu_init(void);
+void menu_warn(struct menu *menu, const char *fmt, ...);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option_modules(void);
+void menu_add_option_defconfig_list(void);
+void menu_add_option_allnoconfig_y(void);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+extern struct menu rootmenu;
+
+bool menu_is_empty(struct menu *menu);
+bool menu_is_visible(struct menu *menu);
+bool menu_has_prompt(struct menu *menu);
+const char *menu_get_prompt(struct menu *menu);
+struct menu *menu_get_root_menu(struct menu *menu);
+struct menu *menu_get_parent_menu(struct menu *menu);
+bool menu_has_help(struct menu *menu);
+const char *menu_get_help(struct menu *menu);
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
+void menu_get_ext_help(struct menu *menu, struct gstr *help);
+
 /* symbol.c */
 void sym_clear_all_valid(void);
 struct symbol *sym_choice_default(struct symbol *sym);
index f9ab982..9e81be3 100644 (file)
@@ -12,20 +12,6 @@ bool conf_get_changed(void);
 void conf_set_changed_callback(void (*fn)(void));
 void conf_set_message_callback(void (*fn)(const char *s));
 
-/* menu.c */
-extern struct menu rootmenu;
-
-bool menu_is_empty(struct menu *menu);
-bool menu_is_visible(struct menu *menu);
-bool menu_has_prompt(struct menu *menu);
-const char * menu_get_prompt(struct menu *menu);
-struct menu * menu_get_root_menu(struct menu *menu);
-struct menu * menu_get_parent_menu(struct menu *menu);
-bool menu_has_help(struct menu *menu);
-const char * menu_get_help(struct menu *menu);
-struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
-void menu_get_ext_help(struct menu *menu, struct gstr *help);
-
 /* symbol.c */
 extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
 
index daf1c15..e0f9655 100644 (file)
@@ -755,7 +755,6 @@ static void build_conf(struct menu *menu)
                        switch (ptype) {
                        case P_MENU:
                                child_count++;
-                               prompt = prompt;
                                if (single_menu_mode) {
                                        item_make(menu, 'm',
                                                "%s%*c%s",
index 8638785..8ce624a 100644 (file)
@@ -1108,6 +1108,11 @@ void ConfigInfoView::menuInfo(void)
                if (showDebug())
                        stream << debug_info(sym);
 
+               struct gstr help_gstr = str_new();
+
+               menu_get_ext_help(_menu, &help_gstr);
+               stream << print_filter(str_get(&help_gstr));
+               str_free(&help_gstr);
        } else if (_menu->prompt) {
                stream << "<big><b>";
                stream << print_filter(_menu->prompt->text);
@@ -1119,11 +1124,11 @@ void ConfigInfoView::menuInfo(void)
                                           expr_print_help, &stream, E_NONE);
                                stream << "<br><br>";
                        }
+
+                       stream << "defined at " << _menu->file->name << ":"
+                              << _menu->lineno << "<br><br>";
                }
        }
-       if (showDebug())
-               stream << "defined at " << _menu->file->name << ":"
-                      << _menu->lineno << "<br><br>";
 
        setText(info);
 }
@@ -1276,7 +1281,7 @@ void ConfigInfoView::clicked(const QUrl &url)
        }
 
        free(result);
-       delete data;
+       delete[] data;
 }
 
 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
index 19857d1..1c78ba4 100755 (executable)
@@ -593,7 +593,10 @@ while ($repeat) {
 }
 
 my %setconfigs;
-my @preserved_kconfigs = split(/:/,$ENV{LMC_KEEP});
+my @preserved_kconfigs;
+if (defined($ENV{'LMC_KEEP'})) {
+       @preserved_kconfigs = split(/:/,$ENV{LMC_KEEP});
+}
 
 sub in_preserved_kconfigs {
     my $kconfig = $config2kfile{$_[0]};
index d1b4456..724528f 100755 (executable)
@@ -1083,7 +1083,7 @@ sub dump_struct($$) {
     my $x = shift;
     my $file = shift;
 
-    if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
+    if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
        my $decl_type = $1;
        $declaration_name = $2;
        my $members = $3;
@@ -1099,6 +1099,7 @@ sub dump_struct($$) {
        $members =~ s/\s*__packed\s*/ /gos;
        $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos;
        $members =~ s/\s*____cacheline_aligned_in_smp/ /gos;
+       $members =~ s/\s*____cacheline_aligned/ /gos;
 
        # replace DECLARE_BITMAP
        $members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos;
@@ -1594,6 +1595,8 @@ sub dump_function($$) {
     my $file = shift;
     my $noret = 0;
 
+    print_lineno($.);
+
     $prototype =~ s/^static +//;
     $prototype =~ s/^extern +//;
     $prototype =~ s/^asmlinkage +//;
index f253681..feb2efa 100644 (file)
@@ -589,7 +589,7 @@ explictly||explicitly
 expresion||expression
 exprimental||experimental
 extened||extended
-exteneded||extended||extended
+exteneded||extended
 extensability||extensibility
 extention||extension
 extenstion||extension
index 32d3f53..fd96734 100755 (executable)
@@ -26,7 +26,11 @@ else
 fi
 
 # ignore userspace tools
-ignore="$ignore ( -path ${tree}tools ) -prune -o"
+if [ -n "$COMPILED_SOURCE" ]; then
+       ignore="$ignore ( -path ./tools ) -prune -o"
+else
+       ignore="$ignore ( -path ${tree}tools ) -prune -o"
+fi
 
 # Detect if ALLSOURCE_ARCHS is set. If not, we assume SRCARCH
 if [ "${ALLSOURCE_ARCHS}" = "" ]; then
@@ -92,7 +96,7 @@ all_sources()
 all_compiled_sources()
 {
        realpath -es $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) \
-               include/generated/autoconf.h $(find -name "*.cmd" -exec \
+               include/generated/autoconf.h $(find $ignore -name "*.cmd" -exec \
                grep -Poh '(?(?=^source_.* \K).*|(?=^  \K\S).*(?= \\))' {} \+ |
                awk '!a[$0]++') | sort -u
 }
@@ -201,6 +205,8 @@ regex_c=(
        '/\<DEVICE_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/dev_attr_\2/'
        '/\<DRIVER_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/driver_attr_\2/'
        '/\<\(DEFINE\|DECLARE\)_STATIC_KEY_\(TRUE\|FALSE\)\(\|_RO\)(\([[:alnum:]_]\+\)/\4/'
+       '/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_t/'
+       '/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_init/'
 )
 regex_kconfig=(
        '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/'
index 7b0e13c..f919ebd 100644 (file)
@@ -577,7 +577,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
                        stack = NULL;
                        break;
                }
-               /* fall through - to X_NAME */
+               fallthrough;    /* to X_NAME */
        case AA_X_NAME:
                if (xindex & AA_X_CHILD)
                        /* released by caller */
index 30c246a..fa49b81 100644 (file)
@@ -292,13 +292,13 @@ void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
        switch (AUDIT_MODE(profile)) {
        case AUDIT_ALL:
                perms->audit = ALL_PERMS_MASK;
-               /* fall through */
+               fallthrough;
        case AUDIT_NOQUIET:
                perms->quiet = 0;
                break;
        case AUDIT_QUIET:
                perms->audit = 0;
-               /* fall through */
+               fallthrough;
        case AUDIT_QUIET_DENIED:
                perms->quiet = ALL_PERMS_MASK;
                break;
index 43ab0ad..04375df 100644 (file)
@@ -354,7 +354,8 @@ static bool match_exception_partial(struct list_head *exceptions, short type,
 {
        struct dev_exception_item *ex;
 
-       list_for_each_entry_rcu(ex, exceptions, list) {
+       list_for_each_entry_rcu(ex, exceptions, list,
+                               lockdep_is_held(&devcgroup_mutex)) {
                if ((type & DEVCG_DEV_BLOCK) && !(ex->type & DEVCG_DEV_BLOCK))
                        continue;
                if ((type & DEVCG_DEV_CHAR) && !(ex->type & DEVCG_DEV_CHAR))
index cfa4127..b86a4a8 100644 (file)
@@ -99,14 +99,22 @@ int asymmetric_verify(struct key *keyring, const char *sig,
        memset(&pks, 0, sizeof(pks));
 
        pks.hash_algo = hash_algo_name[hdr->hash_algo];
-       if (hdr->hash_algo == HASH_ALGO_STREEBOG_256 ||
-           hdr->hash_algo == HASH_ALGO_STREEBOG_512) {
+       switch (hdr->hash_algo) {
+       case HASH_ALGO_STREEBOG_256:
+       case HASH_ALGO_STREEBOG_512:
                /* EC-RDSA and Streebog should go together. */
                pks.pkey_algo = "ecrdsa";
                pks.encoding = "raw";
-       } else {
+               break;
+       case HASH_ALGO_SM3_256:
+               /* SM2 and SM3 should go together. */
+               pks.pkey_algo = "sm2";
+               pks.encoding = "raw";
+               break;
+       default:
                pks.pkey_algo = "rsa";
                pks.encoding = "pkcs1";
+               break;
        }
        pks.digest = (u8 *)data;
        pks.digest_size = datalen;
index 372d163..b8848f5 100644 (file)
@@ -223,7 +223,7 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
        case IMA_XATTR_DIGEST_NG:
                /* first byte contains algorithm id */
                hash_start = 1;
-               /* fall through */
+               fallthrough;
        case IMA_XATTR_DIGEST:
                if (iint->flags & IMA_DIGSIG_REQUIRED) {
                        *cause = "IMA-signature-required";
@@ -395,7 +395,7 @@ int ima_appraise_measurement(enum ima_hooks func,
                /* It's fine not to have xattrs when using a modsig. */
                if (try_modsig)
                        break;
-               /* fall through */
+               fallthrough;
        case INTEGRITY_NOLABEL:         /* No security.evm xattr. */
                cause = "missing-HMAC";
                goto out;
index 07f0336..b4de330 100644 (file)
@@ -1279,12 +1279,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
                case Opt_uid_gt:
                case Opt_euid_gt:
                        entry->uid_op = &uid_gt;
-                       /* fall through */
+                       fallthrough;
                case Opt_uid_lt:
                case Opt_euid_lt:
                        if ((token == Opt_uid_lt) || (token == Opt_euid_lt))
                                entry->uid_op = &uid_lt;
-                       /* fall through */
+                       fallthrough;
                case Opt_uid_eq:
                case Opt_euid_eq:
                        uid_token = (token == Opt_uid_eq) ||
@@ -1313,11 +1313,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
                        break;
                case Opt_fowner_gt:
                        entry->fowner_op = &uid_gt;
-                       /* fall through */
+                       fallthrough;
                case Opt_fowner_lt:
                        if (token == Opt_fowner_lt)
                                entry->fowner_op = &uid_lt;
-                       /* fall through */
+                       fallthrough;
                case Opt_fowner_eq:
                        ima_log_string_op(ab, "fowner", args[0].from,
                                          entry->fowner_op);
index 41a5f43..c022ee9 100644 (file)
@@ -77,7 +77,7 @@ static void ima_show_template_data_ascii(struct seq_file *m,
                /* skip ':' and '\0' */
                buf_ptr += 2;
                buflen -= buf_ptr - field_data->data;
-               /* fall through */
+               fallthrough;
        case DATA_FMT_DIGEST:
        case DATA_FMT_HEX:
                if (!buflen)
index 253fb9a..ee4b4c6 100644 (file)
@@ -66,6 +66,65 @@ static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
 }
 
 /*
+ * load_moklist_certs() - Load MokList certs
+ *
+ * Load the certs contained in the UEFI MokListRT database into the
+ * platform trusted keyring.
+ *
+ * This routine checks the EFI MOK config table first. If and only if
+ * that fails, this routine uses the MokListRT ordinary UEFI variable.
+ *
+ * Return:     Status
+ */
+static int __init load_moklist_certs(void)
+{
+       struct efi_mokvar_table_entry *mokvar_entry;
+       efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
+       void *mok;
+       unsigned long moksize;
+       efi_status_t status;
+       int rc;
+
+       /* First try to load certs from the EFI MOKvar config table.
+        * It's not an error if the MOKvar config table doesn't exist
+        * or the MokListRT entry is not found in it.
+        */
+       mokvar_entry = efi_mokvar_entry_find("MokListRT");
+       if (mokvar_entry) {
+               rc = parse_efi_signature_list("UEFI:MokListRT (MOKvar table)",
+                                             mokvar_entry->data,
+                                             mokvar_entry->data_size,
+                                             get_handler_for_db);
+               /* All done if that worked. */
+               if (!rc)
+                       return rc;
+
+               pr_err("Couldn't parse MokListRT signatures from EFI MOKvar config table: %d\n",
+                      rc);
+       }
+
+       /* Get MokListRT. It might not exist, so it isn't an error
+        * if we can't get it.
+        */
+       mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
+       if (mok) {
+               rc = parse_efi_signature_list("UEFI:MokListRT",
+                                             mok, moksize, get_handler_for_db);
+               kfree(mok);
+               if (rc)
+                       pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
+               return rc;
+       }
+       if (status == EFI_NOT_FOUND)
+               pr_debug("MokListRT variable wasn't found\n");
+       else
+               pr_info("Couldn't get UEFI MokListRT\n");
+       return 0;
+}
+
+/*
+ * load_uefi_certs() - Load certs from UEFI sources
+ *
  * Load the certs contained in the UEFI databases into the platform trusted
  * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist
  * keyring.
@@ -73,17 +132,16 @@ static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
 static int __init load_uefi_certs(void)
 {
        efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
-       efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
-       void *db = NULL, *dbx = NULL, *mok = NULL;
-       unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
+       void *db = NULL, *dbx = NULL;
+       unsigned long dbsize = 0, dbxsize = 0;
        efi_status_t status;
        int rc = 0;
 
        if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
                return false;
 
-       /* Get db, MokListRT, and dbx.  They might not exist, so it isn't
-        * an error if we can't get them.
+       /* Get db and dbx.  They might not exist, so it isn't an error
+        * if we can't get them.
         */
        if (!uefi_check_ignore_db()) {
                db = get_cert_list(L"db", &secure_var, &dbsize, &status);
@@ -102,20 +160,6 @@ static int __init load_uefi_certs(void)
                }
        }
 
-       mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
-       if (!mok) {
-               if (status == EFI_NOT_FOUND)
-                       pr_debug("MokListRT variable wasn't found\n");
-               else
-                       pr_info("Couldn't get UEFI MokListRT\n");
-       } else {
-               rc = parse_efi_signature_list("UEFI:MokListRT",
-                                             mok, moksize, get_handler_for_db);
-               if (rc)
-                       pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
-               kfree(mok);
-       }
-
        dbx = get_cert_list(L"dbx", &secure_var, &dbxsize, &status);
        if (!dbx) {
                if (status == EFI_NOT_FOUND)
@@ -131,6 +175,9 @@ static int __init load_uefi_certs(void)
                kfree(dbx);
        }
 
+       /* Load the MokListRT certs */
+       rc = load_moklist_certs();
+
        return rc;
 }
 late_initcall(load_uefi_certs);
index 6ee9d8f..1545efd 100644 (file)
 #include "internal.h"
 
 /*
- * Instantiate a key with the specified compatibility multipart payload and
- * link the key into the destination keyring if one is given.
- *
- * The caller must have the appropriate instantiation permit set for this to
- * work (see keyctl_assume_authority).  No other permissions are required.
- *
- * If successful, 0 will be returned.
- */
-static long compat_keyctl_instantiate_key_iov(
-       key_serial_t id,
-       const struct compat_iovec __user *_payload_iov,
-       unsigned ioc,
-       key_serial_t ringid)
-{
-       struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
-       struct iov_iter from;
-       long ret;
-
-       if (!_payload_iov)
-               ioc = 0;
-
-       ret = compat_import_iovec(WRITE, _payload_iov, ioc,
-                                 ARRAY_SIZE(iovstack), &iov,
-                                 &from);
-       if (ret < 0)
-               return ret;
-
-       ret = keyctl_instantiate_key_common(id, &from, ringid);
-       kfree(iov);
-       return ret;
-}
-
-/*
  * The key control system call, 32-bit compatibility version for 64-bit archs
  */
 COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
@@ -114,8 +81,8 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
                return keyctl_reject_key(arg2, arg3, arg4, arg5);
 
        case KEYCTL_INSTANTIATE_IOV:
-               return compat_keyctl_instantiate_key_iov(
-                       arg2, compat_ptr(arg3), arg4, arg5);
+               return keyctl_instantiate_key_iov(arg2, compat_ptr(arg3), arg4,
+                                                 arg5);
 
        case KEYCTL_INVALIDATE:
                return keyctl_invalidate_key(arg2);
index 338a526..9b9cf3b 100644 (file)
@@ -262,11 +262,6 @@ extern long keyctl_instantiate_key_iov(key_serial_t,
                                       const struct iovec __user *,
                                       unsigned, key_serial_t);
 extern long keyctl_invalidate_key(key_serial_t);
-
-struct iov_iter;
-extern long keyctl_instantiate_key_common(key_serial_t,
-                                         struct iov_iter *,
-                                         key_serial_t);
 extern long keyctl_restrict_keyring(key_serial_t id,
                                    const char __user *_type,
                                    const char __user *_restriction);
index 9febd37..e26bbcc 100644 (file)
@@ -1164,7 +1164,7 @@ static int keyctl_change_reqkey_auth(struct key *key)
  *
  * If successful, 0 will be returned.
  */
-long keyctl_instantiate_key_common(key_serial_t id,
+static long keyctl_instantiate_key_common(key_serial_t id,
                                   struct iov_iter *from,
                                   key_serial_t ringid)
 {
index 7e0232d..1fe8b93 100644 (file)
@@ -465,7 +465,7 @@ key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx)
                case -EAGAIN: /* no key */
                        if (ret)
                                break;
-                       /* fall through */
+                       fallthrough;
                case -ENOKEY: /* negative key */
                        ret = key_ref;
                        break;
@@ -487,7 +487,7 @@ key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx)
                case -EAGAIN: /* no key */
                        if (ret)
                                break;
-                       /* fall through */
+                       fallthrough;
                case -ENOKEY: /* negative key */
                        ret = key_ref;
                        break;
@@ -509,7 +509,7 @@ key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx)
                case -EAGAIN: /* no key */
                        if (ret)
                                break;
-                       /* fall through */
+                       fallthrough;
                case -ENOKEY: /* negative key */
                        ret = key_ref;
                        break;
index e1b9f1a..2da4404 100644 (file)
@@ -295,26 +295,26 @@ static int construct_get_dest_keyring(struct key **_dest_keyring)
                                }
                        }
 
-                       /* fall through */
+                       fallthrough;
                case KEY_REQKEY_DEFL_THREAD_KEYRING:
                        dest_keyring = key_get(cred->thread_keyring);
                        if (dest_keyring)
                                break;
 
-                       /* fall through */
+                       fallthrough;
                case KEY_REQKEY_DEFL_PROCESS_KEYRING:
                        dest_keyring = key_get(cred->process_keyring);
                        if (dest_keyring)
                                break;
 
-                       /* fall through */
+                       fallthrough;
                case KEY_REQKEY_DEFL_SESSION_KEYRING:
                        dest_keyring = key_get(cred->session_keyring);
 
                        if (dest_keyring)
                                break;
 
-                       /* fall through */
+                       fallthrough;
                case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
                        ret = look_up_user_keyrings(NULL, &dest_keyring);
                        if (ret < 0)
index ca90102..a340986 100644 (file)
@@ -3606,26 +3606,20 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
 
        switch (cmd) {
        case FIONREAD:
-       /* fall through */
        case FIBMAP:
-       /* fall through */
        case FIGETBSZ:
-       /* fall through */
        case FS_IOC_GETFLAGS:
-       /* fall through */
        case FS_IOC_GETVERSION:
                error = file_has_perm(cred, file, FILE__GETATTR);
                break;
 
        case FS_IOC_SETFLAGS:
-       /* fall through */
        case FS_IOC_SETVERSION:
                error = file_has_perm(cred, file, FILE__SETATTR);
                break;
 
        /* sys_ioctl() checks */
        case FIONBIO:
-       /* fall through */
        case FIOASYNC:
                error = file_has_perm(cred, file, 0);
                break;
@@ -3783,7 +3777,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
                        err = file_has_perm(cred, file, FILE__WRITE);
                        break;
                }
-               /* fall through */
+               fallthrough;
        case F_SETOWN:
        case F_SETSIG:
        case F_GETFL:
index 408d306..d338962 100644 (file)
@@ -535,7 +535,7 @@ int mls_compute_sid(struct policydb *p,
                                                  scontext, tcontext);
                }
 
-               /* Fallthrough */
+               fallthrough;
        case AVTAB_CHANGE:
                if ((tclass == p->process_class) || sock)
                        /* Use the process MLS attributes. */
@@ -546,8 +546,6 @@ int mls_compute_sid(struct policydb *p,
        case AVTAB_MEMBER:
                /* Use the process effective MLS attributes. */
                return mls_context_cpy_low(newcontext, scontext);
-
-       /* fall through */
        }
        return -EINVAL;
 }
index 8ffbf95..8c0893e 100644 (file)
@@ -3365,7 +3365,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 * to set mount options simulate setting the
                 * superblock default.
                 */
-               /* Fall through */
+               fallthrough;
        default:
                /*
                 * This isn't an understood special case.
index c16b8c1..4bee32b 100644 (file)
@@ -1240,7 +1240,7 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
                        tomoyo_set_space(head);
                        tomoyo_set_string(head, cond->transit->name);
                }
-               /* fall through */
+               fallthrough;
        case 1:
                {
                        const u16 condc = cond->condc;
@@ -1345,12 +1345,12 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
                        }
                }
                head->r.cond_step++;
-               /* fall through */
+               fallthrough;
        case 2:
                if (!tomoyo_flush(head))
                        break;
                head->r.cond_step++;
-               /* fall through */
+               fallthrough;
        case 3:
                if (cond->grant_log != TOMOYO_GRANTLOG_AUTO)
                        tomoyo_io_printf(head, " grant_log=%s",
@@ -1639,7 +1639,7 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
                                        tomoyo_set_string(head, tomoyo_dif[i]);
                        head->r.index = 0;
                        head->r.step++;
-                       /* fall through */
+                       fallthrough;
                case 1:
                        while (head->r.index < TOMOYO_MAX_ACL_GROUPS) {
                                i = head->r.index++;
@@ -1652,14 +1652,14 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
                        head->r.index = 0;
                        head->r.step++;
                        tomoyo_set_lf(head);
-                       /* fall through */
+                       fallthrough;
                case 2:
                        if (!tomoyo_read_domain2(head, &domain->acl_info_list))
                                return;
                        head->r.step++;
                        if (!tomoyo_set_lf(head))
                                return;
-                       /* fall through */
+                       fallthrough;
                case 3:
                        head->r.step = 0;
                        if (head->r.print_this_domain_only)
@@ -2088,7 +2088,7 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
                /* Check max_learning_entry parameter. */
                if (tomoyo_domain_quota_is_ok(r))
                        break;
-               /* fall through */
+               fallthrough;
        default:
                return 0;
        }
@@ -2710,13 +2710,13 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
                case TOMOYO_DOMAINPOLICY:
                        if (tomoyo_select_domain(head, cp0))
                                continue;
-                       /* fall through */
+                       fallthrough;
                case TOMOYO_EXCEPTIONPOLICY:
                        if (!strcmp(cp0, "select transition_only")) {
                                head->r.print_transition_related_only = true;
                                continue;
                        }
-                       /* fall through */
+                       fallthrough;
                default:
                        if (!tomoyo_manager()) {
                                error = -EPERM;
index 86f7d1b..051f729 100644 (file)
@@ -927,7 +927,7 @@ int tomoyo_path2_perm(const u8 operation, const struct path *path1,
        case TOMOYO_TYPE_LINK:
                if (!d_is_dir(path1->dentry))
                        break;
-               /* fall through */
+               fallthrough;
        case TOMOYO_TYPE_PIVOT_ROOT:
                tomoyo_add_slash(&buf1);
                tomoyo_add_slash(&buf2);
index 3788906..fe27034 100644 (file)
@@ -329,8 +329,8 @@ int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug,
                snd_BUG();
                return -EINVAL;
        }
-       if (snd_BUG_ON(!snd_pcm_format_linear(format->format)))
-               return -ENXIO;
+       if (!snd_pcm_format_linear(format->format))
+               return -EINVAL;
 
        err = snd_pcm_plugin_build(plug, "Mu-Law<->linear conversion",
                                   src_format, dst_format,
index d9f85f2..6e27d87 100644 (file)
@@ -816,9 +816,9 @@ static void snd_timer_clear_callbacks(struct snd_timer *timer,
  * timer tasklet
  *
  */
-static void snd_timer_tasklet(unsigned long arg)
+static void snd_timer_tasklet(struct tasklet_struct *t)
 {
-       struct snd_timer *timer = (struct snd_timer *) arg;
+       struct snd_timer *timer = from_tasklet(timer, t, task_queue);
        unsigned long flags;
 
        if (timer->card && timer->card->shutdown) {
@@ -967,8 +967,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
        INIT_LIST_HEAD(&timer->ack_list_head);
        INIT_LIST_HEAD(&timer->sack_list_head);
        spin_lock_init(&timer->lock);
-       tasklet_init(&timer->task_queue, snd_timer_tasklet,
-                    (unsigned long)timer);
+       tasklet_setup(&timer->task_queue, snd_timer_tasklet);
        timer->max_instances = 1000; /* default limit per timer */
        if (card != NULL) {
                timer->module = card->module;
index f8586f7..ee1c428 100644 (file)
@@ -64,7 +64,7 @@
 #define IT_PKT_HEADER_SIZE_CIP         8 // For 2 CIP header.
 #define IT_PKT_HEADER_SIZE_NO_CIP      0 // Nothing.
 
-static void pcm_period_tasklet(unsigned long data);
+static void pcm_period_tasklet(struct tasklet_struct *t);
 
 /**
  * amdtp_stream_init - initialize an AMDTP stream structure
@@ -94,7 +94,7 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
        s->flags = flags;
        s->context = ERR_PTR(-1);
        mutex_init(&s->mutex);
-       tasklet_init(&s->period_tasklet, pcm_period_tasklet, (unsigned long)s);
+       tasklet_setup(&s->period_tasklet, pcm_period_tasklet);
        s->packet_index = 0;
 
        init_waitqueue_head(&s->callback_wait);
@@ -441,9 +441,9 @@ static void update_pcm_pointers(struct amdtp_stream *s,
        }
 }
 
-static void pcm_period_tasklet(unsigned long data)
+static void pcm_period_tasklet(struct tasklet_struct *t)
 {
-       struct amdtp_stream *s = (void *)data;
+       struct amdtp_stream *s = from_tasklet(s, t, period_tasklet);
        struct snd_pcm_substream *pcm = READ_ONCE(s->pcm);
 
        if (pcm)
index c84b913..ab84089 100644 (file)
@@ -14,6 +14,7 @@ MODULE_LICENSE("GPL v2");
 #define VENDOR_DIGIDESIGN      0x00a07e
 #define MODEL_CONSOLE          0x000001
 #define MODEL_RACK             0x000002
+#define SPEC_VERSION           0x000001
 
 static int name_card(struct snd_dg00x *dg00x)
 {
@@ -175,14 +176,18 @@ static const struct ieee1394_device_id snd_dg00x_id_table[] = {
        /* Both of 002/003 use the same ID. */
        {
                .match_flags = IEEE1394_MATCH_VENDOR_ID |
+                              IEEE1394_MATCH_VERSION |
                               IEEE1394_MATCH_MODEL_ID,
                .vendor_id = VENDOR_DIGIDESIGN,
+               .version = SPEC_VERSION,
                .model_id = MODEL_CONSOLE,
        },
        {
                .match_flags = IEEE1394_MATCH_VENDOR_ID |
+                              IEEE1394_MATCH_VERSION |
                               IEEE1394_MATCH_MODEL_ID,
                .vendor_id = VENDOR_DIGIDESIGN,
+               .version = SPEC_VERSION,
                .model_id = MODEL_RACK,
        },
        {}
index 5dac0d9..75f2edd 100644 (file)
@@ -39,9 +39,6 @@ static const struct snd_tscm_spec model_specs[] = {
                .midi_capture_ports = 2,
                .midi_playback_ports = 4,
        },
-       // This kernel module doesn't support FE-8 because the most of features
-       // can be implemented in userspace without any specific support of this
-       // module.
 };
 
 static int identify_model(struct snd_tscm *tscm)
@@ -211,11 +208,39 @@ static void snd_tscm_remove(struct fw_unit *unit)
 }
 
 static const struct ieee1394_device_id snd_tscm_id_table[] = {
+       // Tascam, FW-1884.
+       {
+               .match_flags = IEEE1394_MATCH_VENDOR_ID |
+                              IEEE1394_MATCH_SPECIFIER_ID |
+                              IEEE1394_MATCH_VERSION,
+               .vendor_id = 0x00022e,
+               .specifier_id = 0x00022e,
+               .version = 0x800000,
+       },
+       // Tascam, FE-8 (.version = 0x800001)
+       // This kernel module doesn't support FE-8 because the most of features
+       // can be implemented in userspace without any specific support of this
+       // module.
+       //
+       // .version = 0x800002 is unknown.
+       //
+       // Tascam, FW-1082.
+       {
+               .match_flags = IEEE1394_MATCH_VENDOR_ID |
+                              IEEE1394_MATCH_SPECIFIER_ID |
+                              IEEE1394_MATCH_VERSION,
+               .vendor_id = 0x00022e,
+               .specifier_id = 0x00022e,
+               .version = 0x800003,
+       },
+       // Tascam, FW-1804.
        {
                .match_flags = IEEE1394_MATCH_VENDOR_ID |
-                              IEEE1394_MATCH_SPECIFIER_ID,
+                              IEEE1394_MATCH_SPECIFIER_ID |
+                              IEEE1394_MATCH_VERSION,
                .vendor_id = 0x00022e,
                .specifier_id = 0x00022e,
+               .version = 0x800004,
        },
        {}
 };
index 333220f..3e9e9ac 100644 (file)
@@ -127,6 +127,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_device_init);
 void snd_hdac_device_exit(struct hdac_device *codec)
 {
        pm_runtime_put_noidle(&codec->dev);
+       /* keep balance of runtime PM child_count in parent device */
+       pm_runtime_set_suspended(&codec->dev);
        snd_hdac_bus_remove_device(codec->bus, codec);
        kfree(codec->vendor_name);
        kfree(codec->chip_name);
index 99aec73..1c5114d 100644 (file)
@@ -54,7 +54,7 @@ static const struct config_entry config_table[] = {
 #endif
 /*
  * Apollolake (Broxton-P)
- * the legacy HDaudio driver is used except on Up Squared (SOF) and
+ * the legacy HDAudio driver is used except on Up Squared (SOF) and
  * Chromebooks (SST)
  */
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
@@ -89,7 +89,7 @@ static const struct config_entry config_table[] = {
        },
 #endif
 /*
- * Skylake and Kabylake use legacy HDaudio driver except for Google
+ * Skylake and Kabylake use legacy HDAudio driver except for Google
  * Chromebooks (SST)
  */
 
@@ -135,7 +135,7 @@ static const struct config_entry config_table[] = {
 #endif
 
 /*
- * Geminilake uses legacy HDaudio driver except for Google
+ * Geminilake uses legacy HDAudio driver except for Google
  * Chromebooks
  */
 /* Geminilake */
@@ -157,7 +157,7 @@ static const struct config_entry config_table[] = {
 
 /*
  * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy
- * HDaudio driver except for Google Chromebooks and when DMICs are
+ * HDAudio driver except for Google Chromebooks and when DMICs are
  * present. Two cases are required since Coreboot does not expose NHLT
  * tables.
  *
@@ -391,7 +391,7 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
        if (pci->class == 0x040300)
                return SND_INTEL_DSP_DRIVER_LEGACY;
        if (pci->class != 0x040100 && pci->class != 0x040380) {
-               dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDA legacy driver\n", pci->class);
+               dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class);
                return SND_INTEL_DSP_DRIVER_LEGACY;
        }
 
index 023c35a..35e7648 100644 (file)
@@ -921,10 +921,10 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
                add_timer(&dpcm->timer);
 }
 
-static void snd_card_asihpi_int_task(unsigned long data)
+static void snd_card_asihpi_int_task(struct tasklet_struct *t)
 {
-       struct hpi_adapter *a = (struct hpi_adapter *)data;
-       struct snd_card_asihpi *asihpi;
+       struct snd_card_asihpi *asihpi = from_tasklet(asihpi, t, t);
+       struct hpi_adapter *a = asihpi->hpi;
 
        WARN_ON(!a || !a->snd_card || !a->snd_card->private_data);
        asihpi = (struct snd_card_asihpi *)a->snd_card->private_data;
@@ -2871,8 +2871,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
        if (hpi->interrupt_mode) {
                asihpi->pcm_start = snd_card_asihpi_pcm_int_start;
                asihpi->pcm_stop = snd_card_asihpi_pcm_int_stop;
-               tasklet_init(&asihpi->t, snd_card_asihpi_int_task,
-                       (unsigned long)hpi);
+               tasklet_setup(&asihpi->t, snd_card_asihpi_int_task);
                hpi->interrupt_callback = snd_card_asihpi_isr;
        } else {
                asihpi->pcm_start = snd_card_asihpi_pcm_timer_start;
index 496dcde..9790f51 100644 (file)
@@ -343,7 +343,7 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
        struct hpi_message hm;
        struct hpi_response hr;
        struct hpi_adapter adapter;
-       struct hpi_pci pci;
+       struct hpi_pci pci = { 0 };
 
        memset(&adapter, 0, sizeof(adapter));
 
@@ -499,7 +499,7 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
        return 0;
 
 err:
-       for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
+       while (--idx >= 0) {
                if (pci.ap_mem_base[idx]) {
                        iounmap(pci.ap_mem_base[idx]);
                        pci.ap_mem_base[idx] = NULL;
index 70d775f..c189f70 100644 (file)
@@ -537,7 +537,8 @@ static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
                else
                        /* Power down */
                        chip->spi_dac_reg[reg] |= bit;
-               return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+               if (snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]) != 0)
+                       return -ENXIO;
        }
        return 0;
 }
index e34a4d5..36a9dbc 100644 (file)
@@ -2127,9 +2127,10 @@ static int azx_probe(struct pci_dev *pci,
         */
        if (dmic_detect) {
                err = snd_intel_dsp_driver_probe(pci);
-               if (err != SND_INTEL_DSP_DRIVER_ANY &&
-                   err != SND_INTEL_DSP_DRIVER_LEGACY)
+               if (err != SND_INTEL_DSP_DRIVER_ANY && err != SND_INTEL_DSP_DRIVER_LEGACY) {
+                       dev_dbg(&pci->dev, "HDAudio driver not selected, aborting probe\n");
                        return -ENODEV;
+               }
        } else {
                dev_warn(&pci->dev, "dmic_detect option is deprecated, pass snd-intel-dspcfg.dsp_driver=1 option instead\n");
        }
@@ -2745,8 +2746,6 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
        /* Zhaoxin */
        { PCI_DEVICE(0x1d17, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN },
-       /* Loongson */
-       { PCI_DEVICE(0x0014, 0x7a07), .driver_data = AZX_DRIVER_GENERIC },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
index c94553b..70164d1 100644 (file)
@@ -179,6 +179,10 @@ static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev)
        struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
 
        if (chip && chip->running) {
+               /* enable controller wake up event */
+               azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) |
+                          STATESTS_INT_MASK);
+
                azx_stop_chip(chip);
                azx_enter_link_reset(chip);
        }
@@ -200,6 +204,9 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev)
        if (chip && chip->running) {
                hda_tegra_init(hda);
                azx_init_chip(chip, 1);
+               /* disable controller wake up event*/
+               azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
+                          ~STATESTS_INT_MASK);
        }
 
        return 0;
index b8c8490..4020500 100644 (file)
@@ -2794,6 +2794,7 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec,
                               hda_nid_t cvt_nid)
 {
        if (per_pin) {
+               haswell_verify_D0(codec, per_pin->cvt_nid, per_pin->pin_nid);
                snd_hda_set_dev_select(codec, per_pin->pin_nid,
                               per_pin->dev_id);
                intel_verify_pin_cvt_connect(codec, per_pin);
@@ -3734,6 +3735,7 @@ static int tegra_hdmi_build_pcms(struct hda_codec *codec)
 
 static int patch_tegra_hdmi(struct hda_codec *codec)
 {
+       struct hdmi_spec *spec;
        int err;
 
        err = patch_generic_hdmi(codec);
@@ -3741,6 +3743,10 @@ static int patch_tegra_hdmi(struct hda_codec *codec)
                return err;
 
        codec->patch_ops.build_pcms = tegra_hdmi_build_pcms;
+       spec = codec->spec;
+       spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+               nvhdmi_chmap_cea_alloc_validate_get_type;
+       spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
 
        return 0;
 }
@@ -4263,6 +4269,7 @@ HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI",    patch_i915_glk_hdmi),
 HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi),
 HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI",    patch_i915_icl_hdmi),
 HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI",  patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi),
 HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
 HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI",        patch_i915_icl_hdmi),
 HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
index a1fa983..d4f17b4 100644 (file)
@@ -3427,7 +3427,11 @@ static void alc256_shutup(struct hda_codec *codec)
 
        /* 3k pull low control for Headset jack. */
        /* NOTE: call this before clearing the pin, otherwise codec stalls */
-       alc_update_coef_idx(codec, 0x46, 0, 3 << 12);
+       /* If disable 3k pulldown control for alc257, the Mic detection will not work correctly
+        * when booting with headset plugged. So skip setting it for the codec alc257
+        */
+       if (codec->core.vendor_id != 0x10ec0257)
+               alc_update_coef_idx(codec, 0x46, 0, 3 << 12);
 
        if (!spec->no_shutup_pins)
                snd_hda_codec_write(codec, hp_pin, 0,
@@ -5867,6 +5871,39 @@ static void alc275_fixup_gpio4_off(struct hda_codec *codec,
        }
 }
 
+/* Quirk for Thinkpad X1 7th and 8th Gen
+ * The following fixed routing needed
+ * DAC1 (NID 0x02) -> Speaker (NID 0x14); some eq applied secretly
+ * DAC2 (NID 0x03) -> Bass (NID 0x17) & Headphone (NID 0x21); sharing a DAC
+ * DAC3 (NID 0x06) -> Unused, due to the lack of volume amp
+ */
+static void alc285_fixup_thinkpad_x1_gen7(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t conn[] = { 0x02, 0x03 }; /* exclude 0x06 */
+       static const hda_nid_t preferred_pairs[] = {
+               0x14, 0x02, 0x17, 0x03, 0x21, 0x03, 0
+       };
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               spec->gen.preferred_dacs = preferred_pairs;
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               /* The generic parser creates somewhat unintuitive volume ctls
+                * with the fixed routing above, and the shared DAC2 may be
+                * confusing for PA.
+                * Rename those to unique names so that PA doesn't touch them
+                * and use only Master volume.
+                */
+               rename_ctl(codec, "Front Playback Volume", "DAC1 Playback Volume");
+               rename_ctl(codec, "Bass Speaker Playback Volume", "DAC2 Playback Volume");
+               break;
+       }
+}
+
 static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
                                         const struct hda_fixup *fix,
                                         int action)
@@ -5959,6 +5996,40 @@ static void alc_fixup_disable_mic_vref(struct hda_codec *codec,
                snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
 }
 
+
+static void alc294_gx502_toggle_output(struct hda_codec *codec,
+                                       struct hda_jack_callback *cb)
+{
+       /* The Windows driver sets the codec up in a very different way where
+        * it appears to leave 0x10 = 0x8a20 set. For Linux we need to toggle it
+        */
+       if (snd_hda_jack_detect_state(codec, 0x21) == HDA_JACK_PRESENT)
+               alc_write_coef_idx(codec, 0x10, 0x8a20);
+       else
+               alc_write_coef_idx(codec, 0x10, 0x0a20);
+}
+
+static void alc294_fixup_gx502_hp(struct hda_codec *codec,
+                                       const struct hda_fixup *fix, int action)
+{
+       /* Pin 0x21: headphones/headset mic */
+       if (!is_jack_detectable(codec, 0x21))
+               return;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_jack_detect_enable_callback(codec, 0x21,
+                               alc294_gx502_toggle_output);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               /* Make sure to start in a correct state, i.e. if
+                * headphones have been plugged in before powering up the system
+                */
+               alc294_gx502_toggle_output(codec, NULL);
+               break;
+       }
+}
+
 static void  alc285_fixup_hp_gpio_amp_init(struct hda_codec *codec,
                              const struct hda_fixup *fix, int action)
 {
@@ -5983,6 +6054,7 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
 #include "hp_x360_helper.c"
 
 enum {
+       ALC269_FIXUP_GPIO2,
        ALC269_FIXUP_SONY_VAIO,
        ALC275_FIXUP_SONY_VAIO_GPIO2,
        ALC269_FIXUP_DELL_M101Z,
@@ -6135,9 +6207,13 @@ enum {
        ALC289_FIXUP_DUAL_SPK,
        ALC294_FIXUP_SPK2_TO_DAC1,
        ALC294_FIXUP_ASUS_DUAL_SPK,
+       ALC285_FIXUP_THINKPAD_X1_GEN7,
        ALC285_FIXUP_THINKPAD_HEADSET_JACK,
        ALC294_FIXUP_ASUS_HPE,
        ALC294_FIXUP_ASUS_COEF_1B,
+       ALC294_FIXUP_ASUS_GX502_HP,
+       ALC294_FIXUP_ASUS_GX502_PINS,
+       ALC294_FIXUP_ASUS_GX502_VERBS,
        ALC285_FIXUP_HP_GPIO_LED,
        ALC285_FIXUP_HP_MUTE_LED,
        ALC236_FIXUP_HP_MUTE_LED,
@@ -6156,9 +6232,14 @@ enum {
        ALC269_FIXUP_LEMOTE_A1802,
        ALC269_FIXUP_LEMOTE_A190X,
        ALC256_FIXUP_INTEL_NUC8_RUGGED,
+       ALC255_FIXUP_XIAOMI_HEADSET_MIC,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
+       [ALC269_FIXUP_GPIO2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_gpio2,
+       },
        [ALC269_FIXUP_SONY_VAIO] = {
                .type = HDA_FIXUP_PINCTLS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -6978,6 +7059,8 @@ static const struct hda_fixup alc269_fixups[] = {
        [ALC233_FIXUP_LENOVO_MULTI_CODECS] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_GPIO2
        },
        [ALC233_FIXUP_ACER_HEADSET_MIC] = {
                .type = HDA_FIXUP_VERBS,
@@ -7280,11 +7363,17 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC294_FIXUP_SPK2_TO_DAC1
        },
+       [ALC285_FIXUP_THINKPAD_X1_GEN7] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_thinkpad_x1_gen7,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
+       },
        [ALC285_FIXUP_THINKPAD_HEADSET_JACK] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_jack,
                .chained = true,
-               .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1
+               .chain_id = ALC285_FIXUP_THINKPAD_X1_GEN7
        },
        [ALC294_FIXUP_ASUS_HPE] = {
                .type = HDA_FIXUP_VERBS,
@@ -7297,6 +7386,33 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
        },
+       [ALC294_FIXUP_ASUS_GX502_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11050 }, /* front HP mic */
+                       { 0x1a, 0x01a11830 }, /* rear external mic */
+                       { 0x21, 0x03211020 }, /* front HP out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_GX502_VERBS
+       },
+       [ALC294_FIXUP_ASUS_GX502_VERBS] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* set 0x15 to HP-OUT ctrl */
+                       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+                       /* unmute the 0x15 amp */
+                       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_GX502_HP
+       },
+       [ALC294_FIXUP_ASUS_GX502_HP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc294_fixup_gx502_hp,
+       },
        [ALC294_FIXUP_ASUS_COEF_1B] = {
                .type = HDA_FIXUP_VERBS,
                .v.verbs = (const struct hda_verb[]) {
@@ -7486,6 +7602,16 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MODE
        },
+       [ALC255_FIXUP_XIAOMI_HEADSET_MIC] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC289_FIXUP_ASUS_GA401
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -7670,6 +7796,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
        SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
        SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
@@ -7695,7 +7822,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
        SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
        SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
-       SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
+       SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
+       SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
        SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
        SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
        SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
@@ -7781,6 +7909,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI),
        SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101),
        SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
+       SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
        SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE),
        SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802),
@@ -7958,6 +8087,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"},
        {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"},
        {.id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc298-samsung-headphone"},
+       {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"},
        {}
 };
 #define ALC225_STANDARD_PINS \
index b4f3002..098c69b 100644 (file)
@@ -1070,9 +1070,9 @@ getmixer(struct cmdif *cif, short num, unsigned short *rval,
        return 0;
 }
 
-static void riptide_handleirq(unsigned long dev_id)
+static void riptide_handleirq(struct tasklet_struct *t)
 {
-       struct snd_riptide *chip = (void *)dev_id;
+       struct snd_riptide *chip = from_tasklet(chip, t, riptide_tq);
        struct cmdif *cif = chip->cif;
        struct snd_pcm_substream *substream[PLAYBACK_SUBSTREAMS + 1];
        struct snd_pcm_runtime *runtime;
@@ -1843,7 +1843,7 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci,
        chip->received_irqs = 0;
        chip->handled_irqs = 0;
        chip->cif = NULL;
-       tasklet_init(&chip->riptide_tq, riptide_handleirq, (unsigned long)chip);
+       tasklet_setup(&chip->riptide_tq, riptide_handleirq);
 
        if ((chip->res_port =
             request_region(chip->port, 64, "RIPTIDE")) == NULL) {
index 227aece..dda56ec 100644 (file)
@@ -3791,9 +3791,9 @@ static int snd_hdsp_set_defaults(struct hdsp *hdsp)
        return 0;
 }
 
-static void hdsp_midi_tasklet(unsigned long arg)
+static void hdsp_midi_tasklet(struct tasklet_struct *t)
 {
-       struct hdsp *hdsp = (struct hdsp *)arg;
+       struct hdsp *hdsp = from_tasklet(hdsp, t, midi_tasklet);
 
        if (hdsp->midi[0].pending)
                snd_hdsp_midi_input_read (&hdsp->midi[0]);
@@ -5182,7 +5182,7 @@ static int snd_hdsp_create(struct snd_card *card,
 
        spin_lock_init(&hdsp->lock);
 
-       tasklet_init(&hdsp->midi_tasklet, hdsp_midi_tasklet, (unsigned long)hdsp);
+       tasklet_setup(&hdsp->midi_tasklet, hdsp_midi_tasklet);
 
        pci_read_config_word(hdsp->pci, PCI_CLASS_REVISION, &hdsp->firmware_rev);
        hdsp->firmware_rev &= 0xff;
index 0fa49f4..572350a 100644 (file)
@@ -2169,9 +2169,9 @@ static int snd_hdspm_create_midi(struct snd_card *card,
 }
 
 
-static void hdspm_midi_tasklet(unsigned long arg)
+static void hdspm_midi_tasklet(struct tasklet_struct *t)
 {
-       struct hdspm *hdspm = (struct hdspm *)arg;
+       struct hdspm *hdspm = from_tasklet(hdspm, t, midi_tasklet);
        int i = 0;
 
        while (i < hdspm->midiPorts) {
@@ -6836,8 +6836,7 @@ static int snd_hdspm_create(struct snd_card *card,
 
        }
 
-       tasklet_init(&hdspm->midi_tasklet,
-                       hdspm_midi_tasklet, (unsigned long) hdspm);
+       tasklet_setup(&hdspm->midi_tasklet, hdspm_midi_tasklet);
 
 
        if (hdspm->io_type != MADIface) {
index b8161a0..58bb49f 100644 (file)
@@ -227,14 +227,14 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
        switch (filltype) {
        case SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL:
                silent = 1;
-               /* intentionally fall thru */
+               fallthrough;
        case SND_PS3_DMA_FILLTYPE_FIRSTFILL:
                ch0_kick_event = PS3_AUDIO_KICK_EVENT_ALWAYS;
                break;
 
        case SND_PS3_DMA_FILLTYPE_SILENT_RUNNING:
                silent = 1;
-               /* intentionally fall thru */
+               fallthrough;
        case SND_PS3_DMA_FILLTYPE_RUNNING:
                ch0_kick_event = PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY;
                break;
index 3cb6388..04acc18 100644 (file)
@@ -536,7 +536,7 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
                /* cpu is BCLK master */
                mrb |= MCHP_I2SMCC_MRB_CLKSEL_INT;
                set_divs = 1;
-               /* fall through */
+               fallthrough;
        case SND_SOC_DAIFMT_CBM_CFM:
                /* cpu is slave */
                mra |= MCHP_I2SMCC_MRA_MODE_SLAVE;
index c0a28f0..298689a 100644 (file)
@@ -202,7 +202,7 @@ static int jz4770_codec_set_bias_level(struct snd_soc_component *codec,
                                   REG_CR_VIC_SB_SLEEP, REG_CR_VIC_SB_SLEEP);
                regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
                                   REG_CR_VIC_SB, REG_CR_VIC_SB);
-       /* fall-through */
+               fallthrough;
        default:
                break;
        }
index 5fe7247..e4675cf 100644 (file)
@@ -838,8 +838,8 @@ static int max98373_sdw_probe(struct sdw_slave *slave,
 
        /* Regmap Initialization */
        regmap = devm_regmap_init_sdw(slave, &max98373_sdw_regmap);
-       if (!regmap)
-               return -EINVAL;
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
 
        return max98373_init(slave, regmap);
 }
index f0da559..b8845f4 100644 (file)
@@ -401,7 +401,7 @@ static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
                break;
        case SND_SOC_DAIFMT_DSP_A:
                priv->tdm_offset += 1;
-               /* fall through */
+               fallthrough;
                /* DSP_A uses the same basic config as DSP_B
                 * except we need to shift the TDM output by one BCK cycle
                 */
index 5e445fe..821e739 100644 (file)
@@ -306,6 +306,13 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
        struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component);
        int ret;
 
+       /*
+        * Some sound card sets 0 Hz as reset,
+        * but it is impossible to set. Ignore it here
+        */
+       if (freq == 0)
+               return 0;
+
        if (freq > PCM3168A_MAX_SYSCLK)
                return -EINVAL;
 
index b0ba0d2..56e952a 100644 (file)
@@ -684,8 +684,8 @@ static int rt1308_sdw_probe(struct sdw_slave *slave,
 
        /* Regmap Initialization */
        regmap = devm_regmap_init_sdw(slave, &rt1308_sdw_regmap);
-       if (!regmap)
-               return -EINVAL;
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
 
        rt1308_sdw_init(&slave->dev, regmap, slave);
 
index 4d14048..1d24bf0 100644 (file)
@@ -452,8 +452,8 @@ static int rt700_sdw_probe(struct sdw_slave *slave,
 
        /* Regmap Initialization */
        sdw_regmap = devm_regmap_init_sdw(slave, &rt700_sdw_regmap);
-       if (!sdw_regmap)
-               return -EINVAL;
+       if (IS_ERR(sdw_regmap))
+               return PTR_ERR(sdw_regmap);
 
        regmap = devm_regmap_init(&slave->dev, NULL,
                &slave->dev, &rt700_regmap);
index 45b9289..7efff13 100644 (file)
@@ -452,8 +452,8 @@ static int rt711_sdw_probe(struct sdw_slave *slave,
 
        /* Regmap Initialization */
        sdw_regmap = devm_regmap_init_sdw(slave, &rt711_sdw_regmap);
-       if (!sdw_regmap)
-               return -EINVAL;
+       if (IS_ERR(sdw_regmap))
+               return PTR_ERR(sdw_regmap);
 
        regmap = devm_regmap_init(&slave->dev, NULL,
                &slave->dev, &rt711_regmap);
index d11b23d..68a3673 100644 (file)
@@ -527,8 +527,8 @@ static int rt715_sdw_probe(struct sdw_slave *slave,
 
        /* Regmap Initialization */
        sdw_regmap = devm_regmap_init_sdw(slave, &rt715_sdw_regmap);
-       if (!sdw_regmap)
-               return -EINVAL;
+       if (IS_ERR(sdw_regmap))
+               return PTR_ERR(sdw_regmap);
 
        regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev,
                &rt715_regmap);
index 5cd50d8..8efe206 100644 (file)
@@ -842,6 +842,18 @@ static int adcx140_codec_probe(struct snd_soc_component *component)
        if (ret)
                goto out;
 
+       if (adcx140->supply_areg == NULL)
+               sleep_cfg_val |= ADCX140_AREG_INTERNAL;
+
+       ret = regmap_write(adcx140->regmap, ADCX140_SLEEP_CFG, sleep_cfg_val);
+       if (ret) {
+               dev_err(adcx140->dev, "setting sleep config failed %d\n", ret);
+               goto out;
+       }
+
+       /* 8.4.3: Wait >= 1ms after entering active mode. */
+       usleep_range(1000, 100000);
+
        pdm_count = device_property_count_u32(adcx140->dev,
                                              "ti,pdm-edge-select");
        if (pdm_count <= ADCX140_NUM_PDM_EDGES && pdm_count > 0) {
@@ -889,18 +901,6 @@ static int adcx140_codec_probe(struct snd_soc_component *component)
        if (ret)
                goto out;
 
-       if (adcx140->supply_areg == NULL)
-               sleep_cfg_val |= ADCX140_AREG_INTERNAL;
-
-       ret = regmap_write(adcx140->regmap, ADCX140_SLEEP_CFG, sleep_cfg_val);
-       if (ret) {
-               dev_err(adcx140->dev, "setting sleep config failed %d\n", ret);
-               goto out;
-       }
-
-       /* 8.4.3: Wait >= 1ms after entering active mode. */
-       usleep_range(1000, 100000);
-
        ret = regmap_update_bits(adcx140->regmap, ADCX140_BIAS_CFG,
                                ADCX140_MIC_BIAS_VAL_MSK |
                                ADCX140_MIC_BIAS_VREF_MSK, bias_cfg);
@@ -980,6 +980,8 @@ static int adcx140_i2c_probe(struct i2c_client *i2c,
        if (!adcx140)
                return -ENOMEM;
 
+       adcx140->dev = &i2c->dev;
+
        adcx140->gpio_reset = devm_gpiod_get_optional(adcx140->dev,
                                                      "reset", GPIOD_OUT_LOW);
        if (IS_ERR(adcx140->gpio_reset))
@@ -1007,7 +1009,7 @@ static int adcx140_i2c_probe(struct i2c_client *i2c,
                        ret);
                return ret;
        }
-       adcx140->dev = &i2c->dev;
+
        i2c_set_clientdata(i2c, adcx140);
 
        return devm_snd_soc_register_component(&i2c->dev,
index 038be66..fc9ea19 100644 (file)
@@ -3514,6 +3514,8 @@ int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *
                return -EINVAL;
        }
 
+       pm_runtime_get_sync(component->dev);
+
        switch (micbias) {
        case 1:
                micdet = &wm8994->micdet[0];
@@ -3561,6 +3563,8 @@ int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *
 
        snd_soc_dapm_sync(dapm);
 
+       pm_runtime_put(component->dev);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm8994_mic_detect);
@@ -3932,6 +3936,8 @@ int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *
                return -EINVAL;
        }
 
+       pm_runtime_get_sync(component->dev);
+
        if (jack) {
                snd_soc_dapm_force_enable_pin(dapm, "CLK_SYS");
                snd_soc_dapm_sync(dapm);
@@ -4000,6 +4006,8 @@ int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *
                snd_soc_dapm_sync(dapm);
        }
 
+       pm_runtime_put(component->dev);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm8958_mic_detect);
@@ -4193,11 +4201,13 @@ static int wm8994_component_probe(struct snd_soc_component *component)
                        wm8994->hubs.dcs_readback_mode = 2;
                        break;
                }
+               wm8994->hubs.micd_scthr = true;
                break;
 
        case WM8958:
                wm8994->hubs.dcs_readback_mode = 1;
                wm8994->hubs.hp_startup_mode = 1;
+               wm8994->hubs.micd_scthr = true;
 
                switch (control->revision) {
                case 0:
index 891effe..0c88184 100644 (file)
@@ -1223,6 +1223,9 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_component *component,
                snd_soc_component_update_bits(component, WM8993_ADDITIONAL_CONTROL,
                                    WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
 
+       if (!hubs->micd_scthr)
+               return 0;
+
        snd_soc_component_update_bits(component, WM8993_MICBIAS,
                            WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
                            WM8993_MICB1_LVL | WM8993_MICB2_LVL,
index 4b8e5f0..988b29e 100644 (file)
@@ -27,6 +27,7 @@ struct wm_hubs_data {
        int hp_startup_mode;
        int series_startup;
        int no_series_update;
+       bool micd_scthr;
 
        bool no_cache_dac_hp_direct;
        struct list_head dcs_cache;
index 4ae3609..79b861a 100644 (file)
@@ -708,9 +708,9 @@ static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx)
                           ESAI_xFCR_xFR, 0);
 }
 
-static void fsl_esai_hw_reset(unsigned long arg)
+static void fsl_esai_hw_reset(struct tasklet_struct *t)
 {
-       struct fsl_esai *esai_priv = (struct fsl_esai *)arg;
+       struct fsl_esai *esai_priv = from_tasklet(esai_priv, t, task);
        bool tx = true, rx = false, enabled[2];
        unsigned long lock_flags;
        u32 tfcr, rfcr;
@@ -1070,8 +1070,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
                return ret;
        }
 
-       tasklet_init(&esai_priv->task, fsl_esai_hw_reset,
-                    (unsigned long)esai_priv);
+       tasklet_setup(&esai_priv->task, fsl_esai_hw_reset);
 
        pm_runtime_enable(&pdev->dev);
 
index d8b9c65..404be27 100644 (file)
@@ -898,7 +898,7 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt)
                                        "missing baudclk for master mode\n");
                                return -EINVAL;
                        }
-                       /* fall through */
+                       fallthrough;
                case SND_SOC_DAIFMT_CBM_CFS:
                        ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER;
                        break;
index fd5dcd6..907f5f1 100644 (file)
@@ -261,13 +261,13 @@ static int hi6210_i2s_hw_params(struct snd_pcm_substream *substream,
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_U16_LE:
                signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
-               /* fall through */
+               fallthrough;
        case SNDRV_PCM_FORMAT_S16_LE:
                bits = HII2S_BITS_16;
                break;
        case SNDRV_PCM_FORMAT_U24_LE:
                signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
-               /* fall through */
+               fallthrough;
        case SNDRV_PCM_FORMAT_S24_LE:
                bits = HII2S_BITS_24;
                break;
index b1cac7a..fba2c79 100644 (file)
@@ -333,6 +333,17 @@ static int sst_media_open(struct snd_pcm_substream *substream,
        if (ret_val < 0)
                goto out_power_up;
 
+       /*
+        * Make sure the period to be multiple of 1ms to align the
+        * design of firmware. Apply same rule to buffer size to make
+        * sure alsa could always find a value for period size
+        * regardless the buffer size given by user space.
+        */
+       snd_pcm_hw_constraint_step(substream->runtime, 0,
+                          SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 48);
+       snd_pcm_hw_constraint_step(substream->runtime, 0,
+                          SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 48);
+
        /* Make sure, that the period size is always even */
        snd_pcm_hw_constraint_step(substream->runtime, 0,
                           SNDRV_PCM_HW_PARAM_PERIODS, 2);
index 54a66cc..d2cda33 100644 (file)
@@ -181,7 +181,7 @@ static int sst_byt_pcm_trigger(struct snd_soc_component *component,
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
                pdata->restore_stream = false;
-               /* fallthrough */
+               fallthrough;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                sst_byt_stream_pause(byt, pcm_data->stream);
                break;
index 414ae4b..7ae34b4 100644 (file)
@@ -573,7 +573,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
                        break;
                default:
                        dev_err(dev, "get speaker GPIO failed: %d\n", ret);
-                       /* fall through */
+                       fallthrough;
                case -EPROBE_DEFER:
                        return ret;
                }
index 479992f..fc20274 100644 (file)
@@ -591,6 +591,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF1 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {       /* MPMAN Converter 9, similar hw as the I.T.Works TW891 2-in-1 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MPMAN"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Converter9"),
+               },
+               .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+                                       BYT_RT5640_MONO_SPEAKER |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {
                /* MPMAN MPWIN895CL */
                .matches = {
index 4e28975..688b5e0 100644 (file)
@@ -1009,7 +1009,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
                        default:
                                dev_err(&pdev->dev, "Failed to get ext-amp-enable GPIO: %d\n",
                                        ret_val);
-                               /* fall through */
+                               fallthrough;
                        case -EPROBE_DEFER:
                                put_device(codec_dev);
                                return ret_val;
@@ -1029,7 +1029,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
                        default:
                                dev_err(&pdev->dev, "Failed to get hp-detect GPIO: %d\n",
                                        ret_val);
-                               /* fall through */
+                               fallthrough;
                        case -EPROBE_DEFER:
                                put_device(codec_dev);
                                return ret_val;
index ca49000..bc50eda 100644 (file)
@@ -181,7 +181,7 @@ static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card)
        struct snd_soc_dai *dai;
 
        for_each_card_rtds(card, rtd) {
-               if (!strstr(rtd->dai_link->codecs->name, "ehdaudio"))
+               if (!strstr(rtd->dai_link->codecs->name, "ehdaudio0D0"))
                        continue;
                dai = asoc_rtd_to_codec(rtd, 0);
                hda_pvt = snd_soc_component_get_drvdata(dai->component);
index 1a69615..b6e63ea 100644 (file)
@@ -66,6 +66,10 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd)
        int j;
        int ret = 0;
 
+       /* set spk pin by playback only */
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               return 0;
+
        for_each_rtd_codec_dais(rtd, j, codec_dai) {
                struct snd_soc_component *component = codec_dai->component;
                struct snd_soc_dapm_context *dapm =
@@ -86,9 +90,6 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd)
                case SNDRV_PCM_TRIGGER_STOP:
                case SNDRV_PCM_TRIGGER_SUSPEND:
                case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-                       /* Make sure no streams are active before disable pin */
-                       if (snd_soc_dai_active(codec_dai) != 1)
-                               break;
                        ret = snd_soc_dapm_disable_pin(dapm, pin_name);
                        if (!ret)
                                snd_soc_dapm_sync(dapm);
index de80e19..88c3f63 100644 (file)
@@ -243,92 +243,45 @@ static irqreturn_t hsw_irq(int irq, void *context)
        return ret;
 }
 
-#define CSR_DEFAULT_VALUE 0x8480040E
-#define ISC_DEFAULT_VALUE 0x0
-#define ISD_DEFAULT_VALUE 0x0
-#define IMC_DEFAULT_VALUE 0x7FFF0003
-#define IMD_DEFAULT_VALUE 0x7FFF0003
-#define IPCC_DEFAULT_VALUE 0x0
-#define IPCD_DEFAULT_VALUE 0x0
-#define CLKCTL_DEFAULT_VALUE 0x7FF
-#define CSR2_DEFAULT_VALUE 0x0
-#define LTR_CTRL_DEFAULT_VALUE 0x0
-#define HMD_CTRL_DEFAULT_VALUE 0x0
-
-static void hsw_set_shim_defaults(struct sst_dsp *sst)
-{
-       sst_dsp_shim_write_unlocked(sst, SST_CSR, CSR_DEFAULT_VALUE);
-       sst_dsp_shim_write_unlocked(sst, SST_ISRX, ISC_DEFAULT_VALUE);
-       sst_dsp_shim_write_unlocked(sst, SST_ISRD, ISD_DEFAULT_VALUE);
-       sst_dsp_shim_write_unlocked(sst, SST_IMRX, IMC_DEFAULT_VALUE);
-       sst_dsp_shim_write_unlocked(sst, SST_IMRD, IMD_DEFAULT_VALUE);
-       sst_dsp_shim_write_unlocked(sst, SST_IPCX, IPCC_DEFAULT_VALUE);
-       sst_dsp_shim_write_unlocked(sst, SST_IPCD, IPCD_DEFAULT_VALUE);
-       sst_dsp_shim_write_unlocked(sst, SST_CLKCTL, CLKCTL_DEFAULT_VALUE);
-       sst_dsp_shim_write_unlocked(sst, SST_CSR2, CSR2_DEFAULT_VALUE);
-       sst_dsp_shim_write_unlocked(sst, SST_LTRC, LTR_CTRL_DEFAULT_VALUE);
-       sst_dsp_shim_write_unlocked(sst, SST_HMDC, HMD_CTRL_DEFAULT_VALUE);
-}
-
-/* all clock-gating minus DCLCGE and DTCGE */
-#define SST_VDRTCL2_CG_OTHER   0xB7D
-
 static void hsw_set_dsp_D3(struct sst_dsp *sst)
 {
+       u32 val;
        u32 reg;
 
-       /* disable clock core gating */
+       /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg &= ~(SST_VDRTCL2_DCLCGE);
+       reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
        writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
 
-       /* stall, reset and set 24MHz XOSC */
-       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
-                       SST_CSR_24MHZ_LPCS | SST_CSR_STALL | SST_CSR_RST,
-                       SST_CSR_24MHZ_LPCS | SST_CSR_STALL | SST_CSR_RST);
-
-       /* DRAM power gating all */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
-       reg |= SST_VDRTCL0_ISRAMPGE_MASK |
-               SST_VDRTCL0_DSRAMPGE_MASK;
-       reg &= ~(SST_VDRTCL0_D3SRAMPGD);
-       reg |= SST_VDRTCL0_D3PGD;
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
-       udelay(50);
+       /* enable power gating and switch off DRAM & IRAM blocks */
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+       val |= SST_VDRTCL0_DSRAMPGE_MASK |
+               SST_VDRTCL0_ISRAMPGE_MASK;
+       val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD);
+       writel(val, sst->addr.pci_cfg + SST_VDRTCTL0);
 
-       /* PLL shutdown enable */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg |= SST_VDRTCL2_APLLSE_MASK;
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+       /* switch off audio PLL */
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+       val |= SST_VDRTCL2_APLLSE_MASK;
+       writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
 
-       /* disable MCLK */
+       /* disable MCLK(clkctl.smos = 0) */
        sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
-                       SST_CLKCTL_MASK, 0);
-
-       /* switch clock gating */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg |= SST_VDRTCL2_CG_OTHER;
-       reg &= ~(SST_VDRTCL2_DTCGE);
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
-       /* enable DTCGE separatelly */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg |= SST_VDRTCL2_DTCGE;
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+               SST_CLKCTL_MASK, 0);
 
-       /* set shim defaults */
-       hsw_set_shim_defaults(sst);
-
-       /* set D3 */
-       reg = readl(sst->addr.pci_cfg + SST_PMCS);
-       reg |= SST_PMCS_PS_MASK;
-       writel(reg, sst->addr.pci_cfg + SST_PMCS);
+       /* Set D3 state, delay 50 us */
+       val = readl(sst->addr.pci_cfg + SST_PMCS);
+       val |= SST_PMCS_PS_MASK;
+       writel(val, sst->addr.pci_cfg + SST_PMCS);
        udelay(50);
 
-       /* enable clock core gating */
+       /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg |= SST_VDRTCL2_DCLCGE;
+       reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
        writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
        udelay(50);
+
 }
 
 static void hsw_reset(struct sst_dsp *sst)
@@ -346,62 +299,75 @@ static void hsw_reset(struct sst_dsp *sst)
                SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
 }
 
-/* recommended CSR state for power-up */
-#define SST_CSR_D0_MASK (0x18A09C0C | SST_CSR_DCS_MASK)
-
 static int hsw_set_dsp_D0(struct sst_dsp *sst)
 {
-       u32 reg;
+       int tries = 10;
+       u32 reg, fw_dump_bit;
 
-       /* disable clock core gating */
+       /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg &= ~(SST_VDRTCL2_DCLCGE);
+       reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
        writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
 
-       /* switch clock gating */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg |= SST_VDRTCL2_CG_OTHER;
-       reg &= ~(SST_VDRTCL2_DTCGE);
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+       /* Disable D3PG (VDRTCTL0.D3PGD = 1) */
+       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+       reg |= SST_VDRTCL0_D3PGD;
+       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
 
-       /* set D0 */
+       /* Set D0 state */
        reg = readl(sst->addr.pci_cfg + SST_PMCS);
-       reg &= ~(SST_PMCS_PS_MASK);
+       reg &= ~SST_PMCS_PS_MASK;
        writel(reg, sst->addr.pci_cfg + SST_PMCS);
 
-       /* DRAM power gating none */
-       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
-       reg &= ~(SST_VDRTCL0_ISRAMPGE_MASK |
-               SST_VDRTCL0_DSRAMPGE_MASK);
-       reg |= SST_VDRTCL0_D3SRAMPGD;
-       reg |= SST_VDRTCL0_D3PGD;
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
-       mdelay(10);
+       /* check that ADSP shim is enabled */
+       while (tries--) {
+               reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK;
+               if (reg == 0)
+                       goto finish;
+
+               msleep(1);
+       }
+
+       return -ENODEV;
 
-       /* set shim defaults */
-       hsw_set_shim_defaults(sst);
+finish:
+       /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+               SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
+
+       /* stall DSP core, set clk to 192/96Mhz */
+       sst_dsp_shim_update_bits_unlocked(sst,
+               SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK,
+               SST_CSR_STALL | SST_CSR_DCS(4));
 
-       /* restore MCLK */
+       /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */
        sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
-                       SST_CLKCTL_MASK, SST_CLKCTL_MASK);
+               SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
+               SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
 
-       /* PLL shutdown disable */
+       /* Stall and reset core, set CSR */
+       hsw_reset(sst);
+
+       /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg &= ~(SST_VDRTCL2_APLLSE_MASK);
+       reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
        writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
 
-       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
-                       SST_CSR_D0_MASK, SST_CSR_SBCS0 | SST_CSR_SBCS1 |
-                       SST_CSR_STALL | SST_CSR_DCS(4));
        udelay(50);
 
-       /* enable clock core gating */
+       /* switch on audio PLL */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
-       reg |= SST_VDRTCL2_DCLCGE;
+       reg &= ~SST_VDRTCL2_APLLSE_MASK;
        writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
 
-       /* clear reset */
-       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_RST, 0);
+       /* set default power gating control, enable power gating control for all blocks. that is,
+       can't be accessed, please enable each block before accessing. */
+       reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+       reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
+       /* for D0, always enable the block(DSRAM[0]) used for FW dump */
+       fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
+       writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+
 
        /* disable DMA finish function for SSP0 & SSP1 */
        sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
@@ -418,6 +384,12 @@ static int hsw_set_dsp_D0(struct sst_dsp *sst)
        sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY |
                                SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0);
 
+       /* clear IPC registers */
+       sst_dsp_shim_write(sst, SST_IPCX, 0x0);
+       sst_dsp_shim_write(sst, SST_IPCD, 0x0);
+       sst_dsp_shim_write(sst, 0x80, 0x6);
+       sst_dsp_shim_write(sst, 0xe0, 0x300a);
+
        return 0;
 }
 
@@ -443,6 +415,11 @@ static void hsw_sleep(struct sst_dsp *sst)
 {
        dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n");
 
+       /* put DSP into reset and stall */
+       sst_dsp_shim_update_bits(sst, SST_CSR,
+               SST_CSR_24MHZ_LPCS | SST_CSR_RST | SST_CSR_STALL,
+               SST_CSR_RST | SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
+
        hsw_set_dsp_D3(sst);
        dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n");
 }
index 5dee55e..bbe8d78 100644 (file)
@@ -488,7 +488,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
                                                        stream->lpib);
                        snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
                }
-               /* fall through */
+               fallthrough;
 
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
index 36df309..c8664ab 100644 (file)
@@ -58,17 +58,17 @@ int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask,
        switch (slot_width) {
        case 0:
                slot_width = 32;
-               /* Fall-through */
+               fallthrough;
        case 32:
                fmt |= SNDRV_PCM_FMTBIT_S32_LE;
-               /* Fall-through */
+               fallthrough;
        case 24:
                fmt |= SNDRV_PCM_FMTBIT_S24_LE;
                fmt |= SNDRV_PCM_FMTBIT_S20_LE;
-               /* Fall-through */
+               fallthrough;
        case 16:
                fmt |= SNDRV_PCM_FMTBIT_S16_LE;
-               /* Fall-through */
+               fallthrough;
        case 8:
                fmt |= SNDRV_PCM_FMTBIT_S8;
                break;
@@ -133,7 +133,7 @@ static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        case SND_SOC_DAIFMT_CBS_CFM:
        case SND_SOC_DAIFMT_CBM_CFS:
                dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n");
-               /* Fall-through */
+               fallthrough;
        default:
                return -EINVAL;
        }
index e711abc..d6adf7e 100644 (file)
@@ -18,6 +18,7 @@
 #define CTRL0_TODDR_SEL_RESAMPLE       BIT(30)
 #define CTRL0_TODDR_EXT_SIGNED         BIT(29)
 #define CTRL0_TODDR_PP_MODE            BIT(28)
+#define CTRL0_TODDR_SYNC_CH            BIT(27)
 #define CTRL0_TODDR_TYPE_MASK          GENMASK(15, 13)
 #define CTRL0_TODDR_TYPE(x)            ((x) << 13)
 #define CTRL0_TODDR_MSB_POS_MASK       GENMASK(12, 8)
@@ -189,10 +190,31 @@ static const struct axg_fifo_match_data axg_toddr_match_data = {
        .dai_drv                = &axg_toddr_dai_drv
 };
 
+static int g12a_toddr_dai_startup(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+       struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       ret = axg_toddr_dai_startup(substream, dai);
+       if (ret)
+               return ret;
+
+       /*
+        * Make sure the first channel ends up in the at beginning of the output
+        * As weird as it looks, without this the first channel may be misplaced
+        * in memory, with a random shift of 2 channels.
+        */
+       regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_SYNC_CH,
+                          CTRL0_TODDR_SYNC_CH);
+
+       return 0;
+}
+
 static const struct snd_soc_dai_ops g12a_toddr_ops = {
        .prepare        = g12a_toddr_dai_prepare,
        .hw_params      = axg_toddr_dai_hw_params,
-       .startup        = axg_toddr_dai_startup,
+       .startup        = g12a_toddr_dai_startup,
        .shutdown       = axg_toddr_dai_shutdown,
 };
 
index d1e09ad..c4e7307 100644 (file)
@@ -488,7 +488,7 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
 
        case SND_SOC_DAIFMT_DSP_A:
                sspsp |= SSPSP_FSRT;
-               /* fall through */
+               fallthrough;
        case SND_SOC_DAIFMT_DSP_B:
                sscr0 |= SSCR0_MOD | SSCR0_PSP;
                sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
index 083413a..575e2ae 100644 (file)
@@ -143,6 +143,7 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev)
 
        card = &data->card;
        card->dev = dev;
+       card->owner = THIS_MODULE;
        card->dapm_widgets = apq8016_sbc_dapm_widgets;
        card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets);
 
index 2535496..1a69bae 100644 (file)
@@ -114,6 +114,7 @@ static int apq8096_platform_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        card->dev = dev;
+       card->owner = THIS_MODULE;
        dev_set_drvdata(dev, card);
        ret = qcom_snd_parse_of(card);
        if (ret)
index 5194d90..fd69cf8 100644 (file)
@@ -52,8 +52,10 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
 
        for_each_child_of_node(dev->of_node, np) {
                dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
-               if (!dlc)
-                       return -ENOMEM;
+               if (!dlc) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
 
                link->cpus      = &dlc[0];
                link->platforms = &dlc[1];
index 0d10fba..ab1bf23 100644 (file)
@@ -555,6 +555,7 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
        card->dapm_widgets = sdm845_snd_widgets;
        card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
        card->dev = dev;
+       card->owner = THIS_MODULE;
        dev_set_drvdata(dev, card);
        ret = qcom_snd_parse_of(card);
        if (ret)
index c0c388d..80c9cf2 100644 (file)
@@ -96,6 +96,7 @@ static int storm_platform_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        card->dev = &pdev->dev;
+       card->owner = THIS_MODULE;
 
        ret = snd_soc_of_parse_card_name(card, "qcom,model");
        if (ret) {
index 1707414..5adb293 100644 (file)
@@ -229,13 +229,13 @@ static int rockchip_pdm_hw_params(struct snd_pcm_substream *substream,
        switch (params_channels(params)) {
        case 8:
                val |= PDM_PATH3_EN;
-               /* fallthrough */
+               fallthrough;
        case 6:
                val |= PDM_PATH2_EN;
-               /* fallthrough */
+               fallthrough;
        case 4:
                val |= PDM_PATH1_EN;
-               /* fallthrough */
+               fallthrough;
        case 2:
                val |= PDM_PATH0_EN;
                break;
index 80ecb5c..df53d4e 100644 (file)
@@ -733,7 +733,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
        switch (params_channels(params)) {
        case 6:
                val |= MOD_DC2_EN;
-               /* Fall through */
+               fallthrough;
        case 4:
                val |= MOD_DC1_EN;
                break;
index bd9de77..50fc781 100644 (file)
@@ -198,9 +198,9 @@ static int siu_pcm_rd_set(struct siu_port *port_info,
        return 0;
 }
 
-static void siu_io_tasklet(unsigned long data)
+static void siu_io_tasklet(struct tasklet_struct *t)
 {
-       struct siu_stream *siu_stream = (struct siu_stream *)data;
+       struct siu_stream *siu_stream = from_tasklet(siu_stream, t, tasklet);
        struct snd_pcm_substream *substream = siu_stream->substream;
        struct device *dev = substream->pcm->card->dev;
        struct snd_pcm_runtime *rt = substream->runtime;
@@ -520,10 +520,8 @@ static int siu_pcm_new(struct snd_soc_component *component,
                (*port_info)->pcm = pcm;
 
                /* IO tasklets */
-               tasklet_init(&(*port_info)->playback.tasklet, siu_io_tasklet,
-                            (unsigned long)&(*port_info)->playback);
-               tasklet_init(&(*port_info)->capture.tasklet, siu_io_tasklet,
-                            (unsigned long)&(*port_info)->capture);
+               tasklet_setup(&(*port_info)->playback.tasklet, siu_io_tasklet);
+               tasklet_setup(&(*port_info)->capture.tasklet, siu_io_tasklet);
        }
 
        dev_info(card->dev, "SuperH SIU driver initialized.\n");
index 2fe1b2e..0544376 100644 (file)
@@ -618,7 +618,7 @@ int snd_soc_suspend(struct device *dev)
                                                "ASoC: idle_bias_off CODEC on over suspend\n");
                                        break;
                                }
-                               /* fall through */
+                               fallthrough;
 
                        case SND_SOC_BIAS_OFF:
                                snd_soc_component_suspend(component);
@@ -834,6 +834,19 @@ struct snd_soc_dai *snd_soc_find_dai(
 }
 EXPORT_SYMBOL_GPL(snd_soc_find_dai);
 
+struct snd_soc_dai *snd_soc_find_dai_with_mutex(
+       const struct snd_soc_dai_link_component *dlc)
+{
+       struct snd_soc_dai *dai;
+
+       mutex_lock(&client_mutex);
+       dai = snd_soc_find_dai(dlc);
+       mutex_unlock(&client_mutex);
+
+       return dai;
+}
+EXPORT_SYMBOL_GPL(snd_soc_find_dai_with_mutex);
+
 static int soc_dai_link_sanity_check(struct snd_soc_card *card,
                                     struct snd_soc_dai_link *link)
 {
index 91a2551..0dbd312 100644 (file)
@@ -412,14 +412,14 @@ void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link)
                supported_codec = false;
 
                for_each_link_cpus(dai_link, i, cpu) {
-                       dai = snd_soc_find_dai(cpu);
+                       dai = snd_soc_find_dai_with_mutex(cpu);
                        if (dai && snd_soc_dai_stream_valid(dai, direction)) {
                                supported_cpu = true;
                                break;
                        }
                }
                for_each_link_codecs(dai_link, i, codec) {
-                       dai = snd_soc_find_dai(codec);
+                       dai = snd_soc_find_dai_with_mutex(codec);
                        if (dai && snd_soc_dai_stream_valid(dai, direction)) {
                                supported_codec = true;
                                break;
index 00ac1cb..4c9d4cd 100644 (file)
@@ -812,7 +812,7 @@ dynamic:
        return 0;
 
 config_err:
-       for_each_rtd_dais(rtd, i, dai)
+       for_each_rtd_dais_rollback(rtd, i, dai)
                snd_soc_dai_shutdown(dai, substream);
 
        snd_soc_link_shutdown(substream);
index cee9986..5b60379 100644 (file)
@@ -1057,7 +1057,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
                                        ec->hdr.name);
                                goto err_denum;
                        }
-                       /* fall through */
+                       fallthrough;
                case SND_SOC_TPLG_CTL_ENUM:
                case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
                case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
@@ -1445,7 +1445,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
                                        ec->hdr.name);
                                goto err_se;
                        }
-                       /* fall through */
+                       fallthrough;
                case SND_SOC_TPLG_CTL_ENUM:
                case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
                case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
index df1c699..c6cb8c2 100644 (file)
@@ -310,7 +310,7 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
                        return ret;
                }
 
-               /* fallthrough */
+               fallthrough;
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                snd_hdac_ext_link_stream_start(link_dev);
@@ -333,7 +333,7 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
 
                link_dev->link_prepared = 0;
 
-               /* fallthrough */
+               fallthrough;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                snd_hdac_ext_link_stream_clear(link_dev);
                break;
index d730e43..71c3f29 100644 (file)
@@ -361,7 +361,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
                        return ret;
                }
 
-               /* fallthrough */
+               fallthrough;
        case SNDRV_PCM_TRIGGER_START:
                if (spcm->stream[substream->stream].suspend_ignored) {
                        /*
@@ -386,7 +386,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
                        spcm->stream[substream->stream].suspend_ignored = true;
                        return 0;
                }
-               /* fallthrough */
+               fallthrough;
        case SNDRV_PCM_TRIGGER_STOP:
                stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
                ipc_first = true;
index 5c47de9..57feb47 100644 (file)
@@ -446,12 +446,12 @@ static const struct snd_soc_dai_ops ams_delta_dai_ops = {
 /* Will be used if the codec ever has its own digital_mute function */
 static int ams_delta_startup(struct snd_pcm_substream *substream)
 {
-       return ams_delta_digital_mute(NULL, 0, substream->stream);
+       return ams_delta_mute(NULL, 0, substream->stream);
 }
 
 static void ams_delta_shutdown(struct snd_pcm_substream *substream)
 {
-       ams_delta_digital_mute(NULL, 1, substream->stream);
+       ams_delta_mute(NULL, 1, substream->stream);
 }
 
 
index d89b5c9..dd34504 100644 (file)
@@ -289,7 +289,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                 * rate is lowered.
                 */
                inv_fs = true;
-               /* fall through */
+               fallthrough;
        case SND_SOC_DAIFMT_DSP_A:
                dev->mode = MOD_DSP_A;
                break;
index 2802a33..ed217b3 100644 (file)
@@ -46,7 +46,7 @@ static void n810_ext_control(struct snd_soc_dapm_context *dapm)
        switch (n810_jack_func) {
        case N810_JACK_HS:
                line1l = 1;
-               /* fall through */
+               fallthrough;
        case N810_JACK_HP:
                hp = 1;
                break;
index 01abf1b..a26588e 100644 (file)
@@ -203,10 +203,10 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
        switch (channels) {
        case 6:
                dmic->ch_enabled |= OMAP_DMIC_UP3_ENABLE;
-               /* fall through */
+               fallthrough;
        case 4:
                dmic->ch_enabled |= OMAP_DMIC_UP2_ENABLE;
-               /* fall through */
+               fallthrough;
        case 2:
                dmic->ch_enabled |= OMAP_DMIC_UP1_ENABLE;
                break;
index d482b62..fafb299 100644 (file)
@@ -309,19 +309,19 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
                        /* up to 3 channels for capture */
                        return -EINVAL;
                link_mask |= 1 << 4;
-               /* fall through */
+               fallthrough;
        case 4:
                if (stream == SNDRV_PCM_STREAM_CAPTURE)
                        /* up to 3 channels for capture */
                        return -EINVAL;
                link_mask |= 1 << 3;
-               /* fall through */
+               fallthrough;
        case 3:
                link_mask |= 1 << 2;
-               /* fall through */
+               fallthrough;
        case 2:
                link_mask |= 1 << 1;
-               /* fall through */
+               fallthrough;
        case 1:
                link_mask |= 1 << 0;
                break;
index 2176a95..a2629cc 100644 (file)
@@ -55,7 +55,7 @@ static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
                break;
        case RX51_JACK_HS:
                hs = 1;
-               /* fall through */
+               fallthrough;
        case RX51_JACK_HP:
                hp = 1;
                break;
index 4b1cd4d..939b33e 100644 (file)
@@ -134,9 +134,9 @@ txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr)
 
 #define NR_DMA_CHAIN           2
 
-static void txx9aclc_dma_tasklet(unsigned long data)
+static void txx9aclc_dma_tasklet(struct tasklet_struct *t)
 {
-       struct txx9aclc_dmadata *dmadata = (struct txx9aclc_dmadata *)data;
+       struct txx9aclc_dmadata *dmadata = from_tasklet(dmadata, t, tasklet);
        struct dma_chan *chan = dmadata->dma_chan;
        struct dma_async_tx_descriptor *desc;
        struct snd_pcm_substream *substream = dmadata->substream;
@@ -352,8 +352,7 @@ static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
                        "playback" : "capture");
                return -EBUSY;
        }
-       tasklet_init(&dmadata->tasklet, txx9aclc_dma_tasklet,
-                    (unsigned long)dmadata);
+       tasklet_setup(&dmadata->tasklet, txx9aclc_dma_tasklet);
        return 0;
 }
 
index 568cde6..1c1a44e 100644 (file)
@@ -294,7 +294,7 @@ static int zx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
                        zx_i2s_rx_dma_en(zx_i2s->reg_base, true);
                else
                        zx_i2s_tx_dma_en(zx_i2s->reg_base, true);
-       /* fall thru */
+               fallthrough;
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                if (capture)
@@ -308,7 +308,7 @@ static int zx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
                        zx_i2s_rx_dma_en(zx_i2s->reg_base, false);
                else
                        zx_i2s_tx_dma_en(zx_i2s->reg_base, false);
-       /* fall thru */
+               fallthrough;
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                if (capture)
index a3a07c0..b4168bd 100644 (file)
@@ -218,7 +218,7 @@ static int zx_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
                val = readl_relaxed(zx_spdif->reg_base + ZX_FIFOCTRL);
                val |= ZX_FIFOCTRL_TX_FIFO_RST;
                writel_relaxed(val, zx_spdif->reg_base + ZX_FIFOCTRL);
-       /* fall thru */
+               fallthrough;
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                zx_spdif_cfg_tx(zx_spdif->reg_base, true);
index df639fe..e8287a0 100644 (file)
@@ -344,10 +344,9 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint *ep)
        spin_unlock_irqrestore(&ep->buffer_lock, flags);
 }
 
-static void snd_usbmidi_out_tasklet(unsigned long data)
+static void snd_usbmidi_out_tasklet(struct tasklet_struct *t)
 {
-       struct snd_usb_midi_out_endpoint *ep =
-               (struct snd_usb_midi_out_endpoint *) data;
+       struct snd_usb_midi_out_endpoint *ep = from_tasklet(ep, t, tasklet);
 
        snd_usbmidi_do_output(ep);
 }
@@ -1441,7 +1440,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi,
        }
 
        spin_lock_init(&ep->buffer_lock);
-       tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep);
+       tasklet_setup(&ep->tasklet, snd_usbmidi_out_tasklet);
        init_waitqueue_head(&ep->drain_wait);
 
        for (i = 0; i < 0x10; ++i)
index 884e740..3b2dce1 100644 (file)
@@ -247,9 +247,9 @@ static inline void add_with_wraparound(struct ua101 *ua,
                *value -= ua->playback.queue_length;
 }
 
-static void playback_tasklet(unsigned long data)
+static void playback_tasklet(struct tasklet_struct *t)
 {
-       struct ua101 *ua = (void *)data;
+       struct ua101 *ua = from_tasklet(ua, t, playback_tasklet);
        unsigned long flags;
        unsigned int frames;
        struct ua101_urb *urb;
@@ -1218,8 +1218,7 @@ static int ua101_probe(struct usb_interface *interface,
        spin_lock_init(&ua->lock);
        mutex_init(&ua->mutex);
        INIT_LIST_HEAD(&ua->ready_playback_urbs);
-       tasklet_init(&ua->playback_tasklet,
-                    playback_tasklet, (unsigned long)ua);
+       tasklet_setup(&ua->playback_tasklet, playback_tasklet);
        init_waitqueue_head(&ua->alsa_capture_wait);
        init_waitqueue_head(&ua->rate_feedback_wait);
        init_waitqueue_head(&ua->alsa_playback_wait);
index 5b43e9e..c369c81 100644 (file)
@@ -371,7 +371,6 @@ static const struct usbmix_name_map asus_rog_map[] = {
 };
 
 static const struct usbmix_name_map lenovo_p620_rear_map[] = {
-       { 19, NULL, 2 }, /* FU, Volume */
        { 19, NULL, 12 }, /* FU, Input Gain Pad */
        {}
 };
index 5600751..b401ee8 100644 (file)
@@ -369,11 +369,13 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
        case USB_ID(0x07fd, 0x0008): /* MOTU M Series */
        case USB_ID(0x31e9, 0x0001): /* Solid State Logic SSL2 */
        case USB_ID(0x31e9, 0x0002): /* Solid State Logic SSL2+ */
+       case USB_ID(0x0499, 0x172f): /* Steinberg UR22C */
        case USB_ID(0x0d9a, 0x00df): /* RTX6001 */
                ep = 0x81;
                ifnum = 2;
                goto add_sync_ep_from_ifnum;
        case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */
+       case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
                ep = 0x82;
                ifnum = 0;
                goto add_sync_ep_from_ifnum;
index f4fb002..23eafd5 100644 (file)
@@ -2827,14 +2827,24 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 /* Lenovo ThinkStation P620 Rear Line-in, Line-out and Microphone */
 {
        USB_DEVICE(0x17aa, 0x1046),
-       QUIRK_DEVICE_PROFILE("Lenovo", "ThinkStation P620 Rear",
-                            "Lenovo-ThinkStation-P620-Rear"),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Lenovo",
+               .product_name = "ThinkStation P620 Rear",
+               .profile_name = "Lenovo-ThinkStation-P620-Rear",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_SETUP_DISABLE_AUTOSUSPEND
+       }
 },
 /* Lenovo ThinkStation P620 Internal Speaker + Front Headset */
 {
        USB_DEVICE(0x17aa, 0x104d),
-       QUIRK_DEVICE_PROFILE("Lenovo", "ThinkStation P620 Main",
-                            "Lenovo-ThinkStation-P620-Main"),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Lenovo",
+               .product_name = "ThinkStation P620 Main",
+               .profile_name = "Lenovo-ThinkStation-P620-Main",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_SETUP_DISABLE_AUTOSUSPEND
+       }
 },
 
 /* Native Instruments MK2 series */
@@ -3549,14 +3559,40 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
 {
        /*
         * Pioneer DJ DJM-250MK2
-        * PCM is 8 channels out @ 48 fixed (endpoints 0x01).
-        * The output from computer to the mixer is usable.
+        * PCM is 8 channels out @ 48 fixed (endpoint 0x01)
+        * and 8 channels in @ 48 fixed (endpoint 0x82).
+        *
+        * Both playback and recording is working, even simultaneously.
         *
-        * The input (phono or line to computer) is not working.
-        * It should be at endpoint 0x82 and probably also 8 channels,
-        * but it seems that it works only with Pioneer proprietary software.
-        * Even on officially supported OS, the Audacity was unable to record
-        * and Mixxx to recognize the control vinyls.
+        * Playback channels could be mapped to:
+        *  - CH1
+        *  - CH2
+        *  - AUX
+        *
+        * Recording channels could be mapped to:
+        *  - Post CH1 Fader
+        *  - Post CH2 Fader
+        *  - Cross Fader A
+        *  - Cross Fader B
+        *  - MIC
+        *  - AUX
+        *  - REC OUT
+        *
+        * There is remaining problem with recording directly from PHONO/LINE.
+        * If we map a channel to:
+        *  - CH1 Control Tone PHONO
+        *  - CH1 Control Tone LINE
+        *  - CH2 Control Tone PHONO
+        *  - CH2 Control Tone LINE
+        * it is silent.
+        * There is no signal even on other operating systems with official drivers.
+        * The signal appears only when a supported application is started.
+        * This needs to be investigated yet...
+        * (there is quite a lot communication on the USB in both directions)
+        *
+        * In current version this mixer could be used for playback
+        * and for recording from vinyls (through Post CH* Fader)
+        * but not for DVS (Digital Vinyl Systems) like in Mixxx.
         */
        USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0017),
        .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
@@ -3580,6 +3616,26 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
                                        .rate_max = 48000,
                                        .nr_rates = 1,
                                        .rate_table = (unsigned int[]) { 48000 }
+                                       }
+                       },
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8, // inputs
+                                       .iface = 0,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC|
+                                               USB_ENDPOINT_SYNC_ASYNC|
+                                               USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 48000 }
                                }
                        },
                        {
index abf99b8..892296d 100644 (file)
@@ -518,6 +518,15 @@ static int setup_fmt_after_resume_quirk(struct snd_usb_audio *chip,
        return 1;       /* Continue with creating streams and mixer */
 }
 
+static int setup_disable_autosuspend(struct snd_usb_audio *chip,
+                                      struct usb_interface *iface,
+                                      struct usb_driver *driver,
+                                      const struct snd_usb_audio_quirk *quirk)
+{
+       driver->supports_autosuspend = 0;
+       return 1;       /* Continue with creating streams and mixer */
+}
+
 /*
  * audio-interface quirks
  *
@@ -557,6 +566,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,
                [QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
                [QUIRK_SETUP_FMT_AFTER_RESUME] = setup_fmt_after_resume_quirk,
+               [QUIRK_SETUP_DISABLE_AUTOSUSPEND] = setup_disable_autosuspend,
        };
 
        if (quirk->type < QUIRK_TYPE_COUNT) {
@@ -1493,6 +1503,7 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
                set_format_emu_quirk(subs, fmt);
                break;
        case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */
+       case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
                pioneer_djm_set_format_quirk(subs);
                break;
        case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
@@ -1667,12 +1678,13 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
            && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
                msleep(20);
 
-       /* Zoom R16/24, Logitech H650e, Jabra 550a, Kingston HyperX needs a tiny
-        * delay here, otherwise requests like get/set frequency return as
-        * failed despite actually succeeding.
+       /* Zoom R16/24, Logitech H650e/H570e, Jabra 550a, Kingston HyperX
+        *  needs a tiny delay here, otherwise requests like get/set
+        *  frequency return as failed despite actually succeeding.
         */
        if ((chip->usb_id == USB_ID(0x1686, 0x00dd) ||
             chip->usb_id == USB_ID(0x046d, 0x0a46) ||
+            chip->usb_id == USB_ID(0x046d, 0x0a56) ||
             chip->usb_id == USB_ID(0x0b0e, 0x0349) ||
             chip->usb_id == USB_ID(0x0951, 0x16ad)) &&
            (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
index b91c4c0..6839915 100644 (file)
@@ -102,6 +102,7 @@ enum quirk_type {
        QUIRK_AUDIO_ALIGN_TRANSFER,
        QUIRK_AUDIO_STANDARD_MIXER,
        QUIRK_SETUP_FMT_AFTER_RESUME,
+       QUIRK_SETUP_DISABLE_AUTOSUSPEND,
 
        QUIRK_TYPE_COUNT
 };
index 7777719..4ffcc5e 100644 (file)
@@ -9,7 +9,7 @@ menuconfig SND_X86
 if SND_X86
 
 config HDMI_LPE_AUDIO
-       tristate "HDMI audio without HDaudio on Intel Atom platforms"
+       tristate "HDMI audio without HDAudio on Intel Atom platforms"
        depends on DRM_I915
        select SND_PCM
        help
diff --git a/tools/arch/x86/include/asm/mcsafe_test.h b/tools/arch/x86/include/asm/mcsafe_test.h
deleted file mode 100644 (file)
index 2ccd588..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _MCSAFE_TEST_H_
-#define _MCSAFE_TEST_H_
-
-.macro MCSAFE_TEST_CTL
-.endm
-
-.macro MCSAFE_TEST_SRC reg count target
-.endm
-
-.macro MCSAFE_TEST_DST reg count target
-.endm
-#endif /* _MCSAFE_TEST_H_ */
index 45f8e1b..0b5b8ae 100644 (file)
@@ -4,7 +4,6 @@
 #include <linux/linkage.h>
 #include <asm/errno.h>
 #include <asm/cpufeatures.h>
-#include <asm/mcsafe_test.h>
 #include <asm/alternative-asm.h>
 #include <asm/export.h>
 
@@ -187,117 +186,3 @@ SYM_FUNC_START(memcpy_orig)
 SYM_FUNC_END(memcpy_orig)
 
 .popsection
-
-#ifndef CONFIG_UML
-
-MCSAFE_TEST_CTL
-
-/*
- * __memcpy_mcsafe - memory copy with machine check exception handling
- * Note that we only catch machine checks when reading the source addresses.
- * Writes to target are posted and don't generate machine checks.
- */
-SYM_FUNC_START(__memcpy_mcsafe)
-       cmpl $8, %edx
-       /* Less than 8 bytes? Go to byte copy loop */
-       jb .L_no_whole_words
-
-       /* Check for bad alignment of source */
-       testl $7, %esi
-       /* Already aligned */
-       jz .L_8byte_aligned
-
-       /* Copy one byte at a time until source is 8-byte aligned */
-       movl %esi, %ecx
-       andl $7, %ecx
-       subl $8, %ecx
-       negl %ecx
-       subl %ecx, %edx
-.L_read_leading_bytes:
-       movb (%rsi), %al
-       MCSAFE_TEST_SRC %rsi 1 .E_leading_bytes
-       MCSAFE_TEST_DST %rdi 1 .E_leading_bytes
-.L_write_leading_bytes:
-       movb %al, (%rdi)
-       incq %rsi
-       incq %rdi
-       decl %ecx
-       jnz .L_read_leading_bytes
-
-.L_8byte_aligned:
-       movl %edx, %ecx
-       andl $7, %edx
-       shrl $3, %ecx
-       jz .L_no_whole_words
-
-.L_read_words:
-       movq (%rsi), %r8
-       MCSAFE_TEST_SRC %rsi 8 .E_read_words
-       MCSAFE_TEST_DST %rdi 8 .E_write_words
-.L_write_words:
-       movq %r8, (%rdi)
-       addq $8, %rsi
-       addq $8, %rdi
-       decl %ecx
-       jnz .L_read_words
-
-       /* Any trailing bytes? */
-.L_no_whole_words:
-       andl %edx, %edx
-       jz .L_done_memcpy_trap
-
-       /* Copy trailing bytes */
-       movl %edx, %ecx
-.L_read_trailing_bytes:
-       movb (%rsi), %al
-       MCSAFE_TEST_SRC %rsi 1 .E_trailing_bytes
-       MCSAFE_TEST_DST %rdi 1 .E_trailing_bytes
-.L_write_trailing_bytes:
-       movb %al, (%rdi)
-       incq %rsi
-       incq %rdi
-       decl %ecx
-       jnz .L_read_trailing_bytes
-
-       /* Copy successful. Return zero */
-.L_done_memcpy_trap:
-       xorl %eax, %eax
-.L_done:
-       ret
-SYM_FUNC_END(__memcpy_mcsafe)
-EXPORT_SYMBOL_GPL(__memcpy_mcsafe)
-
-       .section .fixup, "ax"
-       /*
-        * Return number of bytes not copied for any failure. Note that
-        * there is no "tail" handling since the source buffer is 8-byte
-        * aligned and poison is cacheline aligned.
-        */
-.E_read_words:
-       shll    $3, %ecx
-.E_leading_bytes:
-       addl    %edx, %ecx
-.E_trailing_bytes:
-       mov     %ecx, %eax
-       jmp     .L_done
-
-       /*
-        * For write fault handling, given the destination is unaligned,
-        * we handle faults on multi-byte writes with a byte-by-byte
-        * copy up to the write-protected page.
-        */
-.E_write_words:
-       shll    $3, %ecx
-       addl    %edx, %ecx
-       movl    %ecx, %edx
-       jmp mcsafe_handle_tail
-
-       .previous
-
-       _ASM_EXTABLE_FAULT(.L_read_leading_bytes, .E_leading_bytes)
-       _ASM_EXTABLE_FAULT(.L_read_words, .E_read_words)
-       _ASM_EXTABLE_FAULT(.L_read_trailing_bytes, .E_trailing_bytes)
-       _ASM_EXTABLE(.L_write_leading_bytes, .E_leading_bytes)
-       _ASM_EXTABLE(.L_write_words, .E_write_words)
-       _ASM_EXTABLE(.L_write_trailing_bytes, .E_trailing_bytes)
-#endif
index 56284b9..d295e40 100755 (executable)
@@ -137,6 +137,31 @@ $BOOTCONF $INITRD > $TEMPCONF
 cat $TEMPCONF
 xpass grep \'\"string\"\' $TEMPCONF
 
+echo "Repeat same-key tree"
+cat > $TEMPCONF << EOF
+foo
+bar
+foo { buz }
+EOF
+echo > $INITRD
+
+xpass $BOOTCONF -a $TEMPCONF $INITRD
+$BOOTCONF $INITRD > $OUTFILE
+xpass grep -q "bar" $OUTFILE
+
+
+echo "Remove/keep tailing spaces"
+cat > $TEMPCONF << EOF
+foo = val     # comment
+bar = "val2 " # comment
+EOF
+echo > $INITRD
+
+xpass $BOOTCONF -a $TEMPCONF $INITRD
+$BOOTCONF $INITRD > $OUTFILE
+xfail grep -q val[[:space:]] $OUTFILE
+xpass grep -q val2[[:space:]] $OUTFILE
+
 echo "=== expected failure cases ==="
 for i in samples/bad-* ; do
   xfail $BOOTCONF -a $i $INITRD
index 0a6d09a..39bb322 100644 (file)
@@ -38,7 +38,7 @@ FEATURE_TESTS = libbfd disassembler-four-args
 FEATURE_DISPLAY = libbfd disassembler-four-args
 
 check_feat := 1
-NON_CHECK_FEAT_TARGETS := clean bpftool_clean runqslower_clean
+NON_CHECK_FEAT_TARGETS := clean bpftool_clean runqslower_clean resolve_btfids_clean
 ifdef MAKECMDGOALS
 ifeq ($(filter-out $(NON_CHECK_FEAT_TARGETS),$(MAKECMDGOALS)),)
   check_feat := 0
@@ -89,7 +89,7 @@ $(OUTPUT)bpf_exp.lex.c: $(OUTPUT)bpf_exp.yacc.c
 $(OUTPUT)bpf_exp.yacc.o: $(OUTPUT)bpf_exp.yacc.c
 $(OUTPUT)bpf_exp.lex.o: $(OUTPUT)bpf_exp.lex.c
 
-clean: bpftool_clean runqslower_clean
+clean: bpftool_clean runqslower_clean resolve_btfids_clean
        $(call QUIET_CLEAN, bpf-progs)
        $(Q)$(RM) -r -- $(OUTPUT)*.o $(OUTPUT)bpf_jit_disasm $(OUTPUT)bpf_dbg \
               $(OUTPUT)bpf_asm $(OUTPUT)bpf_exp.yacc.* $(OUTPUT)bpf_exp.lex.*
index 8462690..4828913 100644 (file)
@@ -25,7 +25,7 @@ endif
 
 LIBBPF = $(LIBBPF_PATH)libbpf.a
 
-BPFTOOL_VERSION := $(shell make -rR --no-print-directory -sC ../../.. kernelversion)
+BPFTOOL_VERSION ?= $(shell make -rR --no-print-directory -sC ../../.. kernelversion)
 
 $(LIBBPF): FORCE
        $(if $(LIBBPF_OUTPUT),@mkdir -p $(LIBBPF_OUTPUT))
index a88cd44..fe8eb53 100644 (file)
@@ -80,6 +80,7 @@ libbpf-clean:
 clean: libsubcmd-clean libbpf-clean fixdep-clean
        $(call msg,CLEAN,$(BINARY))
        $(Q)$(RM) -f $(BINARY); \
+       $(RM) -rf $(if $(OUTPUT),$(OUTPUT),.)/feature; \
        find $(if $(OUTPUT),$(OUTPUT),.) -name \*.o -or -name \*.o.cmd -or -name \*.o.d | xargs $(RM)
 
 tags:
diff --git a/tools/include/linux/static_call_types.h b/tools/include/linux/static_call_types.h
new file mode 100644 (file)
index 0000000..89135bb
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _STATIC_CALL_TYPES_H
+#define _STATIC_CALL_TYPES_H
+
+#include <linux/types.h>
+#include <linux/stringify.h>
+
+#define STATIC_CALL_KEY_PREFIX         __SCK__
+#define STATIC_CALL_KEY_PREFIX_STR     __stringify(STATIC_CALL_KEY_PREFIX)
+#define STATIC_CALL_KEY_PREFIX_LEN     (sizeof(STATIC_CALL_KEY_PREFIX_STR) - 1)
+#define STATIC_CALL_KEY(name)          __PASTE(STATIC_CALL_KEY_PREFIX, name)
+
+#define STATIC_CALL_TRAMP_PREFIX       __SCT__
+#define STATIC_CALL_TRAMP_PREFIX_STR   __stringify(STATIC_CALL_TRAMP_PREFIX)
+#define STATIC_CALL_TRAMP_PREFIX_LEN   (sizeof(STATIC_CALL_TRAMP_PREFIX_STR) - 1)
+#define STATIC_CALL_TRAMP(name)                __PASTE(STATIC_CALL_TRAMP_PREFIX, name)
+#define STATIC_CALL_TRAMP_STR(name)    __stringify(STATIC_CALL_TRAMP(name))
+
+/*
+ * Flags in the low bits of static_call_site::key.
+ */
+#define STATIC_CALL_SITE_TAIL 1UL      /* tail call */
+#define STATIC_CALL_SITE_INIT 2UL      /* init section */
+#define STATIC_CALL_SITE_FLAGS 3UL
+
+/*
+ * The static call site table needs to be created by external tooling (objtool
+ * or a compiler plugin).
+ */
+struct static_call_site {
+       s32 addr;
+       s32 key;
+};
+
+#endif /* _STATIC_CALL_TYPES_H */
index 995b36c..f2b5d72 100644 (file)
@@ -140,7 +140,7 @@ __SYSCALL(__NR_renameat, sys_renameat)
 #define __NR_umount2 39
 __SYSCALL(__NR_umount2, sys_umount)
 #define __NR_mount 40
-__SC_COMP(__NR_mount, sys_mount, compat_sys_mount)
+__SYSCALL(__NR_mount, sys_mount)
 #define __NR_pivot_root 41
 __SYSCALL(__NR_pivot_root, sys_pivot_root)
 
@@ -207,9 +207,9 @@ __SYSCALL(__NR_read, sys_read)
 #define __NR_write 64
 __SYSCALL(__NR_write, sys_write)
 #define __NR_readv 65
-__SC_COMP(__NR_readv, sys_readv, compat_sys_readv)
+__SC_COMP(__NR_readv, sys_readv, sys_readv)
 #define __NR_writev 66
-__SC_COMP(__NR_writev, sys_writev, compat_sys_writev)
+__SC_COMP(__NR_writev, sys_writev, sys_writev)
 #define __NR_pread64 67
 __SC_COMP(__NR_pread64, sys_pread64, compat_sys_pread64)
 #define __NR_pwrite64 68
@@ -237,7 +237,7 @@ __SC_COMP(__NR_signalfd4, sys_signalfd4, compat_sys_signalfd4)
 
 /* fs/splice.c */
 #define __NR_vmsplice 75
-__SC_COMP(__NR_vmsplice, sys_vmsplice, compat_sys_vmsplice)
+__SYSCALL(__NR_vmsplice, sys_vmsplice)
 #define __NR_splice 76
 __SYSCALL(__NR_splice, sys_splice)
 #define __NR_tee 77
@@ -727,11 +727,9 @@ __SYSCALL(__NR_setns, sys_setns)
 #define __NR_sendmmsg 269
 __SC_COMP(__NR_sendmmsg, sys_sendmmsg, compat_sys_sendmmsg)
 #define __NR_process_vm_readv 270
-__SC_COMP(__NR_process_vm_readv, sys_process_vm_readv, \
-          compat_sys_process_vm_readv)
+__SYSCALL(__NR_process_vm_readv, sys_process_vm_readv)
 #define __NR_process_vm_writev 271
-__SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \
-          compat_sys_process_vm_writev)
+__SYSCALL(__NR_process_vm_writev, sys_process_vm_writev)
 #define __NR_kcmp 272
 __SYSCALL(__NR_kcmp, sys_kcmp)
 #define __NR_finit_module 273
index 3d0d823..7d66876 100644 (file)
@@ -135,7 +135,7 @@ struct in_addr {
  * this socket to prevent accepting spoofed ones.
  */
 #define IP_PMTUDISC_INTERFACE          4
-/* weaker version of IP_PMTUDISC_INTERFACE, which allos packets to get
+/* weaker version of IP_PMTUDISC_INTERFACE, which allows packets to get
  * fragmented if they exeed the interface mtu
  */
 #define IP_PMTUDISC_OMIT               5
index f6d8603..7d8eced 100644 (file)
@@ -790,9 +790,10 @@ struct kvm_ppc_resize_hpt {
 #define KVM_VM_PPC_HV 1
 #define KVM_VM_PPC_PR 2
 
-/* on MIPS, 0 forces trap & emulate, 1 forces VZ ASE */
-#define KVM_VM_MIPS_TE         0
+/* on MIPS, 0 indicates auto, 1 forces VZ ASE, 2 forces trap & emulate */
+#define KVM_VM_MIPS_AUTO       0
 #define KVM_VM_MIPS_VZ         1
+#define KVM_VM_MIPS_TE         2
 
 #define KVM_S390_SIE_PAGE_OFFSET 1
 
@@ -1035,6 +1036,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_LAST_CPU 184
 #define KVM_CAP_SMALLER_MAXPHYADDR 185
 #define KVM_CAP_S390_DIAG318 186
+#define KVM_CAP_STEAL_TIME 187
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
index 077e7ee..3e5dcdd 100644 (file)
@@ -1196,7 +1196,7 @@ union perf_mem_data_src {
 
 #define PERF_MEM_SNOOPX_FWD    0x01 /* forward */
 /* 1 free */
-#define PERF_MEM_SNOOPX_SHIFT  37
+#define PERF_MEM_SNOOPX_SHIFT  38
 
 /* locked instruction */
 #define PERF_MEM_LOCK_NA       0x01 /* not available */
index 0f25713..7703f01 100644 (file)
@@ -130,7 +130,7 @@ static int io_uring_register_files(struct submitter *s)
                                        s->nr_files);
 }
 
-static int gettid(void)
+static int lk_gettid(void)
 {
        return syscall(__NR_gettid);
 }
@@ -281,7 +281,7 @@ static void *submitter_fn(void *data)
        struct io_sq_ring *ring = &s->sq_ring;
        int ret, prepped;
 
-       printf("submitter=%d\n", gettid());
+       printf("submitter=%d\n", lk_gettid());
 
        srand48_r(pthread_self(), &s->rand);
 
index bf8ed13..9ae8f4e 100644 (file)
@@ -59,7 +59,7 @@ FEATURE_USER = .libbpf
 FEATURE_TESTS = libelf libelf-mmap zlib bpf reallocarray
 FEATURE_DISPLAY = libelf zlib bpf
 
-INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi
+INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/include/uapi
 FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES)
 
 check_feat := 1
@@ -152,6 +152,7 @@ GLOBAL_SYM_COUNT = $(shell readelf -s --wide $(BPF_IN_SHARED) | \
                           awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {print $$NF}' | \
                           sort -u | wc -l)
 VERSIONED_SYM_COUNT = $(shell readelf --dyn-syms --wide $(OUTPUT)libbpf.so | \
+                             awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {print $$NF}' | \
                              grep -Eo '[^ ]+@LIBBPF_' | cut -d@ -f1 | sort -u | wc -l)
 
 CMD_TARGETS = $(LIB_TARGET) $(PC_FILE)
@@ -219,6 +220,7 @@ check_abi: $(OUTPUT)libbpf.so
                    awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {print $$NF}'|  \
                    sort -u > $(OUTPUT)libbpf_global_syms.tmp;           \
                readelf --dyn-syms --wide $(OUTPUT)libbpf.so |           \
+                   awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {print $$NF}'|  \
                    grep -Eo '[^ ]+@LIBBPF_' | cut -d@ -f1 |             \
                    sort -u > $(OUTPUT)libbpf_versioned_syms.tmp;        \
                diff -u $(OUTPUT)libbpf_global_syms.tmp                  \
index 7dfca70..6bdbc38 100644 (file)
@@ -659,6 +659,12 @@ struct btf *btf__parse_raw(const char *path)
                err = -EIO;
                goto err_out;
        }
+       if (magic == __bswap_16(BTF_MAGIC)) {
+               /* non-native endian raw BTF */
+               pr_warn("non-native BTF endianness is not supported\n");
+               err = -LIBBPF_ERRNO__ENDIAN;
+               goto err_out;
+       }
        if (magic != BTF_MAGIC) {
                /* definitely not a raw BTF */
                err = -EPROTO;
index 0ad0b04..e493d60 100644 (file)
@@ -5203,8 +5203,8 @@ static int bpf_object__collect_map_relos(struct bpf_object *obj,
        int i, j, nrels, new_sz;
        const struct btf_var_secinfo *vi = NULL;
        const struct btf_type *sec, *var, *def;
+       struct bpf_map *map = NULL, *targ_map;
        const struct btf_member *member;
-       struct bpf_map *map, *targ_map;
        const char *name, *mname;
        Elf_Data *symbols;
        unsigned int moff;
@@ -6925,7 +6925,7 @@ static const struct bpf_sec_def section_defs[] = {
                                                BPF_XDP_DEVMAP),
        BPF_EAPROG_SEC("xdp_cpumap/",           BPF_PROG_TYPE_XDP,
                                                BPF_XDP_CPUMAP),
-       BPF_EAPROG_SEC("xdp",                   BPF_PROG_TYPE_XDP,
+       BPF_APROG_SEC("xdp",                    BPF_PROG_TYPE_XDP,
                                                BPF_XDP),
        BPF_PROG_SEC("perf_event",              BPF_PROG_TYPE_PERF_EVENT),
        BPF_PROG_SEC("lwt_in",                  BPF_PROG_TYPE_LWT_IN),
index 3ba566d..5acc18b 100644 (file)
@@ -5259,7 +5259,7 @@ static int print_arg_pointer(struct trace_seq *s, const char *format, int plen,
        default:
                ret = 0;
                val = eval_num_arg(data, size, event, arg);
-               trace_seq_printf(s, "%p", (void *)val);
+               trace_seq_printf(s, "%p", (void *)(intptr_t)val);
                break;
        }
 
index 33ba98d..99d0087 100644 (file)
@@ -3,9 +3,9 @@
                                C  Self  R  W  RMW  Self  R  W  DR  DW  RMW  SV
                               --  ----  -  -  ---  ----  -  -  --  --  ---  --
 
-Store, e.g., WRITE_ONCE()            Y                                       Y
-Load, e.g., READ_ONCE()              Y                          Y   Y        Y
-Unsuccessful RMW operation           Y                          Y   Y        Y
+Relaxed store                        Y                                       Y
+Relaxed load                         Y                          Y   Y        Y
+Relaxed RMW operation                Y                          Y   Y        Y
 rcu_dereference()                    Y                          Y   Y        Y
 Successful *_acquire()               R                   Y  Y   Y   Y    Y   Y
 Successful *_release()         C        Y  Y    Y     W                      Y
@@ -17,14 +17,19 @@ smp_mb__before_atomic()       CP        Y  Y    Y        a  a   a   a    Y
 smp_mb__after_atomic()        CP        a  a    Y        Y  Y   Y   Y    Y
 
 
-Key:   C:      Ordering is cumulative
-       P:      Ordering propagates
-       R:      Read, for example, READ_ONCE(), or read portion of RMW
-       W:      Write, for example, WRITE_ONCE(), or write portion of RMW
-       Y:      Provides ordering
-       a:      Provides ordering given intervening RMW atomic operation
-       DR:     Dependent read (address dependency)
-       DW:     Dependent write (address, data, or control dependency)
-       RMW:    Atomic read-modify-write operation
-       SELF:   Orders self, as opposed to accesses before and/or after
-       SV:     Orders later accesses to the same variable
+Key:   Relaxed:  A relaxed operation is either READ_ONCE(), WRITE_ONCE(),
+                 a *_relaxed() RMW operation, an unsuccessful RMW
+                 operation, a non-value-returning RMW operation such
+                 as atomic_inc(), or one of the atomic*_read() and
+                 atomic*_set() family of operations.
+       C:        Ordering is cumulative
+       P:        Ordering propagates
+       R:        Read, for example, READ_ONCE(), or read portion of RMW
+       W:        Write, for example, WRITE_ONCE(), or write portion of RMW
+       Y:        Provides ordering
+       a:        Provides ordering given intervening RMW atomic operation
+       DR:       Dependent read (address dependency)
+       DW:       Dependent write (address, data, or control dependency)
+       RMW:      Atomic read-modify-write operation
+       SELF:     Orders self, as opposed to accesses before and/or after
+       SV:       Orders later accesses to the same variable
diff --git a/tools/memory-model/Documentation/litmus-tests.txt b/tools/memory-model/Documentation/litmus-tests.txt
new file mode 100644 (file)
index 0000000..2f840dc
--- /dev/null
@@ -0,0 +1,1074 @@
+Linux-Kernel Memory Model Litmus Tests
+======================================
+
+This file describes the LKMM litmus-test format by example, describes
+some tricks and traps, and finally outlines LKMM's limitations.  Earlier
+versions of this material appeared in a number of LWN articles, including:
+
+https://lwn.net/Articles/720550/
+       A formal kernel memory-ordering model (part 2)
+https://lwn.net/Articles/608550/
+       Axiomatic validation of memory barriers and atomic instructions
+https://lwn.net/Articles/470681/
+       Validating Memory Barriers and Atomic Instructions
+
+This document presents information in decreasing order of applicability,
+so that, where possible, the information that has proven more commonly
+useful is shown near the beginning.
+
+For information on installing LKMM, including the underlying "herd7"
+tool, please see tools/memory-model/README.
+
+
+Copy-Pasta
+==========
+
+As with other software, it is often better (if less macho) to adapt an
+existing litmus test than it is to create one from scratch.  A number
+of litmus tests may be found in the kernel source tree:
+
+       tools/memory-model/litmus-tests/
+       Documentation/litmus-tests/
+
+Several thousand more example litmus tests are available on github
+and kernel.org:
+
+       https://github.com/paulmckrcu/litmus
+       https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/perfbook.git/tree/CodeSamples/formal/herd
+       https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/perfbook.git/tree/CodeSamples/formal/litmus
+
+The -l and -L arguments to "git grep" can be quite helpful in identifying
+existing litmus tests that are similar to the one you need.  But even if
+you start with an existing litmus test, it is still helpful to have a
+good understanding of the litmus-test format.
+
+
+Examples and Format
+===================
+
+This section describes the overall format of litmus tests, starting
+with a small example of the message-passing pattern and moving on to
+more complex examples that illustrate explicit initialization and LKMM's
+minimalistic set of flow-control statements.
+
+
+Message-Passing Example
+-----------------------
+
+This section gives an overview of the format of a litmus test using an
+example based on the common message-passing use case.  This use case
+appears often in the Linux kernel.  For example, a flag (modeled by "y"
+below) indicates that a buffer (modeled by "x" below) is now completely
+filled in and ready for use.  It would be very bad if the consumer saw the
+flag set, but, due to memory misordering, saw old values in the buffer.
+
+This example asks whether smp_store_release() and smp_load_acquire()
+suffices to avoid this bad outcome:
+
+ 1 C MP+pooncerelease+poacquireonce
+ 2
+ 3 {}
+ 4
+ 5 P0(int *x, int *y)
+ 6 {
+ 7   WRITE_ONCE(*x, 1);
+ 8   smp_store_release(y, 1);
+ 9 }
+10
+11 P1(int *x, int *y)
+12 {
+13   int r0;
+14   int r1;
+15
+16   r0 = smp_load_acquire(y);
+17   r1 = READ_ONCE(*x);
+18 }
+19
+20 exists (1:r0=1 /\ 1:r1=0)
+
+Line 1 starts with "C", which identifies this file as being in the
+LKMM C-language format (which, as we will see, is a small fragment
+of the full C language).  The remainder of line 1 is the name of
+the test, which by convention is the filename with the ".litmus"
+suffix stripped.  In this case, the actual test may be found in
+tools/memory-model/litmus-tests/MP+pooncerelease+poacquireonce.litmus
+in the Linux-kernel source tree.
+
+Mechanically generated litmus tests will often have an optional
+double-quoted comment string on the second line.  Such strings are ignored
+when running the test.  Yes, you can add your own comments to litmus
+tests, but this is a bit involved due to the use of multiple parsers.
+For now, you can use C-language comments in the C code, and these comments
+may be in either the "/* */" or the "//" style.  A later section will
+cover the full litmus-test commenting story.
+
+Line 3 is the initialization section.  Because the default initialization
+to zero suffices for this test, the "{}" syntax is used, which mean the
+initialization section is empty.  Litmus tests requiring non-default
+initialization must have non-empty initialization sections, as in the
+example that will be presented later in this document.
+
+Lines 5-9 show the first process and lines 11-18 the second process.  Each
+process corresponds to a Linux-kernel task (or kthread, workqueue, thread,
+and so on; LKMM discussions often use these terms interchangeably).
+The name of the first process is "P0" and that of the second "P1".
+You can name your processes anything you like as long as the names consist
+of a single "P" followed by a number, and as long as the numbers are
+consecutive starting with zero.  This can actually be quite helpful,
+for example, a .litmus file matching "^P1(" but not matching "^P2("
+must contain a two-process litmus test.
+
+The argument list for each function are pointers to the global variables
+used by that function.  Unlike normal C-language function parameters, the
+names are significant.  The fact that both P0() and P1() have a formal
+parameter named "x" means that these two processes are working with the
+same global variable, also named "x".  So the "int *x, int *y" on P0()
+and P1() mean that both processes are working with two shared global
+variables, "x" and "y".  Global variables are always passed to processes
+by reference, hence "P0(int *x, int *y)", but *never* "P0(int x, int y)".
+
+P0() has no local variables, but P1() has two of them named "r0" and "r1".
+These names may be freely chosen, but for historical reasons stemming from
+other litmus-test formats, it is conventional to use names consisting of
+"r" followed by a number as shown here.  A common bug in litmus tests
+is forgetting to add a global variable to a process's parameter list.
+This will sometimes result in an error message, but can also cause the
+intended global to instead be silently treated as an undeclared local
+variable.
+
+Each process's code is similar to Linux-kernel C, as can be seen on lines
+7-8 and 13-17.  This code may use many of the Linux kernel's atomic
+operations, some of its exclusive-lock functions, and some of its RCU
+and SRCU functions.  An approximate list of the currently supported
+functions may be found in the linux-kernel.def file.
+
+The P0() process does "WRITE_ONCE(*x, 1)" on line 7.  Because "x" is a
+pointer in P0()'s parameter list, this does an unordered store to global
+variable "x".  Line 8 does "smp_store_release(y, 1)", and because "y"
+is also in P0()'s parameter list, this does a release store to global
+variable "y".
+
+The P1() process declares two local variables on lines 13 and 14.
+Line 16 does "r0 = smp_load_acquire(y)" which does an acquire load
+from global variable "y" into local variable "r0".  Line 17 does a
+"r1 = READ_ONCE(*x)", which does an unordered load from "*x" into local
+variable "r1".  Both "x" and "y" are in P1()'s parameter list, so both
+reference the same global variables that are used by P0().
+
+Line 20 is the "exists" assertion expression to evaluate the final state.
+This final state is evaluated after the dust has settled: both processes
+have completed and all of their memory references and memory barriers
+have propagated to all parts of the system.  The references to the local
+variables "r0" and "r1" in line 24 must be prefixed with "1:" to specify
+which process they are local to.
+
+Note that the assertion expression is written in the litmus-test
+language rather than in C.  For example, single "=" is an equality
+operator rather than an assignment.  The "/\" character combination means
+"and".  Similarly, "\/" stands for "or".  Both of these are ASCII-art
+representations of the corresponding mathematical symbols.  Finally,
+"~" stands for "logical not", which is "!" in C, and not to be confused
+with the C-language "~" operator which instead stands for "bitwise not".
+Parentheses may be used to override precedence.
+
+The "exists" assertion on line 20 is satisfied if the consumer sees the
+flag ("y") set but the buffer ("x") as not yet filled in, that is, if P1()
+loaded a value from "x" that was equal to 1 but loaded a value from "y"
+that was still equal to zero.
+
+This example can be checked by running the following command, which
+absolutely must be run from the tools/memory-model directory and from
+this directory only:
+
+herd7 -conf linux-kernel.cfg litmus-tests/MP+pooncerelease+poacquireonce.litmus
+
+The output is the result of something similar to a full state-space
+search, and is as follows:
+
+ 1 Test MP+pooncerelease+poacquireonce Allowed
+ 2 States 3
+ 3 1:r0=0; 1:r1=0;
+ 4 1:r0=0; 1:r1=1;
+ 5 1:r0=1; 1:r1=1;
+ 6 No
+ 7 Witnesses
+ 8 Positive: 0 Negative: 3
+ 9 Condition exists (1:r0=1 /\ 1:r1=0)
+10 Observation MP+pooncerelease+poacquireonce Never 0 3
+11 Time MP+pooncerelease+poacquireonce 0.00
+12 Hash=579aaa14d8c35a39429b02e698241d09
+
+The most pertinent line is line 10, which contains "Never 0 3", which
+indicates that the bad result flagged by the "exists" clause never
+happens.  This line might instead say "Sometimes" to indicate that the
+bad result happened in some but not all executions, or it might say
+"Always" to indicate that the bad result happened in all executions.
+(The herd7 tool doesn't judge, so it is only an LKMM convention that the
+"exists" clause indicates a bad result.  To see this, invert the "exists"
+clause's condition and run the test.)  The numbers ("0 3") at the end
+of this line indicate the number of end states satisfying the "exists"
+clause (0) and the number not not satisfying that clause (3).
+
+Another important part of this output is shown in lines 2-5, repeated here:
+
+ 2 States 3
+ 3 1:r0=0; 1:r1=0;
+ 4 1:r0=0; 1:r1=1;
+ 5 1:r0=1; 1:r1=1;
+
+Line 2 gives the total number of end states, and each of lines 3-5 list
+one of these states, with the first ("1:r0=0; 1:r1=0;") indicating that
+both of P1()'s loads returned the value "0".  As expected, given the
+"Never" on line 10, the state flagged by the "exists" clause is not
+listed.  This full list of states can be helpful when debugging a new
+litmus test.
+
+The rest of the output is not normally needed, either due to irrelevance
+or due to being redundant with the lines discussed above.  However, the
+following paragraph lists them for the benefit of readers possessed of
+an insatiable curiosity.  Other readers should feel free to skip ahead.
+
+Line 1 echos the test name, along with the "Test" and "Allowed".  Line 6's
+"No" says that the "exists" clause was not satisfied by any execution,
+and as such it has the same meaning as line 10's "Never".  Line 7 is a
+lead-in to line 8's "Positive: 0 Negative: 3", which lists the number
+of end states satisfying and not satisfying the "exists" clause, just
+like the two numbers at the end of line 10.  Line 9 repeats the "exists"
+clause so that you don't have to look it up in the litmus-test file.
+The number at the end of line 11 (which begins with "Time") gives the
+time in seconds required to analyze the litmus test.  Small tests such
+as this one complete in a few milliseconds, so "0.00" is quite common.
+Line 12 gives a hash of the contents for the litmus-test file, and is used
+by tooling that manages litmus tests and their output.  This tooling is
+used by people modifying LKMM itself, and among other things lets such
+people know which of the several thousand relevant litmus tests were
+affected by a given change to LKMM.
+
+
+Initialization
+--------------
+
+The previous example relied on the default zero initialization for
+"x" and "y", but a similar litmus test could instead initialize them
+to some other value:
+
+ 1 C MP+pooncerelease+poacquireonce
+ 2
+ 3 {
+ 4   x=42;
+ 5   y=42;
+ 6 }
+ 7
+ 8 P0(int *x, int *y)
+ 9 {
+10   WRITE_ONCE(*x, 1);
+11   smp_store_release(y, 1);
+12 }
+13
+14 P1(int *x, int *y)
+15 {
+16   int r0;
+17   int r1;
+18
+19   r0 = smp_load_acquire(y);
+20   r1 = READ_ONCE(*x);
+21 }
+22
+23 exists (1:r0=1 /\ 1:r1=42)
+
+Lines 3-6 now initialize both "x" and "y" to the value 42.  This also
+means that the "exists" clause on line 23 must change "1:r1=0" to
+"1:r1=42".
+
+Running the test gives the same overall result as before, but with the
+value 42 appearing in place of the value zero:
+
+ 1 Test MP+pooncerelease+poacquireonce Allowed
+ 2 States 3
+ 3 1:r0=1; 1:r1=1;
+ 4 1:r0=42; 1:r1=1;
+ 5 1:r0=42; 1:r1=42;
+ 6 No
+ 7 Witnesses
+ 8 Positive: 0 Negative: 3
+ 9 Condition exists (1:r0=1 /\ 1:r1=42)
+10 Observation MP+pooncerelease+poacquireonce Never 0 3
+11 Time MP+pooncerelease+poacquireonce 0.02
+12 Hash=ab9a9b7940a75a792266be279a980156
+
+It is tempting to avoid the open-coded repetitions of the value "42"
+by defining another global variable "initval=42" and replacing all
+occurrences of "42" with "initval".  This will not, repeat *not*,
+initialize "x" and "y" to 42, but instead to the address of "initval"
+(try it!).  See the section below on linked lists to learn more about
+why this approach to initialization can be useful.
+
+
+Control Structures
+------------------
+
+LKMM supports the C-language "if" statement, which allows modeling of
+conditional branches.  In LKMM, conditional branches can affect ordering,
+but only if you are *very* careful (compilers are surprisingly able
+to optimize away conditional branches).  The following example shows
+the "load buffering" (LB) use case that is used in the Linux kernel to
+synchronize between ring-buffer producers and consumers.  In the example
+below, P0() is one side checking to see if an operation may proceed and
+P1() is the other side completing its update.
+
+ 1 C LB+fencembonceonce+ctrlonceonce
+ 2
+ 3 {}
+ 4
+ 5 P0(int *x, int *y)
+ 6 {
+ 7   int r0;
+ 8
+ 9   r0 = READ_ONCE(*x);
+10   if (r0)
+11     WRITE_ONCE(*y, 1);
+12 }
+13
+14 P1(int *x, int *y)
+15 {
+16   int r0;
+17
+18   r0 = READ_ONCE(*y);
+19   smp_mb();
+20   WRITE_ONCE(*x, 1);
+21 }
+22
+23 exists (0:r0=1 /\ 1:r0=1)
+
+P1()'s "if" statement on line 10 works as expected, so that line 11 is
+executed only if line 9 loads a non-zero value from "x".  Because P1()'s
+write of "1" to "x" happens only after P1()'s read from "y", one would
+hope that the "exists" clause cannot be satisfied.  LKMM agrees:
+
+ 1 Test LB+fencembonceonce+ctrlonceonce Allowed
+ 2 States 2
+ 3 0:r0=0; 1:r0=0;
+ 4 0:r0=1; 1:r0=0;
+ 5 No
+ 6 Witnesses
+ 7 Positive: 0 Negative: 2
+ 8 Condition exists (0:r0=1 /\ 1:r0=1)
+ 9 Observation LB+fencembonceonce+ctrlonceonce Never 0 2
+10 Time LB+fencembonceonce+ctrlonceonce 0.00
+11 Hash=e5260556f6de495fd39b556d1b831c3b
+
+However, there is no "while" statement due to the fact that full
+state-space search has some difficulty with iteration.  However, there
+are tricks that may be used to handle some special cases, which are
+discussed below.  In addition, loop-unrolling tricks may be applied,
+albeit sparingly.
+
+
+Tricks and Traps
+================
+
+This section covers extracting debug output from herd7, emulating
+spin loops, handling trivial linked lists, adding comments to litmus tests,
+emulating call_rcu(), and finally tricks to improve herd7 performance
+in order to better handle large litmus tests.
+
+
+Debug Output
+------------
+
+By default, the herd7 state output includes all variables mentioned
+in the "exists" clause.  But sometimes debugging efforts are greatly
+aided by the values of other variables.  Consider this litmus test
+(tools/memory-order/litmus-tests/SB+rfionceonce-poonceonces.litmus but
+slightly modified), which probes an obscure corner of hardware memory
+ordering:
+
+ 1 C SB+rfionceonce-poonceonces
+ 2
+ 3 {}
+ 4
+ 5 P0(int *x, int *y)
+ 6 {
+ 7   int r1;
+ 8   int r2;
+ 9
+10   WRITE_ONCE(*x, 1);
+11   r1 = READ_ONCE(*x);
+12   r2 = READ_ONCE(*y);
+13 }
+14
+15 P1(int *x, int *y)
+16 {
+17   int r3;
+18   int r4;
+19
+20   WRITE_ONCE(*y, 1);
+21   r3 = READ_ONCE(*y);
+22   r4 = READ_ONCE(*x);
+23 }
+24
+25 exists (0:r2=0 /\ 1:r4=0)
+
+The herd7 output is as follows:
+
+ 1 Test SB+rfionceonce-poonceonces Allowed
+ 2 States 4
+ 3 0:r2=0; 1:r4=0;
+ 4 0:r2=0; 1:r4=1;
+ 5 0:r2=1; 1:r4=0;
+ 6 0:r2=1; 1:r4=1;
+ 7 Ok
+ 8 Witnesses
+ 9 Positive: 1 Negative: 3
+10 Condition exists (0:r2=0 /\ 1:r4=0)
+11 Observation SB+rfionceonce-poonceonces Sometimes 1 3
+12 Time SB+rfionceonce-poonceonces 0.01
+13 Hash=c7f30fe0faebb7d565405d55b7318ada
+
+(This output indicates that CPUs are permitted to "snoop their own
+store buffers", which all of Linux's CPU families other than s390 will
+happily do.  Such snooping results in disagreement among CPUs on the
+order of stores from different CPUs, which is rarely an issue.)
+
+But the herd7 output shows only the two variables mentioned in the
+"exists" clause.  Someone modifying this test might wish to know the
+values of "x", "y", "0:r1", and "0:r3" as well.  The "locations"
+statement on line 25 shows how to cause herd7 to display additional
+variables:
+
+ 1 C SB+rfionceonce-poonceonces
+ 2
+ 3 {}
+ 4
+ 5 P0(int *x, int *y)
+ 6 {
+ 7   int r1;
+ 8   int r2;
+ 9
+10   WRITE_ONCE(*x, 1);
+11   r1 = READ_ONCE(*x);
+12   r2 = READ_ONCE(*y);
+13 }
+14
+15 P1(int *x, int *y)
+16 {
+17   int r3;
+18   int r4;
+19
+20   WRITE_ONCE(*y, 1);
+21   r3 = READ_ONCE(*y);
+22   r4 = READ_ONCE(*x);
+23 }
+24
+25 locations [0:r1; 1:r3; x; y]
+26 exists (0:r2=0 /\ 1:r4=0)
+
+The herd7 output then displays the values of all the variables:
+
+ 1 Test SB+rfionceonce-poonceonces Allowed
+ 2 States 4
+ 3 0:r1=1; 0:r2=0; 1:r3=1; 1:r4=0; x=1; y=1;
+ 4 0:r1=1; 0:r2=0; 1:r3=1; 1:r4=1; x=1; y=1;
+ 5 0:r1=1; 0:r2=1; 1:r3=1; 1:r4=0; x=1; y=1;
+ 6 0:r1=1; 0:r2=1; 1:r3=1; 1:r4=1; x=1; y=1;
+ 7 Ok
+ 8 Witnesses
+ 9 Positive: 1 Negative: 3
+10 Condition exists (0:r2=0 /\ 1:r4=0)
+11 Observation SB+rfionceonce-poonceonces Sometimes 1 3
+12 Time SB+rfionceonce-poonceonces 0.01
+13 Hash=40de8418c4b395388f6501cafd1ed38d
+
+What if you would like to know the value of a particular global variable
+at some particular point in a given process's execution?  One approach
+is to use a READ_ONCE() to load that global variable into a new local
+variable, then add that local variable to the "locations" clause.
+But be careful:  In some litmus tests, adding a READ_ONCE() will change
+the outcome!  For one example, please see the C-READ_ONCE.litmus and
+C-READ_ONCE-omitted.litmus tests located here:
+
+       https://github.com/paulmckrcu/litmus/blob/master/manual/kernel/
+
+
+Spin Loops
+----------
+
+The analysis carried out by herd7 explores full state space, which is
+at best of exponential time complexity.  Adding processes and increasing
+the amount of code in a give process can greatly increase execution time.
+Potentially infinite loops, such as those used to wait for locks to
+become available, are clearly problematic.
+
+Fortunately, it is possible to avoid state-space explosion by specially
+modeling such loops.  For example, the following litmus tests emulates
+locking using xchg_acquire(), but instead of enclosing xchg_acquire()
+in a spin loop, it instead excludes executions that fail to acquire the
+lock using a herd7 "filter" clause.  Note that for exclusive locking, you
+are better off using the spin_lock() and spin_unlock() that LKMM directly
+models, if for no other reason that these are much faster.  However, the
+techniques illustrated in this section can be used for other purposes,
+such as emulating reader-writer locking, which LKMM does not yet model.
+
+ 1 C C-SB+l-o-o-u+l-o-o-u-X
+ 2
+ 3 {
+ 4 }
+ 5
+ 6 P0(int *sl, int *x0, int *x1)
+ 7 {
+ 8   int r2;
+ 9   int r1;
+10
+11   r2 = xchg_acquire(sl, 1);
+12   WRITE_ONCE(*x0, 1);
+13   r1 = READ_ONCE(*x1);
+14   smp_store_release(sl, 0);
+15 }
+16
+17 P1(int *sl, int *x0, int *x1)
+18 {
+19   int r2;
+20   int r1;
+21
+22   r2 = xchg_acquire(sl, 1);
+23   WRITE_ONCE(*x1, 1);
+24   r1 = READ_ONCE(*x0);
+25   smp_store_release(sl, 0);
+26 }
+27
+28 filter (0:r2=0 /\ 1:r2=0)
+29 exists (0:r1=0 /\ 1:r1=0)
+
+This litmus test may be found here:
+
+https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/perfbook.git/tree/CodeSamples/formal/herd/C-SB+l-o-o-u+l-o-o-u-X.litmus
+
+This test uses two global variables, "x1" and "x2", and also emulates a
+single global spinlock named "sl".  This spinlock is held by whichever
+process changes the value of "sl" from "0" to "1", and is released when
+that process sets "sl" back to "0".  P0()'s lock acquisition is emulated
+on line 11 using xchg_acquire(), which unconditionally stores the value
+"1" to "sl" and stores either "0" or "1" to "r2", depending on whether
+the lock acquisition was successful or unsuccessful (due to "sl" already
+having the value "1"), respectively.  P1() operates in a similar manner.
+
+Rather unconventionally, execution appears to proceed to the critical
+section on lines 12 and 13 in either case.  Line 14 then uses an
+smp_store_release() to store zero to "sl", thus emulating lock release.
+
+The case where xchg_acquire() fails to acquire the lock is handled by
+the "filter" clause on line 28, which tells herd7 to keep only those
+executions in which both "0:r2" and "1:r2" are zero, that is to pay
+attention only to those executions in which both locks are actually
+acquired.  Thus, the bogus executions that would execute the critical
+sections are discarded and any effects that they might have had are
+ignored.  Note well that the "filter" clause keeps those executions
+for which its expression is satisfied, that is, for which the expression
+evaluates to true.  In other words, the "filter" clause says what to
+keep, not what to discard.
+
+The result of running this test is as follows:
+
+ 1 Test C-SB+l-o-o-u+l-o-o-u-X Allowed
+ 2 States 2
+ 3 0:r1=0; 1:r1=1;
+ 4 0:r1=1; 1:r1=0;
+ 5 No
+ 6 Witnesses
+ 7 Positive: 0 Negative: 2
+ 8 Condition exists (0:r1=0 /\ 1:r1=0)
+ 9 Observation C-SB+l-o-o-u+l-o-o-u-X Never 0 2
+10 Time C-SB+l-o-o-u+l-o-o-u-X 0.03
+
+The "Never" on line 9 indicates that this use of xchg_acquire() and
+smp_store_release() really does correctly emulate locking.
+
+Why doesn't the litmus test take the simpler approach of using a spin loop
+to handle failed spinlock acquisitions, like the kernel does?  The key
+insight behind this litmus test is that spin loops have no effect on the
+possible "exists"-clause outcomes of program execution in the absence
+of deadlock.  In other words, given a high-quality lock-acquisition
+primitive in a deadlock-free program running on high-quality hardware,
+each lock acquisition will eventually succeed.  Because herd7 already
+explores the full state space, the length of time required to actually
+acquire the lock does not matter.  After all, herd7 already models all
+possible durations of the xchg_acquire() statements.
+
+Why not just add the "filter" clause to the "exists" clause, thus
+avoiding the "filter" clause entirely?  This does work, but is slower.
+The reason that the "filter" clause is faster is that (in the common case)
+herd7 knows to abandon an execution as soon as the "filter" expression
+fails to be satisfied.  In contrast, the "exists" clause is evaluated
+only at the end of time, thus requiring herd7 to waste time on bogus
+executions in which both critical sections proceed concurrently.  In
+addition, some LKMM users like the separation of concerns provided by
+using the both the "filter" and "exists" clauses.
+
+Readers lacking a pathological interest in odd corner cases should feel
+free to skip the remainder of this section.
+
+But what if the litmus test were to temporarily set "0:r2" to a non-zero
+value?  Wouldn't that cause herd7 to abandon the execution prematurely
+due to an early mismatch of the "filter" clause?
+
+Why not just try it?  Line 4 of the following modified litmus test
+introduces a new global variable "x2" that is initialized to "1".  Line 23
+of P1() reads that variable into "1:r2" to force an early mismatch with
+the "filter" clause.  Line 24 does a known-true "if" condition to avoid
+and static analysis that herd7 might do.  Finally the "exists" clause
+on line 32 is updated to a condition that is alway satisfied at the end
+of the test.
+
+ 1 C C-SB+l-o-o-u+l-o-o-u-X
+ 2
+ 3 {
+ 4   x2=1;
+ 5 }
+ 6
+ 7 P0(int *sl, int *x0, int *x1)
+ 8 {
+ 9   int r2;
+10   int r1;
+11
+12   r2 = xchg_acquire(sl, 1);
+13   WRITE_ONCE(*x0, 1);
+14   r1 = READ_ONCE(*x1);
+15   smp_store_release(sl, 0);
+16 }
+17
+18 P1(int *sl, int *x0, int *x1, int *x2)
+19 {
+20   int r2;
+21   int r1;
+22
+23   r2 = READ_ONCE(*x2);
+24   if (r2)
+25     r2 = xchg_acquire(sl, 1);
+26   WRITE_ONCE(*x1, 1);
+27   r1 = READ_ONCE(*x0);
+28   smp_store_release(sl, 0);
+29 }
+30
+31 filter (0:r2=0 /\ 1:r2=0)
+32 exists (x1=1)
+
+If the "filter" clause were to check each variable at each point in the
+execution, running this litmus test would display no executions because
+all executions would be filtered out at line 23.  However, the output
+is instead as follows:
+
+ 1 Test C-SB+l-o-o-u+l-o-o-u-X Allowed
+ 2 States 1
+ 3 x1=1;
+ 4 Ok
+ 5 Witnesses
+ 6 Positive: 2 Negative: 0
+ 7 Condition exists (x1=1)
+ 8 Observation C-SB+l-o-o-u+l-o-o-u-X Always 2 0
+ 9 Time C-SB+l-o-o-u+l-o-o-u-X 0.04
+10 Hash=080bc508da7f291e122c6de76c0088e3
+
+Line 3 shows that there is one execution that did not get filtered out,
+so the "filter" clause is evaluated only on the last assignment to
+the variables that it checks.  In this case, the "filter" clause is a
+disjunction, so it might be evaluated twice, once at the final (and only)
+assignment to "0:r2" and once at the final assignment to "1:r2".
+
+
+Linked Lists
+------------
+
+LKMM can handle linked lists, but only linked lists in which each node
+contains nothing except a pointer to the next node in the list.  This is
+of course quite restrictive, but there is nevertheless quite a bit that
+can be done within these confines, as can be seen in the litmus test
+at tools/memory-model/litmus-tests/MP+onceassign+derefonce.litmus:
+
+ 1 C MP+onceassign+derefonce
+ 2
+ 3 {
+ 4 y=z;
+ 5 z=0;
+ 6 }
+ 7
+ 8 P0(int *x, int **y)
+ 9 {
+10   WRITE_ONCE(*x, 1);
+11   rcu_assign_pointer(*y, x);
+12 }
+13
+14 P1(int *x, int **y)
+15 {
+16   int *r0;
+17   int r1;
+18
+19   rcu_read_lock();
+20   r0 = rcu_dereference(*y);
+21   r1 = READ_ONCE(*r0);
+22   rcu_read_unlock();
+23 }
+24
+25 exists (1:r0=x /\ 1:r1=0)
+
+Line 4's "y=z" may seem odd, given that "z" has not yet been initialized.
+But "y=z" does not set the value of "y" to that of "z", but instead
+sets the value of "y" to the *address* of "z".  Lines 4 and 5 therefore
+create a simple linked list, with "y" pointing to "z" and "z" having a
+NULL pointer.  A much longer linked list could be created if desired,
+and circular singly linked lists can also be created and manipulated.
+
+The "exists" clause works the same way, with the "1:r0=x" comparing P1()'s
+"r0" not to the value of "x", but again to its address.  This term of the
+"exists" clause therefore tests whether line 20's load from "y" saw the
+value stored by line 11, which is in fact what is required in this case.
+
+P0()'s line 10 initializes "x" to the value 1 then line 11 links to "x"
+from "y", replacing "z".
+
+P1()'s line 20 loads a pointer from "y", and line 21 dereferences that
+pointer.  The RCU read-side critical section spanning lines 19-22 is just
+for show in this example.  Note that the address used for line 21's load
+depends on (in this case, "is exactly the same as") the value loaded by
+line 20.  This is an example of what is called an "address dependency".
+This particular address dependency extends from the load on line 20 to the
+load on line 21.  Address dependencies provide a weak form of ordering.
+
+Running this test results in the following:
+
+ 1 Test MP+onceassign+derefonce Allowed
+ 2 States 2
+ 3 1:r0=x; 1:r1=1;
+ 4 1:r0=z; 1:r1=0;
+ 5 No
+ 6 Witnesses
+ 7 Positive: 0 Negative: 2
+ 8 Condition exists (1:r0=x /\ 1:r1=0)
+ 9 Observation MP+onceassign+derefonce Never 0 2
+10 Time MP+onceassign+derefonce 0.00
+11 Hash=49ef7a741563570102448a256a0c8568
+
+The only possible outcomes feature P1() loading a pointer to "z"
+(which contains zero) on the one hand and P1() loading a pointer to "x"
+(which contains the value one) on the other.  This should be reassuring
+because it says that RCU readers cannot see the old preinitialization
+values when accessing a newly inserted list node.  This undesirable
+scenario is flagged by the "exists" clause, and would occur if P1()
+loaded a pointer to "x", but obtained the pre-initialization value of
+zero after dereferencing that pointer.
+
+
+Comments
+--------
+
+Different portions of a litmus test are processed by different parsers,
+which has the charming effect of requiring different comment syntax in
+different portions of the litmus test.  The C-syntax portions use
+C-language comments (either "/* */" or "//"), while the other portions
+use Ocaml comments "(* *)".
+
+The following litmus test illustrates the comment style corresponding
+to each syntactic unit of the test:
+
+ 1 C MP+onceassign+derefonce (* A *)
+ 2
+ 3 (* B *)
+ 4
+ 5 {
+ 6 y=z; (* C *)
+ 7 z=0;
+ 8 } // D
+ 9
+10 // E
+11
+12 P0(int *x, int **y) // F
+13 {
+14   WRITE_ONCE(*x, 1);  // G
+15   rcu_assign_pointer(*y, x);
+16 }
+17
+18 // H
+19
+20 P1(int *x, int **y)
+21 {
+22   int *r0;
+23   int r1;
+24
+25   rcu_read_lock();
+26   r0 = rcu_dereference(*y);
+27   r1 = READ_ONCE(*r0);
+28   rcu_read_unlock();
+29 }
+30
+31 // I
+32
+33 exists (* J *) (1:r0=x /\ (* K *) 1:r1=0) (* L *)
+
+In short, use C-language comments in the C code and Ocaml comments in
+the rest of the litmus test.
+
+On the other hand, if you prefer C-style comments everywhere, the
+C preprocessor is your friend.
+
+
+Asynchronous RCU Grace Periods
+------------------------------
+
+The following litmus test is derived from the example show in
+Documentation/litmus-tests/rcu/RCU+sync+free.litmus, but converted to
+emulate call_rcu():
+
+ 1 C RCU+sync+free
+ 2
+ 3 {
+ 4 int x = 1;
+ 5 int *y = &x;
+ 6 int z = 1;
+ 7 }
+ 8
+ 9 P0(int *x, int *z, int **y)
+10 {
+11   int *r0;
+12   int r1;
+13
+14   rcu_read_lock();
+15   r0 = rcu_dereference(*y);
+16   r1 = READ_ONCE(*r0);
+17   rcu_read_unlock();
+18 }
+19
+20 P1(int *z, int **y, int *c)
+21 {
+22   rcu_assign_pointer(*y, z);
+23   smp_store_release(*c, 1); // Emulate call_rcu().
+24 }
+25
+26 P2(int *x, int *z, int **y, int *c)
+27 {
+28   int r0;
+29
+30   r0 = smp_load_acquire(*c); // Note call_rcu() request.
+31   synchronize_rcu(); // Wait one grace period.
+32   WRITE_ONCE(*x, 0); // Emulate the RCU callback.
+33 }
+34
+35 filter (2:r0=1) (* Reject too-early starts. *)
+36 exists (0:r0=x /\ 0:r1=0)
+
+Lines 4-6 initialize a linked list headed by "y" that initially contains
+"x".  In addition, "z" is pre-initialized to prepare for P1(), which
+will replace "x" with "z" in this list.
+
+P0() on lines 9-18 enters an RCU read-side critical section, loads the
+list header "y" and dereferences it, leaving the node in "0:r0" and
+the node's value in "0:r1".
+
+P1() on lines 20-24 updates the list header to instead reference "z",
+then emulates call_rcu() by doing a release store into "c".
+
+P2() on lines 27-33 emulates the behind-the-scenes effect of doing a
+call_rcu().  Line 30 first does an acquire load from "c", then line 31
+waits for an RCU grace period to elapse, and finally line 32 emulates
+the RCU callback, which in turn emulates a call to kfree().
+
+Of course, it is possible for P2() to start too soon, so that the
+value of "2:r0" is zero rather than the required value of "1".
+The "filter" clause on line 35 handles this possibility, rejecting
+all executions in which "2:r0" is not equal to the value "1".
+
+
+Performance
+-----------
+
+LKMM's exploration of the full state-space can be extremely helpful,
+but it does not come for free.  The price is exponential computational
+complexity in terms of the number of processes, the average number
+of statements in each process, and the total number of stores in the
+litmus test.
+
+So it is best to start small and then work up.  Where possible, break
+your code down into small pieces each representing a core concurrency
+requirement.
+
+That said, herd7 is quite fast.  On an unprepossessing x86 laptop, it
+was able to analyze the following 10-process RCU litmus test in about
+six seconds.
+
+https://github.com/paulmckrcu/litmus/blob/master/auto/C-RW-R+RW-R+RW-G+RW-G+RW-G+RW-G+RW-R+RW-R+RW-R+RW-R.litmus
+
+One way to make herd7 run faster is to use the "-speedcheck true" option.
+This option prevents herd7 from generating all possible end states,
+instead causing it to focus solely on whether or not the "exists"
+clause can be satisfied.  With this option, herd7 evaluates the above
+litmus test in about 300 milliseconds, for more than an order of magnitude
+improvement in performance.
+
+Larger 16-process litmus tests that would normally consume 15 minutes
+of time complete in about 40 seconds with this option.  To be fair,
+you do get an extra 65,535 states when you leave off the "-speedcheck
+true" option.
+
+https://github.com/paulmckrcu/litmus/blob/master/auto/C-RW-R+RW-R+RW-G+RW-G+RW-G+RW-G+RW-R+RW-R+RW-R+RW-R+RW-G+RW-G+RW-G+RW-G+RW-R+RW-R.litmus
+
+Nevertheless, litmus-test analysis really is of exponential complexity,
+whether with or without "-speedcheck true".  Increasing by just three
+processes to a 19-process litmus test requires 2 hours and 40 minutes
+without, and about 8 minutes with "-speedcheck true".  Each of these
+results represent roughly an order of magnitude slowdown compared to the
+16-process litmus test.  Again, to be fair, the multi-hour run explores
+no fewer than 524,287 additional states compared to the shorter one.
+
+https://github.com/paulmckrcu/litmus/blob/master/auto/C-RW-R+RW-R+RW-G+RW-G+RW-G+RW-G+RW-R+RW-R+RW-R+RW-R+RW-R+RW-R+RW-G+RW-G+RW-G+RW-G+RW-R+RW-R+RW-R.litmus
+
+If you don't like command-line arguments, you can obtain a similar speedup
+by adding a "filter" clause with exactly the same expression as your
+"exists" clause.
+
+However, please note that seeing the full set of states can be extremely
+helpful when developing and debugging litmus tests.
+
+
+LIMITATIONS
+===========
+
+Limitations of the Linux-kernel memory model (LKMM) include:
+
+1.     Compiler optimizations are not accurately modeled.  Of course,
+       the use of READ_ONCE() and WRITE_ONCE() limits the compiler's
+       ability to optimize, but under some circumstances it is possible
+       for the compiler to undermine the memory model.  For more
+       information, see Documentation/explanation.txt (in particular,
+       the "THE PROGRAM ORDER RELATION: po AND po-loc" and "A WARNING"
+       sections).
+
+       Note that this limitation in turn limits LKMM's ability to
+       accurately model address, control, and data dependencies.
+       For example, if the compiler can deduce the value of some variable
+       carrying a dependency, then the compiler can break that dependency
+       by substituting a constant of that value.
+
+2.     Multiple access sizes for a single variable are not supported,
+       and neither are misaligned or partially overlapping accesses.
+
+3.     Exceptions and interrupts are not modeled.  In some cases,
+       this limitation can be overcome by modeling the interrupt or
+       exception with an additional process.
+
+4.     I/O such as MMIO or DMA is not supported.
+
+5.     Self-modifying code (such as that found in the kernel's
+       alternatives mechanism, function tracer, Berkeley Packet Filter
+       JIT compiler, and module loader) is not supported.
+
+6.     Complete modeling of all variants of atomic read-modify-write
+       operations, locking primitives, and RCU is not provided.
+       For example, call_rcu() and rcu_barrier() are not supported.
+       However, a substantial amount of support is provided for these
+       operations, as shown in the linux-kernel.def file.
+
+       Here are specific limitations:
+
+       a.      When rcu_assign_pointer() is passed NULL, the Linux
+               kernel provides no ordering, but LKMM models this
+               case as a store release.
+
+       b.      The "unless" RMW operations are not currently modeled:
+               atomic_long_add_unless(), atomic_inc_unless_negative(),
+               and atomic_dec_unless_positive().  These can be emulated
+               in litmus tests, for example, by using atomic_cmpxchg().
+
+               One exception of this limitation is atomic_add_unless(),
+               which is provided directly by herd7 (so no corresponding
+               definition in linux-kernel.def).  atomic_add_unless() is
+               modeled by herd7 therefore it can be used in litmus tests.
+
+       c.      The call_rcu() function is not modeled.  As was shown above,
+               it can be emulated in litmus tests by adding another
+               process that invokes synchronize_rcu() and the body of the
+               callback function, with (for example) a release-acquire
+               from the site of the emulated call_rcu() to the beginning
+               of the additional process.
+
+       d.      The rcu_barrier() function is not modeled.  It can be
+               emulated in litmus tests emulating call_rcu() via
+               (for example) a release-acquire from the end of each
+               additional call_rcu() process to the site of the
+               emulated rcu-barrier().
+
+       e.      Although sleepable RCU (SRCU) is now modeled, there
+               are some subtle differences between its semantics and
+               those in the Linux kernel.  For example, the kernel
+               might interpret the following sequence as two partially
+               overlapping SRCU read-side critical sections:
+
+                        1  r1 = srcu_read_lock(&my_srcu);
+                        2  do_something_1();
+                        3  r2 = srcu_read_lock(&my_srcu);
+                        4  do_something_2();
+                        5  srcu_read_unlock(&my_srcu, r1);
+                        6  do_something_3();
+                        7  srcu_read_unlock(&my_srcu, r2);
+
+               In contrast, LKMM will interpret this as a nested pair of
+               SRCU read-side critical sections, with the outer critical
+               section spanning lines 1-7 and the inner critical section
+               spanning lines 3-5.
+
+               This difference would be more of a concern had anyone
+               identified a reasonable use case for partially overlapping
+               SRCU read-side critical sections.  For more information
+               on the trickiness of such overlapping, please see:
+               https://paulmck.livejournal.com/40593.html
+
+       f.      Reader-writer locking is not modeled.  It can be
+               emulated in litmus tests using atomic read-modify-write
+               operations.
+
+The fragment of the C language supported by these litmus tests is quite
+limited and in some ways non-standard:
+
+1.     There is no automatic C-preprocessor pass.  You can of course
+       run it manually, if you choose.
+
+2.     There is no way to create functions other than the Pn() functions
+       that model the concurrent processes.
+
+3.     The Pn() functions' formal parameters must be pointers to the
+       global shared variables.  Nothing can be passed by value into
+       these functions.
+
+4.     The only functions that can be invoked are those built directly
+       into herd7 or that are defined in the linux-kernel.def file.
+
+5.     The "switch", "do", "for", "while", and "goto" C statements are
+       not supported.  The "switch" statement can be emulated by the
+       "if" statement.  The "do", "for", and "while" statements can
+       often be emulated by manually unrolling the loop, or perhaps by
+       enlisting the aid of the C preprocessor to minimize the resulting
+       code duplication.  Some uses of "goto" can be emulated by "if",
+       and some others by unrolling.
+
+6.     Although you can use a wide variety of types in litmus-test
+       variable declarations, and especially in global-variable
+       declarations, the "herd7" tool understands only int and
+       pointer types.  There is no support for floating-point types,
+       enumerations, characters, strings, arrays, or structures.
+
+7.     Parsing of variable declarations is very loose, with almost no
+       type checking.
+
+8.     Initializers differ from their C-language counterparts.
+       For example, when an initializer contains the name of a shared
+       variable, that name denotes a pointer to that variable, not
+       the current value of that variable.  For example, "int x = y"
+       is interpreted the way "int x = &y" would be in C.
+
+9.     Dynamic memory allocation is not supported, although this can
+       be worked around in some cases by supplying multiple statically
+       allocated variables.
+
+Some of these limitations may be overcome in the future, but others are
+more likely to be addressed by incorporating the Linux-kernel memory model
+into other tools.
+
+Finally, please note that LKMM is subject to change as hardware, use cases,
+and compilers evolve.
index 63c4adf..03f58b1 100644 (file)
@@ -1,7 +1,7 @@
 This document provides "recipes", that is, litmus tests for commonly
 occurring situations, as well as a few that illustrate subtly broken but
 attractive nuisances.  Many of these recipes include example code from
-v4.13 of the Linux kernel.
+v5.7 of the Linux kernel.
 
 The first section covers simple special cases, the second section
 takes off the training wheels to cover more involved examples,
@@ -278,7 +278,7 @@ is present if the value loaded determines the address of a later access
 first place (control dependency).  Note that the term "data dependency"
 is sometimes casually used to cover both address and data dependencies.
 
-In lib/prime_numbers.c, the expand_to_next_prime() function invokes
+In lib/math/prime_numbers.c, the expand_to_next_prime() function invokes
 rcu_assign_pointer(), and the next_prime_number() function invokes
 rcu_dereference().  This combination mediates access to a bit vector
 that is expanded as additional primes are needed.
index ecbbaa5..c5fdfd1 100644 (file)
@@ -120,7 +120,7 @@ o   Jade Alglave, Luc Maranget, and Michael Tautschnig. 2014. "Herding
 
 o      Jade Alglave, Patrick Cousot, and Luc Maranget. 2016. "Syntax and
        semantics of the weak consistency model specification language
-       cat". CoRR abs/1608.07531 (2016). http://arxiv.org/abs/1608.07531
+       cat". CoRR abs/1608.07531 (2016). https://arxiv.org/abs/1608.07531
 
 
 Memory-model comparisons
diff --git a/tools/memory-model/Documentation/simple.txt b/tools/memory-model/Documentation/simple.txt
new file mode 100644 (file)
index 0000000..81e1a0e
--- /dev/null
@@ -0,0 +1,271 @@
+This document provides options for those wishing to keep their
+memory-ordering lives simple, as is necessary for those whose domain
+is complex.  After all, there are bugs other than memory-ordering bugs,
+and the time spent gaining memory-ordering knowledge is not available
+for gaining domain knowledge.  Furthermore Linux-kernel memory model
+(LKMM) is quite complex, with subtle differences in code often having
+dramatic effects on correctness.
+
+The options near the beginning of this list are quite simple.  The idea
+is not that kernel hackers don't already know about them, but rather
+that they might need the occasional reminder.
+
+Please note that this is a generic guide, and that specific subsystems
+will often have special requirements or idioms.  For example, developers
+of MMIO-based device drivers will often need to use mb(), rmb(), and
+wmb(), and therefore might find smp_mb(), smp_rmb(), and smp_wmb()
+to be more natural than smp_load_acquire() and smp_store_release().
+On the other hand, those coming in from other environments will likely
+be more familiar with these last two.
+
+
+Single-threaded code
+====================
+
+In single-threaded code, there is no reordering, at least assuming
+that your toolchain and hardware are working correctly.  In addition,
+it is generally a mistake to assume your code will only run in a single
+threaded context as the kernel can enter the same code path on multiple
+CPUs at the same time.  One important exception is a function that makes
+no external data references.
+
+In the general case, you will need to take explicit steps to ensure that
+your code really is executed within a single thread that does not access
+shared variables.  A simple way to achieve this is to define a global lock
+that you acquire at the beginning of your code and release at the end,
+taking care to ensure that all references to your code's shared data are
+also carried out under that same lock.  Because only one thread can hold
+this lock at a given time, your code will be executed single-threaded.
+This approach is called "code locking".
+
+Code locking can severely limit both performance and scalability, so it
+should be used with caution, and only on code paths that execute rarely.
+After all, a huge amount of effort was required to remove the Linux
+kernel's old "Big Kernel Lock", so let's please be very careful about
+adding new "little kernel locks".
+
+One of the advantages of locking is that, in happy contrast with the
+year 1981, almost all kernel developers are very familiar with locking.
+The Linux kernel's lockdep (CONFIG_PROVE_LOCKING=y) is very helpful with
+the formerly feared deadlock scenarios.
+
+Please use the standard locking primitives provided by the kernel rather
+than rolling your own.  For one thing, the standard primitives interact
+properly with lockdep.  For another thing, these primitives have been
+tuned to deal better with high contention.  And for one final thing, it is
+surprisingly hard to correctly code production-quality lock acquisition
+and release functions.  After all, even simple non-production-quality
+locking functions must carefully prevent both the CPU and the compiler
+from moving code in either direction across the locking function.
+
+Despite the scalability limitations of single-threaded code, RCU
+takes this approach for much of its grace-period processing and also
+for early-boot operation.  The reason RCU is able to scale despite
+single-threaded grace-period processing is use of batching, where all
+updates that accumulated during one grace period are handled by the
+next one.  In other words, slowing down grace-period processing makes
+it more efficient.  Nor is RCU unique:  Similar batching optimizations
+are used in many I/O operations.
+
+
+Packaged code
+=============
+
+Even if performance and scalability concerns prevent your code from
+being completely single-threaded, it is often possible to use library
+functions that handle the concurrency nearly or entirely on their own.
+This approach delegates any LKMM worries to the library maintainer.
+
+In the kernel, what is the "library"?  Quite a bit.  It includes the
+contents of the lib/ directory, much of the include/linux/ directory along
+with a lot of other heavily used APIs.  But heavily used examples include
+the list macros (for example, include/linux/{,rcu}list.h), workqueues,
+smp_call_function(), and the various hash tables and search trees.
+
+
+Data locking
+============
+
+With code locking, we use single-threaded code execution to guarantee
+serialized access to the data that the code is accessing.  However,
+we can also achieve this by instead associating the lock with specific
+instances of the data structures.  This creates a "critical section"
+in the code execution that will execute as though it is single threaded.
+By placing all the accesses and modifications to a shared data structure
+inside a critical section, we ensure that the execution context that
+holds the lock has exclusive access to the shared data.
+
+The poster boy for this approach is the hash table, where placing a lock
+in each hash bucket allows operations on different buckets to proceed
+concurrently.  This works because the buckets do not overlap with each
+other, so that an operation on one bucket does not interfere with any
+other bucket.
+
+As the number of buckets increases, data locking scales naturally.
+In particular, if the amount of data increases with the number of CPUs,
+increasing the number of buckets as the number of CPUs increase results
+in a naturally scalable data structure.
+
+
+Per-CPU processing
+==================
+
+Partitioning processing and data over CPUs allows each CPU to take
+a single-threaded approach while providing excellent performance and
+scalability.  Of course, there is no free lunch:  The dark side of this
+excellence is substantially increased memory footprint.
+
+In addition, it is sometimes necessary to occasionally update some global
+view of this processing and data, in which case something like locking
+must be used to protect this global view.  This is the approach taken
+by the percpu_counter infrastructure. In many cases, there are already
+generic/library variants of commonly used per-cpu constructs available.
+Please use them rather than rolling your own.
+
+RCU uses DEFINE_PER_CPU*() declaration to create a number of per-CPU
+data sets.  For example, each CPU does private quiescent-state processing
+within its instance of the per-CPU rcu_data structure, and then uses data
+locking to report quiescent states up the grace-period combining tree.
+
+
+Packaged primitives: Sequence locking
+=====================================
+
+Lockless programming is considered by many to be more difficult than
+lock-based programming, but there are a few lockless design patterns that
+have been built out into an API.  One of these APIs is sequence locking.
+Although this APIs can be used in extremely complex ways, there are simple
+and effective ways of using it that avoid the need to pay attention to
+memory ordering.
+
+The basic keep-things-simple rule for sequence locking is "do not write
+in read-side code".  Yes, you can do writes from within sequence-locking
+readers, but it won't be so simple.  For example, such writes will be
+lockless and should be idempotent.
+
+For more sophisticated use cases, LKMM can guide you, including use
+cases involving combining sequence locking with other synchronization
+primitives.  (LKMM does not yet know about sequence locking, so it is
+currently necessary to open-code it in your litmus tests.)
+
+Additional information may be found in include/linux/seqlock.h.
+
+Packaged primitives: RCU
+========================
+
+Another lockless design pattern that has been baked into an API
+is RCU.  The Linux kernel makes sophisticated use of RCU, but the
+keep-things-simple rules for RCU are "do not write in read-side code"
+and "do not update anything that is visible to and accessed by readers",
+and "protect updates with locking".
+
+These rules are illustrated by the functions foo_update_a() and
+foo_get_a() shown in Documentation/RCU/whatisRCU.rst.  Additional
+RCU usage patterns maybe found in Documentation/RCU and in the
+source code.
+
+
+Packaged primitives: Atomic operations
+======================================
+
+Back in the day, the Linux kernel had three types of atomic operations:
+
+1.     Initialization and read-out, such as atomic_set() and atomic_read().
+
+2.     Operations that did not return a value and provided no ordering,
+       such as atomic_inc() and atomic_dec().
+
+3.     Operations that returned a value and provided full ordering, such as
+       atomic_add_return() and atomic_dec_and_test().  Note that some
+       value-returning operations provide full ordering only conditionally.
+       For example, cmpxchg() provides ordering only upon success.
+
+More recent kernels have operations that return a value but do not
+provide full ordering.  These are flagged with either a _relaxed()
+suffix (providing no ordering), or an _acquire() or _release() suffix
+(providing limited ordering).
+
+Additional information may be found in these files:
+
+Documentation/atomic_t.txt
+Documentation/atomic_bitops.txt
+Documentation/core-api/atomic_ops.rst
+Documentation/core-api/refcount-vs-atomic.rst
+
+Reading code using these primitives is often also quite helpful.
+
+
+Lockless, fully ordered
+=======================
+
+When using locking, there often comes a time when it is necessary
+to access some variable or another without holding the data lock
+that serializes access to that variable.
+
+If you want to keep things simple, use the initialization and read-out
+operations from the previous section only when there are no racing
+accesses.  Otherwise, use only fully ordered operations when accessing
+or modifying the variable.  This approach guarantees that code prior
+to a given access to that variable will be seen by all CPUs has having
+happened before any code following any later access to that same variable.
+
+Please note that per-CPU functions are not atomic operations and
+hence they do not provide any ordering guarantees at all.
+
+If the lockless accesses are frequently executed reads that are used
+only for heuristics, or if they are frequently executed writes that
+are used only for statistics, please see the next section.
+
+
+Lockless statistics and heuristics
+==================================
+
+Unordered primitives such as atomic_read(), atomic_set(), READ_ONCE(), and
+WRITE_ONCE() can safely be used in some cases.  These primitives provide
+no ordering, but they do prevent the compiler from carrying out a number
+of destructive optimizations (for which please see the next section).
+One example use for these primitives is statistics, such as per-CPU
+counters exemplified by the rt_cache_stat structure's routing-cache
+statistics counters.  Another example use case is heuristics, such as
+the jiffies_till_first_fqs and jiffies_till_next_fqs kernel parameters
+controlling how often RCU scans for idle CPUs.
+
+But be careful.  "Unordered" really does mean "unordered".  It is all
+too easy to assume ordering, and this assumption must be avoided when
+using these primitives.
+
+
+Don't let the compiler trip you up
+==================================
+
+It can be quite tempting to use plain C-language accesses for lockless
+loads from and stores to shared variables.  Although this is both
+possible and quite common in the Linux kernel, it does require a
+surprising amount of analysis, care, and knowledge about the compiler.
+Yes, some decades ago it was not unfair to consider a C compiler to be
+an assembler with added syntax and better portability, but the advent of
+sophisticated optimizing compilers mean that those days are long gone.
+Today's optimizing compilers can profoundly rewrite your code during the
+translation process, and have long been ready, willing, and able to do so.
+
+Therefore, if you really need to use C-language assignments instead of
+READ_ONCE(), WRITE_ONCE(), and so on, you will need to have a very good
+understanding of both the C standard and your compiler.  Here are some
+introductory references and some tooling to start you on this noble quest:
+
+Who's afraid of a big bad optimizing compiler?
+       https://lwn.net/Articles/793253/
+Calibrating your fear of big bad optimizing compilers
+       https://lwn.net/Articles/799218/
+Concurrency bugs should fear the big bad data-race detector (part 1)
+       https://lwn.net/Articles/816850/
+Concurrency bugs should fear the big bad data-race detector (part 2)
+       https://lwn.net/Articles/816854/
+
+
+More complex use cases
+======================
+
+If the alternatives above do not do what you need, please look at the
+recipes-pairs.txt file to peel off the next layer of the memory-ordering
+onion.
index ecb7385..c8144d4 100644 (file)
@@ -63,10 +63,32 @@ BASIC USAGE: HERD7
 ==================
 
 The memory model is used, in conjunction with "herd7", to exhaustively
-explore the state space of small litmus tests.
+explore the state space of small litmus tests.  Documentation describing
+the format, features, capabilities and limitations of these litmus
+tests is available in tools/memory-model/Documentation/litmus-tests.txt.
 
-For example, to run SB+fencembonceonces.litmus against the memory model:
+Example litmus tests may be found in the Linux-kernel source tree:
 
+       tools/memory-model/litmus-tests/
+       Documentation/litmus-tests/
+
+Several thousand more example litmus tests are available here:
+
+       https://github.com/paulmckrcu/litmus
+       https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/perfbook.git/tree/CodeSamples/formal/herd
+       https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/perfbook.git/tree/CodeSamples/formal/litmus
+
+Documentation describing litmus tests and now to use them may be found
+here:
+
+       tools/memory-model/Documentation/litmus-tests.txt
+
+The remainder of this section uses the SB+fencembonceonces.litmus test
+located in the tools/memory-model directory.
+
+To run SB+fencembonceonces.litmus against the memory model:
+
+  $ cd $LINUX_SOURCE_TREE/tools/memory-model
   $ herd7 -conf linux-kernel.cfg litmus-tests/SB+fencembonceonces.litmus
 
 Here is the corresponding output:
@@ -87,7 +109,11 @@ Here is the corresponding output:
 The "Positive: 0 Negative: 3" and the "Never 0 3" each indicate that
 this litmus test's "exists" clause can not be satisfied.
 
-See "herd7 -help" or "herdtools7/doc/" for more information.
+See "herd7 -help" or "herdtools7/doc/" for more information on running the
+tool itself, but please be aware that this documentation is intended for
+people who work on the memory model itself, that is, people making changes
+to the tools/memory-model/linux-kernel.* files.  It is not intended for
+people focusing on writing, understanding, and running LKMM litmus tests.
 
 
 =====================
@@ -124,7 +150,11 @@ that during two million trials, the state specified in this litmus
 test's "exists" clause was not reached.
 
 And, as with "herd7", please see "klitmus7 -help" or "herdtools7/doc/"
-for more information.
+for more information.  And again, please be aware that this documentation
+is intended for people who work on the memory model itself, that is,
+people making changes to the tools/memory-model/linux-kernel.* files.
+It is not intended for people focusing on writing, understanding, and
+running LKMM litmus tests.
 
 
 ====================
@@ -137,12 +167,21 @@ Documentation/cheatsheet.txt
 Documentation/explanation.txt
        Describes the memory model in detail.
 
+Documentation/litmus-tests.txt
+       Describes the format, features, capabilities, and limitations
+       of the litmus tests that LKMM can evaluate.
+
 Documentation/recipes.txt
        Lists common memory-ordering patterns.
 
 Documentation/references.txt
        Provides background reading.
 
+Documentation/simple.txt
+       Starting point for someone new to Linux-kernel concurrency.
+       And also for those needing a reminder of the simpler approaches
+       to concurrency!
+
 linux-kernel.bell
        Categorizes the relevant instructions, including memory
        references, memory barriers, atomic read-modify-write operations,
@@ -187,116 +226,3 @@ README
        This file.
 
 scripts        Various scripts, see scripts/README.
-
-
-===========
-LIMITATIONS
-===========
-
-The Linux-kernel memory model (LKMM) has the following limitations:
-
-1.     Compiler optimizations are not accurately modeled.  Of course,
-       the use of READ_ONCE() and WRITE_ONCE() limits the compiler's
-       ability to optimize, but under some circumstances it is possible
-       for the compiler to undermine the memory model.  For more
-       information, see Documentation/explanation.txt (in particular,
-       the "THE PROGRAM ORDER RELATION: po AND po-loc" and "A WARNING"
-       sections).
-
-       Note that this limitation in turn limits LKMM's ability to
-       accurately model address, control, and data dependencies.
-       For example, if the compiler can deduce the value of some variable
-       carrying a dependency, then the compiler can break that dependency
-       by substituting a constant of that value.
-
-2.     Multiple access sizes for a single variable are not supported,
-       and neither are misaligned or partially overlapping accesses.
-
-3.     Exceptions and interrupts are not modeled.  In some cases,
-       this limitation can be overcome by modeling the interrupt or
-       exception with an additional process.
-
-4.     I/O such as MMIO or DMA is not supported.
-
-5.     Self-modifying code (such as that found in the kernel's
-       alternatives mechanism, function tracer, Berkeley Packet Filter
-       JIT compiler, and module loader) is not supported.
-
-6.     Complete modeling of all variants of atomic read-modify-write
-       operations, locking primitives, and RCU is not provided.
-       For example, call_rcu() and rcu_barrier() are not supported.
-       However, a substantial amount of support is provided for these
-       operations, as shown in the linux-kernel.def file.
-
-       a.      When rcu_assign_pointer() is passed NULL, the Linux
-               kernel provides no ordering, but LKMM models this
-               case as a store release.
-
-       b.      The "unless" RMW operations are not currently modeled:
-               atomic_long_add_unless(), atomic_inc_unless_negative(),
-               and atomic_dec_unless_positive().  These can be emulated
-               in litmus tests, for example, by using atomic_cmpxchg().
-
-               One exception of this limitation is atomic_add_unless(),
-               which is provided directly by herd7 (so no corresponding
-               definition in linux-kernel.def).  atomic_add_unless() is
-               modeled by herd7 therefore it can be used in litmus tests.
-
-       c.      The call_rcu() function is not modeled.  It can be
-               emulated in litmus tests by adding another process that
-               invokes synchronize_rcu() and the body of the callback
-               function, with (for example) a release-acquire from
-               the site of the emulated call_rcu() to the beginning
-               of the additional process.
-
-       d.      The rcu_barrier() function is not modeled.  It can be
-               emulated in litmus tests emulating call_rcu() via
-               (for example) a release-acquire from the end of each
-               additional call_rcu() process to the site of the
-               emulated rcu-barrier().
-
-       e.      Although sleepable RCU (SRCU) is now modeled, there
-               are some subtle differences between its semantics and
-               those in the Linux kernel.  For example, the kernel
-               might interpret the following sequence as two partially
-               overlapping SRCU read-side critical sections:
-
-                        1  r1 = srcu_read_lock(&my_srcu);
-                        2  do_something_1();
-                        3  r2 = srcu_read_lock(&my_srcu);
-                        4  do_something_2();
-                        5  srcu_read_unlock(&my_srcu, r1);
-                        6  do_something_3();
-                        7  srcu_read_unlock(&my_srcu, r2);
-
-               In contrast, LKMM will interpret this as a nested pair of
-               SRCU read-side critical sections, with the outer critical
-               section spanning lines 1-7 and the inner critical section
-               spanning lines 3-5.
-
-               This difference would be more of a concern had anyone
-               identified a reasonable use case for partially overlapping
-               SRCU read-side critical sections.  For more information,
-               please see: https://paulmck.livejournal.com/40593.html
-
-       f.      Reader-writer locking is not modeled.  It can be
-               emulated in litmus tests using atomic read-modify-write
-               operations.
-
-The "herd7" tool has some additional limitations of its own, apart from
-the memory model:
-
-1.     Non-trivial data structures such as arrays or structures are
-       not supported.  However, pointers are supported, allowing trivial
-       linked lists to be constructed.
-
-2.     Dynamic memory allocation is not supported, although this can
-       be worked around in some cases by supplying multiple statically
-       allocated variables.
-
-Some of these limitations may be overcome in the future, but others are
-more likely to be addressed by incorporating the Linux-kernel memory model
-into other tools.
-
-Finally, please note that LKMM is subject to change as hardware, use cases,
-and compilers evolve.
index e034a8f..326ac39 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/hashtable.h>
 #include <linux/kernel.h>
+#include <linux/static_call_types.h>
 
 #define FAKE_JUMP_OFFSET -1
 
@@ -433,6 +434,103 @@ reachable:
        return 0;
 }
 
+static int create_static_call_sections(struct objtool_file *file)
+{
+       struct section *sec, *reloc_sec;
+       struct reloc *reloc;
+       struct static_call_site *site;
+       struct instruction *insn;
+       struct symbol *key_sym;
+       char *key_name, *tmp;
+       int idx;
+
+       sec = find_section_by_name(file->elf, ".static_call_sites");
+       if (sec) {
+               INIT_LIST_HEAD(&file->static_call_list);
+               WARN("file already has .static_call_sites section, skipping");
+               return 0;
+       }
+
+       if (list_empty(&file->static_call_list))
+               return 0;
+
+       idx = 0;
+       list_for_each_entry(insn, &file->static_call_list, static_call_node)
+               idx++;
+
+       sec = elf_create_section(file->elf, ".static_call_sites", SHF_WRITE,
+                                sizeof(struct static_call_site), idx);
+       if (!sec)
+               return -1;
+
+       reloc_sec = elf_create_reloc_section(file->elf, sec, SHT_RELA);
+       if (!reloc_sec)
+               return -1;
+
+       idx = 0;
+       list_for_each_entry(insn, &file->static_call_list, static_call_node) {
+
+               site = (struct static_call_site *)sec->data->d_buf + idx;
+               memset(site, 0, sizeof(struct static_call_site));
+
+               /* populate reloc for 'addr' */
+               reloc = malloc(sizeof(*reloc));
+               if (!reloc) {
+                       perror("malloc");
+                       return -1;
+               }
+               memset(reloc, 0, sizeof(*reloc));
+               reloc->sym = insn->sec->sym;
+               reloc->addend = insn->offset;
+               reloc->type = R_X86_64_PC32;
+               reloc->offset = idx * sizeof(struct static_call_site);
+               reloc->sec = reloc_sec;
+               elf_add_reloc(file->elf, reloc);
+
+               /* find key symbol */
+               key_name = strdup(insn->call_dest->name);
+               if (!key_name) {
+                       perror("strdup");
+                       return -1;
+               }
+               if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR,
+                           STATIC_CALL_TRAMP_PREFIX_LEN)) {
+                       WARN("static_call: trampoline name malformed: %s", key_name);
+                       return -1;
+               }
+               tmp = key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX_LEN;
+               memcpy(tmp, STATIC_CALL_KEY_PREFIX_STR, STATIC_CALL_KEY_PREFIX_LEN);
+
+               key_sym = find_symbol_by_name(file->elf, tmp);
+               if (!key_sym) {
+                       WARN("static_call: can't find static_call_key symbol: %s", tmp);
+                       return -1;
+               }
+               free(key_name);
+
+               /* populate reloc for 'key' */
+               reloc = malloc(sizeof(*reloc));
+               if (!reloc) {
+                       perror("malloc");
+                       return -1;
+               }
+               memset(reloc, 0, sizeof(*reloc));
+               reloc->sym = key_sym;
+               reloc->addend = is_sibling_call(insn) ? STATIC_CALL_SITE_TAIL : 0;
+               reloc->type = R_X86_64_PC32;
+               reloc->offset = idx * sizeof(struct static_call_site) + 4;
+               reloc->sec = reloc_sec;
+               elf_add_reloc(file->elf, reloc);
+
+               idx++;
+       }
+
+       if (elf_rebuild_reloc_section(file->elf, reloc_sec))
+               return -1;
+
+       return 0;
+}
+
 /*
  * Warnings shouldn't be reported for ignored functions.
  */
@@ -528,6 +626,61 @@ static const char *uaccess_safe_builtin[] = {
        "__tsan_write4",
        "__tsan_write8",
        "__tsan_write16",
+       "__tsan_read_write1",
+       "__tsan_read_write2",
+       "__tsan_read_write4",
+       "__tsan_read_write8",
+       "__tsan_read_write16",
+       "__tsan_atomic8_load",
+       "__tsan_atomic16_load",
+       "__tsan_atomic32_load",
+       "__tsan_atomic64_load",
+       "__tsan_atomic8_store",
+       "__tsan_atomic16_store",
+       "__tsan_atomic32_store",
+       "__tsan_atomic64_store",
+       "__tsan_atomic8_exchange",
+       "__tsan_atomic16_exchange",
+       "__tsan_atomic32_exchange",
+       "__tsan_atomic64_exchange",
+       "__tsan_atomic8_fetch_add",
+       "__tsan_atomic16_fetch_add",
+       "__tsan_atomic32_fetch_add",
+       "__tsan_atomic64_fetch_add",
+       "__tsan_atomic8_fetch_sub",
+       "__tsan_atomic16_fetch_sub",
+       "__tsan_atomic32_fetch_sub",
+       "__tsan_atomic64_fetch_sub",
+       "__tsan_atomic8_fetch_and",
+       "__tsan_atomic16_fetch_and",
+       "__tsan_atomic32_fetch_and",
+       "__tsan_atomic64_fetch_and",
+       "__tsan_atomic8_fetch_or",
+       "__tsan_atomic16_fetch_or",
+       "__tsan_atomic32_fetch_or",
+       "__tsan_atomic64_fetch_or",
+       "__tsan_atomic8_fetch_xor",
+       "__tsan_atomic16_fetch_xor",
+       "__tsan_atomic32_fetch_xor",
+       "__tsan_atomic64_fetch_xor",
+       "__tsan_atomic8_fetch_nand",
+       "__tsan_atomic16_fetch_nand",
+       "__tsan_atomic32_fetch_nand",
+       "__tsan_atomic64_fetch_nand",
+       "__tsan_atomic8_compare_exchange_strong",
+       "__tsan_atomic16_compare_exchange_strong",
+       "__tsan_atomic32_compare_exchange_strong",
+       "__tsan_atomic64_compare_exchange_strong",
+       "__tsan_atomic8_compare_exchange_weak",
+       "__tsan_atomic16_compare_exchange_weak",
+       "__tsan_atomic32_compare_exchange_weak",
+       "__tsan_atomic64_compare_exchange_weak",
+       "__tsan_atomic8_compare_exchange_val",
+       "__tsan_atomic16_compare_exchange_val",
+       "__tsan_atomic32_compare_exchange_val",
+       "__tsan_atomic64_compare_exchange_val",
+       "__tsan_atomic_thread_fence",
+       "__tsan_atomic_signal_fence",
        /* KCOV */
        "write_comp_data",
        "check_kcov_mode",
@@ -548,8 +701,9 @@ static const char *uaccess_safe_builtin[] = {
        "__ubsan_handle_shift_out_of_bounds",
        /* misc */
        "csum_partial_copy_generic",
-       "__memcpy_mcsafe",
-       "mcsafe_handle_tail",
+       "copy_mc_fragile",
+       "copy_mc_fragile_handle_tail",
+       "copy_mc_enhanced_fast_string",
        "ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */
        NULL
 };
@@ -619,7 +773,7 @@ static int add_jump_destinations(struct objtool_file *file)
                if (!is_static_jump(insn))
                        continue;
 
-               if (insn->ignore || insn->offset == FAKE_JUMP_OFFSET)
+               if (insn->offset == FAKE_JUMP_OFFSET)
                        continue;
 
                reloc = find_reloc_by_dest_range(file->elf, insn->sec,
@@ -649,6 +803,10 @@ static int add_jump_destinations(struct objtool_file *file)
                } else {
                        /* external sibling call */
                        insn->call_dest = reloc->sym;
+                       if (insn->call_dest->static_call_tramp) {
+                               list_add_tail(&insn->static_call_node,
+                                             &file->static_call_list);
+                       }
                        continue;
                }
 
@@ -700,6 +858,10 @@ static int add_jump_destinations(struct objtool_file *file)
 
                                /* internal sibling call */
                                insn->call_dest = insn->jump_dest->func;
+                               if (insn->call_dest->static_call_tramp) {
+                                       list_add_tail(&insn->static_call_node,
+                                                     &file->static_call_list);
+                               }
                        }
                }
        }
@@ -1522,6 +1684,23 @@ static int read_intra_function_calls(struct objtool_file *file)
        return 0;
 }
 
+static int read_static_call_tramps(struct objtool_file *file)
+{
+       struct section *sec;
+       struct symbol *func;
+
+       for_each_sec(file, sec) {
+               list_for_each_entry(func, &sec->symbol_list, list) {
+                       if (func->bind == STB_GLOBAL &&
+                           !strncmp(func->name, STATIC_CALL_TRAMP_PREFIX_STR,
+                                    strlen(STATIC_CALL_TRAMP_PREFIX_STR)))
+                               func->static_call_tramp = true;
+               }
+       }
+
+       return 0;
+}
+
 static void mark_rodata(struct objtool_file *file)
 {
        struct section *sec;
@@ -1569,6 +1748,10 @@ static int decode_sections(struct objtool_file *file)
        if (ret)
                return ret;
 
+       ret = read_static_call_tramps(file);
+       if (ret)
+               return ret;
+
        ret = add_jump_destinations(file);
        if (ret)
                return ret;
@@ -2432,6 +2615,11 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
                        if (dead_end_function(file, insn->call_dest))
                                return 0;
 
+                       if (insn->type == INSN_CALL && insn->call_dest->static_call_tramp) {
+                               list_add_tail(&insn->static_call_node,
+                                             &file->static_call_list);
+                       }
+
                        break;
 
                case INSN_JUMP_CONDITIONAL:
@@ -2791,6 +2979,7 @@ int check(const char *_objname, bool orc)
 
        INIT_LIST_HEAD(&file.insn_list);
        hash_init(file.insn_hash);
+       INIT_LIST_HEAD(&file.static_call_list);
        file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");
        file.ignore_unreachables = no_unreachable;
        file.hints = false;
@@ -2838,6 +3027,11 @@ int check(const char *_objname, bool orc)
                warnings += ret;
        }
 
+       ret = create_static_call_sections(&file);
+       if (ret < 0)
+               goto out;
+       warnings += ret;
+
        if (orc) {
                ret = create_orc(&file);
                if (ret < 0)
index 061aa96..36d38b9 100644 (file)
@@ -22,6 +22,7 @@ struct insn_state {
 struct instruction {
        struct list_head list;
        struct hlist_node hash;
+       struct list_head static_call_node;
        struct section *sec;
        unsigned long offset;
        unsigned int len;
index 3ddbd66..4e1d746 100644 (file)
@@ -652,7 +652,7 @@ err:
 }
 
 struct section *elf_create_section(struct elf *elf, const char *name,
-                                  size_t entsize, int nr)
+                                  unsigned int sh_flags, size_t entsize, int nr)
 {
        struct section *sec, *shstrtab;
        size_t size = entsize * nr;
@@ -712,7 +712,7 @@ struct section *elf_create_section(struct elf *elf, const char *name,
        sec->sh.sh_entsize = entsize;
        sec->sh.sh_type = SHT_PROGBITS;
        sec->sh.sh_addralign = 1;
-       sec->sh.sh_flags = SHF_ALLOC;
+       sec->sh.sh_flags = SHF_ALLOC | sh_flags;
 
 
        /* Add section name to .shstrtab (or .strtab for Clang) */
@@ -767,7 +767,7 @@ static struct section *elf_create_rel_reloc_section(struct elf *elf, struct sect
        strcpy(relocname, ".rel");
        strcat(relocname, base->name);
 
-       sec = elf_create_section(elf, relocname, sizeof(GElf_Rel), 0);
+       sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rel), 0);
        free(relocname);
        if (!sec)
                return NULL;
@@ -797,7 +797,7 @@ static struct section *elf_create_rela_reloc_section(struct elf *elf, struct sec
        strcpy(relocname, ".rela");
        strcat(relocname, base->name);
 
-       sec = elf_create_section(elf, relocname, sizeof(GElf_Rela), 0);
+       sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rela), 0);
        free(relocname);
        if (!sec)
                return NULL;
index 6cc80a0..807f8c6 100644 (file)
@@ -56,6 +56,7 @@ struct symbol {
        unsigned int len;
        struct symbol *pfunc, *cfunc, *alias;
        bool uaccess_safe;
+       bool static_call_tramp;
 };
 
 struct reloc {
@@ -120,7 +121,7 @@ static inline u32 reloc_hash(struct reloc *reloc)
 }
 
 struct elf *elf_open_read(const char *name, int flags);
-struct section *elf_create_section(struct elf *elf, const char *name, size_t entsize, int nr);
+struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr);
 struct section *elf_create_reloc_section(struct elf *elf, struct section *base, int reltype);
 void elf_add_reloc(struct elf *elf, struct reloc *reloc);
 int elf_write_insn(struct elf *elf, struct section *sec,
index 528028a..9a7cd0b 100644 (file)
@@ -16,6 +16,7 @@ struct objtool_file {
        struct elf *elf;
        struct list_head insn_list;
        DECLARE_HASHTABLE(insn_hash, 20);
+       struct list_head static_call_list;
        bool ignore_unreachables, c_file, hints, rodata;
 };
 
index 968f55e..e6b2363 100644 (file)
@@ -177,7 +177,7 @@ int create_orc_sections(struct objtool_file *file)
 
 
        /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */
-       sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx);
+       sec = elf_create_section(file->elf, ".orc_unwind_ip", 0, sizeof(int), idx);
        if (!sec)
                return -1;
 
@@ -186,7 +186,7 @@ int create_orc_sections(struct objtool_file *file)
                return -1;
 
        /* create .orc_unwind section */
-       u_sec = elf_create_section(file->elf, ".orc_unwind",
+       u_sec = elf_create_section(file->elf, ".orc_unwind", 0,
                                   sizeof(struct orc_entry), idx);
 
        /* populate sections */
index 2a1261b..aa099b2 100755 (executable)
@@ -7,6 +7,7 @@ arch/x86/include/asm/orc_types.h
 arch/x86/include/asm/emulate_prefix.h
 arch/x86/lib/x86-opcode-map.txt
 arch/x86/tools/gen-insn-attr-x86.awk
+include/linux/static_call_types.h
 '
 
 check_2 () {
index 3f72d8e..bd50cdf 100644 (file)
@@ -33,6 +33,10 @@ OPTIONS
         - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
          hexadecimal event descriptor.
 
+        - a symbolic or raw PMU event followed by an optional colon
+         and a list of event modifiers, e.g., cpu-cycles:p.  See the
+         linkperf:perf-list[1] man page for details on event modifiers.
+
        - a symbolically formed PMU event like 'pmu/param1=0x3,param2/' where
          'param1', 'param2', etc are defined as formats for the PMU in
          /sys/bus/event_source/devices/<pmu>/format/*.
index c9bfefc..db420dd 100644 (file)
@@ -39,6 +39,10 @@ report::
        - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
          hexadecimal event descriptor.
 
+        - a symbolic or raw PMU event followed by an optional colon
+         and a list of event modifiers, e.g., cpu-cycles:p.  See the
+         linkperf:perf-list[1] man page for details on event modifiers.
+
        - a symbolically formed event like 'pmu/param1=0x3,param2/' where
          param1 and param2 are defined as formats for the PMU in
          /sys/bus/event_source/devices/<pmu>/format/*
@@ -416,6 +420,9 @@ counts for all hardware threads in a core but show the sum counts per
 hardware thread. This is essentially a replacement for the any bit and
 convenient for post processing.
 
+--summary::
+Print summary for interval mode (-I).
+
 EXAMPLES
 --------
 
index 3ca6fe0..b168364 100644 (file)
@@ -32,7 +32,7 @@
 18     spu     oldstat                         sys_ni_syscall
 19     common  lseek                           sys_lseek                       compat_sys_lseek
 20     common  getpid                          sys_getpid
-21     nospu   mount                           sys_mount                       compat_sys_mount
+21     nospu   mount                           sys_mount
 22     32      umount                          sys_oldumount
 22     64      umount                          sys_ni_syscall
 22     spu     umount                          sys_ni_syscall
 142    common  _newselect                      sys_select                      compat_sys_select
 143    common  flock                           sys_flock
 144    common  msync                           sys_msync
-145    common  readv                           sys_readv                       compat_sys_readv
-146    common  writev                          sys_writev                      compat_sys_writev
+145    common  readv                           sys_readv
+146    common  writev                          sys_writev
 147    common  getsid                          sys_getsid
 148    common  fdatasync                       sys_fdatasync
 149    nospu   _sysctl                         sys_ni_syscall
 282    common  unshare                         sys_unshare
 283    common  splice                          sys_splice
 284    common  tee                             sys_tee
-285    common  vmsplice                        sys_vmsplice                    compat_sys_vmsplice
+285    common  vmsplice                        sys_vmsplice
 286    common  openat                          sys_openat                      compat_sys_openat
 287    common  mkdirat                         sys_mkdirat
 288    common  mknodat                         sys_mknodat
 348    common  syncfs                          sys_syncfs
 349    common  sendmmsg                        sys_sendmmsg                    compat_sys_sendmmsg
 350    common  setns                           sys_setns
-351    nospu   process_vm_readv                sys_process_vm_readv            compat_sys_process_vm_readv
-352    nospu   process_vm_writev               sys_process_vm_writev           compat_sys_process_vm_writev
+351    nospu   process_vm_readv                sys_process_vm_readv
+352    nospu   process_vm_writev               sys_process_vm_writev
 353    nospu   finit_module                    sys_finit_module
 354    nospu   kcmp                            sys_kcmp
 355    common  sched_setattr                   sys_sched_setattr
index 6a0bbea..d2fa964 100644 (file)
@@ -26,7 +26,7 @@
 16   32                lchown                  -                               compat_sys_s390_lchown16
 19   common    lseek                   sys_lseek                       compat_sys_lseek
 20   common    getpid                  sys_getpid                      sys_getpid
-21   common    mount                   sys_mount                       compat_sys_mount
+21   common    mount                   sys_mount
 22   common    umount                  sys_oldumount                   compat_sys_oldumount
 23   32                setuid                  -                               compat_sys_s390_setuid16
 24   32                getuid                  -                               compat_sys_s390_getuid16
 142  64                select                  sys_select                      -
 143  common    flock                   sys_flock                       sys_flock
 144  common    msync                   sys_msync                       compat_sys_msync
-145  common    readv                   sys_readv                       compat_sys_readv
-146  common    writev                  sys_writev                      compat_sys_writev
+145  common    readv                   sys_readv
+146  common    writev                  sys_writev
 147  common    getsid                  sys_getsid                      sys_getsid
 148  common    fdatasync               sys_fdatasync                   sys_fdatasync
 149  common    _sysctl                 -                               -
 306  common    splice                  sys_splice                      compat_sys_splice
 307  common    sync_file_range         sys_sync_file_range             compat_sys_s390_sync_file_range
 308  common    tee                     sys_tee                         compat_sys_tee
-309  common    vmsplice                sys_vmsplice                    compat_sys_vmsplice
+309  common    vmsplice                sys_vmsplice                    sys_vmsplice
 310  common    move_pages              sys_move_pages                  compat_sys_move_pages
 311  common    getcpu                  sys_getcpu                      compat_sys_getcpu
 312  common    epoll_pwait             sys_epoll_pwait                 compat_sys_epoll_pwait
 337  common    clock_adjtime           sys_clock_adjtime               compat_sys_clock_adjtime
 338  common    syncfs                  sys_syncfs                      sys_syncfs
 339  common    setns                   sys_setns                       sys_setns
-340  common    process_vm_readv        sys_process_vm_readv            compat_sys_process_vm_readv
-341  common    process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
+340  common    process_vm_readv        sys_process_vm_readv            sys_process_vm_readv
+341  common    process_vm_writev       sys_process_vm_writev           sys_process_vm_writev
 342  common    s390_runtime_instr      sys_s390_runtime_instr          sys_s390_runtime_instr
 343  common    kcmp                    sys_kcmp                        compat_sys_kcmp
 344  common    finit_module            sys_finit_module                compat_sys_finit_module
index f30d6ae..3478096 100644 (file)
 512    x32     rt_sigaction            compat_sys_rt_sigaction
 513    x32     rt_sigreturn            compat_sys_x32_rt_sigreturn
 514    x32     ioctl                   compat_sys_ioctl
-515    x32     readv                   compat_sys_readv
-516    x32     writev                  compat_sys_writev
+515    x32     readv                   sys_readv
+516    x32     writev                  sys_writev
 517    x32     recvfrom                compat_sys_recvfrom
 518    x32     sendmsg                 compat_sys_sendmsg
 519    x32     recvmsg                 compat_sys_recvmsg
 529    x32     waitid                  compat_sys_waitid
 530    x32     set_robust_list         compat_sys_set_robust_list
 531    x32     get_robust_list         compat_sys_get_robust_list
-532    x32     vmsplice                compat_sys_vmsplice
+532    x32     vmsplice                sys_vmsplice
 533    x32     move_pages              compat_sys_move_pages
 534    x32     preadv                  compat_sys_preadv64
 535    x32     pwritev                 compat_sys_pwritev64
 536    x32     rt_tgsigqueueinfo       compat_sys_rt_tgsigqueueinfo
 537    x32     recvmmsg                compat_sys_recvmmsg_time64
 538    x32     sendmmsg                compat_sys_sendmmsg
-539    x32     process_vm_readv        compat_sys_process_vm_readv
-540    x32     process_vm_writev       compat_sys_process_vm_writev
+539    x32     process_vm_readv        sys_process_vm_readv
+540    x32     process_vm_writev       sys_process_vm_writev
 541    x32     setsockopt              sys_setsockopt
 542    x32     getsockopt              sys_getsockopt
 543    x32     io_setup                compat_sys_io_setup
index dd68a40..878db6a 100644 (file)
@@ -13,7 +13,6 @@ perf-y += synthesize.o
 perf-y += kallsyms-parse.o
 perf-y += find-bit-bench.o
 
-perf-$(CONFIG_X86_64) += mem-memcpy-x86-64-lib.o
 perf-$(CONFIG_X86_64) += mem-memcpy-x86-64-asm.o
 perf-$(CONFIG_X86_64) += mem-memset-x86-64-asm.o
 
diff --git a/tools/perf/bench/mem-memcpy-x86-64-lib.c b/tools/perf/bench/mem-memcpy-x86-64-lib.c
deleted file mode 100644 (file)
index 4130734..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * From code in arch/x86/lib/usercopy_64.c, copied to keep tools/ copy
- * of the kernel's arch/x86/lib/memcpy_64.s used in 'perf bench mem memcpy'
- * happy.
- */
-#include <linux/types.h>
-
-unsigned long __memcpy_mcsafe(void *dst, const void *src, size_t cnt);
-unsigned long mcsafe_handle_tail(char *to, char *from, unsigned len);
-
-unsigned long mcsafe_handle_tail(char *to, char *from, unsigned len)
-{
-       for (; len; --len, to++, from++) {
-               /*
-                * Call the assembly routine back directly since
-                * memcpy_mcsafe() may silently fallback to memcpy.
-                */
-               unsigned long rem = __memcpy_mcsafe(to, from, 1);
-
-               if (rem)
-                       break;
-       }
-       return len;
-}
index 71d830d..cecce93 100644 (file)
@@ -66,11 +66,10 @@ static void fdpair(int fds[2])
 /* Block until we're ready to go */
 static void ready(int ready_out, int wakefd)
 {
-       char dummy;
        struct pollfd pollfd = { .fd = wakefd, .events = POLLIN };
 
        /* Tell them we're ready. */
-       if (write(ready_out, &dummy, 1) != 1)
+       if (write(ready_out, "R", 1) != 1)
                err(EXIT_FAILURE, "CLIENT: ready write");
 
        /* Wait for "GO" signal */
@@ -85,6 +84,7 @@ static void *sender(struct sender_context *ctx)
        unsigned int i, j;
 
        ready(ctx->ready_out, ctx->wakefd);
+       memset(data, 'S', sizeof(data));
 
        /* Now pump to every receiver. */
        for (i = 0; i < nr_loops; i++) {
index 8d624ae..b2924e3 100644 (file)
@@ -162,8 +162,8 @@ static int do_run_multi_threaded(struct target *target,
        init_stats(&event_stats);
        for (i = 0; i < multi_iterations; i++) {
                session = perf_session__new(NULL, false, NULL);
-               if (!session)
-                       return -ENOMEM;
+               if (IS_ERR(session))
+                       return PTR_ERR(session);
 
                atomic_set(&event_count, 0);
                gettimeofday(&start, NULL);
index f91352f..772f105 100644 (file)
@@ -2452,7 +2452,7 @@ static struct option __record_options[] = {
        OPT_BOOLEAN(0, "tail-synthesize", &record.opts.tail_synthesize,
                    "synthesize non-sample events at the end of output"),
        OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"),
-       OPT_BOOLEAN(0, "no-bpf-event", &record.opts.no_bpf_event, "record bpf events"),
+       OPT_BOOLEAN(0, "no-bpf-event", &record.opts.no_bpf_event, "do not record bpf events"),
        OPT_BOOLEAN(0, "strict-freq", &record.opts.strict_freq,
                    "Fail if the specified frequency can't be used"),
        OPT_CALLBACK('F', "freq", &record.opts, "freq or 'max'",
index ece1cdd..3c74c9c 100644 (file)
@@ -1332,6 +1332,9 @@ int cmd_report(int argc, const char **argv)
        if (report.mmaps_mode)
                report.tasks_mode = true;
 
+       if (dump_trace)
+               report.tool.ordered_events = false;
+
        if (quiet)
                perf_quiet_option();
 
index 0c7d599..e6fc297 100644 (file)
@@ -2584,7 +2584,8 @@ static int timehist_sched_change_event(struct perf_tool *tool,
        }
 
        if (!sched->idle_hist || thread->tid == 0) {
-               timehist_update_runtime_stats(tr, t, tprev);
+               if (!cpu_list || test_bit(sample->cpu, cpu_bitmap))
+                       timehist_update_runtime_stats(tr, t, tprev);
 
                if (sched->idle_hist) {
                        struct idle_thread_runtime *itr = (void *)tr;
@@ -2857,6 +2858,9 @@ static void timehist_print_summary(struct perf_sched *sched,
 
        printf("\nIdle stats:\n");
        for (i = 0; i < idle_max_cpu; ++i) {
+               if (cpu_list && !test_bit(i, cpu_bitmap))
+                       continue;
+
                t = idle_threads[i];
                if (!t)
                        continue;
index 483a28e..fddc97c 100644 (file)
@@ -404,7 +404,7 @@ static void read_counters(struct timespec *rs)
 {
        struct evsel *counter;
 
-       if (!stat_config.summary && (read_affinity_counters(rs) < 0))
+       if (!stat_config.stop_read_counter && (read_affinity_counters(rs) < 0))
                return;
 
        evlist__for_each_entry(evsel_list, counter) {
@@ -897,9 +897,9 @@ try_again_reset:
        if (stat_config.walltime_run_table)
                stat_config.walltime_run[run_idx] = t1 - t0;
 
-       if (interval) {
+       if (interval && stat_config.summary) {
                stat_config.interval = 0;
-               stat_config.summary = true;
+               stat_config.stop_read_counter = true;
                init_stats(&walltime_nsecs_stats);
                update_stats(&walltime_nsecs_stats, t1 - t0);
 
@@ -1164,6 +1164,8 @@ static struct option stat_options[] = {
                    "Use with 'percore' event qualifier to show the event "
                    "counts of one hardware thread by sum up total hardware "
                    "threads of same physical core"),
+       OPT_BOOLEAN(0, "summary", &stat_config.summary,
+                      "print summary for interval mode"),
 #ifdef HAVE_LIBPFM
        OPT_CALLBACK(0, "pfm-events", &evsel_list, "event",
                "libpfm4 event selector. use 'perf list' to list available events",
index 994c230..7c64134 100644 (file)
@@ -1746,6 +1746,7 @@ int cmd_top(int argc, const char **argv)
                goto out_delete_evlist;
        }
 
+#ifdef HAVE_LIBBPF_SUPPORT
        if (!top.record_opts.no_bpf_event) {
                top.sb_evlist = evlist__new();
 
@@ -1759,6 +1760,7 @@ int cmd_top(int argc, const char **argv)
                        goto out_delete_evlist;
                }
        }
+#endif
 
        if (perf_evlist__start_sb_thread(top.sb_evlist, target)) {
                pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
index 7e1aa82..653b11b 100644 (file)
@@ -61,7 +61,7 @@
   {
     "EventName": "ex_ret_brn_ind_misp",
     "EventCode": "0xca",
-    "BriefDescription": "Retired Indirect Branch Instructions Mispredicted.",
+    "BriefDescription": "Retired Indirect Branch Instructions Mispredicted."
   },
   {
     "EventName": "ex_ret_mmx_fp_instr.sse_instr",
index de89e5a..4b75183 100644 (file)
   {
     "EventName": "ex_ret_fus_brnch_inst",
     "EventCode": "0x1d0",
-    "BriefDescription": "Retired Fused Instructions. The number of fuse-branch instructions retired per cycle. The number of events logged per cycle can vary from 0-8.",
+    "BriefDescription": "Retired Fused Instructions. The number of fuse-branch instructions retired per cycle. The number of events logged per cycle can vary from 0-8."
   }
 ]
index fa86c5f..fc9c158 100644 (file)
@@ -137,7 +137,7 @@ static char *fixregex(char *s)
                return s;
 
        /* allocate space for a new string */
-       fixed = (char *) malloc(len + 1);
+       fixed = (char *) malloc(len + esc_count + 1);
        if (!fixed)
                return NULL;
 
index 6cd4081..a36f49f 100644 (file)
@@ -49,6 +49,7 @@ Following tests are defined (with perf commands):
   perf record --call-graph fp kill              (test-record-graph-fp)
   perf record --group -e cycles,instructions kill (test-record-group)
   perf record -e '{cycles,instructions}' kill   (test-record-group1)
+  perf record -e '{cycles/period=1/,instructions/period=2/}:S' kill (test-record-group2)
   perf record -D kill                           (test-record-no-delay)
   perf record -i kill                           (test-record-no-inherit)
   perf record -n kill                           (test-record-no-samples)
diff --git a/tools/perf/tests/attr/test-record-group2 b/tools/perf/tests/attr/test-record-group2
new file mode 100644 (file)
index 0000000..6b9f8d1
--- /dev/null
@@ -0,0 +1,29 @@
+[config]
+command = record
+args    = --no-bpf-event -e '{cycles/period=1234000/,instructions/period=6789000/}:S' kill >/dev/null 2>&1
+ret     = 1
+
+[event-1:base-record]
+fd=1
+group_fd=-1
+config=0|1
+sample_period=1234000
+sample_type=87
+read_format=12
+inherit=0
+freq=0
+
+[event-2:base-record]
+fd=2
+group_fd=1
+config=0|1
+sample_period=6789000
+sample_type=87
+read_format=12
+disabled=0
+inherit=0
+mmap=0
+comm=0
+freq=0
+enable_on_exec=0
+task=0
index da8ec1e..cc9fbce 100644 (file)
@@ -45,10 +45,13 @@ volatile long the_var;
 #if defined (__x86_64__)
 extern void __test_function(volatile long *ptr);
 asm (
+       ".pushsection .text;"
        ".globl __test_function\n"
+       ".type __test_function, @function;"
        "__test_function:\n"
        "incq (%rdi)\n"
-       "ret\n");
+       "ret\n"
+       ".popsection\n");
 #else
 static void __test_function(volatile long *ptr)
 {
index 5d20bf8..cd77e33 100644 (file)
@@ -197,7 +197,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
                perf_mmap__read_done(&md->core);
        }
 
-       if (count != expect) {
+       if (count != expect * evlist->core.nr_entries) {
                pr_debug("BPF filter result incorrect, expected %d, got %d samples\n", expect, count);
                goto out_delete_evlist;
        }
index 7f9f87a..aae0fd9 100644 (file)
@@ -719,7 +719,7 @@ static int test__group2(struct evlist *evlist)
        TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
        TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
        TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest);
        TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip);
        TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel));
@@ -842,7 +842,7 @@ static int test__group3(struct evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
        TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
        TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest);
        TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip);
        TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel));
index fc0838a..cd7331a 100644 (file)
@@ -70,6 +70,9 @@ static struct pmu_event pme_test[] = {
 {
        .metric_expr    = "1/m3",
        .metric_name    = "M3",
+},
+{
+       .name   = NULL,
 }
 };
 
@@ -150,8 +153,10 @@ static int __compute_metric(const char *name, struct value *vals,
                return -ENOMEM;
 
        cpus = perf_cpu_map__new("0");
-       if (!cpus)
+       if (!cpus) {
+               evlist__delete(evlist);
                return -ENOMEM;
+       }
 
        perf_evlist__set_maps(&evlist->core, cpus, NULL);
 
@@ -160,10 +165,11 @@ static int __compute_metric(const char *name, struct value *vals,
                                             false, false,
                                             &metric_events);
        if (err)
-               return err;
+               goto out;
 
-       if (perf_evlist__alloc_stats(evlist, false))
-               return -1;
+       err = perf_evlist__alloc_stats(evlist, false);
+       if (err)
+               goto out;
 
        /* Load the runtime stats with given numbers for events. */
        runtime_stat__init(&st);
@@ -175,13 +181,14 @@ static int __compute_metric(const char *name, struct value *vals,
        if (name2 && ratio2)
                *ratio2 = compute_single(&metric_events, evlist, &st, name2);
 
+out:
        /* ... clenup. */
        metricgroup__rblist_exit(&metric_events);
        runtime_stat__exit(&st);
        perf_evlist__free_stats(evlist);
        perf_cpu_map__put(cpus);
        evlist__delete(evlist);
-       return 0;
+       return err;
 }
 
 static int compute_metric(const char *name, struct value *vals, double *ratio)
index eb19f9a..d3517a7 100644 (file)
@@ -274,6 +274,7 @@ static int __test__pmu_event_aliases(char *pmu_name, int *count)
        int res = 0;
        bool use_uncore_table;
        struct pmu_events_map *map = __test_pmu_get_events_map();
+       struct perf_pmu_alias *a, *tmp;
 
        if (!map)
                return -1;
@@ -347,6 +348,10 @@ static int __test__pmu_event_aliases(char *pmu_name, int *count)
                          pmu_name, alias->name);
        }
 
+       list_for_each_entry_safe(a, tmp, &aliases, list) {
+               list_del(&a->list);
+               perf_pmu_free_alias(a);
+       }
        free(pmu);
        return res;
 }
index 5c11fe2..714e683 100644 (file)
@@ -173,6 +173,7 @@ int test__pmu(struct test *test __maybe_unused, int subtest __maybe_unused)
                ret = 0;
        } while (0);
 
+       perf_pmu__del_formats(&formats);
        test_format_dir_put(format);
        return ret;
 }
index be9c4c0..a07626f 100644 (file)
@@ -3629,8 +3629,8 @@ int perf_evlist__tui_browse_hists(struct evlist *evlist, const char *help,
 {
        int nr_entries = evlist->core.nr_entries;
 
-single_entry:
        if (perf_evlist__single_entry(evlist)) {
+single_entry: {
                struct evsel *first = evlist__first(evlist);
 
                return perf_evsel__hists_browse(first, nr_entries, help,
@@ -3638,6 +3638,7 @@ single_entry:
                                                env, warn_lost_event,
                                                annotation_opts);
        }
+       }
 
        if (symbol_conf.event_group) {
                struct evsel *pos;
index 302a14d..93e063f 100644 (file)
@@ -182,15 +182,15 @@ static int arm_spe_read_record(struct arm_spe_decoder *decoder)
                        if (payload & BIT(EV_TLB_ACCESS))
                                decoder->record.type |= ARM_SPE_TLB_ACCESS;
 
-                       if ((idx == 1 || idx == 2 || idx == 3) &&
+                       if ((idx == 2 || idx == 4 || idx == 8) &&
                            (payload & BIT(EV_LLC_MISS)))
                                decoder->record.type |= ARM_SPE_LLC_MISS;
 
-                       if ((idx == 1 || idx == 2 || idx == 3) &&
+                       if ((idx == 2 || idx == 4 || idx == 8) &&
                            (payload & BIT(EV_LLC_ACCESS)))
                                decoder->record.type |= ARM_SPE_LLC_ACCESS;
 
-                       if ((idx == 1 || idx == 2 || idx == 3) &&
+                       if ((idx == 2 || idx == 4 || idx == 8) &&
                            (payload & BIT(EV_REMOTE_ACCESS)))
                                decoder->record.type |= ARM_SPE_REMOTE_ACCESS;
 
index c283223..a2a369e 100644 (file)
@@ -1344,8 +1344,15 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
                attr.sample_type &= ~(u64)PERF_SAMPLE_ADDR;
        }
 
-       if (etm->synth_opts.last_branch)
+       if (etm->synth_opts.last_branch) {
                attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
+               /*
+                * We don't use the hardware index, but the sample generation
+                * code uses the new format branch_stack with this field,
+                * so the event attributes must indicate that it's present.
+                */
+               attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
+       }
 
        if (etm->synth_opts.instructions) {
                attr.config = PERF_COUNT_HW_INSTRUCTIONS;
index e3fa3bf..c0768c6 100644 (file)
@@ -946,6 +946,10 @@ int perf_evlist__create_maps(struct evlist *evlist, struct target *target)
 
        perf_evlist__set_maps(&evlist->core, cpus, threads);
 
+       /* as evlist now has references, put count here */
+       perf_cpu_map__put(cpus);
+       perf_thread_map__put(threads);
+
        return 0;
 
 out_delete_threads:
@@ -1273,11 +1277,12 @@ static int perf_evlist__create_syswide_maps(struct evlist *evlist)
                goto out_put;
 
        perf_evlist__set_maps(&evlist->core, cpus, threads);
-out:
-       return err;
+
+       perf_thread_map__put(threads);
 out_put:
        perf_cpu_map__put(cpus);
-       goto out;
+out:
+       return err;
 }
 
 int evlist__open(struct evlist *evlist)
index fd86500..459b51e 100644 (file)
@@ -976,16 +976,20 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,
         * We default some events to have a default interval. But keep
         * it a weak assumption overridable by the user.
         */
-       if (!attr->sample_period || (opts->user_freq != UINT_MAX ||
-                                    opts->user_interval != ULLONG_MAX)) {
+       if (!attr->sample_period) {
                if (opts->freq) {
-                       evsel__set_sample_bit(evsel, PERIOD);
                        attr->freq              = 1;
                        attr->sample_freq       = opts->freq;
                } else {
                        attr->sample_period = opts->default_interval;
                }
        }
+       /*
+        * If attr->freq was set (here or earlier), ask for period
+        * to be sampled.
+        */
+       if (attr->freq)
+               evsel__set_sample_bit(evsel, PERIOD);
 
        if (opts->no_samples)
                attr->sample_freq = 0;
index 2a8d245..0af4e81 100644 (file)
@@ -3017,8 +3017,15 @@ static int intel_pt_synth_events(struct intel_pt *pt,
 
        if (pt->synth_opts.callchain)
                attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
-       if (pt->synth_opts.last_branch)
+       if (pt->synth_opts.last_branch) {
                attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
+               /*
+                * We don't use the hardware index, but the sample generation
+                * code uses the new format branch_stack with this field,
+                * so the event attributes must indicate that it's present.
+                */
+               attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
+       }
 
        if (pt->synth_opts.instructions) {
                attr.config = PERF_COUNT_HW_INSTRUCTIONS;
index 208b813..85587de 100644 (file)
@@ -736,12 +736,6 @@ int machine__process_switch_event(struct machine *machine __maybe_unused,
        return 0;
 }
 
-static int is_bpf_image(const char *name)
-{
-       return strncmp(name, "bpf_trampoline_", sizeof("bpf_trampoline_") - 1) == 0 ||
-              strncmp(name, "bpf_dispatcher_", sizeof("bpf_dispatcher_") - 1) == 0;
-}
-
 static int machine__process_ksymbol_register(struct machine *machine,
                                             union perf_event *event,
                                             struct perf_sample *sample __maybe_unused)
index 1d72108..cc0faf8 100644 (file)
@@ -267,6 +267,22 @@ bool __map__is_bpf_prog(const struct map *map)
        return name && (strstr(name, "bpf_prog_") == name);
 }
 
+bool __map__is_bpf_image(const struct map *map)
+{
+       const char *name;
+
+       if (map->dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE)
+               return true;
+
+       /*
+        * If PERF_RECORD_KSYMBOL is not included, the dso will not have
+        * type of DSO_BINARY_TYPE__BPF_IMAGE. In such cases, we can
+        * guess the type based on name.
+        */
+       name = map->dso->short_name;
+       return name && is_bpf_image(name);
+}
+
 bool __map__is_ool(const struct map *map)
 {
        return map->dso && map->dso->binary_type == DSO_BINARY_TYPE__OOL;
index 9e312ae..c2f5d28 100644 (file)
@@ -147,12 +147,14 @@ int map__set_kallsyms_ref_reloc_sym(struct map *map, const char *symbol_name,
 bool __map__is_kernel(const struct map *map);
 bool __map__is_extra_kernel_map(const struct map *map);
 bool __map__is_bpf_prog(const struct map *map);
+bool __map__is_bpf_image(const struct map *map);
 bool __map__is_ool(const struct map *map);
 
 static inline bool __map__is_kmodule(const struct map *map)
 {
        return !__map__is_kernel(map) && !__map__is_extra_kernel_map(map) &&
-              !__map__is_bpf_prog(map) && !__map__is_ool(map);
+              !__map__is_bpf_prog(map) && !__map__is_ool(map) &&
+              !__map__is_bpf_image(map);
 }
 
 bool map__has_symbols(const struct map *map);
@@ -164,4 +166,9 @@ static inline bool is_entry_trampoline(const char *name)
        return !strcmp(name, ENTRY_TRAMPOLINE_NAME);
 }
 
+static inline bool is_bpf_image(const char *name)
+{
+       return strncmp(name, "bpf_trampoline_", sizeof("bpf_trampoline_") - 1) == 0 ||
+              strncmp(name, "bpf_dispatcher_", sizeof("bpf_dispatcher_") - 1) == 0;
+}
 #endif /* __PERF_MAP_H */
index 8831b96..ab5030f 100644 (file)
@@ -85,6 +85,7 @@ static void metric_event_delete(struct rblist *rblist __maybe_unused,
 
        list_for_each_entry_safe(expr, tmp, &me->head, nd) {
                free(expr->metric_refs);
+               free(expr->metric_events);
                free(expr);
        }
 
@@ -316,6 +317,7 @@ static int metricgroup__setup_events(struct list_head *groups,
                        if (!metric_refs) {
                                ret = -ENOMEM;
                                free(metric_events);
+                               free(expr);
                                break;
                        }
 
@@ -530,6 +532,9 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
                                                continue;
                                        strlist__add(me->metrics, s);
                                }
+
+                               if (!raw)
+                                       free(s);
                        }
                        free(omg);
                }
@@ -667,7 +672,6 @@ static int __add_metric(struct list_head *metric_list,
                m->has_constraint = metric_no_group || metricgroup__has_constraint(pe);
                INIT_LIST_HEAD(&m->metric_refs);
                m->metric_refs_cnt = 0;
-               *mp = m;
 
                parent = expr_ids__alloc(ids);
                if (!parent) {
@@ -680,6 +684,7 @@ static int __add_metric(struct list_head *metric_list,
                        free(m);
                        return -ENOMEM;
                }
+               *mp = m;
        } else {
                /*
                 * We got here for the referenced metric, via the
@@ -714,8 +719,11 @@ static int __add_metric(struct list_head *metric_list,
         * all the metric's IDs and add it to the parent context.
         */
        if (expr__find_other(pe->metric_expr, NULL, &m->pctx, runtime) < 0) {
-               expr__ctx_clear(&m->pctx);
-               free(m);
+               if (m->metric_refs_cnt == 0) {
+                       expr__ctx_clear(&m->pctx);
+                       free(m);
+                       *mp = NULL;
+               }
                return -EINVAL;
        }
 
@@ -934,7 +942,7 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
 
                ret = add_metric(&list, pe, metric_no_group, &m, NULL, &ids);
                if (ret)
-                       return ret;
+                       goto out;
 
                /*
                 * Process any possible referenced metrics
@@ -943,12 +951,14 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
                ret = resolve_metric(metric_no_group,
                                     &list, map, &ids);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
        /* End of pmu events. */
-       if (!has_match)
-               return -EINVAL;
+       if (!has_match) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        list_for_each_entry(m, &list, nd) {
                if (events->len > 0)
@@ -963,9 +973,14 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
                }
        }
 
+out:
+       /*
+        * add to metric_list so that they can be released
+        * even if it's failed
+        */
        list_splice(&list, metric_list);
        expr_ids__exit(&ids);
-       return 0;
+       return ret;
 }
 
 static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
@@ -1040,7 +1055,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
        ret = metricgroup__add_metric_list(str, metric_no_group,
                                           &extra_events, &metric_list, map);
        if (ret)
-               return ret;
+               goto out;
        pr_debug("adding %s\n", extra_events.buf);
        bzero(&parse_error, sizeof(parse_error));
        ret = __parse_events(perf_evlist, extra_events.buf, &parse_error, fake_pmu);
@@ -1048,11 +1063,11 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
                parse_events_print_error(&parse_error, extra_events.buf);
                goto out;
        }
-       strbuf_release(&extra_events);
        ret = metricgroup__setup_events(&metric_list, metric_no_merge,
                                        perf_evlist, metric_events);
 out:
        metricgroup__free_metrics(&metric_list);
+       strbuf_release(&extra_events);
        return ret;
 }
 
index 9f7260e..667cbca 100644 (file)
@@ -37,6 +37,7 @@
 #include "util/evsel_config.h"
 #include "util/event.h"
 #include "util/pfm.h"
+#include "perf.h"
 
 #define MAX_NAME_LEN 100
 
@@ -410,7 +411,7 @@ static int add_event_tool(struct list_head *list, int *idx,
                return -ENOMEM;
        evsel->tool_event = tool_event;
        if (tool_event == PERF_TOOL_DURATION_TIME)
-               evsel->unit = strdup("ns");
+               evsel->unit = "ns";
        return 0;
 }
 
@@ -1533,19 +1534,23 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
        evsel = __add_event(list, &parse_state->idx, &attr, true,
                            get_config_name(head_config), pmu,
                            &config_terms, auto_merge_stats, NULL);
-       if (evsel) {
-               evsel->unit = info.unit;
-               evsel->scale = info.scale;
-               evsel->per_pkg = info.per_pkg;
-               evsel->snapshot = info.snapshot;
-               evsel->metric_expr = info.metric_expr;
-               evsel->metric_name = info.metric_name;
-               evsel->pmu_name = name ? strdup(name) : NULL;
-               evsel->use_uncore_alias = use_uncore_alias;
-               evsel->percore = config_term_percore(&evsel->config_terms);
-       }
+       if (!evsel)
+               return -ENOMEM;
+
+       evsel->pmu_name = name ? strdup(name) : NULL;
+       evsel->use_uncore_alias = use_uncore_alias;
+       evsel->percore = config_term_percore(&evsel->config_terms);
 
-       return evsel ? 0 : -ENOMEM;
+       if (parse_state->fake_pmu)
+               return 0;
+
+       evsel->unit = info.unit;
+       evsel->scale = info.scale;
+       evsel->per_pkg = info.per_pkg;
+       evsel->snapshot = info.snapshot;
+       evsel->metric_expr = info.metric_expr;
+       evsel->metric_name = info.metric_name;
+       return 0;
 }
 
 int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
@@ -1794,6 +1799,8 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
                if (*str == 'u') {
                        if (!exclude)
                                exclude = eu = ek = eh = 1;
+                       if (!exclude_GH && !perf_guest)
+                               eG = 1;
                        eu = 0;
                } else if (*str == 'k') {
                        if (!exclude)
index b9fb91f..645bf4f 100644 (file)
@@ -511,7 +511,7 @@ PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc
        list = alloc_list();
        ABORT_ON(!list);
        err = parse_events_add_breakpoint(list, &parse_state->idx,
-                                       (void *) $2, $6, $4);
+                                       (void *)(uintptr_t) $2, $6, $4);
        free($6);
        if (err) {
                free(list);
@@ -528,7 +528,7 @@ PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc
        list = alloc_list();
        ABORT_ON(!list);
        if (parse_events_add_breakpoint(list, &parse_state->idx,
-                                               (void *) $2, NULL, $4)) {
+                                               (void *)(uintptr_t) $2, NULL, $4)) {
                free(list);
                YYABORT;
        }
@@ -544,7 +544,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
        list = alloc_list();
        ABORT_ON(!list);
        err = parse_events_add_breakpoint(list, &parse_state->idx,
-                                       (void *) $2, $4, 0);
+                                       (void *)(uintptr_t) $2, $4, 0);
        free($4);
        if (err) {
                free(list);
@@ -561,7 +561,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
        list = alloc_list();
        ABORT_ON(!list);
        if (parse_events_add_breakpoint(list, &parse_state->idx,
-                                               (void *) $2, NULL, 0)) {
+                                               (void *)(uintptr_t) $2, NULL, 0)) {
                free(list);
                YYABORT;
        }
index f1688e1..d41caeb 100644 (file)
@@ -274,7 +274,7 @@ static void perf_pmu_update_alias(struct perf_pmu_alias *old,
 }
 
 /* Delete an alias entry. */
-static void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
+void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
 {
        zfree(&newalias->name);
        zfree(&newalias->desc);
@@ -1354,6 +1354,17 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
                set_bit(b, bits);
 }
 
+void perf_pmu__del_formats(struct list_head *formats)
+{
+       struct perf_pmu_format *fmt, *tmp;
+
+       list_for_each_entry_safe(fmt, tmp, formats, list) {
+               list_del(&fmt->list);
+               free(fmt->name);
+               free(fmt);
+       }
+}
+
 static int sub_non_neg(int a, int b)
 {
        if (b > a)
index 44ccbdb..a64e9c9 100644 (file)
@@ -94,6 +94,7 @@ int perf_pmu__new_format(struct list_head *list, char *name,
                         int config, unsigned long *bits);
 void perf_pmu__set_format(unsigned long *bits, long from, long to);
 int perf_pmu__format_parse(char *dir, struct list_head *head);
+void perf_pmu__del_formats(struct list_head *formats);
 
 struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
 
@@ -113,6 +114,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
 
 struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
+void perf_pmu_free_alias(struct perf_pmu_alias *alias);
 
 int perf_pmu__convert_scale(const char *scale, char **end, double *sval);
 
index a4cc115..ea9aa1d 100644 (file)
@@ -2,6 +2,7 @@
 #include "debug.h"
 #include "evlist.h"
 #include "evsel.h"
+#include "evsel_config.h"
 #include "parse-events.h"
 #include <errno.h>
 #include <limits.h>
@@ -33,11 +34,24 @@ static struct evsel *evsel__read_sampler(struct evsel *evsel, struct evlist *evl
        return leader;
 }
 
+static u64 evsel__config_term_mask(struct evsel *evsel)
+{
+       struct evsel_config_term *term;
+       struct list_head *config_terms = &evsel->config_terms;
+       u64 term_types = 0;
+
+       list_for_each_entry(term, config_terms, list) {
+               term_types |= 1 << term->type;
+       }
+       return term_types;
+}
+
 static void evsel__config_leader_sampling(struct evsel *evsel, struct evlist *evlist)
 {
        struct perf_event_attr *attr = &evsel->core.attr;
        struct evsel *leader = evsel->leader;
        struct evsel *read_sampler;
+       u64 term_types, freq_mask;
 
        if (!leader->sample_read)
                return;
@@ -47,16 +61,20 @@ static void evsel__config_leader_sampling(struct evsel *evsel, struct evlist *ev
        if (evsel == read_sampler)
                return;
 
+       term_types = evsel__config_term_mask(evsel);
        /*
-        * Disable sampling for all group members other than the leader in
-        * case the leader 'leads' the sampling, except when the leader is an
-        * AUX area event, in which case the 2nd event in the group is the one
-        * that 'leads' the sampling.
+        * Disable sampling for all group members except those with explicit
+        * config terms or the leader. In the case of an AUX area event, the 2nd
+        * event in the group is the one that 'leads' the sampling.
         */
-       attr->freq           = 0;
-       attr->sample_freq    = 0;
-       attr->sample_period  = 0;
-       attr->write_backward = 0;
+       freq_mask = (1 << EVSEL__CONFIG_TERM_FREQ) | (1 << EVSEL__CONFIG_TERM_PERIOD);
+       if ((term_types & freq_mask) == 0) {
+               attr->freq           = 0;
+               attr->sample_freq    = 0;
+               attr->sample_period  = 0;
+       }
+       if ((term_types & (1 << EVSEL__CONFIG_TERM_OVERWRITE)) == 0)
+               attr->write_backward = 0;
 
        /*
         * We don't get a sample for slave events, we make them when delivering
index ffbc9d3..7a5f037 100644 (file)
@@ -87,7 +87,7 @@ static int perf_session__process_compressed_event(struct perf_session *session,
                session->decomp_last = decomp;
        }
 
-       pr_debug("decomp (B): %ld to %ld\n", src_size, decomp_size);
+       pr_debug("decomp (B): %zd to %zd\n", src_size, decomp_size);
 
        return 0;
 }
index 57d0706..493ec37 100644 (file)
@@ -117,7 +117,7 @@ static void aggr_printout(struct perf_stat_config *config,
                                cpu_map__id_to_die(id),
                                config->csv_output ? 0 : -3,
                                cpu_map__id_to_cpu(id), config->csv_sep);
-               } else {
+               } else if (id > -1) {
                        fprintf(config->output, "CPU%*d%s",
                                config->csv_output ? 0 : -7,
                                evsel__cpus(evsel)->map[id],
index e1ba6c1..924b54d 100644 (file)
@@ -517,7 +517,7 @@ static void print_l1_dcache_misses(struct perf_stat_config *config,
 
        color = get_ratio_color(GRC_CACHE_MISSES, ratio);
 
-       out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-dcache hits", ratio);
+       out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-dcache accesses", ratio);
 }
 
 static void print_l1_icache_misses(struct perf_stat_config *config,
@@ -538,7 +538,7 @@ static void print_l1_icache_misses(struct perf_stat_config *config,
                ratio = avg / total * 100.0;
 
        color = get_ratio_color(GRC_CACHE_MISSES, ratio);
-       out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-icache hits", ratio);
+       out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-icache accesses", ratio);
 }
 
 static void print_dtlb_cache_misses(struct perf_stat_config *config,
@@ -558,7 +558,7 @@ static void print_dtlb_cache_misses(struct perf_stat_config *config,
                ratio = avg / total * 100.0;
 
        color = get_ratio_color(GRC_CACHE_MISSES, ratio);
-       out->print_metric(config, out->ctx, color, "%7.2f%%", "of all dTLB cache hits", ratio);
+       out->print_metric(config, out->ctx, color, "%7.2f%%", "of all dTLB cache accesses", ratio);
 }
 
 static void print_itlb_cache_misses(struct perf_stat_config *config,
@@ -578,7 +578,7 @@ static void print_itlb_cache_misses(struct perf_stat_config *config,
                ratio = avg / total * 100.0;
 
        color = get_ratio_color(GRC_CACHE_MISSES, ratio);
-       out->print_metric(config, out->ctx, color, "%7.2f%%", "of all iTLB cache hits", ratio);
+       out->print_metric(config, out->ctx, color, "%7.2f%%", "of all iTLB cache accesses", ratio);
 }
 
 static void print_ll_cache_misses(struct perf_stat_config *config,
@@ -598,7 +598,7 @@ static void print_ll_cache_misses(struct perf_stat_config *config,
                ratio = avg / total * 100.0;
 
        color = get_ratio_color(GRC_CACHE_MISSES, ratio);
-       out->print_metric(config, out->ctx, color, "%7.2f%%", "of all LL-cache hits", ratio);
+       out->print_metric(config, out->ctx, color, "%7.2f%%", "of all LL-cache accesses", ratio);
 }
 
 /*
@@ -853,14 +853,16 @@ static void generic_metric(struct perf_stat_config *config,
 double test_generic_metric(struct metric_expr *mexp, int cpu, struct runtime_stat *st)
 {
        struct expr_parse_ctx pctx;
-       double ratio;
+       double ratio = 0.0;
 
        if (prepare_metric(mexp->metric_events, mexp->metric_refs, &pctx, cpu, st) < 0)
-               return 0.;
+               goto out;
 
        if (expr__parse(&ratio, &pctx, mexp->metric_expr, 1))
-               return 0.;
+               ratio = 0.0;
 
+out:
+       expr__ctx_clear(&pctx);
        return ratio;
 }
 
@@ -918,7 +920,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                if (runtime_stat_n(st, STAT_L1_DCACHE, ctx, cpu) != 0)
                        print_l1_dcache_misses(config, cpu, evsel, avg, out, st);
                else
-                       print_metric(config, ctxp, NULL, NULL, "of all L1-dcache hits", 0);
+                       print_metric(config, ctxp, NULL, NULL, "of all L1-dcache accesses", 0);
        } else if (
                evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
                evsel->core.attr.config ==  ( PERF_COUNT_HW_CACHE_L1I |
@@ -928,7 +930,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                if (runtime_stat_n(st, STAT_L1_ICACHE, ctx, cpu) != 0)
                        print_l1_icache_misses(config, cpu, evsel, avg, out, st);
                else
-                       print_metric(config, ctxp, NULL, NULL, "of all L1-icache hits", 0);
+                       print_metric(config, ctxp, NULL, NULL, "of all L1-icache accesses", 0);
        } else if (
                evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
                evsel->core.attr.config ==  ( PERF_COUNT_HW_CACHE_DTLB |
@@ -938,7 +940,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                if (runtime_stat_n(st, STAT_DTLB_CACHE, ctx, cpu) != 0)
                        print_dtlb_cache_misses(config, cpu, evsel, avg, out, st);
                else
-                       print_metric(config, ctxp, NULL, NULL, "of all dTLB cache hits", 0);
+                       print_metric(config, ctxp, NULL, NULL, "of all dTLB cache accesses", 0);
        } else if (
                evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
                evsel->core.attr.config ==  ( PERF_COUNT_HW_CACHE_ITLB |
@@ -948,7 +950,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                if (runtime_stat_n(st, STAT_ITLB_CACHE, ctx, cpu) != 0)
                        print_itlb_cache_misses(config, cpu, evsel, avg, out, st);
                else
-                       print_metric(config, ctxp, NULL, NULL, "of all iTLB cache hits", 0);
+                       print_metric(config, ctxp, NULL, NULL, "of all iTLB cache accesses", 0);
        } else if (
                evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
                evsel->core.attr.config ==  ( PERF_COUNT_HW_CACHE_LL |
@@ -958,7 +960,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                if (runtime_stat_n(st, STAT_LL_CACHE, ctx, cpu) != 0)
                        print_ll_cache_misses(config, cpu, evsel, avg, out, st);
                else
-                       print_metric(config, ctxp, NULL, NULL, "of all LL-cache hits", 0);
+                       print_metric(config, ctxp, NULL, NULL, "of all LL-cache accesses", 0);
        } else if (evsel__match(evsel, HARDWARE, HW_CACHE_MISSES)) {
                total = runtime_stat_avg(st, STAT_CACHEREFS, ctx, cpu);
 
index f8778cf..aa3bed4 100644 (file)
@@ -113,6 +113,7 @@ struct perf_stat_config {
        bool                     summary;
        bool                     metric_no_group;
        bool                     metric_no_merge;
+       bool                     stop_read_counter;
        FILE                    *output;
        unsigned int             interval;
        unsigned int             timeout;
index 1f5fcb8..5151a8c 100644 (file)
@@ -663,6 +663,7 @@ static bool symbol__is_idle(const char *name)
                "exit_idle",
                "mwait_idle",
                "mwait_idle_with_hints",
+               "mwait_idle_with_hints.constprop.0",
                "poll_idle",
                "ppc64_runlatch_off",
                "pseries_dedicated_idle_sleep",
index d220239..48dd2b0 100644 (file)
@@ -99,7 +99,7 @@ size_t zstd_decompress_stream(struct zstd_data *data, void *src, size_t src_size
        while (input.pos < input.size) {
                ret = ZSTD_decompressStream(data->dstream, &output, &input);
                if (ZSTD_isError(ret)) {
-                       pr_err("failed to decompress (B): %ld -> %ld, dst_size %ld : %s\n",
+                       pr_err("failed to decompress (B): %zd -> %zd, dst_size %zd : %s\n",
                               src_size, output.size, dst_size, ZSTD_getErrorName(ret));
                        break;
                }
index 46ff97e..1bc36a1 100755 (executable)
@@ -171,7 +171,7 @@ class SystemValues:
        tracefuncs = {
                'sys_sync': {},
                'ksys_sync': {},
-               '__pm_notifier_call_chain': {},
+               'pm_notifier_call_chain_robust': {},
                'pm_prepare_console': {},
                'pm_notifier_call_chain': {},
                'freeze_processes': {},
index a1a5dc6..2ac0fff 100644 (file)
@@ -23,7 +23,8 @@
 #include "nfit_test.h"
 #include "../watermark.h"
 
-#include <asm/mcsafe_test.h>
+#include <asm/copy_mc_test.h>
+#include <asm/mce.h>
 
 /*
  * Generate an NFIT table to describe the following topology:
@@ -3283,7 +3284,7 @@ static struct platform_driver nfit_test_driver = {
        .id_table = nfit_test_id,
 };
 
-static char mcsafe_buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+static char copy_mc_buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
 enum INJECT {
        INJECT_NONE,
@@ -3291,7 +3292,7 @@ enum INJECT {
        INJECT_DST,
 };
 
-static void mcsafe_test_init(char *dst, char *src, size_t size)
+static void copy_mc_test_init(char *dst, char *src, size_t size)
 {
        size_t i;
 
@@ -3300,7 +3301,7 @@ static void mcsafe_test_init(char *dst, char *src, size_t size)
                src[i] = (char) i;
 }
 
-static bool mcsafe_test_validate(unsigned char *dst, unsigned char *src,
+static bool copy_mc_test_validate(unsigned char *dst, unsigned char *src,
                size_t size, unsigned long rem)
 {
        size_t i;
@@ -3321,12 +3322,12 @@ static bool mcsafe_test_validate(unsigned char *dst, unsigned char *src,
        return true;
 }
 
-void mcsafe_test(void)
+void copy_mc_test(void)
 {
        char *inject_desc[] = { "none", "source", "destination" };
        enum INJECT inj;
 
-       if (IS_ENABLED(CONFIG_MCSAFE_TEST)) {
+       if (IS_ENABLED(CONFIG_COPY_MC_TEST)) {
                pr_info("%s: run...\n", __func__);
        } else {
                pr_info("%s: disabled, skip.\n", __func__);
@@ -3344,31 +3345,31 @@ void mcsafe_test(void)
 
                        switch (inj) {
                        case INJECT_NONE:
-                               mcsafe_inject_src(NULL);
-                               mcsafe_inject_dst(NULL);
-                               dst = &mcsafe_buf[2048];
-                               src = &mcsafe_buf[1024 - i];
+                               copy_mc_inject_src(NULL);
+                               copy_mc_inject_dst(NULL);
+                               dst = &copy_mc_buf[2048];
+                               src = &copy_mc_buf[1024 - i];
                                expect = 0;
                                break;
                        case INJECT_SRC:
-                               mcsafe_inject_src(&mcsafe_buf[1024]);
-                               mcsafe_inject_dst(NULL);
-                               dst = &mcsafe_buf[2048];
-                               src = &mcsafe_buf[1024 - i];
+                               copy_mc_inject_src(&copy_mc_buf[1024]);
+                               copy_mc_inject_dst(NULL);
+                               dst = &copy_mc_buf[2048];
+                               src = &copy_mc_buf[1024 - i];
                                expect = 512 - i;
                                break;
                        case INJECT_DST:
-                               mcsafe_inject_src(NULL);
-                               mcsafe_inject_dst(&mcsafe_buf[2048]);
-                               dst = &mcsafe_buf[2048 - i];
-                               src = &mcsafe_buf[1024];
+                               copy_mc_inject_src(NULL);
+                               copy_mc_inject_dst(&copy_mc_buf[2048]);
+                               dst = &copy_mc_buf[2048 - i];
+                               src = &copy_mc_buf[1024];
                                expect = 512 - i;
                                break;
                        }
 
-                       mcsafe_test_init(dst, src, 512);
-                       rem = __memcpy_mcsafe(dst, src, 512);
-                       valid = mcsafe_test_validate(dst, src, 512, expect);
+                       copy_mc_test_init(dst, src, 512);
+                       rem = copy_mc_fragile(dst, src, 512);
+                       valid = copy_mc_test_validate(dst, src, 512, expect);
                        if (rem == expect && valid)
                                continue;
                        pr_info("%s: copy(%#lx, %#lx, %d) off: %d rem: %ld %s expect: %ld\n",
@@ -3380,8 +3381,8 @@ void mcsafe_test(void)
                }
        }
 
-       mcsafe_inject_src(NULL);
-       mcsafe_inject_dst(NULL);
+       copy_mc_inject_src(NULL);
+       copy_mc_inject_dst(NULL);
 }
 
 static __init int nfit_test_init(void)
@@ -3392,7 +3393,7 @@ static __init int nfit_test_init(void)
        libnvdimm_test();
        acpi_nfit_test();
        device_dax_test();
-       mcsafe_test();
+       copy_mc_test();
        dax_pmem_test();
        dax_pmem_core_test();
 #ifdef CONFIG_DEV_DAX_PMEM_COMPAT
index 93b567d..2c9d012 100644 (file)
@@ -4,7 +4,7 @@
 ARCH ?= $(shell uname -m 2>/dev/null || echo not)
 
 ifneq (,$(filter $(ARCH),aarch64 arm64))
-ARM64_SUBTARGETS ?= tags signal
+ARM64_SUBTARGETS ?= tags signal pauth fp mte
 else
 ARM64_SUBTARGETS :=
 endif
diff --git a/tools/testing/selftests/arm64/fp/.gitignore b/tools/testing/selftests/arm64/fp/.gitignore
new file mode 100644 (file)
index 0000000..d66f76d
--- /dev/null
@@ -0,0 +1,5 @@
+fpsimd-test
+sve-probe-vls
+sve-ptrace
+sve-test
+vlset
diff --git a/tools/testing/selftests/arm64/fp/Makefile b/tools/testing/selftests/arm64/fp/Makefile
new file mode 100644 (file)
index 0000000..a57009d
--- /dev/null
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+
+CFLAGS += -I../../../../../usr/include/
+TEST_GEN_PROGS := sve-ptrace sve-probe-vls
+TEST_PROGS_EXTENDED := fpsimd-test fpsimd-stress sve-test sve-stress vlset
+
+all: $(TEST_GEN_PROGS) $(TEST_PROGS_EXTENDED)
+
+fpsimd-test: fpsimd-test.o
+       $(CC) -nostdlib $^ -o $@
+sve-ptrace: sve-ptrace.o sve-ptrace-asm.o
+sve-probe-vls: sve-probe-vls.o
+sve-test: sve-test.o
+       $(CC) -nostdlib $^ -o $@
+vlset: vlset.o
+
+include ../../lib.mk
diff --git a/tools/testing/selftests/arm64/fp/README b/tools/testing/selftests/arm64/fp/README
new file mode 100644 (file)
index 0000000..03e3dad
--- /dev/null
@@ -0,0 +1,100 @@
+This directory contains a mix of tests integrated with kselftest and
+standalone stress tests.
+
+kselftest tests
+===============
+
+sve-probe-vls - Checks the SVE vector length enumeration interface
+sve-ptrace - Checks the SVE ptrace interface
+
+Running the non-kselftest tests
+===============================
+
+sve-stress performs an SVE context switch stress test, as described
+below.
+
+(The fpsimd-stress test works the same way; just substitute "fpsimd" for
+"sve" in the following commands.)
+
+
+The test runs until killed by the user.
+
+If no context switch error was detected, you will see output such as
+the following:
+
+$ ./sve-stress
+(wait for some time)
+^C
+Vector length:        512 bits
+PID:    1573
+Terminated by signal 15, no error, iterations=9467, signals=1014
+Vector length:  512 bits
+PID:    1575
+Terminated by signal 15, no error, iterations=9448, signals=1028
+Vector length:  512 bits
+PID:    1577
+Terminated by signal 15, no error, iterations=9436, signals=1039
+Vector length:  512 bits
+PID:    1579
+Terminated by signal 15, no error, iterations=9421, signals=1039
+Vector length:  512 bits
+PID:    1581
+Terminated by signal 15, no error, iterations=9403, signals=1039
+Vector length:  512 bits
+PID:    1583
+Terminated by signal 15, no error, iterations=9385, signals=1036
+Vector length:  512 bits
+PID:    1585
+Terminated by signal 15, no error, iterations=9376, signals=1039
+Vector length:  512 bits
+PID:    1587
+Terminated by signal 15, no error, iterations=9361, signals=1039
+Vector length:  512 bits
+PID:    1589
+Terminated by signal 15, no error, iterations=9350, signals=1039
+
+
+If an error was detected, details of the mismatch will be printed
+instead of "no error".
+
+Ideally, the test should be allowed to run for many minutes or hours
+to maximise test coverage.
+
+
+KVM stress testing
+==================
+
+To try to reproduce the bugs that we have been observing, sve-stress
+should be run in parallel in two KVM guests, while simultaneously
+running on the host.
+
+1) Start 2 guests, using the following command for each:
+
+$ lkvm run --console=virtio -pconsole=hvc0 --sve Image
+
+(Depending on the hardware GIC implementation, you may also need
+--irqchip=gicv3.  New kvmtool defaults to that if appropriate, but I
+can't remember whether my branch is new enough for that.  Try without
+the option first.)
+
+Kvmtool occupies the terminal until you kill it (Ctrl+A x),
+or until the guest terminates.  It is therefore recommended to run
+each instance in separate terminal (use screen or ssh etc.)  This
+allows multiple guests to be run in parallel while running other
+commands on the host.
+
+Within the guest, the host filesystem is accessible, mounted on /host.
+
+2) Run the sve-stress on *each* guest with the Vector-Length set to 32:
+guest$ ./vlset --inherit 32 ./sve-stress
+
+3) Run the sve-stress on the host with the maximum Vector-Length:
+host$ ./vlset --inherit --max ./sve-stress
+
+
+Again, the test should be allowed to run for many minutes or hours to
+maximise test coverage.
+
+If no error is detected, you will see output from each sve-stress
+instance similar to that illustrated above; otherwise details of the
+observed mismatches will be printed.
diff --git a/tools/testing/selftests/arm64/fp/asm-offsets.h b/tools/testing/selftests/arm64/fp/asm-offsets.h
new file mode 100644 (file)
index 0000000..a180851
--- /dev/null
@@ -0,0 +1,11 @@
+#define sa_sz 32
+#define sa_flags 8
+#define sa_handler 0
+#define sa_mask_sz 8
+#define SIGUSR1 10
+#define SIGTERM 15
+#define SIGINT 2
+#define SIGABRT 6
+#define SA_NODEFER 1073741824
+#define SA_SIGINFO 4
+#define ucontext_regs 184
diff --git a/tools/testing/selftests/arm64/fp/assembler.h b/tools/testing/selftests/arm64/fp/assembler.h
new file mode 100644 (file)
index 0000000..8944f21
--- /dev/null
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2015-2019 ARM Limited.
+// Original author: Dave Martin <Dave.Martin@arm.com>
+
+#ifndef ASSEMBLER_H
+#define ASSEMBLER_H
+
+.macro __for from:req, to:req
+       .if (\from) == (\to)
+               _for__body %\from
+       .else
+               __for \from, %(\from) + ((\to) - (\from)) / 2
+               __for %(\from) + ((\to) - (\from)) / 2 + 1, \to
+       .endif
+.endm
+
+.macro _for var:req, from:req, to:req, insn:vararg
+       .macro _for__body \var:req
+               .noaltmacro
+               \insn
+               .altmacro
+       .endm
+
+       .altmacro
+       __for \from, \to
+       .noaltmacro
+
+       .purgem _for__body
+.endm
+
+.macro function name
+       .macro endfunction
+               .type \name, @function
+               .purgem endfunction
+       .endm
+\name:
+.endm
+
+.macro define_accessor name, num, insn
+       .macro \name\()_entry n
+               \insn \n, 1
+               ret
+       .endm
+
+function \name
+       adr     x2, .L__accessor_tbl\@
+       add     x2, x2, x0, lsl #3
+       br      x2
+
+.L__accessor_tbl\@:
+       _for x, 0, (\num) - 1, \name\()_entry \x
+endfunction
+
+       .purgem \name\()_entry
+.endm
+
+#endif /* ! ASSEMBLER_H */
diff --git a/tools/testing/selftests/arm64/fp/fpsimd-stress b/tools/testing/selftests/arm64/fp/fpsimd-stress
new file mode 100755 (executable)
index 0000000..781b5b0
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2015-2019 ARM Limited.
+# Original author: Dave Martin <Dave.Martin@arm.com>
+
+set -ue
+
+NR_CPUS=`nproc`
+
+pids=
+logs=
+
+cleanup () {
+       trap - INT TERM CHLD
+       set +e
+
+       if [ -n "$pids" ]; then
+               kill $pids
+               wait $pids
+               pids=
+       fi
+
+       if [ -n "$logs" ]; then
+               cat $logs
+               rm $logs
+               logs=
+       fi
+}
+
+interrupt () {
+       cleanup
+       exit 0
+}
+
+child_died () {
+       cleanup
+       exit 1
+}
+
+trap interrupt INT TERM EXIT
+trap child_died CHLD
+
+for x in `seq 0 $((NR_CPUS * 4))`; do
+       log=`mktemp`
+       logs=$logs\ $log
+       ./fpsimd-test >$log &
+       pids=$pids\ $!
+done
+
+# Wait for all child processes to be created:
+sleep 10
+
+while :; do
+       kill -USR1 $pids
+done &
+pids=$pids\ $!
+
+wait
+
+exit 1
diff --git a/tools/testing/selftests/arm64/fp/fpsimd-test.S b/tools/testing/selftests/arm64/fp/fpsimd-test.S
new file mode 100644 (file)
index 0000000..1c5556b
--- /dev/null
@@ -0,0 +1,482 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2015-2019 ARM Limited.
+// Original author: Dave Martin <Dave.Martin@arm.com>
+//
+// Simple FPSIMD context switch test
+// Repeatedly writes unique test patterns into each FPSIMD register
+// and reads them back to verify integrity.
+//
+// for x in `seq 1 NR_CPUS`; do fpsimd-test & pids=$pids\ $! ; done
+// (leave it running for as long as you want...)
+// kill $pids
+
+#include <asm/unistd.h>
+#include "assembler.h"
+#include "asm-offsets.h"
+
+#define NVR    32
+#define MAXVL_B        (128 / 8)
+
+.macro _vldr Vn:req, Xt:req
+       ld1     {v\Vn\().2d}, [x\Xt]
+.endm
+
+.macro _vstr Vn:req, Xt:req
+       st1     {v\Vn\().2d}, [x\Xt]
+.endm
+
+// Generate accessor functions to read/write programmatically selected
+// FPSIMD registers.
+// x0 is the register index to access
+// x1 is the memory address to read from (getv,setp) or store to (setv,setp)
+// All clobber x0-x2
+define_accessor setv, NVR, _vldr
+define_accessor getv, NVR, _vstr
+
+// Print a single character x0 to stdout
+// Clobbers x0-x2,x8
+function putc
+       str     x0, [sp, #-16]!
+
+       mov     x0, #1                  // STDOUT_FILENO
+       mov     x1, sp
+       mov     x2, #1
+       mov     x8, #__NR_write
+       svc     #0
+
+       add     sp, sp, #16
+       ret
+endfunction
+
+// Print a NUL-terminated string starting at address x0 to stdout
+// Clobbers x0-x3,x8
+function puts
+       mov     x1, x0
+
+       mov     x2, #0
+0:     ldrb    w3, [x0], #1
+       cbz     w3, 1f
+       add     x2, x2, #1
+       b       0b
+
+1:     mov     w0, #1                  // STDOUT_FILENO
+       mov     x8, #__NR_write
+       svc     #0
+
+       ret
+endfunction
+
+// Utility macro to print a literal string
+// Clobbers x0-x4,x8
+.macro puts string
+       .pushsection .rodata.str1.1, "aMS", 1
+.L__puts_literal\@: .string "\string"
+       .popsection
+
+       ldr     x0, =.L__puts_literal\@
+       bl      puts
+.endm
+
+// Print an unsigned decimal number x0 to stdout
+// Clobbers x0-x4,x8
+function putdec
+       mov     x1, sp
+       str     x30, [sp, #-32]!        // Result can't be > 20 digits
+
+       mov     x2, #0
+       strb    w2, [x1, #-1]!          // Write the NUL terminator
+
+       mov     x2, #10
+0:     udiv    x3, x0, x2              // div-mod loop to generate the digits
+       msub    x0, x3, x2, x0
+       add     w0, w0, #'0'
+       strb    w0, [x1, #-1]!
+       mov     x0, x3
+       cbnz    x3, 0b
+
+       ldrb    w0, [x1]
+       cbnz    w0, 1f
+       mov     w0, #'0'                // Print "0" for 0, not ""
+       strb    w0, [x1, #-1]!
+
+1:     mov     x0, x1
+       bl      puts
+
+       ldr     x30, [sp], #32
+       ret
+endfunction
+
+// Print an unsigned decimal number x0 to stdout, followed by a newline
+// Clobbers x0-x5,x8
+function putdecn
+       mov     x5, x30
+
+       bl      putdec
+       mov     x0, #'\n'
+       bl      putc
+
+       ret     x5
+endfunction
+
+
+// Clobbers x0-x3,x8
+function puthexb
+       str     x30, [sp, #-0x10]!
+
+       mov     w3, w0
+       lsr     w0, w0, #4
+       bl      puthexnibble
+       mov     w0, w3
+
+       ldr     x30, [sp], #0x10
+       // fall through to puthexnibble
+endfunction
+// Clobbers x0-x2,x8
+function puthexnibble
+       and     w0, w0, #0xf
+       cmp     w0, #10
+       blo     1f
+       add     w0, w0, #'a' - ('9' + 1)
+1:     add     w0, w0, #'0'
+       b       putc
+endfunction
+
+// x0=data in, x1=size in, clobbers x0-x5,x8
+function dumphex
+       str     x30, [sp, #-0x10]!
+
+       mov     x4, x0
+       mov     x5, x1
+
+0:     subs    x5, x5, #1
+       b.lo    1f
+       ldrb    w0, [x4], #1
+       bl      puthexb
+       b       0b
+
+1:     ldr     x30, [sp], #0x10
+       ret
+endfunction
+
+// Declare some storate space to shadow the SVE register contents:
+.pushsection .text
+.data
+.align 4
+vref:
+       .space  MAXVL_B * NVR
+scratch:
+       .space  MAXVL_B
+.popsection
+
+// Trivial memory copy: copy x2 bytes, starting at address x1, to address x0.
+// Clobbers x0-x3
+function memcpy
+       cmp     x2, #0
+       b.eq    1f
+0:     ldrb    w3, [x1], #1
+       strb    w3, [x0], #1
+       subs    x2, x2, #1
+       b.ne    0b
+1:     ret
+endfunction
+
+// Generate a test pattern for storage in SVE registers
+// x0: pid     (16 bits)
+// x1: register number (6 bits)
+// x2: generation (4 bits)
+function pattern
+       orr     w1, w0, w1, lsl #16
+       orr     w2, w1, w2, lsl #28
+
+       ldr     x0, =scratch
+       mov     w1, #MAXVL_B / 4
+
+0:     str     w2, [x0], #4
+       add     w2, w2, #(1 << 22)
+       subs    w1, w1, #1
+       bne     0b
+
+       ret
+endfunction
+
+// Get the address of shadow data for FPSIMD V-register V<xn>
+.macro _adrv xd, xn, nrtmp
+       ldr     \xd, =vref
+       mov     x\nrtmp, #16
+       madd    \xd, x\nrtmp, \xn, \xd
+.endm
+
+// Set up test pattern in a FPSIMD V-register
+// x0: pid
+// x1: register number
+// x2: generation
+function setup_vreg
+       mov     x4, x30
+
+       mov     x6, x1
+       bl      pattern
+       _adrv   x0, x6, 2
+       mov     x5, x0
+       ldr     x1, =scratch
+       bl      memcpy
+
+       mov     x0, x6
+       mov     x1, x5
+       bl      setv
+
+       ret     x4
+endfunction
+
+// Fill x1 bytes starting at x0 with 0xae (for canary purposes)
+// Clobbers x1, x2.
+function memfill_ae
+       mov     w2, #0xae
+       b       memfill
+endfunction
+
+// Fill x1 bytes starting at x0 with 0.
+// Clobbers x1, x2.
+function memclr
+       mov     w2, #0
+endfunction
+       // fall through to memfill
+
+// Trivial memory fill: fill x1 bytes starting at address x0 with byte w2
+// Clobbers x1
+function memfill
+       cmp     x1, #0
+       b.eq    1f
+
+0:     strb    w2, [x0], #1
+       subs    x1, x1, #1
+       b.ne    0b
+
+1:     ret
+endfunction
+
+// Trivial memory compare: compare x2 bytes starting at address x0 with
+// bytes starting at address x1.
+// Returns only if all bytes match; otherwise, the program is aborted.
+// Clobbers x0-x5.
+function memcmp
+       cbz     x2, 1f
+
+       mov     x5, #0
+0:     ldrb    w3, [x0, x5]
+       ldrb    w4, [x1, x5]
+       add     x5, x5, #1
+       cmp     w3, w4
+       b.ne    barf
+       subs    x2, x2, #1
+       b.ne    0b
+
+1:     ret
+endfunction
+
+// Verify that a FPSIMD V-register matches its shadow in memory, else abort
+// x0: reg number
+// Clobbers x0-x5.
+function check_vreg
+       mov     x3, x30
+
+       _adrv   x5, x0, 6
+       mov     x4, x0
+       ldr     x7, =scratch
+
+       mov     x0, x7
+       mov     x1, x6
+       bl      memfill_ae
+
+       mov     x0, x4
+       mov     x1, x7
+       bl      getv
+
+       mov     x0, x5
+       mov     x1, x7
+       mov     x2, x6
+       mov     x30, x3
+       b       memcmp
+endfunction
+
+// Any SVE register modified here can cause corruption in the main
+// thread -- but *only* the registers modified here.
+function irritator_handler
+       // Increment the irritation signal count (x23):
+       ldr     x0, [x2, #ucontext_regs + 8 * 23]
+       add     x0, x0, #1
+       str     x0, [x2, #ucontext_regs + 8 * 23]
+
+       // Corrupt some random V-regs
+       adr     x0, .text + (irritator_handler - .text) / 16 * 16
+       movi    v0.8b, #7
+       movi    v9.16b, #9
+       movi    v31.8b, #31
+
+       ret
+endfunction
+
+function terminate_handler
+       mov     w21, w0
+       mov     x20, x2
+
+       puts    "Terminated by signal "
+       mov     w0, w21
+       bl      putdec
+       puts    ", no error, iterations="
+       ldr     x0, [x20, #ucontext_regs + 8 * 22]
+       bl      putdec
+       puts    ", signals="
+       ldr     x0, [x20, #ucontext_regs + 8 * 23]
+       bl      putdecn
+
+       mov     x0, #0
+       mov     x8, #__NR_exit
+       svc     #0
+endfunction
+
+// w0: signal number
+// x1: sa_action
+// w2: sa_flags
+// Clobbers x0-x6,x8
+function setsignal
+       str     x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
+
+       mov     w4, w0
+       mov     x5, x1
+       mov     w6, w2
+
+       add     x0, sp, #16
+       mov     x1, #sa_sz
+       bl      memclr
+
+       mov     w0, w4
+       add     x1, sp, #16
+       str     w6, [x1, #sa_flags]
+       str     x5, [x1, #sa_handler]
+       mov     x2, #0
+       mov     x3, #sa_mask_sz
+       mov     x8, #__NR_rt_sigaction
+       svc     #0
+
+       cbz     w0, 1f
+
+       puts    "sigaction failure\n"
+       b       .Labort
+
+1:     ldr     x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
+       ret
+endfunction
+
+// Main program entry point
+.globl _start
+function _start
+_start:
+       // Sanity-check and report the vector length
+
+       mov     x19, #128
+       cmp     x19, #128
+       b.lo    1f
+       cmp     x19, #2048
+       b.hi    1f
+       tst     x19, #(8 - 1)
+       b.eq    2f
+
+1:     puts    "Bad vector length: "
+       mov     x0, x19
+       bl      putdecn
+       b       .Labort
+
+2:     puts    "Vector length:\t"
+       mov     x0, x19
+       bl      putdec
+       puts    " bits\n"
+
+       // Obtain our PID, to ensure test pattern uniqueness between processes
+
+       mov     x8, #__NR_getpid
+       svc     #0
+       mov     x20, x0
+
+       puts    "PID:\t"
+       mov     x0, x20
+       bl      putdecn
+
+       mov     x23, #0         // Irritation signal count
+
+       mov     w0, #SIGINT
+       adr     x1, terminate_handler
+       mov     w2, #SA_SIGINFO
+       bl      setsignal
+
+       mov     w0, #SIGTERM
+       adr     x1, terminate_handler
+       mov     w2, #SA_SIGINFO
+       bl      setsignal
+
+       mov     w0, #SIGUSR1
+       adr     x1, irritator_handler
+       mov     w2, #SA_SIGINFO
+       orr     w2, w2, #SA_NODEFER
+       bl      setsignal
+
+       mov     x22, #0         // generation number, increments per iteration
+.Ltest_loop:
+
+       mov     x21, #0         // Set up V-regs & shadow with test pattern
+0:     mov     x0, x20
+       mov     x1, x21
+       and     x2, x22, #0xf
+       bl      setup_vreg
+       add     x21, x21, #1
+       cmp     x21, #NVR
+       b.lo    0b
+
+// Can't do this when SVE state is volatile across SVC:
+       mov     x8, #__NR_sched_yield   // Encourage preemption
+       svc     #0
+
+       mov     x21, #0
+0:     mov     x0, x21
+       bl      check_vreg
+       add     x21, x21, #1
+       cmp     x21, #NVR
+       b.lo    0b
+
+       add     x22, x22, #1
+       b       .Ltest_loop
+
+.Labort:
+       mov     x0, #0
+       mov     x1, #SIGABRT
+       mov     x8, #__NR_kill
+       svc     #0
+endfunction
+
+function barf
+       mov     x10, x0 // expected data
+       mov     x11, x1 // actual data
+       mov     x12, x2 // data size
+
+       puts    "Mistatch: PID="
+       mov     x0, x20
+       bl      putdec
+       puts    ", iteration="
+       mov     x0, x22
+       bl      putdec
+       puts    ", reg="
+       mov     x0, x21
+       bl      putdecn
+       puts    "\tExpected ["
+       mov     x0, x10
+       mov     x1, x12
+       bl      dumphex
+       puts    "]\n\tGot      ["
+       mov     x0, x11
+       mov     x1, x12
+       bl      dumphex
+       puts    "]\n"
+
+       mov     x8, #__NR_exit
+       mov     x1, #1
+       svc     #0
+endfunction
diff --git a/tools/testing/selftests/arm64/fp/sve-probe-vls.c b/tools/testing/selftests/arm64/fp/sve-probe-vls.c
new file mode 100644 (file)
index 0000000..b29cbc6
--- /dev/null
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2015-2020 ARM Limited.
+ * Original author: Dave Martin <Dave.Martin@arm.com>
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <asm/sigcontext.h>
+
+#include "../../kselftest.h"
+
+int main(int argc, char **argv)
+{
+       unsigned int vq;
+       int vl;
+       static unsigned int vqs[SVE_VQ_MAX];
+       unsigned int nvqs = 0;
+
+       ksft_print_header();
+       ksft_set_plan(2);
+
+       if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
+               ksft_exit_skip("SVE not available");
+
+       /*
+        * Enumerate up to SVE_VQ_MAX vector lengths
+        */
+       for (vq = SVE_VQ_MAX; vq > 0; --vq) {
+               vl = prctl(PR_SVE_SET_VL, vq * 16);
+               if (vl == -1)
+                       ksft_exit_fail_msg("PR_SVE_SET_VL failed: %s (%d)\n",
+                                          strerror(errno), errno);
+
+               vl &= PR_SVE_VL_LEN_MASK;
+
+               if (!sve_vl_valid(vl))
+                       ksft_exit_fail_msg("VL %d invalid\n", vl);
+               vq = sve_vq_from_vl(vl);
+
+               if (!(nvqs < SVE_VQ_MAX))
+                       ksft_exit_fail_msg("Too many VLs %u >= SVE_VQ_MAX\n",
+                                          nvqs);
+               vqs[nvqs++] = vq;
+       }
+       ksft_test_result_pass("Enumerated %d vector lengths\n", nvqs);
+       ksft_test_result_pass("All vector lengths valid\n");
+
+       /* Print out the vector lengths in ascending order: */
+       while (nvqs--)
+               ksft_print_msg("%u\n", 16 * vqs[nvqs]);
+
+       ksft_exit_pass();
+}
diff --git a/tools/testing/selftests/arm64/fp/sve-ptrace-asm.S b/tools/testing/selftests/arm64/fp/sve-ptrace-asm.S
new file mode 100644 (file)
index 0000000..3e81f9f
--- /dev/null
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2015-2019 ARM Limited.
+// Original author: Dave Martin <Dave.Martin@arm.com>
+#include <asm/unistd.h>
+
+.arch_extension sve
+
+.globl sve_store_patterns
+
+sve_store_patterns:
+       mov     x1, x0
+
+       index   z0.b, #0, #1
+       str     q0, [x1]
+
+       mov     w8, #__NR_getpid
+       svc     #0
+       str     q0, [x1, #0x10]
+
+       mov     z1.d, z0.d
+       str     q0, [x1, #0x20]
+
+       mov     w8, #__NR_getpid
+       svc     #0
+       str     q0, [x1, #0x30]
+
+       mov     z1.d, z0.d
+       str     q0, [x1, #0x40]
+
+       ret
+
+.size  sve_store_patterns, . - sve_store_patterns
+.type  sve_store_patterns, @function
diff --git a/tools/testing/selftests/arm64/fp/sve-ptrace.c b/tools/testing/selftests/arm64/fp/sve-ptrace.c
new file mode 100644 (file)
index 0000000..b2282be
--- /dev/null
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2015-2020 ARM Limited.
+ * Original author: Dave Martin <Dave.Martin@arm.com>
+ */
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/auxv.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <asm/sigcontext.h>
+#include <asm/ptrace.h>
+
+#include "../../kselftest.h"
+
+/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
+#ifndef NT_ARM_SVE
+#define NT_ARM_SVE 0x405
+#endif
+
+/* Number of registers filled in by sve_store_patterns */
+#define NR_VREGS 5
+
+void sve_store_patterns(__uint128_t v[NR_VREGS]);
+
+static void dump(const void *buf, size_t size)
+{
+       size_t i;
+       const unsigned char *p = buf;
+
+       for (i = 0; i < size; ++i)
+               printf(" %.2x", *p++);
+}
+
+static int check_vregs(const __uint128_t vregs[NR_VREGS])
+{
+       int i;
+       int ok = 1;
+
+       for (i = 0; i < NR_VREGS; ++i) {
+               printf("# v[%d]:", i);
+               dump(&vregs[i], sizeof vregs[i]);
+               putchar('\n');
+
+               if (vregs[i] != vregs[0])
+                       ok = 0;
+       }
+
+       return ok;
+}
+
+static int do_child(void)
+{
+       if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
+               ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
+
+       if (raise(SIGSTOP))
+               ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
+
+       return EXIT_SUCCESS;
+}
+
+static struct user_sve_header *get_sve(pid_t pid, void **buf, size_t *size)
+{
+       struct user_sve_header *sve;
+       void *p;
+       size_t sz = sizeof *sve;
+       struct iovec iov;
+
+       while (1) {
+               if (*size < sz) {
+                       p = realloc(*buf, sz);
+                       if (!p) {
+                               errno = ENOMEM;
+                               goto error;
+                       }
+
+                       *buf = p;
+                       *size = sz;
+               }
+
+               iov.iov_base = *buf;
+               iov.iov_len = sz;
+               if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_SVE, &iov))
+                       goto error;
+
+               sve = *buf;
+               if (sve->size <= sz)
+                       break;
+
+               sz = sve->size;
+       }
+
+       return sve;
+
+error:
+       return NULL;
+}
+
+static int set_sve(pid_t pid, const struct user_sve_header *sve)
+{
+       struct iovec iov;
+
+       iov.iov_base = (void *)sve;
+       iov.iov_len = sve->size;
+       return ptrace(PTRACE_SETREGSET, pid, NT_ARM_SVE, &iov);
+}
+
+static void dump_sve_regs(const struct user_sve_header *sve, unsigned int num,
+                         unsigned int vlmax)
+{
+       unsigned int vq;
+       unsigned int i;
+
+       if ((sve->flags & SVE_PT_REGS_MASK) != SVE_PT_REGS_SVE)
+               ksft_exit_fail_msg("Dumping non-SVE register\n");
+
+       if (vlmax > sve->vl)
+               vlmax = sve->vl;
+
+       vq = sve_vq_from_vl(sve->vl);
+       for (i = 0; i < num; ++i) {
+               printf("# z%u:", i);
+               dump((const char *)sve + SVE_PT_SVE_ZREG_OFFSET(vq, i),
+                    vlmax);
+               printf("%s\n", vlmax == sve->vl ? "" : " ...");
+       }
+}
+
+static int do_parent(pid_t child)
+{
+       int ret = EXIT_FAILURE;
+       pid_t pid;
+       int status;
+       siginfo_t si;
+       void *svebuf = NULL, *newsvebuf;
+       size_t svebufsz = 0, newsvebufsz;
+       struct user_sve_header *sve, *new_sve;
+       struct user_fpsimd_state *fpsimd;
+       unsigned int i, j;
+       unsigned char *p;
+       unsigned int vq;
+
+       /* Attach to the child */
+       while (1) {
+               int sig;
+
+               pid = wait(&status);
+               if (pid == -1) {
+                       perror("wait");
+                       goto error;
+               }
+
+               /*
+                * This should never happen but it's hard to flag in
+                * the framework.
+                */
+               if (pid != child)
+                       continue;
+
+               if (WIFEXITED(status) || WIFSIGNALED(status))
+                       ksft_exit_fail_msg("Child died unexpectedly\n");
+
+               ksft_test_result(WIFSTOPPED(status), "WIFSTOPPED(%d)\n",
+                                status);
+               if (!WIFSTOPPED(status))
+                       goto error;
+
+               sig = WSTOPSIG(status);
+
+               if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
+                       if (errno == ESRCH)
+                               goto disappeared;
+
+                       if (errno == EINVAL) {
+                               sig = 0; /* bust group-stop */
+                               goto cont;
+                       }
+
+                       ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
+                                             strerror(errno));
+                       goto error;
+               }
+
+               if (sig == SIGSTOP && si.si_code == SI_TKILL &&
+                   si.si_pid == pid)
+                       break;
+
+       cont:
+               if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
+                       if (errno == ESRCH)
+                               goto disappeared;
+
+                       ksft_test_result_fail("PTRACE_CONT: %s\n",
+                                             strerror(errno));
+                       goto error;
+               }
+       }
+
+       sve = get_sve(pid, &svebuf, &svebufsz);
+       if (!sve) {
+               int e = errno;
+
+               ksft_test_result_fail("get_sve: %s\n", strerror(errno));
+               if (e == ESRCH)
+                       goto disappeared;
+
+               goto error;
+       } else {
+               ksft_test_result_pass("get_sve\n");
+       }
+
+       ksft_test_result((sve->flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD,
+                        "FPSIMD registers\n");
+       if ((sve->flags & SVE_PT_REGS_MASK) != SVE_PT_REGS_FPSIMD)
+               goto error;
+
+       fpsimd = (struct user_fpsimd_state *)((char *)sve +
+                                             SVE_PT_FPSIMD_OFFSET);
+       for (i = 0; i < 32; ++i) {
+               p = (unsigned char *)&fpsimd->vregs[i];
+
+               for (j = 0; j < sizeof fpsimd->vregs[i]; ++j)
+                       p[j] = j;
+       }
+
+       if (set_sve(pid, sve)) {
+               int e = errno;
+
+               ksft_test_result_fail("set_sve(FPSIMD): %s\n",
+                                     strerror(errno));
+               if (e == ESRCH)
+                       goto disappeared;
+
+               goto error;
+       }
+
+       vq = sve_vq_from_vl(sve->vl);
+
+       newsvebufsz = SVE_PT_SVE_ZREG_OFFSET(vq, 1);
+       new_sve = newsvebuf = malloc(newsvebufsz);
+       if (!new_sve) {
+               errno = ENOMEM;
+               perror(NULL);
+               goto error;
+       }
+
+       *new_sve = *sve;
+       new_sve->flags &= ~SVE_PT_REGS_MASK;
+       new_sve->flags |= SVE_PT_REGS_SVE;
+       memset((char *)new_sve + SVE_PT_SVE_ZREG_OFFSET(vq, 0),
+              0, SVE_PT_SVE_ZREG_SIZE(vq));
+       new_sve->size = SVE_PT_SVE_ZREG_OFFSET(vq, 1);
+       if (set_sve(pid, new_sve)) {
+               int e = errno;
+
+               ksft_test_result_fail("set_sve(ZREG): %s\n", strerror(errno));
+               if (e == ESRCH)
+                       goto disappeared;
+
+               goto error;
+       }
+
+       new_sve = get_sve(pid, &newsvebuf, &newsvebufsz);
+       if (!new_sve) {
+               int e = errno;
+
+               ksft_test_result_fail("get_sve(ZREG): %s\n", strerror(errno));
+               if (e == ESRCH)
+                       goto disappeared;
+
+               goto error;
+       }
+
+       ksft_test_result((new_sve->flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE,
+                        "SVE registers\n");
+       if ((new_sve->flags & SVE_PT_REGS_MASK) != SVE_PT_REGS_SVE)
+               goto error;
+
+       dump_sve_regs(new_sve, 3, sizeof fpsimd->vregs[0]);
+
+       p = (unsigned char *)new_sve + SVE_PT_SVE_ZREG_OFFSET(vq, 1);
+       for (i = 0; i < sizeof fpsimd->vregs[0]; ++i) {
+               unsigned char expected = i;
+
+               if (__BYTE_ORDER == __BIG_ENDIAN)
+                       expected = sizeof fpsimd->vregs[0] - 1 - expected;
+
+               ksft_test_result(p[i] == expected, "p[%d] == expected\n", i);
+               if (p[i] != expected)
+                       goto error;
+       }
+
+       ret = EXIT_SUCCESS;
+
+error:
+       kill(child, SIGKILL);
+
+disappeared:
+       return ret;
+}
+
+int main(void)
+{
+       int ret = EXIT_SUCCESS;
+       __uint128_t v[NR_VREGS];
+       pid_t child;
+
+       ksft_print_header();
+       ksft_set_plan(20);
+
+       if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
+               ksft_exit_skip("SVE not available\n");
+
+       sve_store_patterns(v);
+
+       if (!check_vregs(v))
+               ksft_exit_fail_msg("Initial check_vregs() failed\n");
+
+       child = fork();
+       if (!child)
+               return do_child();
+
+       if (do_parent(child))
+               ret = EXIT_FAILURE;
+
+       ksft_print_cnts();
+
+       return 0;
+}
diff --git a/tools/testing/selftests/arm64/fp/sve-stress b/tools/testing/selftests/arm64/fp/sve-stress
new file mode 100755 (executable)
index 0000000..24dd092
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2015-2019 ARM Limited.
+# Original author: Dave Martin <Dave.Martin@arm.com>
+
+set -ue
+
+NR_CPUS=`nproc`
+
+pids=
+logs=
+
+cleanup () {
+       trap - INT TERM CHLD
+       set +e
+
+       if [ -n "$pids" ]; then
+               kill $pids
+               wait $pids
+               pids=
+       fi
+
+       if [ -n "$logs" ]; then
+               cat $logs
+               rm $logs
+               logs=
+       fi
+}
+
+interrupt () {
+       cleanup
+       exit 0
+}
+
+child_died () {
+       cleanup
+       exit 1
+}
+
+trap interrupt INT TERM EXIT
+
+for x in `seq 0 $((NR_CPUS * 4))`; do
+       log=`mktemp`
+       logs=$logs\ $log
+       ./sve-test >$log &
+       pids=$pids\ $!
+done
+
+# Wait for all child processes to be created:
+sleep 10
+
+while :; do
+       kill -USR1 $pids
+done &
+pids=$pids\ $!
+
+wait
+
+exit 1
diff --git a/tools/testing/selftests/arm64/fp/sve-test.S b/tools/testing/selftests/arm64/fp/sve-test.S
new file mode 100644 (file)
index 0000000..f95074c
--- /dev/null
@@ -0,0 +1,672 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2015-2019 ARM Limited.
+// Original author: Dave Martin <Dave.Martin@arm.com>
+//
+// Simple Scalable Vector Extension context switch test
+// Repeatedly writes unique test patterns into each SVE register
+// and reads them back to verify integrity.
+//
+// for x in `seq 1 NR_CPUS`; do sve-test & pids=$pids\ $! ; done
+// (leave it running for as long as you want...)
+// kill $pids
+
+#include <asm/unistd.h>
+#include "assembler.h"
+#include "asm-offsets.h"
+
+#define NZR    32
+#define NPR    16
+#define MAXVL_B        (2048 / 8)
+
+.arch_extension sve
+
+.macro _sve_ldr_v zt, xn
+       ldr     z\zt, [x\xn]
+.endm
+
+.macro _sve_str_v zt, xn
+       str     z\zt, [x\xn]
+.endm
+
+.macro _sve_ldr_p pt, xn
+       ldr     p\pt, [x\xn]
+.endm
+
+.macro _sve_str_p pt, xn
+       str     p\pt, [x\xn]
+.endm
+
+// Generate accessor functions to read/write programmatically selected
+// SVE registers.
+// x0 is the register index to access
+// x1 is the memory address to read from (getz,setp) or store to (setz,setp)
+// All clobber x0-x2
+define_accessor setz, NZR, _sve_ldr_v
+define_accessor getz, NZR, _sve_str_v
+define_accessor setp, NPR, _sve_ldr_p
+define_accessor getp, NPR, _sve_str_p
+
+// Print a single character x0 to stdout
+// Clobbers x0-x2,x8
+function putc
+       str     x0, [sp, #-16]!
+
+       mov     x0, #1                  // STDOUT_FILENO
+       mov     x1, sp
+       mov     x2, #1
+       mov     x8, #__NR_write
+       svc     #0
+
+       add     sp, sp, #16
+       ret
+endfunction
+
+// Print a NUL-terminated string starting at address x0 to stdout
+// Clobbers x0-x3,x8
+function puts
+       mov     x1, x0
+
+       mov     x2, #0
+0:     ldrb    w3, [x0], #1
+       cbz     w3, 1f
+       add     x2, x2, #1
+       b       0b
+
+1:     mov     w0, #1                  // STDOUT_FILENO
+       mov     x8, #__NR_write
+       svc     #0
+
+       ret
+endfunction
+
+// Utility macro to print a literal string
+// Clobbers x0-x4,x8
+.macro puts string
+       .pushsection .rodata.str1.1, "aMS", 1
+.L__puts_literal\@: .string "\string"
+       .popsection
+
+       ldr     x0, =.L__puts_literal\@
+       bl      puts
+.endm
+
+// Print an unsigned decimal number x0 to stdout
+// Clobbers x0-x4,x8
+function putdec
+       mov     x1, sp
+       str     x30, [sp, #-32]!        // Result can't be > 20 digits
+
+       mov     x2, #0
+       strb    w2, [x1, #-1]!          // Write the NUL terminator
+
+       mov     x2, #10
+0:     udiv    x3, x0, x2              // div-mod loop to generate the digits
+       msub    x0, x3, x2, x0
+       add     w0, w0, #'0'
+       strb    w0, [x1, #-1]!
+       mov     x0, x3
+       cbnz    x3, 0b
+
+       ldrb    w0, [x1]
+       cbnz    w0, 1f
+       mov     w0, #'0'                // Print "0" for 0, not ""
+       strb    w0, [x1, #-1]!
+
+1:     mov     x0, x1
+       bl      puts
+
+       ldr     x30, [sp], #32
+       ret
+endfunction
+
+// Print an unsigned decimal number x0 to stdout, followed by a newline
+// Clobbers x0-x5,x8
+function putdecn
+       mov     x5, x30
+
+       bl      putdec
+       mov     x0, #'\n'
+       bl      putc
+
+       ret     x5
+endfunction
+
+// Clobbers x0-x3,x8
+function puthexb
+       str     x30, [sp, #-0x10]!
+
+       mov     w3, w0
+       lsr     w0, w0, #4
+       bl      puthexnibble
+       mov     w0, w3
+
+       ldr     x30, [sp], #0x10
+       // fall through to puthexnibble
+endfunction
+// Clobbers x0-x2,x8
+function puthexnibble
+       and     w0, w0, #0xf
+       cmp     w0, #10
+       blo     1f
+       add     w0, w0, #'a' - ('9' + 1)
+1:     add     w0, w0, #'0'
+       b       putc
+endfunction
+
+// x0=data in, x1=size in, clobbers x0-x5,x8
+function dumphex
+       str     x30, [sp, #-0x10]!
+
+       mov     x4, x0
+       mov     x5, x1
+
+0:     subs    x5, x5, #1
+       b.lo    1f
+       ldrb    w0, [x4], #1
+       bl      puthexb
+       b       0b
+
+1:     ldr     x30, [sp], #0x10
+       ret
+endfunction
+
+// Declare some storate space to shadow the SVE register contents:
+.pushsection .text
+.data
+.align 4
+zref:
+       .space  MAXVL_B * NZR
+pref:
+       .space  MAXVL_B / 8 * NPR
+ffrref:
+       .space  MAXVL_B / 8
+scratch:
+       .space  MAXVL_B
+.popsection
+
+// Trivial memory copy: copy x2 bytes, starting at address x1, to address x0.
+// Clobbers x0-x3
+function memcpy
+       cmp     x2, #0
+       b.eq    1f
+0:     ldrb    w3, [x1], #1
+       strb    w3, [x0], #1
+       subs    x2, x2, #1
+       b.ne    0b
+1:     ret
+endfunction
+
+// Generate a test pattern for storage in SVE registers
+// x0: pid     (16 bits)
+// x1: register number (6 bits)
+// x2: generation (4 bits)
+
+// These values are used to constuct a 32-bit pattern that is repeated in the
+// scratch buffer as many times as will fit:
+// bits 31:28  generation number (increments once per test_loop)
+// bits 27:22  32-bit lane index
+// bits 21:16  register number
+// bits 15: 0  pid
+
+function pattern
+       orr     w1, w0, w1, lsl #16
+       orr     w2, w1, w2, lsl #28
+
+       ldr     x0, =scratch
+       mov     w1, #MAXVL_B / 4
+
+0:     str     w2, [x0], #4
+       add     w2, w2, #(1 << 22)
+       subs    w1, w1, #1
+       bne     0b
+
+       ret
+endfunction
+
+// Get the address of shadow data for SVE Z-register Z<xn>
+.macro _adrz xd, xn, nrtmp
+       ldr     \xd, =zref
+       rdvl    x\nrtmp, #1
+       madd    \xd, x\nrtmp, \xn, \xd
+.endm
+
+// Get the address of shadow data for SVE P-register P<xn - NZR>
+.macro _adrp xd, xn, nrtmp
+       ldr     \xd, =pref
+       rdvl    x\nrtmp, #1
+       lsr     x\nrtmp, x\nrtmp, #3
+       sub     \xn, \xn, #NZR
+       madd    \xd, x\nrtmp, \xn, \xd
+.endm
+
+// Set up test pattern in a SVE Z-register
+// x0: pid
+// x1: register number
+// x2: generation
+function setup_zreg
+       mov     x4, x30
+
+       mov     x6, x1
+       bl      pattern
+       _adrz   x0, x6, 2
+       mov     x5, x0
+       ldr     x1, =scratch
+       bl      memcpy
+
+       mov     x0, x6
+       mov     x1, x5
+       bl      setz
+
+       ret     x4
+endfunction
+
+// Set up test pattern in a SVE P-register
+// x0: pid
+// x1: register number
+// x2: generation
+function setup_preg
+       mov     x4, x30
+
+       mov     x6, x1
+       bl      pattern
+       _adrp   x0, x6, 2
+       mov     x5, x0
+       ldr     x1, =scratch
+       bl      memcpy
+
+       mov     x0, x6
+       mov     x1, x5
+       bl      setp
+
+       ret     x4
+endfunction
+
+// Set up test pattern in the FFR
+// x0: pid
+// x2: generation
+// Beware: corrupts P0.
+function setup_ffr
+       mov     x4, x30
+
+       bl      pattern
+       ldr     x0, =ffrref
+       ldr     x1, =scratch
+       rdvl    x2, #1
+       lsr     x2, x2, #3
+       bl      memcpy
+
+       mov     x0, #0
+       ldr     x1, =ffrref
+       bl      setp
+
+       wrffr   p0.b
+
+       ret     x4
+endfunction
+
+// Fill x1 bytes starting at x0 with 0xae (for canary purposes)
+// Clobbers x1, x2.
+function memfill_ae
+       mov     w2, #0xae
+       b       memfill
+endfunction
+
+// Fill x1 bytes starting at x0 with 0.
+// Clobbers x1, x2.
+function memclr
+       mov     w2, #0
+endfunction
+       // fall through to memfill
+
+// Trivial memory fill: fill x1 bytes starting at address x0 with byte w2
+// Clobbers x1
+function memfill
+       cmp     x1, #0
+       b.eq    1f
+
+0:     strb    w2, [x0], #1
+       subs    x1, x1, #1
+       b.ne    0b
+
+1:     ret
+endfunction
+
+// Trivial memory compare: compare x2 bytes starting at address x0 with
+// bytes starting at address x1.
+// Returns only if all bytes match; otherwise, the program is aborted.
+// Clobbers x0-x5.
+function memcmp
+       cbz     x2, 2f
+
+       stp     x0, x1, [sp, #-0x20]!
+       str     x2, [sp, #0x10]
+
+       mov     x5, #0
+0:     ldrb    w3, [x0, x5]
+       ldrb    w4, [x1, x5]
+       add     x5, x5, #1
+       cmp     w3, w4
+       b.ne    1f
+       subs    x2, x2, #1
+       b.ne    0b
+
+1:     ldr     x2, [sp, #0x10]
+       ldp     x0, x1, [sp], #0x20
+       b.ne    barf
+
+2:     ret
+endfunction
+
+// Verify that a SVE Z-register matches its shadow in memory, else abort
+// x0: reg number
+// Clobbers x0-x7.
+function check_zreg
+       mov     x3, x30
+
+       _adrz   x5, x0, 6
+       mov     x4, x0
+       ldr     x7, =scratch
+
+       mov     x0, x7
+       mov     x1, x6
+       bl      memfill_ae
+
+       mov     x0, x4
+       mov     x1, x7
+       bl      getz
+
+       mov     x0, x5
+       mov     x1, x7
+       mov     x2, x6
+       mov     x30, x3
+       b       memcmp
+endfunction
+
+// Verify that a SVE P-register matches its shadow in memory, else abort
+// x0: reg number
+// Clobbers x0-x7.
+function check_preg
+       mov     x3, x30
+
+       _adrp   x5, x0, 6
+       mov     x4, x0
+       ldr     x7, =scratch
+
+       mov     x0, x7
+       mov     x1, x6
+       bl      memfill_ae
+
+       mov     x0, x4
+       mov     x1, x7
+       bl      getp
+
+       mov     x0, x5
+       mov     x1, x7
+       mov     x2, x6
+       mov     x30, x3
+       b       memcmp
+endfunction
+
+// Verify that the FFR matches its shadow in memory, else abort
+// Beware -- corrupts P0.
+// Clobbers x0-x5.
+function check_ffr
+       mov     x3, x30
+
+       ldr     x4, =scratch
+       rdvl    x5, #1
+       lsr     x5, x5, #3
+
+       mov     x0, x4
+       mov     x1, x5
+       bl      memfill_ae
+
+       rdffr   p0.b
+       mov     x0, #0
+       mov     x1, x4
+       bl      getp
+
+       ldr     x0, =ffrref
+       mov     x1, x4
+       mov     x2, x5
+       mov     x30, x3
+       b       memcmp
+endfunction
+
+// Any SVE register modified here can cause corruption in the main
+// thread -- but *only* the registers modified here.
+function irritator_handler
+       // Increment the irritation signal count (x23):
+       ldr     x0, [x2, #ucontext_regs + 8 * 23]
+       add     x0, x0, #1
+       str     x0, [x2, #ucontext_regs + 8 * 23]
+
+       // Corrupt some random Z-regs
+       adr     x0, .text + (irritator_handler - .text) / 16 * 16
+       movi    v0.8b, #1
+       movi    v9.16b, #2
+       movi    v31.8b, #3
+       // And P0
+       rdffr   p0.b
+       // And FFR
+       wrffr   p15.b
+
+       ret
+endfunction
+
+function terminate_handler
+       mov     w21, w0
+       mov     x20, x2
+
+       puts    "Terminated by signal "
+       mov     w0, w21
+       bl      putdec
+       puts    ", no error, iterations="
+       ldr     x0, [x20, #ucontext_regs + 8 * 22]
+       bl      putdec
+       puts    ", signals="
+       ldr     x0, [x20, #ucontext_regs + 8 * 23]
+       bl      putdecn
+
+       mov     x0, #0
+       mov     x8, #__NR_exit
+       svc     #0
+endfunction
+
+// w0: signal number
+// x1: sa_action
+// w2: sa_flags
+// Clobbers x0-x6,x8
+function setsignal
+       str     x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
+
+       mov     w4, w0
+       mov     x5, x1
+       mov     w6, w2
+
+       add     x0, sp, #16
+       mov     x1, #sa_sz
+       bl      memclr
+
+       mov     w0, w4
+       add     x1, sp, #16
+       str     w6, [x1, #sa_flags]
+       str     x5, [x1, #sa_handler]
+       mov     x2, #0
+       mov     x3, #sa_mask_sz
+       mov     x8, #__NR_rt_sigaction
+       svc     #0
+
+       cbz     w0, 1f
+
+       puts    "sigaction failure\n"
+       b       .Labort
+
+1:     ldr     x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
+       ret
+endfunction
+
+// Main program entry point
+.globl _start
+function _start
+_start:
+       // Sanity-check and report the vector length
+
+       rdvl    x19, #8
+       cmp     x19, #128
+       b.lo    1f
+       cmp     x19, #2048
+       b.hi    1f
+       tst     x19, #(8 - 1)
+       b.eq    2f
+
+1:     puts    "Bad vector length: "
+       mov     x0, x19
+       bl      putdecn
+       b       .Labort
+
+2:     puts    "Vector length:\t"
+       mov     x0, x19
+       bl      putdec
+       puts    " bits\n"
+
+       // Obtain our PID, to ensure test pattern uniqueness between processes
+
+       mov     x8, #__NR_getpid
+       svc     #0
+       mov     x20, x0
+
+       puts    "PID:\t"
+       mov     x0, x20
+       bl      putdecn
+
+       mov     x23, #0         // Irritation signal count
+
+       mov     w0, #SIGINT
+       adr     x1, terminate_handler
+       mov     w2, #SA_SIGINFO
+       bl      setsignal
+
+       mov     w0, #SIGTERM
+       adr     x1, terminate_handler
+       mov     w2, #SA_SIGINFO
+       bl      setsignal
+
+       mov     w0, #SIGUSR1
+       adr     x1, irritator_handler
+       mov     w2, #SA_SIGINFO
+       orr     w2, w2, #SA_NODEFER
+       bl      setsignal
+
+       mov     x22, #0         // generation number, increments per iteration
+.Ltest_loop:
+       rdvl    x0, #8
+       cmp     x0, x19
+       b.ne    vl_barf
+
+       mov     x21, #0         // Set up Z-regs & shadow with test pattern
+0:     mov     x0, x20
+       mov     x1, x21
+       and     x2, x22, #0xf
+       bl      setup_zreg
+       add     x21, x21, #1
+       cmp     x21, #NZR
+       b.lo    0b
+
+       mov     x0, x20         // Set up FFR & shadow with test pattern
+       mov     x1, #NZR + NPR
+       and     x2, x22, #0xf
+       bl      setup_ffr
+
+0:     mov     x0, x20         // Set up P-regs & shadow with test pattern
+       mov     x1, x21
+       and     x2, x22, #0xf
+       bl      setup_preg
+       add     x21, x21, #1
+       cmp     x21, #NZR + NPR
+       b.lo    0b
+
+// Can't do this when SVE state is volatile across SVC:
+//     mov     x8, #__NR_sched_yield   // Encourage preemption
+//     svc     #0
+
+       mov     x21, #0
+0:     mov     x0, x21
+       bl      check_zreg
+       add     x21, x21, #1
+       cmp     x21, #NZR
+       b.lo    0b
+
+0:     mov     x0, x21
+       bl      check_preg
+       add     x21, x21, #1
+       cmp     x21, #NZR + NPR
+       b.lo    0b
+
+       bl      check_ffr
+
+       add     x22, x22, #1
+       b       .Ltest_loop
+
+.Labort:
+       mov     x0, #0
+       mov     x1, #SIGABRT
+       mov     x8, #__NR_kill
+       svc     #0
+endfunction
+
+function barf
+// fpsimd.c acitivty log dump hack
+//     ldr     w0, =0xdeadc0de
+//     mov     w8, #__NR_exit
+//     svc     #0
+// end hack
+       mov     x10, x0 // expected data
+       mov     x11, x1 // actual data
+       mov     x12, x2 // data size
+
+       puts    "Mistatch: PID="
+       mov     x0, x20
+       bl      putdec
+       puts    ", iteration="
+       mov     x0, x22
+       bl      putdec
+       puts    ", reg="
+       mov     x0, x21
+       bl      putdecn
+       puts    "\tExpected ["
+       mov     x0, x10
+       mov     x1, x12
+       bl      dumphex
+       puts    "]\n\tGot      ["
+       mov     x0, x11
+       mov     x1, x12
+       bl      dumphex
+       puts    "]\n"
+
+       mov     x8, #__NR_getpid
+       svc     #0
+// fpsimd.c acitivty log dump hack
+//     ldr     w0, =0xdeadc0de
+//     mov     w8, #__NR_exit
+//     svc     #0
+// ^ end of hack
+       mov     x1, #SIGABRT
+       mov     x8, #__NR_kill
+       svc     #0
+//     mov     x8, #__NR_exit
+//     mov     x1, #1
+//     svc     #0
+endfunction
+
+function vl_barf
+       mov     x10, x0
+
+       puts    "Bad active VL: "
+       mov     x0, x10
+       bl      putdecn
+
+       mov     x8, #__NR_exit
+       mov     x1, #1
+       svc     #0
+endfunction
diff --git a/tools/testing/selftests/arm64/fp/vlset.c b/tools/testing/selftests/arm64/fp/vlset.c
new file mode 100644 (file)
index 0000000..308d27a
--- /dev/null
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2015-2019 ARM Limited.
+ * Original author: Dave Martin <Dave.Martin@arm.com>
+ */
+#define _GNU_SOURCE
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <asm/hwcap.h>
+#include <asm/sigcontext.h>
+
+static int inherit = 0;
+static int no_inherit = 0;
+static int force = 0;
+static unsigned long vl;
+
+static const struct option options[] = {
+       { "force",      no_argument, NULL, 'f' },
+       { "inherit",    no_argument, NULL, 'i' },
+       { "max",        no_argument, NULL, 'M' },
+       { "no-inherit", no_argument, &no_inherit, 1 },
+       { "help",       no_argument, NULL, '?' },
+       {}
+};
+
+static char const *program_name;
+
+static int parse_options(int argc, char **argv)
+{
+       int c;
+       char *rest;
+
+       program_name = strrchr(argv[0], '/');
+       if (program_name)
+               ++program_name;
+       else
+               program_name = argv[0];
+
+       while ((c = getopt_long(argc, argv, "Mfhi", options, NULL)) != -1)
+               switch (c) {
+               case 'M':       vl = SVE_VL_MAX; break;
+               case 'f':       force = 1; break;
+               case 'i':       inherit = 1; break;
+               case 0:         break;
+               default:        goto error;
+               }
+
+       if (inherit && no_inherit)
+               goto error;
+
+       if (!vl) {
+               /* vector length */
+               if (optind >= argc)
+                       goto error;
+
+               errno = 0;
+               vl = strtoul(argv[optind], &rest, 0);
+               if (*rest) {
+                       vl = ULONG_MAX;
+                       errno = EINVAL;
+               }
+               if (vl == ULONG_MAX && errno) {
+                       fprintf(stderr, "%s: %s: %s\n",
+                               program_name, argv[optind], strerror(errno));
+                       goto error;
+               }
+
+               ++optind;
+       }
+
+       /* command */
+       if (optind >= argc)
+               goto error;
+
+       return 0;
+
+error:
+       fprintf(stderr,
+               "Usage: %s [-f | --force] "
+               "[-i | --inherit | --no-inherit] "
+               "{-M | --max | <vector length>} "
+               "<command> [<arguments> ...]\n",
+               program_name);
+       return -1;
+}
+
+int main(int argc, char **argv)
+{
+       int ret = 126;  /* same as sh(1) command-not-executable error */
+       long flags;
+       char *path;
+       int t, e;
+
+       if (parse_options(argc, argv))
+               return 2;       /* same as sh(1) builtin incorrect-usage */
+
+       if (vl & ~(vl & PR_SVE_VL_LEN_MASK)) {
+               fprintf(stderr, "%s: Invalid vector length %lu\n",
+                       program_name, vl);
+               return 2;       /* same as sh(1) builtin incorrect-usage */
+       }
+
+       if (!(getauxval(AT_HWCAP) & HWCAP_SVE)) {
+               fprintf(stderr, "%s: Scalable Vector Extension not present\n",
+                       program_name);
+
+               if (!force)
+                       goto error;
+
+               fputs("Going ahead anyway (--force):  "
+                     "This is a debug option.  Don't rely on it.\n",
+                     stderr);
+       }
+
+       flags = PR_SVE_SET_VL_ONEXEC;
+       if (inherit)
+               flags |= PR_SVE_VL_INHERIT;
+
+       t = prctl(PR_SVE_SET_VL, vl | flags);
+       if (t < 0) {
+               fprintf(stderr, "%s: PR_SVE_SET_VL: %s\n",
+                       program_name, strerror(errno));
+               goto error;
+       }
+
+       t = prctl(PR_SVE_GET_VL);
+       if (t == -1) {
+               fprintf(stderr, "%s: PR_SVE_GET_VL: %s\n",
+                       program_name, strerror(errno));
+               goto error;
+       }
+       flags = PR_SVE_VL_LEN_MASK;
+       flags = t & ~flags;
+
+       assert(optind < argc);
+       path = argv[optind];
+
+       execvp(path, &argv[optind]);
+       e = errno;
+       if (errno == ENOENT)
+               ret = 127;      /* same as sh(1) not-found error */
+       fprintf(stderr, "%s: %s: %s\n", program_name, path, strerror(e));
+
+error:
+       return ret;             /* same as sh(1) not-executable error */
+}
diff --git a/tools/testing/selftests/arm64/mte/.gitignore b/tools/testing/selftests/arm64/mte/.gitignore
new file mode 100644 (file)
index 0000000..bc3ac63
--- /dev/null
@@ -0,0 +1,6 @@
+check_buffer_fill
+check_tags_inclusion
+check_child_memory
+check_mmap_options
+check_ksm_options
+check_user_mem
diff --git a/tools/testing/selftests/arm64/mte/Makefile b/tools/testing/selftests/arm64/mte/Makefile
new file mode 100644 (file)
index 0000000..2480226
--- /dev/null
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020 ARM Limited
+
+CFLAGS += -std=gnu99 -I.
+SRCS := $(filter-out mte_common_util.c,$(wildcard *.c))
+PROGS := $(patsubst %.c,%,$(SRCS))
+
+#Add mte compiler option
+ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep gcc),)
+CFLAGS += -march=armv8.5-a+memtag
+endif
+
+#check if the compiler works well
+mte_cc_support := $(shell if ($(CC) $(CFLAGS) -E -x c /dev/null -o /dev/null 2>&1) then echo "1"; fi)
+
+ifeq ($(mte_cc_support),1)
+# Generated binaries to be installed by top KSFT script
+TEST_GEN_PROGS := $(PROGS)
+
+# Get Kernel headers installed and use them.
+KSFT_KHDR_INSTALL := 1
+endif
+
+# Include KSFT lib.mk.
+include ../../lib.mk
+
+ifeq ($(mte_cc_support),1)
+$(TEST_GEN_PROGS): mte_common_util.c mte_common_util.h mte_helper.S
+endif
diff --git a/tools/testing/selftests/arm64/mte/check_buffer_fill.c b/tools/testing/selftests/arm64/mte/check_buffer_fill.c
new file mode 100644 (file)
index 0000000..242635d
--- /dev/null
@@ -0,0 +1,475 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 ARM Limited
+
+#define _GNU_SOURCE
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "kselftest.h"
+#include "mte_common_util.h"
+#include "mte_def.h"
+
+#define OVERFLOW_RANGE MT_GRANULE_SIZE
+
+static int sizes[] = {
+       1, 555, 1033, MT_GRANULE_SIZE - 1, MT_GRANULE_SIZE,
+       /* page size - 1*/ 0, /* page_size */ 0, /* page size + 1 */ 0
+};
+
+enum mte_block_test_alloc {
+       UNTAGGED_TAGGED,
+       TAGGED_UNTAGGED,
+       TAGGED_TAGGED,
+       BLOCK_ALLOC_MAX,
+};
+
+static int check_buffer_by_byte(int mem_type, int mode)
+{
+       char *ptr;
+       int i, j, item;
+       bool err;
+
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       item = sizeof(sizes)/sizeof(int);
+
+       for (i = 0; i < item; i++) {
+               ptr = (char *)mte_allocate_memory(sizes[i], mem_type, 0, true);
+               if (check_allocated_memory(ptr, sizes[i], mem_type, true) != KSFT_PASS)
+                       return KSFT_FAIL;
+               mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[i]);
+               /* Set some value in tagged memory */
+               for (j = 0; j < sizes[i]; j++)
+                       ptr[j] = '1';
+               mte_wait_after_trig();
+               err = cur_mte_cxt.fault_valid;
+               /* Check the buffer whether it is filled. */
+               for (j = 0; j < sizes[i] && !err; j++) {
+                       if (ptr[j] != '1')
+                               err = true;
+               }
+               mte_free_memory((void *)ptr, sizes[i], mem_type, true);
+
+               if (err)
+                       break;
+       }
+       if (!err)
+               return KSFT_PASS;
+       else
+               return KSFT_FAIL;
+}
+
+static int check_buffer_underflow_by_byte(int mem_type, int mode,
+                                         int underflow_range)
+{
+       char *ptr;
+       int i, j, item, last_index;
+       bool err;
+       char *und_ptr = NULL;
+
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       item = sizeof(sizes)/sizeof(int);
+       for (i = 0; i < item; i++) {
+               ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
+                                                           underflow_range, 0);
+               if (check_allocated_memory_range(ptr, sizes[i], mem_type,
+                                              underflow_range, 0) != KSFT_PASS)
+                       return KSFT_FAIL;
+
+               mte_initialize_current_context(mode, (uintptr_t)ptr, -underflow_range);
+               last_index = 0;
+               /* Set some value in tagged memory and make the buffer underflow */
+               for (j = sizes[i] - 1; (j >= -underflow_range) &&
+                                      (cur_mte_cxt.fault_valid == false); j--) {
+                       ptr[j] = '1';
+                       last_index = j;
+               }
+               mte_wait_after_trig();
+               err = false;
+               /* Check whether the buffer is filled */
+               for (j = 0; j < sizes[i]; j++) {
+                       if (ptr[j] != '1') {
+                               err = true;
+                               ksft_print_msg("Buffer is not filled at index:%d of ptr:0x%lx\n",
+                                               j, ptr);
+                               break;
+                       }
+               }
+               if (err)
+                       goto check_buffer_underflow_by_byte_err;
+
+               switch (mode) {
+               case MTE_NONE_ERR:
+                       if (cur_mte_cxt.fault_valid == true || last_index != -underflow_range) {
+                               err = true;
+                               break;
+                       }
+                       /* There were no fault so the underflow area should be filled */
+                       und_ptr = (char *) MT_CLEAR_TAG((size_t) ptr - underflow_range);
+                       for (j = 0 ; j < underflow_range; j++) {
+                               if (und_ptr[j] != '1') {
+                                       err = true;
+                                       break;
+                               }
+                       }
+                       break;
+               case MTE_ASYNC_ERR:
+                       /* Imprecise fault should occur otherwise return error */
+                       if (cur_mte_cxt.fault_valid == false) {
+                               err = true;
+                               break;
+                       }
+                       /*
+                        * The imprecise fault is checked after the write to the buffer,
+                        * so the underflow area before the fault should be filled.
+                        */
+                       und_ptr = (char *) MT_CLEAR_TAG((size_t) ptr);
+                       for (j = last_index ; j < 0 ; j++) {
+                               if (und_ptr[j] != '1') {
+                                       err = true;
+                                       break;
+                               }
+                       }
+                       break;
+               case MTE_SYNC_ERR:
+                       /* Precise fault should occur otherwise return error */
+                       if (!cur_mte_cxt.fault_valid || (last_index != (-1))) {
+                               err = true;
+                               break;
+                       }
+                       /* Underflow area should not be filled */
+                       und_ptr = (char *) MT_CLEAR_TAG((size_t) ptr);
+                       if (und_ptr[-1] == '1')
+                               err = true;
+                       break;
+               default:
+                       err = true;
+               break;
+               }
+check_buffer_underflow_by_byte_err:
+               mte_free_memory_tag_range((void *)ptr, sizes[i], mem_type, underflow_range, 0);
+               if (err)
+                       break;
+       }
+       return (err ? KSFT_FAIL : KSFT_PASS);
+}
+
+static int check_buffer_overflow_by_byte(int mem_type, int mode,
+                                         int overflow_range)
+{
+       char *ptr;
+       int i, j, item, last_index;
+       bool err;
+       size_t tagged_size, overflow_size;
+       char *over_ptr = NULL;
+
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       item = sizeof(sizes)/sizeof(int);
+       for (i = 0; i < item; i++) {
+               ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
+                                                           0, overflow_range);
+               if (check_allocated_memory_range(ptr, sizes[i], mem_type,
+                                                0, overflow_range) != KSFT_PASS)
+                       return KSFT_FAIL;
+
+               tagged_size = MT_ALIGN_UP(sizes[i]);
+
+               mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[i] + overflow_range);
+
+               /* Set some value in tagged memory and make the buffer underflow */
+               for (j = 0, last_index = 0 ; (j < (sizes[i] + overflow_range)) &&
+                                            (cur_mte_cxt.fault_valid == false); j++) {
+                       ptr[j] = '1';
+                       last_index = j;
+               }
+               mte_wait_after_trig();
+               err = false;
+               /* Check whether the buffer is filled */
+               for (j = 0; j < sizes[i]; j++) {
+                       if (ptr[j] != '1') {
+                               err = true;
+                               ksft_print_msg("Buffer is not filled at index:%d of ptr:0x%lx\n",
+                                               j, ptr);
+                               break;
+                       }
+               }
+               if (err)
+                       goto check_buffer_overflow_by_byte_err;
+
+               overflow_size = overflow_range - (tagged_size - sizes[i]);
+
+               switch (mode) {
+               case MTE_NONE_ERR:
+                       if ((cur_mte_cxt.fault_valid == true) ||
+                           (last_index != (sizes[i] + overflow_range - 1))) {
+                               err = true;
+                               break;
+                       }
+                       /* There were no fault so the overflow area should be filled */
+                       over_ptr = (char *) MT_CLEAR_TAG((size_t) ptr + tagged_size);
+                       for (j = 0 ; j < overflow_size; j++) {
+                               if (over_ptr[j] != '1') {
+                                       err = true;
+                                       break;
+                               }
+                       }
+                       break;
+               case MTE_ASYNC_ERR:
+                       /* Imprecise fault should occur otherwise return error */
+                       if (cur_mte_cxt.fault_valid == false) {
+                               err = true;
+                               break;
+                       }
+                       /*
+                        * The imprecise fault is checked after the write to the buffer,
+                        * so the overflow area should be filled before the fault.
+                        */
+                       over_ptr = (char *) MT_CLEAR_TAG((size_t) ptr);
+                       for (j = tagged_size ; j < last_index; j++) {
+                               if (over_ptr[j] != '1') {
+                                       err = true;
+                                       break;
+                               }
+                       }
+                       break;
+               case MTE_SYNC_ERR:
+                       /* Precise fault should occur otherwise return error */
+                       if (!cur_mte_cxt.fault_valid || (last_index != tagged_size)) {
+                               err = true;
+                               break;
+                       }
+                       /* Underflow area should not be filled */
+                       over_ptr = (char *) MT_CLEAR_TAG((size_t) ptr + tagged_size);
+                       for (j = 0 ; j < overflow_size; j++) {
+                               if (over_ptr[j] == '1')
+                                       err = true;
+                       }
+                       break;
+               default:
+                       err = true;
+               break;
+               }
+check_buffer_overflow_by_byte_err:
+               mte_free_memory_tag_range((void *)ptr, sizes[i], mem_type, 0, overflow_range);
+               if (err)
+                       break;
+       }
+       return (err ? KSFT_FAIL : KSFT_PASS);
+}
+
+static int check_buffer_by_block_iterate(int mem_type, int mode, size_t size)
+{
+       char *src, *dst;
+       int j, result = KSFT_PASS;
+       enum mte_block_test_alloc alloc_type = UNTAGGED_TAGGED;
+
+       for (alloc_type = UNTAGGED_TAGGED; alloc_type < (int) BLOCK_ALLOC_MAX; alloc_type++) {
+               switch (alloc_type) {
+               case UNTAGGED_TAGGED:
+                       src = (char *)mte_allocate_memory(size, mem_type, 0, false);
+                       if (check_allocated_memory(src, size, mem_type, false) != KSFT_PASS)
+                               return KSFT_FAIL;
+
+                       dst = (char *)mte_allocate_memory(size, mem_type, 0, true);
+                       if (check_allocated_memory(dst, size, mem_type, true) != KSFT_PASS) {
+                               mte_free_memory((void *)src, size, mem_type, false);
+                               return KSFT_FAIL;
+                       }
+
+                       break;
+               case TAGGED_UNTAGGED:
+                       dst = (char *)mte_allocate_memory(size, mem_type, 0, false);
+                       if (check_allocated_memory(dst, size, mem_type, false) != KSFT_PASS)
+                               return KSFT_FAIL;
+
+                       src = (char *)mte_allocate_memory(size, mem_type, 0, true);
+                       if (check_allocated_memory(src, size, mem_type, true) != KSFT_PASS) {
+                               mte_free_memory((void *)dst, size, mem_type, false);
+                               return KSFT_FAIL;
+                       }
+                       break;
+               case TAGGED_TAGGED:
+                       src = (char *)mte_allocate_memory(size, mem_type, 0, true);
+                       if (check_allocated_memory(src, size, mem_type, true) != KSFT_PASS)
+                               return KSFT_FAIL;
+
+                       dst = (char *)mte_allocate_memory(size, mem_type, 0, true);
+                       if (check_allocated_memory(dst, size, mem_type, true) != KSFT_PASS) {
+                               mte_free_memory((void *)src, size, mem_type, true);
+                               return KSFT_FAIL;
+                       }
+                       break;
+               default:
+                       return KSFT_FAIL;
+               }
+
+               cur_mte_cxt.fault_valid = false;
+               result = KSFT_PASS;
+               mte_initialize_current_context(mode, (uintptr_t)dst, size);
+               /* Set some value in memory and copy*/
+               memset((void *)src, (int)'1', size);
+               memcpy((void *)dst, (void *)src, size);
+               mte_wait_after_trig();
+               if (cur_mte_cxt.fault_valid) {
+                       result = KSFT_FAIL;
+                       goto check_buffer_by_block_err;
+               }
+               /* Check the buffer whether it is filled. */
+               for (j = 0; j < size; j++) {
+                       if (src[j] != dst[j] || src[j] != '1') {
+                               result = KSFT_FAIL;
+                               break;
+                       }
+               }
+check_buffer_by_block_err:
+               mte_free_memory((void *)src, size, mem_type,
+                               MT_FETCH_TAG((uintptr_t)src) ? true : false);
+               mte_free_memory((void *)dst, size, mem_type,
+                               MT_FETCH_TAG((uintptr_t)dst) ? true : false);
+               if (result != KSFT_PASS)
+                       return result;
+       }
+       return result;
+}
+
+static int check_buffer_by_block(int mem_type, int mode)
+{
+       int i, item, result = KSFT_PASS;
+
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       item = sizeof(sizes)/sizeof(int);
+       cur_mte_cxt.fault_valid = false;
+       for (i = 0; i < item; i++) {
+               result = check_buffer_by_block_iterate(mem_type, mode, sizes[i]);
+               if (result != KSFT_PASS)
+                       break;
+       }
+       return result;
+}
+
+static int compare_memory_tags(char *ptr, size_t size, int tag)
+{
+       int i, new_tag;
+
+       for (i = 0 ; i < size ; i += MT_GRANULE_SIZE) {
+               new_tag = MT_FETCH_TAG((uintptr_t)(mte_get_tag_address(ptr + i)));
+               if (tag != new_tag) {
+                       ksft_print_msg("FAIL: child mte tag mismatch\n");
+                       return KSFT_FAIL;
+               }
+       }
+       return KSFT_PASS;
+}
+
+static int check_memory_initial_tags(int mem_type, int mode, int mapping)
+{
+       char *ptr;
+       int run, fd;
+       int total = sizeof(sizes)/sizeof(int);
+
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       for (run = 0; run < total; run++) {
+               /* check initial tags for anonymous mmap */
+               ptr = (char *)mte_allocate_memory(sizes[run], mem_type, mapping, false);
+               if (check_allocated_memory(ptr, sizes[run], mem_type, false) != KSFT_PASS)
+                       return KSFT_FAIL;
+               if (compare_memory_tags(ptr, sizes[run], 0) != KSFT_PASS) {
+                       mte_free_memory((void *)ptr, sizes[run], mem_type, false);
+                       return KSFT_FAIL;
+               }
+               mte_free_memory((void *)ptr, sizes[run], mem_type, false);
+
+               /* check initial tags for file mmap */
+               fd = create_temp_file();
+               if (fd == -1)
+                       return KSFT_FAIL;
+               ptr = (char *)mte_allocate_file_memory(sizes[run], mem_type, mapping, false, fd);
+               if (check_allocated_memory(ptr, sizes[run], mem_type, false) != KSFT_PASS) {
+                       close(fd);
+                       return KSFT_FAIL;
+               }
+               if (compare_memory_tags(ptr, sizes[run], 0) != KSFT_PASS) {
+                       mte_free_memory((void *)ptr, sizes[run], mem_type, false);
+                       close(fd);
+                       return KSFT_FAIL;
+               }
+               mte_free_memory((void *)ptr, sizes[run], mem_type, false);
+               close(fd);
+       }
+       return KSFT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+       int err;
+       size_t page_size = getpagesize();
+       int item = sizeof(sizes)/sizeof(int);
+
+       sizes[item - 3] = page_size - 1;
+       sizes[item - 2] = page_size;
+       sizes[item - 1] = page_size + 1;
+
+       err = mte_default_setup();
+       if (err)
+               return err;
+
+       /* Register SIGSEGV handler */
+       mte_register_signal(SIGSEGV, mte_default_handler);
+
+       /* Buffer by byte tests */
+       evaluate_test(check_buffer_by_byte(USE_MMAP, MTE_SYNC_ERR),
+       "Check buffer correctness by byte with sync err mode and mmap memory\n");
+       evaluate_test(check_buffer_by_byte(USE_MMAP, MTE_ASYNC_ERR),
+       "Check buffer correctness by byte with async err mode and mmap memory\n");
+       evaluate_test(check_buffer_by_byte(USE_MPROTECT, MTE_SYNC_ERR),
+       "Check buffer correctness by byte with sync err mode and mmap/mprotect memory\n");
+       evaluate_test(check_buffer_by_byte(USE_MPROTECT, MTE_ASYNC_ERR),
+       "Check buffer correctness by byte with async err mode and mmap/mprotect memory\n");
+
+       /* Check buffer underflow with underflow size as 16 */
+       evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_SYNC_ERR, MT_GRANULE_SIZE),
+       "Check buffer write underflow by byte with sync mode and mmap memory\n");
+       evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_ASYNC_ERR, MT_GRANULE_SIZE),
+       "Check buffer write underflow by byte with async mode and mmap memory\n");
+       evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_NONE_ERR, MT_GRANULE_SIZE),
+       "Check buffer write underflow by byte with tag check fault ignore and mmap memory\n");
+
+       /* Check buffer underflow with underflow size as page size */
+       evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_SYNC_ERR, page_size),
+       "Check buffer write underflow by byte with sync mode and mmap memory\n");
+       evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_ASYNC_ERR, page_size),
+       "Check buffer write underflow by byte with async mode and mmap memory\n");
+       evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_NONE_ERR, page_size),
+       "Check buffer write underflow by byte with tag check fault ignore and mmap memory\n");
+
+       /* Check buffer overflow with overflow size as 16 */
+       evaluate_test(check_buffer_overflow_by_byte(USE_MMAP, MTE_SYNC_ERR, MT_GRANULE_SIZE),
+       "Check buffer write overflow by byte with sync mode and mmap memory\n");
+       evaluate_test(check_buffer_overflow_by_byte(USE_MMAP, MTE_ASYNC_ERR, MT_GRANULE_SIZE),
+       "Check buffer write overflow by byte with async mode and mmap memory\n");
+       evaluate_test(check_buffer_overflow_by_byte(USE_MMAP, MTE_NONE_ERR, MT_GRANULE_SIZE),
+       "Check buffer write overflow by byte with tag fault ignore mode and mmap memory\n");
+
+       /* Buffer by block tests */
+       evaluate_test(check_buffer_by_block(USE_MMAP, MTE_SYNC_ERR),
+       "Check buffer write correctness by block with sync mode and mmap memory\n");
+       evaluate_test(check_buffer_by_block(USE_MMAP, MTE_ASYNC_ERR),
+       "Check buffer write correctness by block with async mode and mmap memory\n");
+       evaluate_test(check_buffer_by_block(USE_MMAP, MTE_NONE_ERR),
+       "Check buffer write correctness by block with tag fault ignore and mmap memory\n");
+
+       /* Initial tags are supposed to be 0 */
+       evaluate_test(check_memory_initial_tags(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
+       "Check initial tags with private mapping, sync error mode and mmap memory\n");
+       evaluate_test(check_memory_initial_tags(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE),
+       "Check initial tags with private mapping, sync error mode and mmap/mprotect memory\n");
+       evaluate_test(check_memory_initial_tags(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
+       "Check initial tags with shared mapping, sync error mode and mmap memory\n");
+       evaluate_test(check_memory_initial_tags(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED),
+       "Check initial tags with shared mapping, sync error mode and mmap/mprotect memory\n");
+
+       mte_restore_setup();
+       ksft_print_cnts();
+       return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
+}
diff --git a/tools/testing/selftests/arm64/mte/check_child_memory.c b/tools/testing/selftests/arm64/mte/check_child_memory.c
new file mode 100644 (file)
index 0000000..97bebde
--- /dev/null
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 ARM Limited
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+#include <sys/wait.h>
+
+#include "kselftest.h"
+#include "mte_common_util.h"
+#include "mte_def.h"
+
+#define BUFFER_SIZE            (5 * MT_GRANULE_SIZE)
+#define RUNS                   (MT_TAG_COUNT)
+#define UNDERFLOW              MT_GRANULE_SIZE
+#define OVERFLOW               MT_GRANULE_SIZE
+
+static size_t page_size;
+static int sizes[] = {
+       1, 537, 989, 1269, MT_GRANULE_SIZE - 1, MT_GRANULE_SIZE,
+       /* page size - 1*/ 0, /* page_size */ 0, /* page size + 1 */ 0
+};
+
+static int check_child_tag_inheritance(char *ptr, int size, int mode)
+{
+       int i, parent_tag, child_tag, fault, child_status;
+       pid_t child;
+
+       parent_tag = MT_FETCH_TAG((uintptr_t)ptr);
+       fault = 0;
+
+       child = fork();
+       if (child == -1) {
+               ksft_print_msg("FAIL: child process creation\n");
+               return KSFT_FAIL;
+       } else if (child == 0) {
+               mte_initialize_current_context(mode, (uintptr_t)ptr, size);
+               /* Do copy on write */
+               memset(ptr, '1', size);
+               mte_wait_after_trig();
+               if (cur_mte_cxt.fault_valid == true) {
+                       fault = 1;
+                       goto check_child_tag_inheritance_err;
+               }
+               for (i = 0 ; i < size ; i += MT_GRANULE_SIZE) {
+                       child_tag = MT_FETCH_TAG((uintptr_t)(mte_get_tag_address(ptr + i)));
+                       if (parent_tag != child_tag) {
+                               ksft_print_msg("FAIL: child mte tag mismatch\n");
+                               fault = 1;
+                               goto check_child_tag_inheritance_err;
+                       }
+               }
+               mte_initialize_current_context(mode, (uintptr_t)ptr, -UNDERFLOW);
+               memset(ptr - UNDERFLOW, '2', UNDERFLOW);
+               mte_wait_after_trig();
+               if (cur_mte_cxt.fault_valid == false) {
+                       fault = 1;
+                       goto check_child_tag_inheritance_err;
+               }
+               mte_initialize_current_context(mode, (uintptr_t)ptr, size + OVERFLOW);
+               memset(ptr + size, '3', OVERFLOW);
+               mte_wait_after_trig();
+               if (cur_mte_cxt.fault_valid == false) {
+                       fault = 1;
+                       goto check_child_tag_inheritance_err;
+               }
+check_child_tag_inheritance_err:
+               _exit(fault);
+       }
+       /* Wait for child process to terminate */
+       wait(&child_status);
+       if (WIFEXITED(child_status))
+               fault = WEXITSTATUS(child_status);
+       else
+               fault = 1;
+       return (fault) ? KSFT_FAIL : KSFT_PASS;
+}
+
+static int check_child_memory_mapping(int mem_type, int mode, int mapping)
+{
+       char *ptr;
+       int run, result;
+       int item = sizeof(sizes)/sizeof(int);
+
+       item = sizeof(sizes)/sizeof(int);
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       for (run = 0; run < item; run++) {
+               ptr = (char *)mte_allocate_memory_tag_range(sizes[run], mem_type, mapping,
+                                                           UNDERFLOW, OVERFLOW);
+               if (check_allocated_memory_range(ptr, sizes[run], mem_type,
+                                                UNDERFLOW, OVERFLOW) != KSFT_PASS)
+                       return KSFT_FAIL;
+               result = check_child_tag_inheritance(ptr, sizes[run], mode);
+               mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW);
+               if (result == KSFT_FAIL)
+                       return result;
+       }
+       return KSFT_PASS;
+}
+
+static int check_child_file_mapping(int mem_type, int mode, int mapping)
+{
+       char *ptr, *map_ptr;
+       int run, fd, map_size, result = KSFT_PASS;
+       int total = sizeof(sizes)/sizeof(int);
+
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       for (run = 0; run < total; run++) {
+               fd = create_temp_file();
+               if (fd == -1)
+                       return KSFT_FAIL;
+
+               map_size = sizes[run] + OVERFLOW + UNDERFLOW;
+               map_ptr = (char *)mte_allocate_file_memory(map_size, mem_type, mapping, false, fd);
+               if (check_allocated_memory(map_ptr, map_size, mem_type, false) != KSFT_PASS) {
+                       close(fd);
+                       return KSFT_FAIL;
+               }
+               ptr = map_ptr + UNDERFLOW;
+               mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[run]);
+               /* Only mte enabled memory will allow tag insertion */
+               ptr = mte_insert_tags((void *)ptr, sizes[run]);
+               if (!ptr || cur_mte_cxt.fault_valid == true) {
+                       ksft_print_msg("FAIL: Insert tags on file based memory\n");
+                       munmap((void *)map_ptr, map_size);
+                       close(fd);
+                       return KSFT_FAIL;
+               }
+               result = check_child_tag_inheritance(ptr, sizes[run], mode);
+               mte_clear_tags((void *)ptr, sizes[run]);
+               munmap((void *)map_ptr, map_size);
+               close(fd);
+               if (result != KSFT_PASS)
+                       return KSFT_FAIL;
+       }
+       return KSFT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+       int err;
+       int item = sizeof(sizes)/sizeof(int);
+
+       page_size = getpagesize();
+       if (!page_size) {
+               ksft_print_msg("ERR: Unable to get page size\n");
+               return KSFT_FAIL;
+       }
+       sizes[item - 3] = page_size - 1;
+       sizes[item - 2] = page_size;
+       sizes[item - 1] = page_size + 1;
+
+       err = mte_default_setup();
+       if (err)
+               return err;
+
+       /* Register SIGSEGV handler */
+       mte_register_signal(SIGSEGV, mte_default_handler);
+       mte_register_signal(SIGBUS, mte_default_handler);
+
+       evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
+               "Check child anonymous memory with private mapping, precise mode and mmap memory\n");
+       evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
+               "Check child anonymous memory with shared mapping, precise mode and mmap memory\n");
+       evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
+               "Check child anonymous memory with private mapping, imprecise mode and mmap memory\n");
+       evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
+               "Check child anonymous memory with shared mapping, imprecise mode and mmap memory\n");
+       evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE),
+               "Check child anonymous memory with private mapping, precise mode and mmap/mprotect memory\n");
+       evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED),
+               "Check child anonymous memory with shared mapping, precise mode and mmap/mprotect memory\n");
+
+       evaluate_test(check_child_file_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
+               "Check child file memory with private mapping, precise mode and mmap memory\n");
+       evaluate_test(check_child_file_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
+               "Check child file memory with shared mapping, precise mode and mmap memory\n");
+       evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
+               "Check child file memory with private mapping, imprecise mode and mmap memory\n");
+       evaluate_test(check_child_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
+               "Check child file memory with shared mapping, imprecise mode and mmap memory\n");
+       evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE),
+               "Check child file memory with private mapping, precise mode and mmap/mprotect memory\n");
+       evaluate_test(check_child_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED),
+               "Check child file memory with shared mapping, precise mode and mmap/mprotect memory\n");
+
+       mte_restore_setup();
+       ksft_print_cnts();
+       return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
+}
diff --git a/tools/testing/selftests/arm64/mte/check_ksm_options.c b/tools/testing/selftests/arm64/mte/check_ksm_options.c
new file mode 100644 (file)
index 0000000..bc41ae6
--- /dev/null
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 ARM Limited
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+#include <sys/mman.h>
+
+#include "kselftest.h"
+#include "mte_common_util.h"
+#include "mte_def.h"
+
+#define TEST_UNIT      10
+#define PATH_KSM       "/sys/kernel/mm/ksm/"
+#define MAX_LOOP       4
+
+static size_t page_sz;
+static unsigned long ksm_sysfs[5];
+
+static unsigned long read_sysfs(char *str)
+{
+       FILE *f;
+       unsigned long val = 0;
+
+       f = fopen(str, "r");
+       if (!f) {
+               ksft_print_msg("ERR: missing %s\n", str);
+               return 0;
+       }
+       fscanf(f, "%lu", &val);
+       fclose(f);
+       return val;
+}
+
+static void write_sysfs(char *str, unsigned long val)
+{
+       FILE *f;
+
+       f = fopen(str, "w");
+       if (!f) {
+               ksft_print_msg("ERR: missing %s\n", str);
+               return;
+       }
+       fprintf(f, "%lu", val);
+       fclose(f);
+}
+
+static void mte_ksm_setup(void)
+{
+       ksm_sysfs[0] = read_sysfs(PATH_KSM "merge_across_nodes");
+       write_sysfs(PATH_KSM "merge_across_nodes", 1);
+       ksm_sysfs[1] = read_sysfs(PATH_KSM "sleep_millisecs");
+       write_sysfs(PATH_KSM "sleep_millisecs", 0);
+       ksm_sysfs[2] = read_sysfs(PATH_KSM "run");
+       write_sysfs(PATH_KSM "run", 1);
+       ksm_sysfs[3] = read_sysfs(PATH_KSM "max_page_sharing");
+       write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3] + TEST_UNIT);
+       ksm_sysfs[4] = read_sysfs(PATH_KSM "pages_to_scan");
+       write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4] + TEST_UNIT);
+}
+
+static void mte_ksm_restore(void)
+{
+       write_sysfs(PATH_KSM "merge_across_nodes", ksm_sysfs[0]);
+       write_sysfs(PATH_KSM "sleep_millisecs", ksm_sysfs[1]);
+       write_sysfs(PATH_KSM "run", ksm_sysfs[2]);
+       write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3]);
+       write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4]);
+}
+
+static void mte_ksm_scan(void)
+{
+       int cur_count = read_sysfs(PATH_KSM "full_scans");
+       int scan_count = cur_count + 1;
+       int max_loop_count = MAX_LOOP;
+
+       while ((cur_count < scan_count) && max_loop_count) {
+               sleep(1);
+               cur_count = read_sysfs(PATH_KSM "full_scans");
+               max_loop_count--;
+       }
+#ifdef DEBUG
+       ksft_print_msg("INFO: pages_shared=%lu pages_sharing=%lu\n",
+                       read_sysfs(PATH_KSM "pages_shared"),
+                       read_sysfs(PATH_KSM "pages_sharing"));
+#endif
+}
+
+static int check_madvise_options(int mem_type, int mode, int mapping)
+{
+       char *ptr;
+       int err, ret;
+
+       err = KSFT_FAIL;
+       if (access(PATH_KSM, F_OK) == -1) {
+               ksft_print_msg("ERR: Kernel KSM config not enabled\n");
+               return err;
+       }
+
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       ptr = mte_allocate_memory(TEST_UNIT * page_sz, mem_type, mapping, true);
+       if (check_allocated_memory(ptr, TEST_UNIT * page_sz, mem_type, false) != KSFT_PASS)
+               return KSFT_FAIL;
+
+       /* Insert same data in all the pages */
+       memset(ptr, 'A', TEST_UNIT * page_sz);
+       ret = madvise(ptr, TEST_UNIT * page_sz, MADV_MERGEABLE);
+       if (ret) {
+               ksft_print_msg("ERR: madvise failed to set MADV_UNMERGEABLE\n");
+               goto madvise_err;
+       }
+       mte_ksm_scan();
+       /* Tagged pages should not merge */
+       if ((read_sysfs(PATH_KSM "pages_shared") < 1) ||
+           (read_sysfs(PATH_KSM "pages_sharing") < (TEST_UNIT - 1)))
+               err = KSFT_PASS;
+madvise_err:
+       mte_free_memory(ptr, TEST_UNIT * page_sz, mem_type, true);
+       return err;
+}
+
+int main(int argc, char *argv[])
+{
+       int err;
+
+       err = mte_default_setup();
+       if (err)
+               return err;
+       page_sz = getpagesize();
+       if (!page_sz) {
+               ksft_print_msg("ERR: Unable to get page size\n");
+               return KSFT_FAIL;
+       }
+       /* Register signal handlers */
+       mte_register_signal(SIGBUS, mte_default_handler);
+       mte_register_signal(SIGSEGV, mte_default_handler);
+       /* Enable KSM */
+       mte_ksm_setup();
+
+       evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
+               "Check KSM mte page merge for private mapping, sync mode and mmap memory\n");
+       evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
+               "Check KSM mte page merge for private mapping, async mode and mmap memory\n");
+       evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
+               "Check KSM mte page merge for shared mapping, sync mode and mmap memory\n");
+       evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
+               "Check KSM mte page merge for shared mapping, async mode and mmap memory\n");
+
+       mte_ksm_restore();
+       mte_restore_setup();
+       ksft_print_cnts();
+       return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
+}
diff --git a/tools/testing/selftests/arm64/mte/check_mmap_options.c b/tools/testing/selftests/arm64/mte/check_mmap_options.c
new file mode 100644 (file)
index 0000000..33b13b8
--- /dev/null
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 ARM Limited
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "kselftest.h"
+#include "mte_common_util.h"
+#include "mte_def.h"
+
+#define RUNS                   (MT_TAG_COUNT)
+#define UNDERFLOW              MT_GRANULE_SIZE
+#define OVERFLOW               MT_GRANULE_SIZE
+#define TAG_CHECK_ON           0
+#define TAG_CHECK_OFF          1
+
+static size_t page_size;
+static int sizes[] = {
+       1, 537, 989, 1269, MT_GRANULE_SIZE - 1, MT_GRANULE_SIZE,
+       /* page size - 1*/ 0, /* page_size */ 0, /* page size + 1 */ 0
+};
+
+static int check_mte_memory(char *ptr, int size, int mode, int tag_check)
+{
+       mte_initialize_current_context(mode, (uintptr_t)ptr, size);
+       memset(ptr, '1', size);
+       mte_wait_after_trig();
+       if (cur_mte_cxt.fault_valid == true)
+               return KSFT_FAIL;
+
+       mte_initialize_current_context(mode, (uintptr_t)ptr, -UNDERFLOW);
+       memset(ptr - UNDERFLOW, '2', UNDERFLOW);
+       mte_wait_after_trig();
+       if (cur_mte_cxt.fault_valid == false && tag_check == TAG_CHECK_ON)
+               return KSFT_FAIL;
+       if (cur_mte_cxt.fault_valid == true && tag_check == TAG_CHECK_OFF)
+               return KSFT_FAIL;
+
+       mte_initialize_current_context(mode, (uintptr_t)ptr, size + OVERFLOW);
+       memset(ptr + size, '3', OVERFLOW);
+       mte_wait_after_trig();
+       if (cur_mte_cxt.fault_valid == false && tag_check == TAG_CHECK_ON)
+               return KSFT_FAIL;
+       if (cur_mte_cxt.fault_valid == true && tag_check == TAG_CHECK_OFF)
+               return KSFT_FAIL;
+
+       return KSFT_PASS;
+}
+
+static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping, int tag_check)
+{
+       char *ptr, *map_ptr;
+       int run, result, map_size;
+       int item = sizeof(sizes)/sizeof(int);
+
+       item = sizeof(sizes)/sizeof(int);
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       for (run = 0; run < item; run++) {
+               map_size = sizes[run] + OVERFLOW + UNDERFLOW;
+               map_ptr = (char *)mte_allocate_memory(map_size, mem_type, mapping, false);
+               if (check_allocated_memory(map_ptr, map_size, mem_type, false) != KSFT_PASS)
+                       return KSFT_FAIL;
+
+               ptr = map_ptr + UNDERFLOW;
+               mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[run]);
+               /* Only mte enabled memory will allow tag insertion */
+               ptr = mte_insert_tags((void *)ptr, sizes[run]);
+               if (!ptr || cur_mte_cxt.fault_valid == true) {
+                       ksft_print_msg("FAIL: Insert tags on anonymous mmap memory\n");
+                       munmap((void *)map_ptr, map_size);
+                       return KSFT_FAIL;
+               }
+               result = check_mte_memory(ptr, sizes[run], mode, tag_check);
+               mte_clear_tags((void *)ptr, sizes[run]);
+               mte_free_memory((void *)map_ptr, map_size, mem_type, false);
+               if (result == KSFT_FAIL)
+                       return KSFT_FAIL;
+       }
+       return KSFT_PASS;
+}
+
+static int check_file_memory_mapping(int mem_type, int mode, int mapping, int tag_check)
+{
+       char *ptr, *map_ptr;
+       int run, fd, map_size;
+       int total = sizeof(sizes)/sizeof(int);
+       int result = KSFT_PASS;
+
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       for (run = 0; run < total; run++) {
+               fd = create_temp_file();
+               if (fd == -1)
+                       return KSFT_FAIL;
+
+               map_size = sizes[run] + UNDERFLOW + OVERFLOW;
+               map_ptr = (char *)mte_allocate_file_memory(map_size, mem_type, mapping, false, fd);
+               if (check_allocated_memory(map_ptr, map_size, mem_type, false) != KSFT_PASS) {
+                       close(fd);
+                       return KSFT_FAIL;
+               }
+               ptr = map_ptr + UNDERFLOW;
+               mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[run]);
+               /* Only mte enabled memory will allow tag insertion */
+               ptr = mte_insert_tags((void *)ptr, sizes[run]);
+               if (!ptr || cur_mte_cxt.fault_valid == true) {
+                       ksft_print_msg("FAIL: Insert tags on file based memory\n");
+                       munmap((void *)map_ptr, map_size);
+                       close(fd);
+                       return KSFT_FAIL;
+               }
+               result = check_mte_memory(ptr, sizes[run], mode, tag_check);
+               mte_clear_tags((void *)ptr, sizes[run]);
+               munmap((void *)map_ptr, map_size);
+               close(fd);
+               if (result == KSFT_FAIL)
+                       break;
+       }
+       return result;
+}
+
+static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping)
+{
+       char *ptr, *map_ptr;
+       int run, prot_flag, result, fd, map_size;
+       int total = sizeof(sizes)/sizeof(int);
+
+       prot_flag = PROT_READ | PROT_WRITE;
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       for (run = 0; run < total; run++) {
+               map_size = sizes[run] + OVERFLOW + UNDERFLOW;
+               ptr = (char *)mte_allocate_memory_tag_range(sizes[run], mem_type, mapping,
+                                                           UNDERFLOW, OVERFLOW);
+               if (check_allocated_memory_range(ptr, sizes[run], mem_type,
+                                                UNDERFLOW, OVERFLOW) != KSFT_PASS)
+                       return KSFT_FAIL;
+               map_ptr = ptr - UNDERFLOW;
+               /* Try to clear PROT_MTE property and verify it by tag checking */
+               if (mprotect(map_ptr, map_size, prot_flag)) {
+                       mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type,
+                                                 UNDERFLOW, OVERFLOW);
+                       ksft_print_msg("FAIL: mprotect not ignoring clear PROT_MTE property\n");
+                       return KSFT_FAIL;
+               }
+               result = check_mte_memory(ptr, sizes[run], mode, TAG_CHECK_ON);
+               mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW);
+               if (result != KSFT_PASS)
+                       return KSFT_FAIL;
+
+               fd = create_temp_file();
+               if (fd == -1)
+                       return KSFT_FAIL;
+               ptr = (char *)mte_allocate_file_memory_tag_range(sizes[run], mem_type, mapping,
+                                                                UNDERFLOW, OVERFLOW, fd);
+               if (check_allocated_memory_range(ptr, sizes[run], mem_type,
+                                                UNDERFLOW, OVERFLOW) != KSFT_PASS) {
+                       close(fd);
+                       return KSFT_FAIL;
+               }
+               map_ptr = ptr - UNDERFLOW;
+               /* Try to clear PROT_MTE property and verify it by tag checking */
+               if (mprotect(map_ptr, map_size, prot_flag)) {
+                       ksft_print_msg("FAIL: mprotect not ignoring clear PROT_MTE property\n");
+                       mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type,
+                                                 UNDERFLOW, OVERFLOW);
+                       close(fd);
+                       return KSFT_FAIL;
+               }
+               result = check_mte_memory(ptr, sizes[run], mode, TAG_CHECK_ON);
+               mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW);
+               close(fd);
+               if (result != KSFT_PASS)
+                       return KSFT_FAIL;
+       }
+       return KSFT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+       int err;
+       int item = sizeof(sizes)/sizeof(int);
+
+       err = mte_default_setup();
+       if (err)
+               return err;
+       page_size = getpagesize();
+       if (!page_size) {
+               ksft_print_msg("ERR: Unable to get page size\n");
+               return KSFT_FAIL;
+       }
+       sizes[item - 3] = page_size - 1;
+       sizes[item - 2] = page_size;
+       sizes[item - 1] = page_size + 1;
+
+       /* Register signal handlers */
+       mte_register_signal(SIGBUS, mte_default_handler);
+       mte_register_signal(SIGSEGV, mte_default_handler);
+
+       mte_enable_pstate_tco();
+       evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF),
+       "Check anonymous memory with private mapping, sync error mode, mmap memory and tag check off\n");
+       evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF),
+       "Check file memory with private mapping, sync error mode, mmap/mprotect memory and tag check off\n");
+
+       mte_disable_pstate_tco();
+       evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF),
+       "Check anonymous memory with private mapping, no error mode, mmap memory and tag check off\n");
+       evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF),
+       "Check file memory with private mapping, no error mode, mmap/mprotect memory and tag check off\n");
+
+       evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
+       "Check anonymous memory with private mapping, sync error mode, mmap memory and tag check on\n");
+       evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
+       "Check anonymous memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n");
+       evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
+       "Check anonymous memory with shared mapping, sync error mode, mmap memory and tag check on\n");
+       evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
+       "Check anonymous memory with shared mapping, sync error mode, mmap/mprotect memory and tag check on\n");
+       evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
+       "Check anonymous memory with private mapping, async error mode, mmap memory and tag check on\n");
+       evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
+       "Check anonymous memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n");
+       evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
+       "Check anonymous memory with shared mapping, async error mode, mmap memory and tag check on\n");
+       evaluate_test(check_anonymous_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
+       "Check anonymous memory with shared mapping, async error mode, mmap/mprotect memory and tag check on\n");
+
+       evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
+       "Check file memory with private mapping, sync error mode, mmap memory and tag check on\n");
+       evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
+       "Check file memory with private mapping, sync error mode, mmap/mprotect memory and tag check on\n");
+       evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
+       "Check file memory with shared mapping, sync error mode, mmap memory and tag check on\n");
+       evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
+       "Check file memory with shared mapping, sync error mode, mmap/mprotect memory and tag check on\n");
+       evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
+       "Check file memory with private mapping, async error mode, mmap memory and tag check on\n");
+       evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON),
+       "Check file memory with private mapping, async error mode, mmap/mprotect memory and tag check on\n");
+       evaluate_test(check_file_memory_mapping(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
+       "Check file memory with shared mapping, async error mode, mmap memory and tag check on\n");
+       evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_ASYNC_ERR, MAP_SHARED, TAG_CHECK_ON),
+       "Check file memory with shared mapping, async error mode, mmap/mprotect memory and tag check on\n");
+
+       evaluate_test(check_clear_prot_mte_flag(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
+       "Check clear PROT_MTE flags with private mapping, sync error mode and mmap memory\n");
+       evaluate_test(check_clear_prot_mte_flag(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE),
+       "Check clear PROT_MTE flags with private mapping and sync error mode and mmap/mprotect memory\n");
+
+       mte_restore_setup();
+       ksft_print_cnts();
+       return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
+}
diff --git a/tools/testing/selftests/arm64/mte/check_tags_inclusion.c b/tools/testing/selftests/arm64/mte/check_tags_inclusion.c
new file mode 100644 (file)
index 0000000..94d245a
--- /dev/null
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 ARM Limited
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+#include <sys/wait.h>
+
+#include "kselftest.h"
+#include "mte_common_util.h"
+#include "mte_def.h"
+
+#define BUFFER_SIZE            (5 * MT_GRANULE_SIZE)
+#define RUNS                   (MT_TAG_COUNT * 2)
+#define MTE_LAST_TAG_MASK      (0x7FFF)
+
+static int verify_mte_pointer_validity(char *ptr, int mode)
+{
+       mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE);
+       /* Check the validity of the tagged pointer */
+       memset((void *)ptr, '1', BUFFER_SIZE);
+       mte_wait_after_trig();
+       if (cur_mte_cxt.fault_valid)
+               return KSFT_FAIL;
+       /* Proceed further for nonzero tags */
+       if (!MT_FETCH_TAG((uintptr_t)ptr))
+               return KSFT_PASS;
+       mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE + 1);
+       /* Check the validity outside the range */
+       ptr[BUFFER_SIZE] = '2';
+       mte_wait_after_trig();
+       if (!cur_mte_cxt.fault_valid)
+               return KSFT_FAIL;
+       else
+               return KSFT_PASS;
+}
+
+static int check_single_included_tags(int mem_type, int mode)
+{
+       char *ptr;
+       int tag, run, result = KSFT_PASS;
+
+       ptr = (char *)mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
+       if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
+                                  mem_type, false) != KSFT_PASS)
+               return KSFT_FAIL;
+
+       for (tag = 0; (tag < MT_TAG_COUNT) && (result == KSFT_PASS); tag++) {
+               mte_switch_mode(mode, MT_INCLUDE_VALID_TAG(tag));
+               /* Try to catch a excluded tag by a number of tries. */
+               for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
+                       ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
+                       /* Check tag value */
+                       if (MT_FETCH_TAG((uintptr_t)ptr) == tag) {
+                               ksft_print_msg("FAIL: wrong tag = 0x%x with include mask=0x%x\n",
+                                              MT_FETCH_TAG((uintptr_t)ptr),
+                                              MT_INCLUDE_VALID_TAG(tag));
+                               result = KSFT_FAIL;
+                               break;
+                       }
+                       result = verify_mte_pointer_validity(ptr, mode);
+               }
+       }
+       mte_free_memory_tag_range((void *)ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
+       return result;
+}
+
+static int check_multiple_included_tags(int mem_type, int mode)
+{
+       char *ptr;
+       int tag, run, result = KSFT_PASS;
+       unsigned long excl_mask = 0;
+
+       ptr = (char *)mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
+       if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
+                                  mem_type, false) != KSFT_PASS)
+               return KSFT_FAIL;
+
+       for (tag = 0; (tag < MT_TAG_COUNT - 1) && (result == KSFT_PASS); tag++) {
+               excl_mask |= 1 << tag;
+               mte_switch_mode(mode, MT_INCLUDE_VALID_TAGS(excl_mask));
+               /* Try to catch a excluded tag by a number of tries. */
+               for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
+                       ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
+                       /* Check tag value */
+                       if (MT_FETCH_TAG((uintptr_t)ptr) < tag) {
+                               ksft_print_msg("FAIL: wrong tag = 0x%x with include mask=0x%x\n",
+                                              MT_FETCH_TAG((uintptr_t)ptr),
+                                              MT_INCLUDE_VALID_TAGS(excl_mask));
+                               result = KSFT_FAIL;
+                               break;
+                       }
+                       result = verify_mte_pointer_validity(ptr, mode);
+               }
+       }
+       mte_free_memory_tag_range((void *)ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
+       return result;
+}
+
+static int check_all_included_tags(int mem_type, int mode)
+{
+       char *ptr;
+       int run, result = KSFT_PASS;
+
+       ptr = (char *)mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
+       if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
+                                  mem_type, false) != KSFT_PASS)
+               return KSFT_FAIL;
+
+       mte_switch_mode(mode, MT_INCLUDE_TAG_MASK);
+       /* Try to catch a excluded tag by a number of tries. */
+       for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
+               ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
+               /*
+                * Here tag byte can be between 0x0 to 0xF (full allowed range)
+                * so no need to match so just verify if it is writable.
+                */
+               result = verify_mte_pointer_validity(ptr, mode);
+       }
+       mte_free_memory_tag_range((void *)ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
+       return result;
+}
+
+static int check_none_included_tags(int mem_type, int mode)
+{
+       char *ptr;
+       int run;
+
+       ptr = (char *)mte_allocate_memory(BUFFER_SIZE, mem_type, 0, false);
+       if (check_allocated_memory(ptr, BUFFER_SIZE, mem_type, false) != KSFT_PASS)
+               return KSFT_FAIL;
+
+       mte_switch_mode(mode, MT_EXCLUDE_TAG_MASK);
+       /* Try to catch a excluded tag by a number of tries. */
+       for (run = 0; run < RUNS; run++) {
+               ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
+               /* Here all tags exluded so tag value generated should be 0 */
+               if (MT_FETCH_TAG((uintptr_t)ptr)) {
+                       ksft_print_msg("FAIL: included tag value found\n");
+                       mte_free_memory((void *)ptr, BUFFER_SIZE, mem_type, true);
+                       return KSFT_FAIL;
+               }
+               mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE);
+               /* Check the write validity of the untagged pointer */
+               memset((void *)ptr, '1', BUFFER_SIZE);
+               mte_wait_after_trig();
+               if (cur_mte_cxt.fault_valid)
+                       break;
+       }
+       mte_free_memory((void *)ptr, BUFFER_SIZE, mem_type, false);
+       if (cur_mte_cxt.fault_valid)
+               return KSFT_FAIL;
+       else
+               return KSFT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+       int err;
+
+       err = mte_default_setup();
+       if (err)
+               return err;
+
+       /* Register SIGSEGV handler */
+       mte_register_signal(SIGSEGV, mte_default_handler);
+
+       evaluate_test(check_single_included_tags(USE_MMAP, MTE_SYNC_ERR),
+                     "Check an included tag value with sync mode\n");
+       evaluate_test(check_multiple_included_tags(USE_MMAP, MTE_SYNC_ERR),
+                     "Check different included tags value with sync mode\n");
+       evaluate_test(check_none_included_tags(USE_MMAP, MTE_SYNC_ERR),
+                     "Check none included tags value with sync mode\n");
+       evaluate_test(check_all_included_tags(USE_MMAP, MTE_SYNC_ERR),
+                     "Check all included tags value with sync mode\n");
+
+       mte_restore_setup();
+       ksft_print_cnts();
+       return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
+}
diff --git a/tools/testing/selftests/arm64/mte/check_user_mem.c b/tools/testing/selftests/arm64/mte/check_user_mem.c
new file mode 100644 (file)
index 0000000..594e98e
--- /dev/null
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 ARM Limited
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ucontext.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "kselftest.h"
+#include "mte_common_util.h"
+#include "mte_def.h"
+
+static size_t page_sz;
+
+static int check_usermem_access_fault(int mem_type, int mode, int mapping)
+{
+       int fd, i, err;
+       char val = 'A';
+       size_t len, read_len;
+       void *ptr, *ptr_next;
+
+       err = KSFT_FAIL;
+       len = 2 * page_sz;
+       mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+       fd = create_temp_file();
+       if (fd == -1)
+               return KSFT_FAIL;
+       for (i = 0; i < len; i++)
+               write(fd, &val, sizeof(val));
+       lseek(fd, 0, 0);
+       ptr = mte_allocate_memory(len, mem_type, mapping, true);
+       if (check_allocated_memory(ptr, len, mem_type, true) != KSFT_PASS) {
+               close(fd);
+               return KSFT_FAIL;
+       }
+       mte_initialize_current_context(mode, (uintptr_t)ptr, len);
+       /* Copy from file into buffer with valid tag */
+       read_len = read(fd, ptr, len);
+       mte_wait_after_trig();
+       if (cur_mte_cxt.fault_valid || read_len < len)
+               goto usermem_acc_err;
+       /* Verify same pattern is read */
+       for (i = 0; i < len; i++)
+               if (*(char *)(ptr + i) != val)
+                       break;
+       if (i < len)
+               goto usermem_acc_err;
+
+       /* Tag the next half of memory with different value */
+       ptr_next = (void *)((unsigned long)ptr + page_sz);
+       ptr_next = mte_insert_new_tag(ptr_next);
+       mte_set_tag_address_range(ptr_next, page_sz);
+
+       lseek(fd, 0, 0);
+       /* Copy from file into buffer with invalid tag */
+       read_len = read(fd, ptr, len);
+       mte_wait_after_trig();
+       /*
+        * Accessing user memory in kernel with invalid tag should fail in sync
+        * mode without fault but may not fail in async mode as per the
+        * implemented MTE userspace support in Arm64 kernel.
+        */
+       if (mode == MTE_SYNC_ERR &&
+           !cur_mte_cxt.fault_valid && read_len < len) {
+               err = KSFT_PASS;
+       } else if (mode == MTE_ASYNC_ERR &&
+                  !cur_mte_cxt.fault_valid && read_len == len) {
+               err = KSFT_PASS;
+       }
+usermem_acc_err:
+       mte_free_memory((void *)ptr, len, mem_type, true);
+       close(fd);
+       return err;
+}
+
+int main(int argc, char *argv[])
+{
+       int err;
+
+       page_sz = getpagesize();
+       if (!page_sz) {
+               ksft_print_msg("ERR: Unable to get page size\n");
+               return KSFT_FAIL;
+       }
+       err = mte_default_setup();
+       if (err)
+               return err;
+       /* Register signal handlers */
+       mte_register_signal(SIGSEGV, mte_default_handler);
+
+       evaluate_test(check_usermem_access_fault(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
+               "Check memory access from kernel in sync mode, private mapping and mmap memory\n");
+       evaluate_test(check_usermem_access_fault(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
+               "Check memory access from kernel in sync mode, shared mapping and mmap memory\n");
+
+       evaluate_test(check_usermem_access_fault(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
+               "Check memory access from kernel in async mode, private mapping and mmap memory\n");
+       evaluate_test(check_usermem_access_fault(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
+               "Check memory access from kernel in async mode, shared mapping and mmap memory\n");
+
+       mte_restore_setup();
+       ksft_print_cnts();
+       return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
+}
diff --git a/tools/testing/selftests/arm64/mte/mte_common_util.c b/tools/testing/selftests/arm64/mte/mte_common_util.c
new file mode 100644 (file)
index 0000000..39f8908
--- /dev/null
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 ARM Limited
+
+#include <fcntl.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <linux/auxvec.h>
+#include <sys/auxv.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+
+#include <asm/hwcap.h>
+
+#include "kselftest.h"
+#include "mte_common_util.h"
+#include "mte_def.h"
+
+#define INIT_BUFFER_SIZE       256
+
+struct mte_fault_cxt cur_mte_cxt;
+static unsigned int mte_cur_mode;
+static unsigned int mte_cur_pstate_tco;
+
+void mte_default_handler(int signum, siginfo_t *si, void *uc)
+{
+       unsigned long addr = (unsigned long)si->si_addr;
+
+       if (signum == SIGSEGV) {
+#ifdef DEBUG
+               ksft_print_msg("INFO: SIGSEGV signal at pc=%lx, fault addr=%lx, si_code=%lx\n",
+                               ((ucontext_t *)uc)->uc_mcontext.pc, addr, si->si_code);
+#endif
+               if (si->si_code == SEGV_MTEAERR) {
+                       if (cur_mte_cxt.trig_si_code == si->si_code)
+                               cur_mte_cxt.fault_valid = true;
+                       return;
+               }
+               /* Compare the context for precise error */
+               else if (si->si_code == SEGV_MTESERR) {
+                       if (cur_mte_cxt.trig_si_code == si->si_code &&
+                           ((cur_mte_cxt.trig_range >= 0 &&
+                             addr >= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) &&
+                             addr <= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range)) ||
+                            (cur_mte_cxt.trig_range < 0 &&
+                             addr <= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) &&
+                             addr >= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range)))) {
+                               cur_mte_cxt.fault_valid = true;
+                               /* Adjust the pc by 4 */
+                               ((ucontext_t *)uc)->uc_mcontext.pc += 4;
+                       } else {
+                               ksft_print_msg("Invalid MTE synchronous exception caught!\n");
+                               exit(1);
+                       }
+               } else {
+                       ksft_print_msg("Unknown SIGSEGV exception caught!\n");
+                       exit(1);
+               }
+       } else if (signum == SIGBUS) {
+               ksft_print_msg("INFO: SIGBUS signal at pc=%lx, fault addr=%lx, si_code=%lx\n",
+                               ((ucontext_t *)uc)->uc_mcontext.pc, addr, si->si_code);
+               if ((cur_mte_cxt.trig_range >= 0 &&
+                    addr >= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) &&
+                    addr <= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range)) ||
+                   (cur_mte_cxt.trig_range < 0 &&
+                    addr <= MT_CLEAR_TAG(cur_mte_cxt.trig_addr) &&
+                    addr >= (MT_CLEAR_TAG(cur_mte_cxt.trig_addr) + cur_mte_cxt.trig_range))) {
+                       cur_mte_cxt.fault_valid = true;
+                       /* Adjust the pc by 4 */
+                       ((ucontext_t *)uc)->uc_mcontext.pc += 4;
+               }
+       }
+}
+
+void mte_register_signal(int signal, void (*handler)(int, siginfo_t *, void *))
+{
+       struct sigaction sa;
+
+       sa.sa_sigaction = handler;
+       sa.sa_flags = SA_SIGINFO;
+       sigemptyset(&sa.sa_mask);
+       sigaction(signal, &sa, NULL);
+}
+
+void mte_wait_after_trig(void)
+{
+       sched_yield();
+}
+
+void *mte_insert_tags(void *ptr, size_t size)
+{
+       void *tag_ptr;
+       int align_size;
+
+       if (!ptr || (unsigned long)(ptr) & MT_ALIGN_GRANULE) {
+               ksft_print_msg("FAIL: Addr=%lx: invalid\n", ptr);
+               return NULL;
+       }
+       align_size = MT_ALIGN_UP(size);
+       tag_ptr = mte_insert_random_tag(ptr);
+       mte_set_tag_address_range(tag_ptr, align_size);
+       return tag_ptr;
+}
+
+void mte_clear_tags(void *ptr, size_t size)
+{
+       if (!ptr || (unsigned long)(ptr) & MT_ALIGN_GRANULE) {
+               ksft_print_msg("FAIL: Addr=%lx: invalid\n", ptr);
+               return;
+       }
+       size = MT_ALIGN_UP(size);
+       ptr = (void *)MT_CLEAR_TAG((unsigned long)ptr);
+       mte_clear_tag_address_range(ptr, size);
+}
+
+static void *__mte_allocate_memory_range(size_t size, int mem_type, int mapping,
+                                        size_t range_before, size_t range_after,
+                                        bool tags, int fd)
+{
+       void *ptr;
+       int prot_flag, map_flag;
+       size_t entire_size = size + range_before + range_after;
+
+       if (mem_type != USE_MALLOC && mem_type != USE_MMAP &&
+           mem_type != USE_MPROTECT) {
+               ksft_print_msg("FAIL: Invalid allocate request\n");
+               return NULL;
+       }
+       if (mem_type == USE_MALLOC)
+               return malloc(entire_size) + range_before;
+
+       prot_flag = PROT_READ | PROT_WRITE;
+       if (mem_type == USE_MMAP)
+               prot_flag |= PROT_MTE;
+
+       map_flag = mapping;
+       if (fd == -1)
+               map_flag = MAP_ANONYMOUS | map_flag;
+       if (!(mapping & MAP_SHARED))
+               map_flag |= MAP_PRIVATE;
+       ptr = mmap(NULL, entire_size, prot_flag, map_flag, fd, 0);
+       if (ptr == MAP_FAILED) {
+               ksft_print_msg("FAIL: mmap allocation\n");
+               return NULL;
+       }
+       if (mem_type == USE_MPROTECT) {
+               if (mprotect(ptr, entire_size, prot_flag | PROT_MTE)) {
+                       munmap(ptr, size);
+                       ksft_print_msg("FAIL: mprotect PROT_MTE property\n");
+                       return NULL;
+               }
+       }
+       if (tags)
+               ptr = mte_insert_tags(ptr + range_before, size);
+       return ptr;
+}
+
+void *mte_allocate_memory_tag_range(size_t size, int mem_type, int mapping,
+                                   size_t range_before, size_t range_after)
+{
+       return __mte_allocate_memory_range(size, mem_type, mapping, range_before,
+                                          range_after, true, -1);
+}
+
+void *mte_allocate_memory(size_t size, int mem_type, int mapping, bool tags)
+{
+       return __mte_allocate_memory_range(size, mem_type, mapping, 0, 0, tags, -1);
+}
+
+void *mte_allocate_file_memory(size_t size, int mem_type, int mapping, bool tags, int fd)
+{
+       int index;
+       char buffer[INIT_BUFFER_SIZE];
+
+       if (mem_type != USE_MPROTECT && mem_type != USE_MMAP) {
+               ksft_print_msg("FAIL: Invalid mmap file request\n");
+               return NULL;
+       }
+       /* Initialize the file for mappable size */
+       lseek(fd, 0, SEEK_SET);
+       for (index = INIT_BUFFER_SIZE; index < size; index += INIT_BUFFER_SIZE)
+               write(fd, buffer, INIT_BUFFER_SIZE);
+       index -= INIT_BUFFER_SIZE;
+       write(fd, buffer, size - index);
+       return __mte_allocate_memory_range(size, mem_type, mapping, 0, 0, tags, fd);
+}
+
+void *mte_allocate_file_memory_tag_range(size_t size, int mem_type, int mapping,
+                                        size_t range_before, size_t range_after, int fd)
+{
+       int index;
+       char buffer[INIT_BUFFER_SIZE];
+       int map_size = size + range_before + range_after;
+
+       if (mem_type != USE_MPROTECT && mem_type != USE_MMAP) {
+               ksft_print_msg("FAIL: Invalid mmap file request\n");
+               return NULL;
+       }
+       /* Initialize the file for mappable size */
+       lseek(fd, 0, SEEK_SET);
+       for (index = INIT_BUFFER_SIZE; index < map_size; index += INIT_BUFFER_SIZE)
+               write(fd, buffer, INIT_BUFFER_SIZE);
+       index -= INIT_BUFFER_SIZE;
+       write(fd, buffer, map_size - index);
+       return __mte_allocate_memory_range(size, mem_type, mapping, range_before,
+                                          range_after, true, fd);
+}
+
+static void __mte_free_memory_range(void *ptr, size_t size, int mem_type,
+                                   size_t range_before, size_t range_after, bool tags)
+{
+       switch (mem_type) {
+       case USE_MALLOC:
+               free(ptr - range_before);
+               break;
+       case USE_MMAP:
+       case USE_MPROTECT:
+               if (tags)
+                       mte_clear_tags(ptr, size);
+               munmap(ptr - range_before, size + range_before + range_after);
+               break;
+       default:
+               ksft_print_msg("FAIL: Invalid free request\n");
+               break;
+       }
+}
+
+void mte_free_memory_tag_range(void *ptr, size_t size, int mem_type,
+                              size_t range_before, size_t range_after)
+{
+       __mte_free_memory_range(ptr, size, mem_type, range_before, range_after, true);
+}
+
+void mte_free_memory(void *ptr, size_t size, int mem_type, bool tags)
+{
+       __mte_free_memory_range(ptr, size, mem_type, 0, 0, tags);
+}
+
+void mte_initialize_current_context(int mode, uintptr_t ptr, ssize_t range)
+{
+       cur_mte_cxt.fault_valid = false;
+       cur_mte_cxt.trig_addr = ptr;
+       cur_mte_cxt.trig_range = range;
+       if (mode == MTE_SYNC_ERR)
+               cur_mte_cxt.trig_si_code = SEGV_MTESERR;
+       else if (mode == MTE_ASYNC_ERR)
+               cur_mte_cxt.trig_si_code = SEGV_MTEAERR;
+       else
+               cur_mte_cxt.trig_si_code = 0;
+}
+
+int mte_switch_mode(int mte_option, unsigned long incl_mask)
+{
+       unsigned long en = 0;
+
+       if (!(mte_option == MTE_SYNC_ERR || mte_option == MTE_ASYNC_ERR ||
+             mte_option == MTE_NONE_ERR || incl_mask <= MTE_ALLOW_NON_ZERO_TAG)) {
+               ksft_print_msg("FAIL: Invalid mte config option\n");
+               return -EINVAL;
+       }
+       en = PR_TAGGED_ADDR_ENABLE;
+       if (mte_option == MTE_SYNC_ERR)
+               en |= PR_MTE_TCF_SYNC;
+       else if (mte_option == MTE_ASYNC_ERR)
+               en |= PR_MTE_TCF_ASYNC;
+       else if (mte_option == MTE_NONE_ERR)
+               en |= PR_MTE_TCF_NONE;
+
+       en |= (incl_mask << PR_MTE_TAG_SHIFT);
+       /* Enable address tagging ABI, mte error reporting mode and tag inclusion mask. */
+       if (!prctl(PR_SET_TAGGED_ADDR_CTRL, en, 0, 0, 0) == 0) {
+               ksft_print_msg("FAIL:prctl PR_SET_TAGGED_ADDR_CTRL for mte mode\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+#define ID_AA64PFR1_MTE_SHIFT          8
+#define ID_AA64PFR1_MTE                        2
+
+int mte_default_setup(void)
+{
+       unsigned long hwcaps = getauxval(AT_HWCAP);
+       unsigned long en = 0;
+       int ret;
+
+       if (!(hwcaps & HWCAP_CPUID)) {
+               ksft_print_msg("FAIL: CPUID registers unavailable\n");
+               return KSFT_FAIL;
+       }
+       /* Read ID_AA64PFR1_EL1 register */
+       asm volatile("mrs %0, id_aa64pfr1_el1" : "=r"(hwcaps) : : "memory");
+       if (((hwcaps >> ID_AA64PFR1_MTE_SHIFT) & MT_TAG_MASK) != ID_AA64PFR1_MTE) {
+               ksft_print_msg("FAIL: MTE features unavailable\n");
+               return KSFT_SKIP;
+       }
+       /* Get current mte mode */
+       ret = prctl(PR_GET_TAGGED_ADDR_CTRL, en, 0, 0, 0);
+       if (ret < 0) {
+               ksft_print_msg("FAIL:prctl PR_GET_TAGGED_ADDR_CTRL with error =%d\n", ret);
+               return KSFT_FAIL;
+       }
+       if (ret & PR_MTE_TCF_SYNC)
+               mte_cur_mode = MTE_SYNC_ERR;
+       else if (ret & PR_MTE_TCF_ASYNC)
+               mte_cur_mode = MTE_ASYNC_ERR;
+       else if (ret & PR_MTE_TCF_NONE)
+               mte_cur_mode = MTE_NONE_ERR;
+
+       mte_cur_pstate_tco = mte_get_pstate_tco();
+       /* Disable PSTATE.TCO */
+       mte_disable_pstate_tco();
+       return 0;
+}
+
+void mte_restore_setup(void)
+{
+       mte_switch_mode(mte_cur_mode, MTE_ALLOW_NON_ZERO_TAG);
+       if (mte_cur_pstate_tco == MT_PSTATE_TCO_EN)
+               mte_enable_pstate_tco();
+       else if (mte_cur_pstate_tco == MT_PSTATE_TCO_DIS)
+               mte_disable_pstate_tco();
+}
+
+int create_temp_file(void)
+{
+       int fd;
+       char filename[] = "/dev/shm/tmp_XXXXXX";
+
+       /* Create a file in the tmpfs filesystem */
+       fd = mkstemp(&filename[0]);
+       if (fd == -1) {
+               ksft_print_msg("FAIL: Unable to open temporary file\n");
+               return 0;
+       }
+       unlink(&filename[0]);
+       return fd;
+}
diff --git a/tools/testing/selftests/arm64/mte/mte_common_util.h b/tools/testing/selftests/arm64/mte/mte_common_util.h
new file mode 100644 (file)
index 0000000..195a7d1
--- /dev/null
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020 ARM Limited */
+
+#ifndef _MTE_COMMON_UTIL_H
+#define _MTE_COMMON_UTIL_H
+
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/auxv.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include "mte_def.h"
+#include "kselftest.h"
+
+enum mte_mem_type {
+       USE_MALLOC,
+       USE_MMAP,
+       USE_MPROTECT,
+};
+
+enum mte_mode {
+       MTE_NONE_ERR,
+       MTE_SYNC_ERR,
+       MTE_ASYNC_ERR,
+};
+
+struct mte_fault_cxt {
+       /* Address start which triggers mte tag fault */
+       unsigned long trig_addr;
+       /* Address range for mte tag fault and negative value means underflow */
+       ssize_t trig_range;
+       /* siginfo si code */
+       unsigned long trig_si_code;
+       /* Flag to denote if correct fault caught */
+       bool fault_valid;
+};
+
+extern struct mte_fault_cxt cur_mte_cxt;
+
+/* MTE utility functions */
+void mte_default_handler(int signum, siginfo_t *si, void *uc);
+void mte_register_signal(int signal, void (*handler)(int, siginfo_t *, void *));
+void mte_wait_after_trig(void);
+void *mte_allocate_memory(size_t size, int mem_type, int mapping, bool tags);
+void *mte_allocate_memory_tag_range(size_t size, int mem_type, int mapping,
+                                   size_t range_before, size_t range_after);
+void *mte_allocate_file_memory(size_t size, int mem_type, int mapping,
+                              bool tags, int fd);
+void *mte_allocate_file_memory_tag_range(size_t size, int mem_type, int mapping,
+                                        size_t range_before, size_t range_after, int fd);
+void mte_free_memory(void *ptr, size_t size, int mem_type, bool tags);
+void mte_free_memory_tag_range(void *ptr, size_t size, int mem_type,
+                              size_t range_before, size_t range_after);
+void *mte_insert_tags(void *ptr, size_t size);
+void mte_clear_tags(void *ptr, size_t size);
+int mte_default_setup(void);
+void mte_restore_setup(void);
+int mte_switch_mode(int mte_option, unsigned long incl_mask);
+void mte_initialize_current_context(int mode, uintptr_t ptr, ssize_t range);
+
+/* Common utility functions */
+int create_temp_file(void);
+
+/* Assembly MTE utility functions */
+void *mte_insert_random_tag(void *ptr);
+void *mte_insert_new_tag(void *ptr);
+void *mte_get_tag_address(void *ptr);
+void mte_set_tag_address_range(void *ptr, int range);
+void mte_clear_tag_address_range(void *ptr, int range);
+void mte_disable_pstate_tco(void);
+void mte_enable_pstate_tco(void);
+unsigned int mte_get_pstate_tco(void);
+
+/* Test framework static inline functions/macros */
+static inline void evaluate_test(int err, const char *msg)
+{
+       if (err == KSFT_PASS)
+               ksft_test_result_pass(msg);
+       else if (err == KSFT_FAIL)
+               ksft_test_result_fail(msg);
+}
+
+static inline int check_allocated_memory(void *ptr, size_t size,
+                                        int mem_type, bool tags)
+{
+       if (ptr == NULL) {
+               ksft_print_msg("FAIL: memory allocation\n");
+               return KSFT_FAIL;
+       }
+
+       if (tags && !MT_FETCH_TAG((uintptr_t)ptr)) {
+               ksft_print_msg("FAIL: tag not found at addr(%p)\n", ptr);
+               mte_free_memory((void *)ptr, size, mem_type, false);
+               return KSFT_FAIL;
+       }
+
+       return KSFT_PASS;
+}
+
+static inline int check_allocated_memory_range(void *ptr, size_t size, int mem_type,
+                                              size_t range_before, size_t range_after)
+{
+       if (ptr == NULL) {
+               ksft_print_msg("FAIL: memory allocation\n");
+               return KSFT_FAIL;
+       }
+
+       if (!MT_FETCH_TAG((uintptr_t)ptr)) {
+               ksft_print_msg("FAIL: tag not found at addr(%p)\n", ptr);
+               mte_free_memory_tag_range((void *)ptr, size, mem_type, range_before,
+                                         range_after);
+               return KSFT_FAIL;
+       }
+       return KSFT_PASS;
+}
+
+#endif /* _MTE_COMMON_UTIL_H */
diff --git a/tools/testing/selftests/arm64/mte/mte_def.h b/tools/testing/selftests/arm64/mte/mte_def.h
new file mode 100644 (file)
index 0000000..9b18825
--- /dev/null
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020 ARM Limited */
+
+/*
+ * Below definitions may be found in kernel headers, However, they are
+ * redefined here to decouple the MTE selftests compilations from them.
+ */
+#ifndef SEGV_MTEAERR
+#define        SEGV_MTEAERR    8
+#endif
+#ifndef SEGV_MTESERR
+#define        SEGV_MTESERR    9
+#endif
+#ifndef PROT_MTE
+#define PROT_MTE        0x20
+#endif
+#ifndef HWCAP2_MTE
+#define HWCAP2_MTE     (1 << 18)
+#endif
+
+#ifndef PR_MTE_TCF_SHIFT
+#define PR_MTE_TCF_SHIFT       1
+#endif
+#ifndef PR_MTE_TCF_NONE
+#define PR_MTE_TCF_NONE                (0UL << PR_MTE_TCF_SHIFT)
+#endif
+#ifndef PR_MTE_TCF_SYNC
+#define        PR_MTE_TCF_SYNC         (1UL << PR_MTE_TCF_SHIFT)
+#endif
+#ifndef PR_MTE_TCF_ASYNC
+#define PR_MTE_TCF_ASYNC       (2UL << PR_MTE_TCF_SHIFT)
+#endif
+#ifndef PR_MTE_TAG_SHIFT
+#define        PR_MTE_TAG_SHIFT        3
+#endif
+
+/* MTE Hardware feature definitions below. */
+#define MT_TAG_SHIFT           56
+#define MT_TAG_MASK            0xFUL
+#define MT_FREE_TAG            0x0UL
+#define MT_GRANULE_SIZE         16
+#define MT_TAG_COUNT           16
+#define MT_INCLUDE_TAG_MASK    0xFFFF
+#define MT_EXCLUDE_TAG_MASK    0x0
+
+#define MT_ALIGN_GRANULE       (MT_GRANULE_SIZE - 1)
+#define MT_CLEAR_TAG(x)                ((x) & ~(MT_TAG_MASK << MT_TAG_SHIFT))
+#define MT_SET_TAG(x, y)       ((x) | (y << MT_TAG_SHIFT))
+#define MT_FETCH_TAG(x)                ((x >> MT_TAG_SHIFT) & (MT_TAG_MASK))
+#define MT_ALIGN_UP(x)         ((x + MT_ALIGN_GRANULE) & ~(MT_ALIGN_GRANULE))
+
+#define MT_PSTATE_TCO_SHIFT    25
+#define MT_PSTATE_TCO_MASK     ~(0x1 << MT_PSTATE_TCO_SHIFT)
+#define MT_PSTATE_TCO_EN       1
+#define MT_PSTATE_TCO_DIS      0
+
+#define MT_EXCLUDE_TAG(x)              (1 << (x))
+#define MT_INCLUDE_VALID_TAG(x)                (MT_INCLUDE_TAG_MASK ^ MT_EXCLUDE_TAG(x))
+#define MT_INCLUDE_VALID_TAGS(x)       (MT_INCLUDE_TAG_MASK ^ (x))
+#define MTE_ALLOW_NON_ZERO_TAG         MT_INCLUDE_VALID_TAG(0)
diff --git a/tools/testing/selftests/arm64/mte/mte_helper.S b/tools/testing/selftests/arm64/mte/mte_helper.S
new file mode 100644 (file)
index 0000000..a02c04c
--- /dev/null
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020 ARM Limited */
+
+#include "mte_def.h"
+
+#define ENTRY(name) \
+       .globl name ;\
+       .p2align 2;\
+       .type name, @function ;\
+name:
+
+#define ENDPROC(name) \
+       .size name, .-name ;
+
+       .text
+/*
+ * mte_insert_random_tag: Insert random tag and might be same as the source tag if
+ *                       the source pointer has it.
+ * Input:
+ *             x0 - source pointer with a tag/no-tag
+ * Return:
+ *             x0 - pointer with random tag
+ */
+ENTRY(mte_insert_random_tag)
+       irg     x0, x0, xzr
+       ret
+ENDPROC(mte_insert_random_tag)
+
+/*
+ * mte_insert_new_tag: Insert new tag and different from the source tag if
+ *                    source pointer has it.
+ * Input:
+ *             x0 - source pointer with a tag/no-tag
+ * Return:
+ *             x0 - pointer with random tag
+ */
+ENTRY(mte_insert_new_tag)
+       gmi     x1, x0, xzr
+       irg     x0, x0, x1
+       ret
+ENDPROC(mte_insert_new_tag)
+
+/*
+ * mte_get_tag_address: Get the tag from given address.
+ * Input:
+ *             x0 - source pointer
+ * Return:
+ *             x0 - pointer with appended tag
+ */
+ENTRY(mte_get_tag_address)
+       ldg     x0, [x0]
+       ret
+ENDPROC(mte_get_tag_address)
+
+/*
+ * mte_set_tag_address_range: Set the tag range from the given address
+ * Input:
+ *             x0 - source pointer with tag data
+ *             x1 - range
+ * Return:
+ *             none
+ */
+ENTRY(mte_set_tag_address_range)
+       cbz     x1, 2f
+1:
+       stg     x0, [x0, #0x0]
+       add     x0, x0, #MT_GRANULE_SIZE
+       sub     x1, x1, #MT_GRANULE_SIZE
+       cbnz    x1, 1b
+2:
+       ret
+ENDPROC(mte_set_tag_address_range)
+
+/*
+ * mt_clear_tag_address_range: Clear the tag range from the given address
+ * Input:
+ *             x0 - source pointer with tag data
+ *             x1 - range
+ * Return:
+ *             none
+ */
+ENTRY(mte_clear_tag_address_range)
+       cbz     x1, 2f
+1:
+       stzg    x0, [x0, #0x0]
+       add     x0, x0, #MT_GRANULE_SIZE
+       sub     x1, x1, #MT_GRANULE_SIZE
+       cbnz    x1, 1b
+2:
+       ret
+ENDPROC(mte_clear_tag_address_range)
+
+/*
+ * mte_enable_pstate_tco: Enable PSTATE.TCO (tag check override) field
+ * Input:
+ *             none
+ * Return:
+ *             none
+ */
+ENTRY(mte_enable_pstate_tco)
+       msr     tco, #MT_PSTATE_TCO_EN
+       ret
+ENDPROC(mte_enable_pstate_tco)
+
+/*
+ * mte_disable_pstate_tco: Disable PSTATE.TCO (tag check override) field
+ * Input:
+ *             none
+ * Return:
+ *             none
+ */
+ENTRY(mte_disable_pstate_tco)
+       msr     tco, #MT_PSTATE_TCO_DIS
+       ret
+ENDPROC(mte_disable_pstate_tco)
+
+/*
+ * mte_get_pstate_tco: Get PSTATE.TCO (tag check override) field
+ * Input:
+ *             none
+ * Return:
+ *             x0
+ */
+ENTRY(mte_get_pstate_tco)
+       mrs     x0, tco
+       ubfx    x0, x0, #MT_PSTATE_TCO_SHIFT, #1
+       ret
+ENDPROC(mte_get_pstate_tco)
diff --git a/tools/testing/selftests/arm64/pauth/.gitignore b/tools/testing/selftests/arm64/pauth/.gitignore
new file mode 100644 (file)
index 0000000..155137d
--- /dev/null
@@ -0,0 +1,2 @@
+exec_target
+pac
diff --git a/tools/testing/selftests/arm64/pauth/Makefile b/tools/testing/selftests/arm64/pauth/Makefile
new file mode 100644 (file)
index 0000000..72e290b
--- /dev/null
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020 ARM Limited
+
+# preserve CC value from top level Makefile
+ifeq ($(CC),cc)
+CC := $(CROSS_COMPILE)gcc
+endif
+
+CFLAGS += -mbranch-protection=pac-ret
+# check if the compiler supports ARMv8.3 and branch protection with PAuth
+pauth_cc_support := $(shell if ($(CC) $(CFLAGS) -march=armv8.3-a -E -x c /dev/null -o /dev/null 2>&1) then echo "1"; fi)
+
+ifeq ($(pauth_cc_support),1)
+TEST_GEN_PROGS := pac
+TEST_GEN_FILES := pac_corruptor.o helper.o
+TEST_GEN_PROGS_EXTENDED := exec_target
+endif
+
+include ../../lib.mk
+
+ifeq ($(pauth_cc_support),1)
+# pac* and aut* instructions are not available on architectures berfore
+# ARMv8.3. Therefore target ARMv8.3 wherever they are used directly
+$(OUTPUT)/pac_corruptor.o: pac_corruptor.S
+       $(CC) -c $^ -o $@ $(CFLAGS) -march=armv8.3-a
+
+$(OUTPUT)/helper.o: helper.c
+       $(CC) -c $^ -o $@ $(CFLAGS) -march=armv8.3-a
+
+# when -mbranch-protection is enabled and the target architecture is ARMv8.3 or
+# greater, gcc emits pac* instructions which are not in HINT NOP space,
+# preventing the tests from occurring at all. Compile for ARMv8.2 so tests can
+# run on earlier targets and print a meaningful error messages
+$(OUTPUT)/exec_target: exec_target.c $(OUTPUT)/helper.o
+       $(CC) $^ -o $@ $(CFLAGS) -march=armv8.2-a
+
+$(OUTPUT)/pac: pac.c $(OUTPUT)/pac_corruptor.o $(OUTPUT)/helper.o
+       $(CC) $^ -o $@ $(CFLAGS) -march=armv8.2-a
+endif
diff --git a/tools/testing/selftests/arm64/pauth/exec_target.c b/tools/testing/selftests/arm64/pauth/exec_target.c
new file mode 100644 (file)
index 0000000..4435600
--- /dev/null
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 ARM Limited
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/auxv.h>
+
+#include "helper.h"
+
+int main(void)
+{
+       struct signatures signed_vals;
+       unsigned long hwcaps;
+       size_t val;
+
+       fread(&val, sizeof(size_t), 1, stdin);
+
+       /* don't try to execute illegal (unimplemented) instructions) caller
+        * should have checked this and keep worker simple
+        */
+       hwcaps = getauxval(AT_HWCAP);
+
+       if (hwcaps & HWCAP_PACA) {
+               signed_vals.keyia = keyia_sign(val);
+               signed_vals.keyib = keyib_sign(val);
+               signed_vals.keyda = keyda_sign(val);
+               signed_vals.keydb = keydb_sign(val);
+       }
+       signed_vals.keyg = (hwcaps & HWCAP_PACG) ?  keyg_sign(val) : 0;
+
+       fwrite(&signed_vals, sizeof(struct signatures), 1, stdout);
+
+       return 0;
+}
diff --git a/tools/testing/selftests/arm64/pauth/helper.c b/tools/testing/selftests/arm64/pauth/helper.c
new file mode 100644 (file)
index 0000000..2c201e7
--- /dev/null
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 ARM Limited
+
+#include "helper.h"
+
+size_t keyia_sign(size_t ptr)
+{
+       asm volatile("paciza %0" : "+r" (ptr));
+       return ptr;
+}
+
+size_t keyib_sign(size_t ptr)
+{
+       asm volatile("pacizb %0" : "+r" (ptr));
+       return ptr;
+}
+
+size_t keyda_sign(size_t ptr)
+{
+       asm volatile("pacdza %0" : "+r" (ptr));
+       return ptr;
+}
+
+size_t keydb_sign(size_t ptr)
+{
+       asm volatile("pacdzb %0" : "+r" (ptr));
+       return ptr;
+}
+
+size_t keyg_sign(size_t ptr)
+{
+       /* output is encoded in the upper 32 bits */
+       size_t dest = 0;
+       size_t modifier = 0;
+
+       asm volatile("pacga %0, %1, %2" : "=r" (dest) : "r" (ptr), "r" (modifier));
+
+       return dest;
+}
diff --git a/tools/testing/selftests/arm64/pauth/helper.h b/tools/testing/selftests/arm64/pauth/helper.h
new file mode 100644 (file)
index 0000000..652496c
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020 ARM Limited */
+
+#ifndef _HELPER_H_
+#define _HELPER_H_
+
+#include <stdlib.h>
+
+#define NKEYS 5
+
+struct signatures {
+       size_t keyia;
+       size_t keyib;
+       size_t keyda;
+       size_t keydb;
+       size_t keyg;
+};
+
+void pac_corruptor(void);
+
+/* PAuth sign a value with key ia and modifier value 0 */
+size_t keyia_sign(size_t val);
+size_t keyib_sign(size_t val);
+size_t keyda_sign(size_t val);
+size_t keydb_sign(size_t val);
+size_t keyg_sign(size_t val);
+
+#endif
diff --git a/tools/testing/selftests/arm64/pauth/pac.c b/tools/testing/selftests/arm64/pauth/pac.c
new file mode 100644 (file)
index 0000000..592fe53
--- /dev/null
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 ARM Limited
+
+#define _GNU_SOURCE
+
+#include <sys/auxv.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sched.h>
+
+#include "../../kselftest_harness.h"
+#include "helper.h"
+
+#define PAC_COLLISION_ATTEMPTS 10
+/*
+ * The kernel sets TBID by default. So bits 55 and above should remain
+ * untouched no matter what.
+ * The VA space size is 48 bits. Bigger is opt-in.
+ */
+#define PAC_MASK (~0xff80ffffffffffff)
+#define ARBITRARY_VALUE (0x1234)
+#define ASSERT_PAUTH_ENABLED() \
+do { \
+       unsigned long hwcaps = getauxval(AT_HWCAP); \
+       /* data key instructions are not in NOP space. This prevents a SIGILL */ \
+       ASSERT_NE(0, hwcaps & HWCAP_PACA) TH_LOG("PAUTH not enabled"); \
+} while (0)
+#define ASSERT_GENERIC_PAUTH_ENABLED() \
+do { \
+       unsigned long hwcaps = getauxval(AT_HWCAP); \
+       /* generic key instructions are not in NOP space. This prevents a SIGILL */ \
+       ASSERT_NE(0, hwcaps & HWCAP_PACG) TH_LOG("Generic PAUTH not enabled"); \
+} while (0)
+
+void sign_specific(struct signatures *sign, size_t val)
+{
+       sign->keyia = keyia_sign(val);
+       sign->keyib = keyib_sign(val);
+       sign->keyda = keyda_sign(val);
+       sign->keydb = keydb_sign(val);
+}
+
+void sign_all(struct signatures *sign, size_t val)
+{
+       sign->keyia = keyia_sign(val);
+       sign->keyib = keyib_sign(val);
+       sign->keyda = keyda_sign(val);
+       sign->keydb = keydb_sign(val);
+       sign->keyg  = keyg_sign(val);
+}
+
+int n_same(struct signatures *old, struct signatures *new, int nkeys)
+{
+       int res = 0;
+
+       res += old->keyia == new->keyia;
+       res += old->keyib == new->keyib;
+       res += old->keyda == new->keyda;
+       res += old->keydb == new->keydb;
+       if (nkeys == NKEYS)
+               res += old->keyg == new->keyg;
+
+       return res;
+}
+
+int n_same_single_set(struct signatures *sign, int nkeys)
+{
+       size_t vals[nkeys];
+       int same = 0;
+
+       vals[0] = sign->keyia & PAC_MASK;
+       vals[1] = sign->keyib & PAC_MASK;
+       vals[2] = sign->keyda & PAC_MASK;
+       vals[3] = sign->keydb & PAC_MASK;
+
+       if (nkeys >= 4)
+               vals[4] = sign->keyg & PAC_MASK;
+
+       for (int i = 0; i < nkeys - 1; i++) {
+               for (int j = i + 1; j < nkeys; j++) {
+                       if (vals[i] == vals[j])
+                               same += 1;
+               }
+       }
+       return same;
+}
+
+int exec_sign_all(struct signatures *signed_vals, size_t val)
+{
+       int new_stdin[2];
+       int new_stdout[2];
+       int status;
+       int i;
+       ssize_t ret;
+       pid_t pid;
+       cpu_set_t mask;
+
+       ret = pipe(new_stdin);
+       if (ret == -1) {
+               perror("pipe returned error");
+               return -1;
+       }
+
+       ret = pipe(new_stdout);
+       if (ret == -1) {
+               perror("pipe returned error");
+               return -1;
+       }
+
+       /*
+        * pin this process and all its children to a single CPU, so it can also
+        * guarantee a context switch with its child
+        */
+       sched_getaffinity(0, sizeof(mask), &mask);
+
+       for (i = 0; i < sizeof(cpu_set_t); i++)
+               if (CPU_ISSET(i, &mask))
+                       break;
+
+       CPU_ZERO(&mask);
+       CPU_SET(i, &mask);
+       sched_setaffinity(0, sizeof(mask), &mask);
+
+       pid = fork();
+       // child
+       if (pid == 0) {
+               dup2(new_stdin[0], STDIN_FILENO);
+               if (ret == -1) {
+                       perror("dup2 returned error");
+                       exit(1);
+               }
+
+               dup2(new_stdout[1], STDOUT_FILENO);
+               if (ret == -1) {
+                       perror("dup2 returned error");
+                       exit(1);
+               }
+
+               close(new_stdin[0]);
+               close(new_stdin[1]);
+               close(new_stdout[0]);
+               close(new_stdout[1]);
+
+               ret = execl("exec_target", "exec_target", (char *)NULL);
+               if (ret == -1) {
+                       perror("exec returned error");
+                       exit(1);
+               }
+       }
+
+       close(new_stdin[0]);
+       close(new_stdout[1]);
+
+       ret = write(new_stdin[1], &val, sizeof(size_t));
+       if (ret == -1) {
+               perror("write returned error");
+               return -1;
+       }
+
+       /*
+        * wait for the worker to finish, so that read() reads all data
+        * will also context switch with worker so that this function can be used
+        * for context switch tests
+        */
+       waitpid(pid, &status, 0);
+       if (WIFEXITED(status) == 0) {
+               fprintf(stderr, "worker exited unexpectedly\n");
+               return -1;
+       }
+       if (WEXITSTATUS(status) != 0) {
+               fprintf(stderr, "worker exited with error\n");
+               return -1;
+       }
+
+       ret = read(new_stdout[0], signed_vals, sizeof(struct signatures));
+       if (ret == -1) {
+               perror("read returned error");
+               return -1;
+       }
+
+       return 0;
+}
+
+sigjmp_buf jmpbuf;
+void pac_signal_handler(int signum, siginfo_t *si, void *uc)
+{
+       if (signum == SIGSEGV || signum == SIGILL)
+               siglongjmp(jmpbuf, 1);
+}
+
+/* check that a corrupted PAC results in SIGSEGV or SIGILL */
+TEST(corrupt_pac)
+{
+       struct sigaction sa;
+
+       ASSERT_PAUTH_ENABLED();
+       if (sigsetjmp(jmpbuf, 1) == 0) {
+               sa.sa_sigaction = pac_signal_handler;
+               sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
+               sigemptyset(&sa.sa_mask);
+
+               sigaction(SIGSEGV, &sa, NULL);
+               sigaction(SIGILL, &sa, NULL);
+
+               pac_corruptor();
+               ASSERT_TRUE(0) TH_LOG("SIGSEGV/SIGILL signal did not occur");
+       }
+}
+
+/*
+ * There are no separate pac* and aut* controls so checking only the pac*
+ * instructions is sufficient
+ */
+TEST(pac_instructions_not_nop)
+{
+       size_t keyia = 0;
+       size_t keyib = 0;
+       size_t keyda = 0;
+       size_t keydb = 0;
+
+       ASSERT_PAUTH_ENABLED();
+
+       for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++) {
+               keyia |= keyia_sign(i) & PAC_MASK;
+               keyib |= keyib_sign(i) & PAC_MASK;
+               keyda |= keyda_sign(i) & PAC_MASK;
+               keydb |= keydb_sign(i) & PAC_MASK;
+       }
+
+       ASSERT_NE(0, keyia) TH_LOG("keyia instructions did nothing");
+       ASSERT_NE(0, keyib) TH_LOG("keyib instructions did nothing");
+       ASSERT_NE(0, keyda) TH_LOG("keyda instructions did nothing");
+       ASSERT_NE(0, keydb) TH_LOG("keydb instructions did nothing");
+}
+
+TEST(pac_instructions_not_nop_generic)
+{
+       size_t keyg = 0;
+
+       ASSERT_GENERIC_PAUTH_ENABLED();
+
+       for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++)
+               keyg |= keyg_sign(i) & PAC_MASK;
+
+       ASSERT_NE(0, keyg)  TH_LOG("keyg instructions did nothing");
+}
+
+TEST(single_thread_different_keys)
+{
+       int same = 10;
+       int nkeys = NKEYS;
+       int tmp;
+       struct signatures signed_vals;
+       unsigned long hwcaps = getauxval(AT_HWCAP);
+
+       /* generic and data key instructions are not in NOP space. This prevents a SIGILL */
+       ASSERT_NE(0, hwcaps & HWCAP_PACA) TH_LOG("PAUTH not enabled");
+       if (!(hwcaps & HWCAP_PACG)) {
+               TH_LOG("WARNING: Generic PAUTH not enabled. Skipping generic key checks");
+               nkeys = NKEYS - 1;
+       }
+
+       /*
+        * In Linux the PAC field can be up to 7 bits wide. Even if keys are
+        * different, there is about 5% chance for PACs to collide with
+        * different addresses. This chance rapidly increases with fewer bits
+        * allocated for the PAC (e.g. wider address). A comparison of the keys
+        * directly will be more reliable.
+        * All signed values need to be different at least once out of n
+        * attempts to be certain that the keys are different
+        */
+       for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++) {
+               if (nkeys == NKEYS)
+                       sign_all(&signed_vals, i);
+               else
+                       sign_specific(&signed_vals, i);
+
+               tmp = n_same_single_set(&signed_vals, nkeys);
+               if (tmp < same)
+                       same = tmp;
+       }
+
+       ASSERT_EQ(0, same) TH_LOG("%d keys clashed every time", same);
+}
+
+/*
+ * fork() does not change keys. Only exec() does so call a worker program.
+ * Its only job is to sign a value and report back the resutls
+ */
+TEST(exec_changed_keys)
+{
+       struct signatures new_keys;
+       struct signatures old_keys;
+       int ret;
+       int same = 10;
+       int nkeys = NKEYS;
+       unsigned long hwcaps = getauxval(AT_HWCAP);
+
+       /* generic and data key instructions are not in NOP space. This prevents a SIGILL */
+       ASSERT_NE(0, hwcaps & HWCAP_PACA) TH_LOG("PAUTH not enabled");
+       if (!(hwcaps & HWCAP_PACG)) {
+               TH_LOG("WARNING: Generic PAUTH not enabled. Skipping generic key checks");
+               nkeys = NKEYS - 1;
+       }
+
+       for (int i = 0; i < PAC_COLLISION_ATTEMPTS; i++) {
+               ret = exec_sign_all(&new_keys, i);
+               ASSERT_EQ(0, ret) TH_LOG("failed to run worker");
+
+               if (nkeys == NKEYS)
+                       sign_all(&old_keys, i);
+               else
+                       sign_specific(&old_keys, i);
+
+               ret = n_same(&old_keys, &new_keys, nkeys);
+               if (ret < same)
+                       same = ret;
+       }
+
+       ASSERT_EQ(0, same) TH_LOG("exec() did not change %d keys", same);
+}
+
+TEST(context_switch_keep_keys)
+{
+       int ret;
+       struct signatures trash;
+       struct signatures before;
+       struct signatures after;
+
+       ASSERT_PAUTH_ENABLED();
+
+       sign_specific(&before, ARBITRARY_VALUE);
+
+       /* will context switch with a process with different keys at least once */
+       ret = exec_sign_all(&trash, ARBITRARY_VALUE);
+       ASSERT_EQ(0, ret) TH_LOG("failed to run worker");
+
+       sign_specific(&after, ARBITRARY_VALUE);
+
+       ASSERT_EQ(before.keyia, after.keyia) TH_LOG("keyia changed after context switching");
+       ASSERT_EQ(before.keyib, after.keyib) TH_LOG("keyib changed after context switching");
+       ASSERT_EQ(before.keyda, after.keyda) TH_LOG("keyda changed after context switching");
+       ASSERT_EQ(before.keydb, after.keydb) TH_LOG("keydb changed after context switching");
+}
+
+TEST(context_switch_keep_keys_generic)
+{
+       int ret;
+       struct signatures trash;
+       size_t before;
+       size_t after;
+
+       ASSERT_GENERIC_PAUTH_ENABLED();
+
+       before = keyg_sign(ARBITRARY_VALUE);
+
+       /* will context switch with a process with different keys at least once */
+       ret = exec_sign_all(&trash, ARBITRARY_VALUE);
+       ASSERT_EQ(0, ret) TH_LOG("failed to run worker");
+
+       after = keyg_sign(ARBITRARY_VALUE);
+
+       ASSERT_EQ(before, after) TH_LOG("keyg changed after context switching");
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/arm64/pauth/pac_corruptor.S b/tools/testing/selftests/arm64/pauth/pac_corruptor.S
new file mode 100644 (file)
index 0000000..aa65880
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020 ARM Limited */
+
+.global pac_corruptor
+
+.text
+/*
+ * Corrupting a single bit of the PAC ensures the authentication will fail.  It
+ * also guarantees no possible collision. TCR_EL1.TBI0 is set by default so no
+ * top byte PAC is tested
+ */
+ pac_corruptor:
+       paciasp
+
+       /* corrupt the top bit of the PAC */
+       eor lr, lr, #1 << 53
+
+       autiasp
+       ret
index 07ddbfd..6dfce3f 100644 (file)
@@ -47,7 +47,10 @@ int dump_bpf_hash_map(struct bpf_iter__bpf_map_elem *ctx)
        __u32 seq_num = ctx->meta->seq_num;
        struct bpf_map *map = ctx->map;
        struct key_t *key = ctx->key;
+       struct key_t tmp_key;
        __u64 *val = ctx->value;
+       __u64 tmp_val = 0;
+       int ret;
 
        if (in_test_mode) {
                /* test mode is used by selftests to
@@ -61,6 +64,18 @@ int dump_bpf_hash_map(struct bpf_iter__bpf_map_elem *ctx)
                if (key == (void *)0 || val == (void *)0)
                        return 0;
 
+               /* update the value and then delete the <key, value> pair.
+                * it should not impact the existing 'val' which is still
+                * accessible under rcu.
+                */
+               __builtin_memcpy(&tmp_key, key, sizeof(struct key_t));
+               ret = bpf_map_update_elem(&hashmap1, &tmp_key, &tmp_val, 0);
+               if (ret)
+                       return 0;
+               ret = bpf_map_delete_elem(&hashmap1, &tmp_key);
+               if (ret)
+                       return 0;
+
                key_sum_a += key->a;
                key_sum_b += key->b;
                key_sum_c += key->c;
index 754cf61..0d92ebc 100644 (file)
@@ -1274,6 +1274,8 @@ static void __run_parallel(unsigned int tasks,
        pid_t pid[tasks];
        int i;
 
+       fflush(stdout);
+
        for (i = 0; i < tasks; i++) {
                pid[i] = fork();
                if (pid[i] == 0) {
index b1e4dad..22943b5 100644 (file)
@@ -618,7 +618,9 @@ int cd_flavor_subdir(const char *exec_name)
        if (!flavor)
                return 0;
        flavor++;
-       fprintf(stdout, "Switching to flavor '%s' subdirectory...\n", flavor);
+       if (env.verbosity > VERBOSE_NONE)
+               fprintf(stdout, "Switching to flavor '%s' subdirectory...\n", flavor);
+
        return chdir(flavor);
 }
 
index b8d14f9..2fc6b3a 100644 (file)
@@ -73,7 +73,7 @@ int main(void)
        int i;
        /* Instruction lengths starting at ss_start */
        int ss_size[4] = {
-               3,              /* xor */
+               2,              /* xor */
                2,              /* cpuid */
                5,              /* mov */
                2,              /* rdmsr */
index 7c38a90..8a2fe6d 100755 (executable)
@@ -1175,6 +1175,51 @@ kci_test_neigh_get()
        echo "PASS: neigh get"
 }
 
+kci_test_bridge_parent_id()
+{
+       local ret=0
+       sysfsnet=/sys/bus/netdevsim/devices/netdevsim
+       probed=false
+
+       if [ ! -w /sys/bus/netdevsim/new_device ] ; then
+               modprobe -q netdevsim
+               check_err $?
+               if [ $ret -ne 0 ]; then
+                       echo "SKIP: bridge_parent_id can't load netdevsim"
+                       return $ksft_skip
+               fi
+               probed=true
+       fi
+
+       echo "10 1" > /sys/bus/netdevsim/new_device
+       while [ ! -d ${sysfsnet}10 ] ; do :; done
+       echo "20 1" > /sys/bus/netdevsim/new_device
+       while [ ! -d ${sysfsnet}20 ] ; do :; done
+       udevadm settle
+       dev10=`ls ${sysfsnet}10/net/`
+       dev20=`ls ${sysfsnet}20/net/`
+
+       ip link add name test-bond0 type bond mode 802.3ad
+       ip link set dev $dev10 master test-bond0
+       ip link set dev $dev20 master test-bond0
+       ip link add name test-br0 type bridge
+       ip link set dev test-bond0 master test-br0
+       check_err $?
+
+       # clean up any leftovers
+       ip link del dev test-br0
+       ip link del dev test-bond0
+       echo 20 > /sys/bus/netdevsim/del_device
+       echo 10 > /sys/bus/netdevsim/del_device
+       $probed && rmmod netdevsim
+
+       if [ $ret -ne 0 ]; then
+               echo "FAIL: bridge_parent_id"
+               return 1
+       fi
+       echo "PASS: bridge_parent_id"
+}
+
 kci_test_rtnl()
 {
        local ret=0
@@ -1224,6 +1269,8 @@ kci_test_rtnl()
        check_err $?
        kci_test_neigh_get
        check_err $?
+       kci_test_bridge_parent_id
+       check_err $?
 
        kci_del_dummy
        return $ret
index a47d1d8..431296c 100755 (executable)
@@ -11,7 +11,7 @@
 # result in fragmentation and/or PMTU discovery.
 #
 # You can check with different Orgininator/Link/Responder MTU eg:
-# sh nft_flowtable.sh -o1000 -l500 -r100
+# nft_flowtable.sh -o8000 -l1500 -r2000
 #
 
 
@@ -27,8 +27,7 @@ ns2out=""
 log_netns=$(sysctl -n net.netfilter.nf_log_all_netns)
 
 checktool (){
-       $1 > /dev/null 2>&1
-       if [ $? -ne 0 ];then
+       if ! $1 > /dev/null 2>&1; then
                echo "SKIP: Could not $2"
                exit $ksft_skip
        fi
@@ -87,19 +86,36 @@ omtu=9000
 lmtu=1500
 rmtu=2000
 
+usage(){
+       echo "nft_flowtable.sh [OPTIONS]"
+       echo
+       echo "MTU options"
+       echo "   -o originator"
+       echo "   -l link"
+       echo "   -r responder"
+       exit 1
+}
+
 while getopts "o:l:r:" o
 do
        case $o in
                o) omtu=$OPTARG;;
                l) lmtu=$OPTARG;;
                r) rmtu=$OPTARG;;
+               *) usage;;
        esac
 done
 
-ip -net nsr1 link set veth0 mtu $omtu
+if ! ip -net nsr1 link set veth0 mtu $omtu; then
+       exit 1
+fi
+
 ip -net ns1 link set eth0 mtu $omtu
 
-ip -net nsr2 link set veth1 mtu $rmtu
+if ! ip -net nsr2 link set veth1 mtu $rmtu; then
+       exit 1
+fi
+
 ip -net ns2 link set eth0 mtu $rmtu
 
 # transfer-net between nsr1 and nsr2.
@@ -120,7 +136,10 @@ for i in 1 2; do
   ip -net ns$i route add default via 10.0.$i.1
   ip -net ns$i addr add dead:$i::99/64 dev eth0
   ip -net ns$i route add default via dead:$i::1
-  ip netns exec ns$i sysctl net.ipv4.tcp_no_metrics_save=1 > /dev/null
+  if ! ip netns exec ns$i sysctl net.ipv4.tcp_no_metrics_save=1 > /dev/null; then
+       echo "ERROR: Check Originator/Responder values (problem during address addition)"
+       exit 1
+  fi
 
   # don't set ip DF bit for first two tests
   ip netns exec ns$i sysctl net.ipv4.ip_no_pmtu_disc=1 > /dev/null
@@ -178,15 +197,13 @@ if [ $? -ne 0 ]; then
 fi
 
 # test basic connectivity
-ip netns exec ns1 ping -c 1 -q 10.0.2.99 > /dev/null
-if [ $? -ne 0 ];then
+if ! ip netns exec ns1 ping -c 1 -q 10.0.2.99 > /dev/null; then
   echo "ERROR: ns1 cannot reach ns2" 1>&2
   bash
   exit 1
 fi
 
-ip netns exec ns2 ping -c 1 -q 10.0.1.99 > /dev/null
-if [ $? -ne 0 ];then
+if ! ip netns exec ns2 ping -c 1 -q 10.0.1.99 > /dev/null; then
   echo "ERROR: ns2 cannot reach ns1" 1>&2
   exit 1
 fi
@@ -203,7 +220,6 @@ ns2out=$(mktemp)
 make_file()
 {
        name=$1
-       who=$2
 
        SIZE=$((RANDOM % (1024 * 8)))
        TSIZE=$((SIZE * 1024))
@@ -222,8 +238,7 @@ check_transfer()
        out=$2
        what=$3
 
-       cmp "$in" "$out" > /dev/null 2>&1
-       if [ $? -ne 0 ] ;then
+       if ! cmp "$in" "$out" > /dev/null 2>&1; then
                echo "FAIL: file mismatch for $what" 1>&2
                ls -l "$in"
                ls -l "$out"
@@ -260,13 +275,11 @@ test_tcp_forwarding_ip()
 
        wait
 
-       check_transfer "$ns1in" "$ns2out" "ns1 -> ns2"
-       if [ $? -ne 0 ];then
+       if ! check_transfer "$ns1in" "$ns2out" "ns1 -> ns2"; then
                lret=1
        fi
 
-       check_transfer "$ns2in" "$ns1out" "ns1 <- ns2"
-       if [ $? -ne 0 ];then
+       if ! check_transfer "$ns2in" "$ns1out" "ns1 <- ns2"; then
                lret=1
        fi
 
@@ -295,13 +308,12 @@ test_tcp_forwarding_nat()
        return $lret
 }
 
-make_file "$ns1in" "ns1"
-make_file "$ns2in" "ns2"
+make_file "$ns1in"
+make_file "$ns2in"
 
 # First test:
 # No PMTU discovery, nsr1 is expected to fragment packets from ns1 to ns2 as needed.
-test_tcp_forwarding ns1 ns2
-if [ $? -eq 0 ] ;then
+if test_tcp_forwarding ns1 ns2; then
        echo "PASS: flow offloaded for ns1/ns2"
 else
        echo "FAIL: flow offload for ns1/ns2:" 1>&2
@@ -332,9 +344,7 @@ table ip nat {
 }
 EOF
 
-test_tcp_forwarding_nat ns1 ns2
-
-if [ $? -eq 0 ] ;then
+if test_tcp_forwarding_nat ns1 ns2; then
        echo "PASS: flow offloaded for ns1/ns2 with NAT"
 else
        echo "FAIL: flow offload for ns1/ns2 with NAT" 1>&2
@@ -346,8 +356,7 @@ fi
 # Same as second test, but with PMTU discovery enabled.
 handle=$(ip netns exec nsr1 nft -a list table inet filter | grep something-to-grep-for | cut -d \# -f 2)
 
-ip netns exec nsr1 nft delete rule inet filter forward $handle
-if [ $? -ne 0 ] ;then
+if ! ip netns exec nsr1 nft delete rule inet filter forward $handle; then
        echo "FAIL: Could not delete large-packet accept rule"
        exit 1
 fi
@@ -355,8 +364,7 @@ fi
 ip netns exec ns1 sysctl net.ipv4.ip_no_pmtu_disc=0 > /dev/null
 ip netns exec ns2 sysctl net.ipv4.ip_no_pmtu_disc=0 > /dev/null
 
-test_tcp_forwarding_nat ns1 ns2
-if [ $? -eq 0 ] ;then
+if test_tcp_forwarding_nat ns1 ns2; then
        echo "PASS: flow offloaded for ns1/ns2 with NAT and pmtu discovery"
 else
        echo "FAIL: flow offload for ns1/ns2 with NAT and pmtu discovery" 1>&2
@@ -402,8 +410,7 @@ ip -net ns2 route del 192.168.10.1 via 10.0.2.1
 ip -net ns2 route add default via 10.0.2.1
 ip -net ns2 route add default via dead:2::1
 
-test_tcp_forwarding ns1 ns2
-if [ $? -eq 0 ] ;then
+if test_tcp_forwarding ns1 ns2; then
        echo "PASS: ipsec tunnel mode for ns1/ns2"
 else
        echo "FAIL: ipsec tunnel mode for ns1/ns2"
index ddaf140..994b11a 100644 (file)
@@ -12,4 +12,4 @@ memcpy_p7_t1
 copyuser_64_exc_t0
 copyuser_64_exc_t1
 copyuser_64_exc_t2
-memcpy_mcsafe_64
+copy_mc_64
index 0917983..3095b1f 100644 (file)
@@ -12,7 +12,7 @@ ASFLAGS = $(CFLAGS) -Wa,-mpower4
 TEST_GEN_PROGS := copyuser_64_t0 copyuser_64_t1 copyuser_64_t2 \
                copyuser_p7_t0 copyuser_p7_t1 \
                memcpy_64_t0 memcpy_64_t1 memcpy_64_t2 \
-               memcpy_p7_t0 memcpy_p7_t1 memcpy_mcsafe_64 \
+               memcpy_p7_t0 memcpy_p7_t1 copy_mc_64 \
                copyuser_64_exc_t0 copyuser_64_exc_t1 copyuser_64_exc_t2
 
 EXTRA_SOURCES := validate.c ../harness.c stubs.S
@@ -45,9 +45,9 @@ $(OUTPUT)/memcpy_p7_t%:       memcpy_power7.S $(EXTRA_SOURCES)
                -D SELFTEST_CASE=$(subst memcpy_p7_t,,$(notdir $@)) \
                -o $@ $^
 
-$(OUTPUT)/memcpy_mcsafe_64: memcpy_mcsafe_64.S $(EXTRA_SOURCES)
+$(OUTPUT)/copy_mc_64: copy_mc_64.S $(EXTRA_SOURCES)
        $(CC) $(CPPFLAGS) $(CFLAGS) \
-               -D COPY_LOOP=test_memcpy_mcsafe \
+               -D COPY_LOOP=test_copy_mc_generic \
                -o $@ $^
 
 $(OUTPUT)/copyuser_64_exc_t%: copyuser_64.S exc_validate.c ../harness.c \
diff --git a/tools/testing/selftests/powerpc/copyloops/copy_mc_64.S b/tools/testing/selftests/powerpc/copyloops/copy_mc_64.S
new file mode 120000 (symlink)
index 0000000..dcbe06d
--- /dev/null
@@ -0,0 +1 @@
+../../../../../arch/powerpc/lib/copy_mc_64.S
\ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/copyloops/memcpy_mcsafe_64.S b/tools/testing/selftests/powerpc/copyloops/memcpy_mcsafe_64.S
deleted file mode 120000 (symlink)
index f0feef3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../arch/powerpc/lib/memcpy_mcsafe_64.S
\ No newline at end of file
index 91c775c..aac4a59 100644 (file)
@@ -2,6 +2,7 @@
 hugetlb_vs_thp_test
 subpage_prot
 tempfile
+prot_sao
 segv_errors
 wild_bctr
 large_vm_fork_separation
index 250ce17..defe488 100644 (file)
@@ -2,7 +2,7 @@
 noarg:
        $(MAKE) -C ../
 
-TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot segv_errors wild_bctr \
+TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors wild_bctr \
                  large_vm_fork_separation bad_accesses pkey_exec_prot \
                  pkey_siginfo stack_expansion_signal stack_expansion_ldst
 
@@ -14,6 +14,8 @@ include ../../lib.mk
 
 $(TEST_GEN_PROGS): ../harness.c ../utils.c
 
+$(OUTPUT)/prot_sao: ../utils.c
+
 $(OUTPUT)/wild_bctr: CFLAGS += -m64
 $(OUTPUT)/large_vm_fork_separation: CFLAGS += -m64
 $(OUTPUT)/bad_accesses: CFLAGS += -m64
diff --git a/tools/testing/selftests/powerpc/mm/prot_sao.c b/tools/testing/selftests/powerpc/mm/prot_sao.c
new file mode 100644 (file)
index 0000000..30b71b1
--- /dev/null
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2016, Michael Ellerman, IBM Corp.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <asm/cputable.h>
+
+#include "utils.h"
+
+#define SIZE (64 * 1024)
+
+int test_prot_sao(void)
+{
+       char *p;
+
+       /*
+        * SAO was introduced in 2.06 and removed in 3.1. It's disabled in
+        * guests/LPARs by default, so also skip if we are running in a guest.
+        */
+       SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06) ||
+               have_hwcap2(PPC_FEATURE2_ARCH_3_1) ||
+               access("/proc/device-tree/rtas/ibm,hypertas-functions", F_OK) == 0);
+
+       /*
+        * Ensure we can ask for PROT_SAO.
+        * We can't really verify that it does the right thing, but at least we
+        * confirm the kernel will accept it.
+        */
+       p = mmap(NULL, SIZE, PROT_READ | PROT_WRITE | PROT_SAO,
+                MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+       FAIL_IF(p == MAP_FAILED);
+
+       /* Write to the mapping, to at least cause a fault */
+       memset(p, 0xaa, SIZE);
+
+       return 0;
+}
+
+int main(void)
+{
+       return test_harness(test_prot_sao, "prot-sao");
+}
index e8a657a..3845890 100644 (file)
@@ -1,8 +1,10 @@
 // SPDX-License-Identifier: LGPL-2.1
 #define _GNU_SOURCE
 #include <assert.h>
+#include <linux/membarrier.h>
 #include <pthread.h>
 #include <sched.h>
+#include <stdatomic.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -1131,6 +1133,220 @@ static int set_signal_handler(void)
        return ret;
 }
 
+struct test_membarrier_thread_args {
+       int stop;
+       intptr_t percpu_list_ptr;
+};
+
+/* Worker threads modify data in their "active" percpu lists. */
+void *test_membarrier_worker_thread(void *arg)
+{
+       struct test_membarrier_thread_args *args =
+               (struct test_membarrier_thread_args *)arg;
+       const int iters = opt_reps;
+       int i;
+
+       if (rseq_register_current_thread()) {
+               fprintf(stderr, "Error: rseq_register_current_thread(...) failed(%d): %s\n",
+                       errno, strerror(errno));
+               abort();
+       }
+
+       /* Wait for initialization. */
+       while (!atomic_load(&args->percpu_list_ptr)) {}
+
+       for (i = 0; i < iters; ++i) {
+               int ret;
+
+               do {
+                       int cpu = rseq_cpu_start();
+
+                       ret = rseq_offset_deref_addv(&args->percpu_list_ptr,
+                               sizeof(struct percpu_list_entry) * cpu, 1, cpu);
+               } while (rseq_unlikely(ret));
+       }
+
+       if (rseq_unregister_current_thread()) {
+               fprintf(stderr, "Error: rseq_unregister_current_thread(...) failed(%d): %s\n",
+                       errno, strerror(errno));
+               abort();
+       }
+       return NULL;
+}
+
+void test_membarrier_init_percpu_list(struct percpu_list *list)
+{
+       int i;
+
+       memset(list, 0, sizeof(*list));
+       for (i = 0; i < CPU_SETSIZE; i++) {
+               struct percpu_list_node *node;
+
+               node = malloc(sizeof(*node));
+               assert(node);
+               node->data = 0;
+               node->next = NULL;
+               list->c[i].head = node;
+       }
+}
+
+void test_membarrier_free_percpu_list(struct percpu_list *list)
+{
+       int i;
+
+       for (i = 0; i < CPU_SETSIZE; i++)
+               free(list->c[i].head);
+}
+
+static int sys_membarrier(int cmd, int flags, int cpu_id)
+{
+       return syscall(__NR_membarrier, cmd, flags, cpu_id);
+}
+
+/*
+ * The manager thread swaps per-cpu lists that worker threads see,
+ * and validates that there are no unexpected modifications.
+ */
+void *test_membarrier_manager_thread(void *arg)
+{
+       struct test_membarrier_thread_args *args =
+               (struct test_membarrier_thread_args *)arg;
+       struct percpu_list list_a, list_b;
+       intptr_t expect_a = 0, expect_b = 0;
+       int cpu_a = 0, cpu_b = 0;
+
+       if (rseq_register_current_thread()) {
+               fprintf(stderr, "Error: rseq_register_current_thread(...) failed(%d): %s\n",
+                       errno, strerror(errno));
+               abort();
+       }
+
+       /* Init lists. */
+       test_membarrier_init_percpu_list(&list_a);
+       test_membarrier_init_percpu_list(&list_b);
+
+       atomic_store(&args->percpu_list_ptr, (intptr_t)&list_a);
+
+       while (!atomic_load(&args->stop)) {
+               /* list_a is "active". */
+               cpu_a = rand() % CPU_SETSIZE;
+               /*
+                * As list_b is "inactive", we should never see changes
+                * to list_b.
+                */
+               if (expect_b != atomic_load(&list_b.c[cpu_b].head->data)) {
+                       fprintf(stderr, "Membarrier test failed\n");
+                       abort();
+               }
+
+               /* Make list_b "active". */
+               atomic_store(&args->percpu_list_ptr, (intptr_t)&list_b);
+               if (sys_membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ,
+                                       MEMBARRIER_CMD_FLAG_CPU, cpu_a) &&
+                               errno != ENXIO /* missing CPU */) {
+                       perror("sys_membarrier");
+                       abort();
+               }
+               /*
+                * Cpu A should now only modify list_b, so the values
+                * in list_a should be stable.
+                */
+               expect_a = atomic_load(&list_a.c[cpu_a].head->data);
+
+               cpu_b = rand() % CPU_SETSIZE;
+               /*
+                * As list_a is "inactive", we should never see changes
+                * to list_a.
+                */
+               if (expect_a != atomic_load(&list_a.c[cpu_a].head->data)) {
+                       fprintf(stderr, "Membarrier test failed\n");
+                       abort();
+               }
+
+               /* Make list_a "active". */
+               atomic_store(&args->percpu_list_ptr, (intptr_t)&list_a);
+               if (sys_membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ,
+                                       MEMBARRIER_CMD_FLAG_CPU, cpu_b) &&
+                               errno != ENXIO /* missing CPU*/) {
+                       perror("sys_membarrier");
+                       abort();
+               }
+               /* Remember a value from list_b. */
+               expect_b = atomic_load(&list_b.c[cpu_b].head->data);
+       }
+
+       test_membarrier_free_percpu_list(&list_a);
+       test_membarrier_free_percpu_list(&list_b);
+
+       if (rseq_unregister_current_thread()) {
+               fprintf(stderr, "Error: rseq_unregister_current_thread(...) failed(%d): %s\n",
+                       errno, strerror(errno));
+               abort();
+       }
+       return NULL;
+}
+
+/* Test MEMBARRIER_CMD_PRIVATE_RESTART_RSEQ_ON_CPU membarrier command. */
+#ifdef RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV
+void test_membarrier(void)
+{
+       const int num_threads = opt_threads;
+       struct test_membarrier_thread_args thread_args;
+       pthread_t worker_threads[num_threads];
+       pthread_t manager_thread;
+       int i, ret;
+
+       if (sys_membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ, 0, 0)) {
+               perror("sys_membarrier");
+               abort();
+       }
+
+       thread_args.stop = 0;
+       thread_args.percpu_list_ptr = 0;
+       ret = pthread_create(&manager_thread, NULL,
+                       test_membarrier_manager_thread, &thread_args);
+       if (ret) {
+               errno = ret;
+               perror("pthread_create");
+               abort();
+       }
+
+       for (i = 0; i < num_threads; i++) {
+               ret = pthread_create(&worker_threads[i], NULL,
+                               test_membarrier_worker_thread, &thread_args);
+               if (ret) {
+                       errno = ret;
+                       perror("pthread_create");
+                       abort();
+               }
+       }
+
+
+       for (i = 0; i < num_threads; i++) {
+               ret = pthread_join(worker_threads[i], NULL);
+               if (ret) {
+                       errno = ret;
+                       perror("pthread_join");
+                       abort();
+               }
+       }
+
+       atomic_store(&thread_args.stop, 1);
+       ret = pthread_join(manager_thread, NULL);
+       if (ret) {
+               errno = ret;
+               perror("pthread_join");
+               abort();
+       }
+}
+#else /* RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV */
+void test_membarrier(void)
+{
+       fprintf(stderr, "rseq_offset_deref_addv is not implemented on this architecture. "
+                       "Skipping membarrier test.\n");
+}
+#endif
+
 static void show_usage(int argc, char **argv)
 {
        printf("Usage : %s <OPTIONS>\n",
@@ -1153,7 +1369,7 @@ static void show_usage(int argc, char **argv)
        printf("        [-r N] Number of repetitions per thread (default 5000)\n");
        printf("        [-d] Disable rseq system call (no initialization)\n");
        printf("        [-D M] Disable rseq for each M threads\n");
-       printf("        [-T test] Choose test: (s)pinlock, (l)ist, (b)uffer, (m)emcpy, (i)ncrement\n");
+       printf("        [-T test] Choose test: (s)pinlock, (l)ist, (b)uffer, (m)emcpy, (i)ncrement, membarrie(r)\n");
        printf("        [-M] Push into buffer and memcpy buffer with memory barriers.\n");
        printf("        [-v] Verbose output.\n");
        printf("        [-h] Show this help.\n");
@@ -1268,6 +1484,7 @@ int main(int argc, char **argv)
                        case 'i':
                        case 'b':
                        case 'm':
+                       case 'r':
                                break;
                        default:
                                show_usage(argc, argv);
@@ -1320,6 +1537,10 @@ int main(int argc, char **argv)
                printf_verbose("counter increment\n");
                test_percpu_inc();
                break;
+       case 'r':
+               printf_verbose("membarrier\n");
+               test_membarrier();
+               break;
        }
        if (!opt_disable_rseq && rseq_unregister_current_thread())
                abort();
index b2da600..6404115 100644 (file)
@@ -279,6 +279,63 @@ error1:
 #endif
 }
 
+#define RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV
+
+/*
+ *   pval = *(ptr+off)
+ *  *pval += inc;
+ */
+static inline __attribute__((always_inline))
+int rseq_offset_deref_addv(intptr_t *ptr, off_t off, intptr_t inc, int cpu)
+{
+       RSEQ_INJECT_C(9)
+
+       __asm__ __volatile__ goto (
+               RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
+#endif
+               /* Start rseq by storing table entry pointer into rseq_cs. */
+               RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
+               RSEQ_INJECT_ASM(3)
+#ifdef RSEQ_COMPARE_TWICE
+               RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
+#endif
+               /* get p+v */
+               "movq %[ptr], %%rbx\n\t"
+               "addq %[off], %%rbx\n\t"
+               /* get pv */
+               "movq (%%rbx), %%rcx\n\t"
+               /* *pv += inc */
+               "addq %[inc], (%%rcx)\n\t"
+               "2:\n\t"
+               RSEQ_INJECT_ASM(4)
+               RSEQ_ASM_DEFINE_ABORT(4, "", abort)
+               : /* gcc asm goto does not allow outputs */
+               : [cpu_id]              "r" (cpu),
+                 [rseq_abi]            "r" (&__rseq_abi),
+                 /* final store input */
+                 [ptr]                 "m" (*ptr),
+                 [off]                 "er" (off),
+                 [inc]                 "er" (inc)
+               : "memory", "cc", "rax", "rbx", "rcx"
+                 RSEQ_INJECT_CLOBBER
+               : abort
+#ifdef RSEQ_COMPARE_TWICE
+                 , error1
+#endif
+       );
+       return 0;
+abort:
+       RSEQ_INJECT_FAILED
+       return -1;
+#ifdef RSEQ_COMPARE_TWICE
+error1:
+       rseq_bug("cpu_id comparison failed");
+#endif
+}
+
 static inline __attribute__((always_inline))
 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
                                 intptr_t *v2, intptr_t newv2,
index e426304..f51bc83 100755 (executable)
@@ -15,6 +15,7 @@ TEST_LIST=(
        "-T m"
        "-T m -M"
        "-T i"
+       "-T r"
 )
 
 TEST_NAME=(
@@ -25,6 +26,7 @@ TEST_NAME=(
        "memcpy"
        "memcpy with barrier"
        "increment"
+       "membarrier"
 )
 IFS="$OLDIFS"
 
index 7656c7c..0e73a16 100644 (file)
@@ -13,6 +13,7 @@ DESTRUCTIVE_TESTS = alarmtimer-suspend valid-adjtimex adjtick change_skew \
 
 TEST_GEN_PROGS_EXTENDED = $(DESTRUCTIVE_TESTS)
 
+TEST_FILES := settings
 
 include ../lib.mk
 
diff --git a/tools/testing/selftests/timers/settings b/tools/testing/selftests/timers/settings
new file mode 100644 (file)
index 0000000..e7b9417
--- /dev/null
@@ -0,0 +1 @@
+timeout=0
index 6af9519..312889e 100644 (file)
@@ -83,7 +83,7 @@ int main(int argc, char **argv)
        }
 
        if (shift)
-               printf("%u kB hugepages\n", 1 << shift);
+               printf("%u kB hugepages\n", 1 << (shift - 10));
        else
                printf("Default size hugepages\n");
        printf("Mapping %lu Mbytes\n", (unsigned long)length >> 20);
index 9983195..7161cfc 100644 (file)
@@ -443,6 +443,68 @@ static void test_unexpected_base(void)
 
 #define USER_REGS_OFFSET(r) offsetof(struct user_regs_struct, r)
 
+static void test_ptrace_write_gs_read_base(void)
+{
+       int status;
+       pid_t child = fork();
+
+       if (child < 0)
+               err(1, "fork");
+
+       if (child == 0) {
+               printf("[RUN]\tPTRACE_POKE GS, read GSBASE back\n");
+
+               printf("[RUN]\tARCH_SET_GS to 1\n");
+               if (syscall(SYS_arch_prctl, ARCH_SET_GS, 1) != 0)
+                       err(1, "ARCH_SET_GS");
+
+               if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0)
+                       err(1, "PTRACE_TRACEME");
+
+               raise(SIGTRAP);
+               _exit(0);
+       }
+
+       wait(&status);
+
+       if (WSTOPSIG(status) == SIGTRAP) {
+               unsigned long base;
+               unsigned long gs_offset = USER_REGS_OFFSET(gs);
+               unsigned long base_offset = USER_REGS_OFFSET(gs_base);
+
+               /* Read the initial base.  It should be 1. */
+               base = ptrace(PTRACE_PEEKUSER, child, base_offset, NULL);
+               if (base == 1) {
+                       printf("[OK]\tGSBASE started at 1\n");
+               } else {
+                       nerrs++;
+                       printf("[FAIL]\tGSBASE started at 0x%lx\n", base);
+               }
+
+               printf("[RUN]\tSet GS = 0x7, read GSBASE\n");
+
+               /* Poke an LDT selector into GS. */
+               if (ptrace(PTRACE_POKEUSER, child, gs_offset, 0x7) != 0)
+                       err(1, "PTRACE_POKEUSER");
+
+               /* And read the base. */
+               base = ptrace(PTRACE_PEEKUSER, child, base_offset, NULL);
+
+               if (base == 0 || base == 1) {
+                       printf("[OK]\tGSBASE reads as 0x%lx with invalid GS\n", base);
+               } else {
+                       nerrs++;
+                       printf("[FAIL]\tGSBASE=0x%lx (should be 0 or 1)\n", base);
+               }
+       }
+
+       ptrace(PTRACE_CONT, child, NULL, NULL);
+
+       wait(&status);
+       if (!WIFEXITED(status))
+               printf("[WARN]\tChild didn't exit cleanly.\n");
+}
+
 static void test_ptrace_write_gsbase(void)
 {
        int status;
@@ -517,6 +579,9 @@ static void test_ptrace_write_gsbase(void)
 
 END:
        ptrace(PTRACE_CONT, child, NULL, NULL);
+       wait(&status);
+       if (!WIFEXITED(status))
+               printf("[WARN]\tChild didn't exit cleanly.\n");
 }
 
 int main()
@@ -526,6 +591,9 @@ int main()
        shared_scratch = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
                              MAP_ANONYMOUS | MAP_SHARED, -1, 0);
 
+       /* Do these tests before we have an LDT. */
+       test_ptrace_write_gs_read_base();
+
        /* Probe FSGSBASE */
        sethandler(SIGILL, sigill, 0);
        if (sigsetjmp(jmpbuf, 1) == 0) {
index c41f24b..65c141e 100644 (file)
@@ -462,6 +462,17 @@ static int test_vsys_x(void)
        return 0;
 }
 
+/*
+ * Debuggers expect ptrace() to be able to peek at the vsyscall page.
+ * Use process_vm_readv() as a proxy for ptrace() to test this.  We
+ * want it to work in the vsyscall=emulate case and to fail in the
+ * vsyscall=xonly case.
+ *
+ * It's worth noting that this ABI is a bit nutty.  write(2) can't
+ * read from the vsyscall page on any kernel version or mode.  The
+ * fact that ptrace() ever worked was a nice courtesy of old kernels,
+ * but the code to support it is fairly gross.
+ */
 static int test_process_vm_readv(void)
 {
 #ifdef __x86_64__
@@ -477,8 +488,12 @@ static int test_process_vm_readv(void)
        remote.iov_len = 4096;
        ret = process_vm_readv(getpid(), &local, 1, &remote, 1, 0);
        if (ret != 4096) {
-               printf("[OK]\tprocess_vm_readv() failed (ret = %d, errno = %d)\n", ret, errno);
-               return 0;
+               /*
+                * We expect process_vm_readv() to work if and only if the
+                * vsyscall page is readable.
+                */
+               printf("[%s]\tprocess_vm_readv() failed (ret = %d, errno = %d)\n", vsyscall_map_r ? "FAIL" : "OK", ret, errno);
+               return vsyscall_map_r ? 1 : 0;
        }
 
        if (vsyscall_map_r) {
@@ -488,6 +503,9 @@ static int test_process_vm_readv(void)
                        printf("[FAIL]\tIt worked but returned incorrect data\n");
                        return 1;
                }
+       } else {
+               printf("[FAIL]\tprocess_rm_readv() succeeded, but it should have failed in this configuration\n");
+               return 1;
        }
 #endif
 
diff --git a/tools/usb/Build b/tools/usb/Build
new file mode 100644 (file)
index 0000000..2ad6f97
--- /dev/null
@@ -0,0 +1,2 @@
+testusb-y += testusb.o
+ffs-test-y += ffs-test.o
index 01d758d..1b128e5 100644 (file)
@@ -1,14 +1,51 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for USB tools
+include ../scripts/Makefile.include
 
-PTHREAD_LIBS = -lpthread
-WARNINGS = -Wall -Wextra
-CFLAGS = $(WARNINGS) -g -I../include
-LDFLAGS = $(PTHREAD_LIBS)
+bindir ?= /usr/bin
 
-all: testusb ffs-test
-%: %.c
-       $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+endif
+
+# Do not use make's built-in rules
+# (this improves performance and avoids hard-to-debug behaviour);
+MAKEFLAGS += -r
+
+override CFLAGS += -O2 -Wall -Wextra -g -D_GNU_SOURCE -I$(OUTPUT)include -I$(srctree)/tools/include
+override LDFLAGS += -lpthread
+
+ALL_TARGETS := testusb ffs-test
+ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
+
+all: $(ALL_PROGRAMS)
+
+export srctree OUTPUT CC LD CFLAGS
+include $(srctree)/tools/build/Makefile.include
+
+TESTUSB_IN := $(OUTPUT)testusb-in.o
+$(TESTUSB_IN): FORCE
+       $(Q)$(MAKE) $(build)=testusb
+$(OUTPUT)testusb: $(TESTUSB_IN)
+       $(QUIET_LINK)$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
+
+FFS_TEST_IN := $(OUTPUT)ffs-test-in.o
+$(FFS_TEST_IN): FORCE
+       $(Q)$(MAKE) $(build)=ffs-test
+$(OUTPUT)ffs-test: $(FFS_TEST_IN)
+       $(QUIET_LINK)$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
 
 clean:
-       $(RM) testusb ffs-test
+       rm -f $(ALL_PROGRAMS)
+       find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete -o -name '\.*.o.cmd' -delete
+
+install: $(ALL_PROGRAMS)
+       install -d -m 755 $(DESTDIR)$(bindir);          \
+       for program in $(ALL_PROGRAMS); do              \
+               install $$program $(DESTDIR)$(bindir);  \
+       done
+
+FORCE:
+
+.PHONY: all install clean FORCE prepare
index 58c0eab..0517c74 100644 (file)
@@ -78,6 +78,7 @@
 #define KPF_ARCH               38
 #define KPF_UNCACHED           39
 #define KPF_SOFTDIRTY          40
+#define KPF_ARCH_2             41
 
 /* [48-] take some arbitrary free slots for expanding overloaded flags
  * not part of kernel API
@@ -135,6 +136,7 @@ static const char * const page_flag_names[] = {
        [KPF_ARCH]              = "h:arch",
        [KPF_UNCACHED]          = "c:uncached",
        [KPF_SOFTDIRTY]         = "f:softdirty",
+       [KPF_ARCH_2]            = "H:arch_2",
 
        [KPF_READAHEAD]         = "I:readahead",
        [KPF_SLOB_FREE]         = "P:slob_free",
index 67cd0b8..cf88233 100644 (file)
@@ -4332,7 +4332,7 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
 void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
                               struct kvm_io_device *dev)
 {
-       int i;
+       int i, j;
        struct kvm_io_bus *new_bus, *bus;
 
        bus = kvm_get_bus(kvm, bus_idx);
@@ -4349,17 +4349,20 @@ void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
 
        new_bus = kmalloc(struct_size(bus, range, bus->dev_count - 1),
                          GFP_KERNEL_ACCOUNT);
-       if (!new_bus)  {
+       if (new_bus) {
+               memcpy(new_bus, bus, sizeof(*bus) + i * sizeof(struct kvm_io_range));
+               new_bus->dev_count--;
+               memcpy(new_bus->range + i, bus->range + i + 1,
+                      (new_bus->dev_count - i) * sizeof(struct kvm_io_range));
+       } else {
                pr_err("kvm: failed to shrink bus, removing it completely\n");
-               goto broken;
+               for (j = 0; j < bus->dev_count; j++) {
+                       if (j == i)
+                               continue;
+                       kvm_iodevice_destructor(bus->range[j].dev);
+               }
        }
 
-       memcpy(new_bus, bus, sizeof(*bus) + i * sizeof(struct kvm_io_range));
-       new_bus->dev_count--;
-       memcpy(new_bus->range + i, bus->range + i + 1,
-              (new_bus->dev_count - i) * sizeof(struct kvm_io_range));
-
-broken:
        rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
        synchronize_srcu_expedited(&kvm->srcu);
        kfree(bus);